Some Sass

Some Sass is a language server extension for Visual Studio Code. It brings improved code suggestions, documentation and code navigation for SCSS.

Some features include:

  • Full support for @use and @forward, including aliases, prefixes and hiding.
  • Workspace-wide code navigation and refactoring, such as Rename Symbol.
  • Rich documentation through SassDoc.
  • Language features for %placeholders, both when using them and writing them.

Get the extension

You can find the extension here:

See the User guide section to learn more about what the extension can do.

Some Sass Language Server

Some Sass is also a language server using the Language Server Protocol (LSP).

The language server is published on npm, and can be used with any editor that has an LSP client. See Getting started to learn more.

To navigate between pages you can click the arrow buttons, press the left and right arrow keys on your keyboard, or use the sidebar menu.

To search click the magnifying class icon to the top left or press s on your keyboard.

IntelliSense

This page describes what Some Sass adds to code completions, also called IntelliSense in Visual Studio Code.

Namespaced suggestions

With the recommended settings, suggestions get limited to only the symbols available in that namespace. Code completions from Some Sass has full support for:

  • aliasing (@use "foo" as f;)
  • prefixes (@forward "foo" as bar-*;)
  • hide/show

Sass built-in modules (such as "sass:map") get the same treatment when imported with @use.

SassDoc block

Some Sass works best when you document your codebase with SassDoc. To make it easier you can let Some Sass generate a skeleton by typing /// and choosing SassDoc block.

SassDoc string literal union types

If you have a function or mixin that expects only a set of string values you can document them with a string literal union type. Some Sass will present the list of choices when you use them.

/// Get a timing value for use in animations.
/// @param {"sonic" | "link" | "homer" | "snorlax"} $mode - The timing you want
/// @return {String} - the timing value in ms
@function timing($mode) {
	@if map.has-key($_timings, $mode) {
		@return map.get($_timings, $mode);
	} @else {
		@error 'Unable to find a mode for #{$mode}';
	}
}

Signature helpers

For functions and mixins, Some Sass gives you signature helpers. These are small popups that show information about the mixin or function's parameters, and which one you are about to enter.

Placeholder selectors

There are two ways which Some Sass helps with code suggestions for placeholder selectors:

  • %placeholder-first workflows
  • @extend-first workflows

Placeholder first

This is where you write a placeholder selector first, and then @extend it somewhere else in your code. Some Sass will suggest all available placeholder selectors when you type @extend %.

Extend first

This workflow can be useful in scenarios where the selectors change, but the style should stay the same. You define a stylesheet with the selectors, @extend stable placeholder selectors, and then implement those placeholders. This workflow is for instance used in parts of the Discord theming community.

Import suggestions

When you write imports Some Sass reads the file system to help you complete the string.

pkg: imports

You can get a list of packages in the closest node_modules folder by manually triggering IntelliSense (Ctrl + Space) to help you write pkg: imports.

Navigation

This document describes the navigation features of Some Sass.

Go to definition

To use this feature, either:

  • Hold down Cmd/Ctrl and click a symbol.
  • Right-click a symbol and choose Go to Definition.
  • Press F12 when the cursor is at a symbol.

Go to definition reference.

Find references

To use this feature, either:

  • Right-click a symbol and choose Find all references.
  • Press Shift + Alt/Opt + F12 when the cursor is at a symbol.

Find all references reference.

Go to symbol

To use this feature, open the Go menu and choos either:

  • Go to symbol in Editor
  • Go to symbol in Workspace

Go to symbol reference.

Hover info

This document describes the hover information given by Some Sass.

Symbol information

When you hover over a symbol Some Sass shows a preview of the declaration and the name of the file where it is declared. Things get more interesting when you add SassDoc though.

SassDoc documentation

If a symbol is documented with SassDoc, the documentation is shown in the hover information like how you might see JSDoc. This is especially helpful if you have a core set of utility functions and mixins, or if you use a Sass library provided by a third party.

/// Calculate a responsive size value relative to a given screen size
/// Will return a CSS rule that corresponds to the given pixel size at
/// the given screen size and scales with changes in screen size
/// @param {Number} $px-size - Size to calculate from, in px without unit
/// @param {Number} $screen-width - Screen width to calculate from, in px without unit, default 1400
/// @param {Number} $screen-height - Screen height to calculate from, in px without unit, default 900
/// @return {Number} - Input expressed as a responsive value
@function relative-size($px-size, $screen-width: 1400, $screen-height: 900) {
	// ...
}

Screenshot showing hover info for a function named relative-size. There's a description of what the function does. There's a list of three parameters of type Number, two of them shown with default values and each with a description.

Sass built-ins

Hover information for Sass built-ins include links to the reference documentation.

Screenshot showing hover info for the floor function. The information reads Rounds down to the nearest number and includes a link titled Sass reference.

SassDoc annotations

Hover information for Sassdoc annotations link to the reference documentation.

Screenshot showing hover info for @param in a SassDoc block. @param and a link to SassDoc reference.

Refactoring

This document describes the refactoring features of Some Sass.

Rename symbol

With Some Sass installed you can rename a symbol and it is renamed across the whole workspace.

Rename symbols reference

Extract

Some Sass adds code actions to extract a selection to a variable, function or mixin.

Extract actions reference

Diagnostics

This document describes the diagnostics features of Some Sass.

Deprecated symbols

Symbols documented as @deprecated with SassDoc is shown with a strikethrough.

Color decorators

This document describes the color decorators features of Some Sass.

Decorators for Sass variables

Some Sass adds decorators for color variables where they are used.

Settings

This document describes the settings available in Some Sass.

These are the recommended settings:

{
	// Recommended if you don't rely on @import
	"somesass.suggestOnlyFromUse": true,

	// Optional, if you get suggestions from the current document after namespace.$ (you don't need the $ for narrowing down suggestions)
	"editor.wordBasedSuggestions": false,

	// Optional, for Vue, Svelte, Astro: add `scss` to the list of excluded languages for Emmet to avoid suggestions in Vue, Svelte or Astro files.
	// VS Code understands that <style lang="scss">`blocks are SCSS, and so won't show Emmet suggestions in that block.
	"emmet.excludeLanguages": [
		// Markdown is excluded by default in VS Code
		"markdown",
		"scss",
	],
}

About word-based suggestions

When you get completion suggestions and type namespace.$, Visual Studio Code treats $ as a fresh start for suggestions. It will start matching any variable in the current document. There are two ways to get around this:

  1. Turn off word-based suggestions by setting "editor.wordBasedSuggestions": false.
  2. Don't type the $ when you write the variable name, let completions fill it out for you.

With the second approach you can keep word-based suggestions turned on.

Settings reference

These are the settings you can use to tune Some Sass.

Code suggestion

Only include suggestions from used modules

If your project is on the modern module syntax (@use and @forward instead of @import), you may want to turn on this setting.

With this setting turned on, Some Sass will only suggest variables, mixins and functions from the namespaces that are in use in the open document. This setting will be turned on by default at some point after @import becomes CSS-only.

  • JSON key: somesass.suggestOnlyFromUse.
  • Default value: false.

Suggest variables, mixins, and functions from the open document

Visual Studio Code has built-in suggestions for variables, mixins and functions created in the open document.

By default Some Sass will not send suggestions for the same symbols. If you prefer the suggestions from Some Sass (for instance if you use SassDoc), you can opt in by turning on this setting. There will unfortunately be duplicates.

  • JSON key: somesass.suggestAllFromOpenDocument
  • Default value: false.

Suggestion style

Mixins with @content SassDoc annotations and %placeholders get two suggestions by default:

  • One without { }.
  • One with { }. This one creates a new block, and moves the cursor inside the block.

If you find this noisy, you can control which suggestions you would like to see:

  • All suggestions (default).
  • No brackets.
  • Only brackets. This still includes other suggestions, where there are no brackets to begin with.

Decide when function suggestions should kick in

Suggest functions after the specified symbols when in a string context. For example, if you add the / symbol to this setting, then background: url(images/he|) could suggest a hello() function (| in this case indicates cursor position).

  • JSON key: somesass.suggestFunctionsInStringContextAfterSymbols.
  • Default value: " (+-*%".

Workspace scanner

Exclude files or folders

List of micromatch patterns for directories that are excluded when scanning.

  • JSON key: somesass.scannerExclude.
  • Default value: ["**/.git/**", "**/node_modules/**", "**/bower_components/**"].

Adjust scanner depth

Depending on your project size, you may want to tweak this setting to control how many files are included.

  • JSON key: somesass.scannerDepth.
  • Default: 30.

@deprecated

If you don't want Some Sass to follow @import, @use or @forward links you can turn this setting off. This will limit functionality, and is not recommended. This setting will be removed at some point after @import becomes CSS-only.

  • JSON key: somesass.scanImportedFiles.
  • Default: true.

Use Some Sass outside Visual Studio Code

Some Sass is a language server using the Language Server Protocol (LSP).

The language server is published independently to npm, and can be used with any editor that has an LSP client. The server is designed to run alongside the VS Code CSS language server.

Getting started

You can install the language server with npm:

npm install --global some-sass-language-server

Then start the language server like so:

some-sass-language-server --stdio

Options

--debug โ€“ runs the development build of the language server, helpful to get more context if the server crashes

Settings

The language server requests settings via workspace/configuration on the somesass key. All fields are optional.

Configure a client

The next step is to configure a language client.

Configure a client

An editor needs a language client for the Language Server Protocol (LSP) to use a language server.

To configure a client for an editor that doesn't have one yet, check the documentation for your editor to see if it supports LSP natively. If not, there may be an extension, add-on or plugin that adds support for LSP.

Existing clients

This list of language client implementations may be a helpful starting point. You may also want to look at existing clients.

Existing clients

Editors with ready-configured clients, maintained by the community.

Neovim

Neovim has a ready-to-use client configuration maintained by the community.

There are two options:

New contributors

Thank you for showing an interest in contributing ๐ŸŒŸ

If you've never worked on Some Sass you're in the right place. There are several ways you can help.

  • Share your setup in Discussions' Show and tell.
  • Research open issues to find out what needs to be done.
  • Configure language clients for more editors.
  • Improve this documentation, add screenshots or recordings.
  • Add unit tests or end-to-end tests where missing.
  • Volunteer to fix bugs or add missing features.

Have a look at Writing documentation if you want to work on the docs.

Diving in to code? You may be interested in:

Extensions for Visual Studio Code

This is not required reading, but if you want to learn more about extension development these links are a good place to start.

Some Sass is a language server extension. It can also run in the browser. The project has automated end-to-end tests for both Electron and the browser.

Language Server Protocol

From Why Language Server?:

[The] Language Server Protocol [...] standardizes the communication between language tooling and code editor. This way [...] any LSP-compliant language toolings can integrate with multiple LSP-compliant code editors, and any LSP-compliant code editors can easily pick up multiple LSP-compliant language toolings. LSP is a win for both language tooling providers and code editor vendors!

In other words, LSP lets you build the language support tools once and run in any editor that has an LSP client.

For the most part you don't need to worry about the implementation details of the LSP. Microsoft's TypeScript implementation handles the nitty-gritty.

Language features

The Visual Studio Code documentation for Programatic language features gives a good sense of what's possible with LSP. If you want to dive deep, the specification lists all the messages and their parameters.

Development environment

The language server is written in TypeScript and runs both in Node and the browser. While the server can be used outside of Visual Studio Code, it's recommended to use VS Code for development.

You need:

Recommended extensions:

  • Vitest to help run and debug individual tests.

To preview the documentation you need mdbook. If you're on macOS and use Homebrew you can brew install mdbook.

Getting started

Clone the repo and install dependencies:

git clone git@github.com:wkillerud/some-sass.git
cd some-sass
npm install

Run the build and automated tests. Some of the automated tests open a new window and run in Visual Studio Code Insiders.

npm run build
npm run test:all

Watch mode

You can have nx watch the workspace for changes and rerun a minimum build:

npm run dev

Some packages have watch mode for unit tests using Vitest:

  • packages/language-server/
  • packages/language-services/

In packages with Vitest you start watch mode with the test script:

npm test

Next steps

You may want to have a look at the architecture of the language server. Most of the functionality of the language server is in the language-services package in packages/.

Test-driven development with Vitest and the VS Code debugger gives the shortest feedback loop.

Architecture

Being a language server extension, Some Sass consists of a client and a server. The client starts the server when it opens a file with SCSS. This is called activation.

From there everything happens via messages.

Some Sass also works with Visual Studio Code in the browser. It works more or less the same as the regular Node version, except it doesn't have direct access to the file system.

To work around this, the server makes requests to the client, which then uses the FileSystem API to work with files and directories, before sending the result back to the server.

Server architecture

The code for the server is divided in three packages:

  1. Language server
  2. Language services
  3. VS Code CSS language service โ€“ย the SCSS parser and language features that are included in VS Code.

Language server

This package handles communication with the language client, and not much else.

Language services

This is where you find the functionality of the language server, organized in classes that inherit from a base LanguageFeature class.

All features will parse the given document, but parses are cached for performance reasons. The flow looks something like this:

A language feature takes a text document and will try to get a data structure representing the document's Sass semantics such as variables, classes, functions and mixins.

The first time this happens the document gets sent to the parser, which returns this data structure. That result is cached. The next time a feature tries to get the data structure it will read from the cache. The cache entry is removed when the document changes so the new document can be parsed.

In addition to the parsed document, the cache also holds:

  • The results from resolving links (@use, @forward, @import).
  • The results from parsing the document's Sassdoc.
  • The document's symbols, as returned from findDocumentSymbols().

VS Code CSS language service

The project includes a private fork of the vscode-css-languageservice module. The original vscode-css-languageservice powers the CSS, SCSS and Less features in Visual Studio Code. Some Sass uses this module's parser and some of its language features. It's kept as a separate package to simplify updates, and to make it easier to send patches upstream.

Building

This document describes how to build Some Sass.

The workspace

This repo is an npm workspace with several packages listed in the "workspaces" key in the root package.json. The packages are listed in order with the "base" package at the top and the published language server and extension toward the bottom.

A full build

Run this command at the root level of the repo to build all packages:

npm run build

This will build all packages and the Visual Studio Code extension.

Partial builds

Each package has its own build command. If you made a change in the language-server folder you only have to build that and the vscode-extension packages. Of course you can allways do a full build if you want.

Clean builds

If something unexpected happens with your build you can do a clean build:

npm run clean
npm run build

This deletes any old build you may have before doing a new build.

Automated tests

This document describes how to run the automated tests and what the different tests cover.

Unit tests

All packages in packages/ have unit tests. To run them:

npm run test

The main test runner is Vitest. vscode-css-languageservice uses Mocha.

Unit tests typically cover either a utility function or a language feature such as doHover. For language features the tests are typically split in several files, each focusing on part of the functionality of the language feature.

End-to-end tests

The Visual Studio Code extension includes end-to-end tests. To run them:

npm run test:e2e

It also includes end-to-end tests for the web extension. To run them:

npm run test:web

The end-to-end tests have some overlap with the unit tests for language features, but are useful to confirm the communication between client and server works as expected.

Run all tests

A convenience script lets you run all unit tests and end-to-end tests:

npm run test:all

Test coverage

While there's no target for test coverage in the project, coverage reports can be useful to see if there's a corner case that should be tested.

Generate a coverage report

Coverage reports are generated per package. To generate a report run:

npm run coverage

Coverage reports are printed to the terminal. HTML versions you can open in a browser get generated in each package's directory. Look for a coverage/ folder and open index.html in your browser.

Debugging

This page assumes you're using Visual Studio Code as the debugger. Go to the Run and Debug pane in VS Code to find the different launch configurations.

  • Launch extension
  • Launch web extension
  • Launch integration tests
  • Launch web integration tests

Launch extension

This opens a new window of Visual Studio Code running as a local extension host. Open the Sass project you're using to test in the extension host window. If you don't have one you can open the folder vscode-extension/test/fixtures/ in this repository.

Set breakpoints

Find node-server.js in the vscode-extension/dist/ folder to set breakpoints. A good place to start is to search for the request handlers in server.ts like onCompletion and onHover.

Restart the debugger after building to see any changes you make in the code.

See log output

You'll find the log output in two places:

  1. The Debug console in the window where you started the debugger.
  2. The Output pane in the extension host (pick Some Sass from the dropdown).

Launch web extension

This opens a new window of Visual Studio Code running as a web extension host. Open the Sass project you're using to test in the extension host window. If you don't have one you can open the folder vscode-extension/test/fixtures/ in this repository.

Find browser-server.js in the vscode-extension/dist/ folder to set breakpoints.

Restart the debugger after building to see any changes you make in the code.

Debugging in the browser

You can use Some Sass with Visual Studio Code running in the browser. This document describes how you can test Some Sass running in Chromium.

Run the test command

In a terminal, run:

npm run start:web

This opens Visual Studio Code running as a web extension host in Chromium. The language server runs as a web worker, and is started when you open a Sass file.

Open the Sass project you're using to test in the extension host window. If you don't have one you can open the folder vscode-extension/test/fixtures/ in this repository.

Open the developer tools and click the Sources tab to set breakpoints.

The web worker for browser-server.js is in the left panel of the Sources tab. If you don't see it, make sure you open a Sass file to activate the extension.

In the WorkerExtensionHost you'll see localhost:3000 and serverExportVar. You may find it easier to navigate in severExportVar since it uses source maps to match the source code of the language server package.

Debugging unit tests

This document assumes you use Visual Studio Code and have the Vitest extension.

Open a unit test file (excluding tests in vscode-css-languageservice, which use Mocha) and find the test you want to debug.

You should see an icon in the gutter. To debug the test, right click and select Debug test.

Test-driven development

When you work on a language feature it's useful to set up a test and use that while developing.

The tests have an in-memory file system provider, so you can test how a language feature works with Sass code without making files on disk.

By using the Vitest debugger you can shorten the feedback loop significantly compared to building the whole project and testing manually in Visual Studio Code.

Debugging end-to-end tests

End-to-end tests run in Visual Studio Code and are helpful to ensure the user experience is as we expect. However, they can be tricky to write sometimes. This document describes how you can debug the tests themselves.

Prepare Visual Studio Code

The debugger runs tests in your version of Visual Studio Code, not VS Code insiders like when running the tests from the command line. You need to use the default settings for Some Sass (use the included workspace settings from the repo).

Launch the debugger

Go to the Run and Debug pane in VS Code and run Launch integration tests. The tests will start running immediately, and the window closes when the test run is finished.

You can set breakpoints directly in the test code in vscode-extension/test/e2e/.

Releasing new versions

This document describes how to release a new version of Some Sass.

Conventional Commits

This repository uses nx to manage release

nx reads conventional commits to determine what the new versions should be, and to generate changelogs. Which version is released depends on how you write the commit message.

Commit messageRelease type
docs: add guide for configuring sublimeNo new release.
fix: update css-languageservicePatch. Bugfix release, updates for runtime dependencies.
feat: add support for show keyword in forwardMinor. New feature release.
refactor: remove reduntant options for latest language version

BREAKING CHANGE: The scanImportedFiles option has been removed.
Major. Breaking release, like removing an option or changing engines version.
(Note that the BREAKING CHANGE: token must be in the footer of the commit)

Release process

To start a new release:

  1. Get the latest main branch with git checkout main && git pull.
  2. Run npx nx release --skip-publish.
  3. Push the changes and tags with git push && git push --tags.

GitHub Actions is configured to do the actual publishing when there are new tags.

Manual fallback

For npm packages:

npm version [major|minor|patch]
npm publish

For the VS Code extension:

vsce package

Then publish manually via Visual Studio Marketplace, Open VSX and GitHub Releases (attach the .vsix file to the release).

References:

Writing documentation

Help others get the most out of their software by contributing to documentation.

  • Do you have a pro tip you want to share?
  • Did you take a screenshot that can help visualize something?

New contributors are especially welcome to write documentation and add examples. As a new contributor you know best what is confusing or difficult.

Quick start

Fork and clone the repository from GitHub. The documentation is in the docs/src/ folder.

git clone git@github.com:wkillerud/some-sass.git

Once you're happy, commit the changes and prefix the commit message with docs:

git commit -m "docs: add GIF demoing Go to definition"

Preview the documentation

You need mdbook to preview the documentation on your machine.

If you're on macOS and use Homebrew you can brew install mdbook. Otherwise, check the mdbook user guide.

Once you have it installed, open a terminal and navigate to the docs/ directory.

cd docs
mdbook serve --open

Changes you make in Markdown files in docs/src/ are live updated in the browser.

Who we are writing for

We write for three different groups:

  1. Stylesheet developers who use Some Sass
  2. Users of editors other than Visual Studio Code who want to use Some Sass
  3. Developers who want to fix a bug or add to Some Sass

Each group should find sections and chapters in the sidebar to help guide them to what they are looking for.

Writing for stylesheet developers

A stylesheet developer doesn't need to learn about the inner workings of Some Sass. They are here to learn what the tool can do, or because something is not matching their expectations.

Introduce the reader to recommended settings early, including settings for the editor itself.

Screenshots and recordings

Show what you explained in writing using one or more screenshots if you can. Media should come after the paragraph explaining a feature.

If something is better conveyed in a screen recording, prefer an image format like GIF over video. Recordings should be short and showcase one thing. The quality must be good enough that text is legible. For an example, see the IntelliSense documentation in Visual Studio Code.

Writing for users of editors other than Visual Studio Code

Users of editors other than Visual Studio Code who want to use Some Sass need to know:

  1. That it's possible to do so
  2. How to do it

Assume the reader is new to the language server protocol and has never configured a language server client. Examples are a great help here.

Writing for developers who want to change or add to Some Sass

Here we need to consider both new and returning developers.

Onboarding

For new developers:

  • Assume the reader has never written an extension for Visual Studio Code.
  • Assume the reader is new to the Language Server Protocol.

Introduce new contributors to these topics, and link to external material if they want to learn more. Also introduce the architecture so they have a better idea of where to start. Visualize with diagrams.

Explain how they should set up their development environment to be productive.

Guides

All developers (including your future self) could use a guide for common tasks like testing and debugging. This documentation can assume the reader completed the onboarding.

Writing style guide

These are more guidelines than actual rules.

  • The first time you reference Visual Studio Code below a heading, write out the full name. After that you can use VS Code.
  • Prefer Excalidraw for diagrams, exported as PNG and included in Markdown as an image.

The Hemingway Editor is a free tool to help edit your writing. You can also refer to these notes from Google Technical Writing One if you'd like. That said, don't worry too much about the details.