Skip to content

Commit

Permalink
Merge pull request #35 from sass/docs
Browse files Browse the repository at this point in the history
docs: document public API, how to add new features
  • Loading branch information
wkillerud authored Jan 11, 2025
2 parents 1dd4921 + 41233e1 commit f896f67
Show file tree
Hide file tree
Showing 37 changed files with 720 additions and 411 deletions.
8 changes: 6 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ Thank you for showing an interest in contributing.

This project is an early proof of concept of a language server for Sass written in Dart to make use of [sass_api](https://pub.dev/packages/sass_api).

Check the documentation to get started:
Note that the Sass parser currently requires a valid document to generate an AST ([sass/dart-sass#2476](https://github.com/sass/dart-sass/issues/2476)),
making it impossible to implement certain features such as completions/IntelliSense.

You are still welcome to test and contribute where you can. Check the documentation and list of open issues to get started:

- [Development environment](./docs/contributing/development-environment.md)
- [Debugging](./docs/contributing/debugging.md)
- [Testing and debugging](./docs/contributing/testing-and-debugging.md)
- [Building](./docs/contributing/building.md)
- [Architecture](./docs/contributing/architecture.md)
- [Adding new language- or workspace features](./docs/contributing/adding-new-features.md)
29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,29 @@

This is a work-in-progress language server for Sass written in Dart to
use [sass_api](https://pub.dev/packages/sass_api).
It uses [the language server protocol](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#languageFeatures) (LSP).

See the [initial version roadmap](https://github.com/sass/dart-sass-language-server/issues/2) for the state of different features or check the documentation to get started:
## Status

- [Development environment](./docs/contributing/development-environment.md)
- [Testing and debugging](./docs/contributing/testing-and-debugging.md)
- [Building](./docs/contributing/building.md)
- [Architecture](./docs/contributing/architecture.md)
[Development of new features is paused](https://github.com/sass/dart-sass/issues/2476). See the Issues and Pull request tabs for planned and partially implemented features.

The [Testing and debugging](docs/contributing/testing-and-debugging.md) docs explain how to run the language server from source code.

These features are implemented:

| Feature | Specification |
| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Document highlights](pkgs/sass_language_services/lib/src/features/document_highlights/) | [textDocument/documentHighlight](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_documentHighlight) |
| [Document links](pkgs/sass_language_services/lib/src/features/document_links/) | [textDocument/documentLink](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_documentLink) |
| [Document symbols](pkgs/sass_language_services/lib/src/features/document_symbols/) | [textDocument/documentSymbol](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_documentSymbol) |
| [Find references](pkgs/sass_language_services/lib/src/features/find_references/) | [textDocument/references](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_references) |
| [Folding ranges](pkgs/sass_language_services/lib/src/features/folding_ranges/) | [textDocument/foldingRange](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_foldingRange) |
| [Go to definition](pkgs/sass_language_services/lib/src/features/go_to_definition/) | [textDocument/definition](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_definition) |
| [Hover](pkgs/sass_language_services/lib/src/features/hover/) | [textDocument/hover](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_hover) |
| [Rename](pkgs/sass_language_services/lib/src/features/rename/) | [textDocument/prepareRename](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_prepareRename), [textDocument/rename](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_rename) |
| [Selection ranges](pkgs/sass_language_services/lib/src/features/selection_ranges/) | [textDocument/selectionRange](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_selectionRange) |
| [Workspace symbol](pkgs/sass_language_services/lib/src/features/workspace_symbols/) | [workspace/symbol](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#workspace_symbol) |

## How to contribute

See [Contributing](./CONTRIBUTING.md), but note that the parser currently requires a valid Sass document to generate an AST ([sass/dart-sass#2476](https://github.com/sass/dart-sass/issues/2476)).
22 changes: 22 additions & 0 deletions docs/contributing/adding-new-features.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# How to add new features

This document explains some of the steps involved in adding a new language- or workspace feature.

For some complete examples, see:

- [Folding ranges (#32)](https://github.com/sass/dart-sass-language-server/pull/32/files)
- [Workspace symbols (#26)](https://github.com/sass/dart-sass-language-server/pull/26/files)

A summary of what you need:

1. Extend [language_configuration.dart](../../pkgs/sass_language_services/lib/src/configuration/language_configuration.dart) to parse the user's configuration for the feature.
2. Set defaults for the same user configuration in [the extension's package.json](../../extension/package.json) (look for the `"configuration"` key, and check for existing options).
3. Declare that the language server has the new capability in [language_server.dart](../../pkgs/sass_language_server/lib/src/language_server.dart) (look for `ServerCapabilities`).
4. Add a request handler for the feature in `language_server.dart` using `_connection.on<FeatureName>`. If a method doesn't exist for the feature, use the generic `_connection.peer.registerMethod()`.
5. Create a folder for the feature in [sass_language_services](../../pkgs/sass_language_services/lib/src/features/).
6. Implement the feature in a class that extends `LanguageFeature`.
- Look at existing features for some common patterns, such as how to parse a `TextDocument` to get the AST.
- You may want to know what AST node is at a given `Position`. See `node_at_offset_visitor.dart`.
- Use `findInWorkspace` to run a callback on each linked document, recursively (with a `lazy` option).
7. Add the feature to the public API in [language_services.dart](../../pkgs/sass_language_services/lib/src/language_services.dart).
8. Use the feature in the request handler in `language_server.dart`.
12 changes: 10 additions & 2 deletions docs/contributing/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@ We have this split so the language server features are reusable [for embedded la

This is the language server executable. Users will install this package, and the language client will run the server when needed.

This executable listens for incoming [JSON-RPC messages](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#languageServerProtocol). It handles [lifecycle messages](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#lifeCycleMessages) and [document synchronization](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_synchronization) so the language server can keep track of the document and workspace state.

It has handlers for the different [language features](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#languageFeatures) and [workspace features](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#workspaceFeatures), but the implementation of those features are in [sass_language_services](#sass_language_services).

## sass_language_services

This is where you find the core functionality of the language server. Individual features are in the `lib/src/features/` directory. Each feature extends a base `LanguageFeature` class.
This is where you find the core functionality of the language server. Individual features are in the [lib/src/features/](../../pkgs/sass_language_services/lib/src/features/) directory. Each feature extends a base `LanguageFeature` class.

When used, all features parse a given `TextDocument` using [`sass_api`](https://pub.dev/packages/sass_api) to get the [`Stylesheet` node](https://pub.dev/documentation/sass_api/latest/sass/Stylesheet-class.html). Parses are cached, along with other often-used information such as resolved links.

A feature typically returns a `Future` of some kind so it can traverse linked documents in order to be workspace-aware for features like Go to definition and Hover.

When used, all features parse the given `TextDocument` using [`sass_api`](https://pub.dev/packages/sass_api) to get the [`Stylesheet` node](https://pub.dev/documentation/sass_api/latest/sass/Stylesheet-class.html). Parses are cached, along with other often-used information such as resolved links.
A feature also typically returns a language server protocol response type, such as [Hover](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#hover).

## extension

Expand Down
6 changes: 4 additions & 2 deletions docs/contributing/building.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ Here we assume you have set up a [development environment](./development-environ

## Building the language server

In `pkgs/sass_language_server`:
In `pkgs/sass_language_server`, run this command:

```sh
dart compile exe bin/sass_language_server.dart -o bin/sass-language-server
```

This builds an executable for your current operating system named `sass-language-server`.
This builds an executable for your current operating system named `sass-language-server`. You can add this to your `PATH` and use it with any editor that has an LSP client.

Run `sass-language-server --help` to see available options.

## Building the language extension

Expand Down
3 changes: 0 additions & 3 deletions docs/contributing/development-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ To work on the language extension, or test your changes in Visual Studio Code:

- [Node.js v20 or higher](https://nodejs.org/en)
- [Visual Studio Code](https://code.visualstudio.com/) or [VSCodium](https://github.com/VSCodium/vscodium) (we'll refer to Visual Studio Code, VS Code for short, in the documentation)

### Recommended software

- [Dart extension for VS Code](https://github.com/Dart-Code/Dart-Code)

## Install dependencies
Expand Down
39 changes: 13 additions & 26 deletions docs/contributing/testing-and-debugging.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ Here we assume you have set up a [development environment](./development-environ

## Run the language extension and server

The quickest way to test the language server is to debug the language extension in Visual Studio Code. A debugging launch configuration is included in the repository. To use it:
The quickest way to test the language server is to debug the language extension in [Visual Studio Code](https://code.visualstudio.com). A debugging launch configuration is included in the repository. To use it:

1. Open this repository in VS Code.
2. Go to the Run and Debug view.
2. Go to the [Run and Debug view](https://code.visualstudio.com/docs/editor/debugging).
3. Pick Debug extension and language server from the menu.
4. Click Start debugging.

This will open another window of Visual Studio Code, this one running as an `[Extension Development Host]`.

### Find the link to Dart DevTools or VM service
### Attach the debugger

When debugging, the client runs [`dart run --enable-vm-service`](https://github.com/sass/dart-sass-language-server/blob/main/extension/src/server.ts#L49)
in the local `sass_language_server` package.
in the local `sass_language_server` package. This lets us attach a debugger to set breakpoints.

The video below demonstrates how to attach a debugger.

https://github.com/user-attachments/assets/d5143197-e092-483d-9d66-f1c9c52a075b

Use the `[Extension Development Host]` window to find the link to open Dart DevTools or to [attach the debugger](#attach-to-language-server).

Expand All @@ -32,37 +36,20 @@ The Dart VM service is listening on http://127.0.0.1:8181/SMIxtkPzlAY=/
The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8181/SMIxtkPzlAY=/devtools/?uri=ws://127.0.0.1:8181/SMIxtkPzlAY=/ws
```

Click the second link to open Dart DevTools, or copy the first link to [attach a debugger](#attach-to-language-server).

![screenshot showing the output pane and the dropdown with sass selected](https://github.com/user-attachments/assets/85839d2f-4305-4fb9-aeb0-d78f435e8b7d)

### Attach to language server

The debugger in Dart DevTools is deprecated in favor the debugger that ships with [Dart for Visual Studio Code][vscodedart].

To start debugging in VS Code (provided you have the Dart extension):

1. [Run the language server and extension](#run-the-language-extension-and-server) in debug mode.
2. [Find the link to the Dart VM](#find-the-link-to-dart-devtools-or-vm-service).

You should see output similar to this in the `[Extension Development Host]`.

```
The Dart VM service is listening on http://127.0.0.1:8181/SMIxtkPzlAY=/
The Dart DevTools debugger and profiler is available at: http://127.0.0.1:8181/SMIxtkPzlAY=/devtools/?uri=ws://127.0.0.1:8181/SMIxtkPzlAY=/ws
```

Copy the first link, then go back to the Run and debug window where you started the language server and extension.

1. Click the Run and debug drop-down and run `Attach to language server`.
2. Paste the link you copied and hit Enter.

Your debugger should be attached, allowing you to place breakpoints and step through code.

_The video below demonstrates how to attach a debugger._
### Dart DevTools

https://github.com/user-attachments/assets/d5143197-e092-483d-9d66-f1c9c52a075b
The second link in the Output pane is to the [Dart DevTools](https://dart.dev/tools/dart-devtools).

The debugger in Dart DevTools is deprecated in favor the debugger that ships with [Dart for Visual Studio Code][vscodedart], but the DevTools have other usefool tools such as a memory and CPU profiler.

![screenshot showing the output pane and the dropdown with sass selected](https://github.com/user-attachments/assets/85839d2f-4305-4fb9-aeb0-d78f435e8b7d)

### Test in VS Code without built-in SCSS features

Expand Down
8 changes: 6 additions & 2 deletions pkgs/sass_language_server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ A Dart implementation of a language server for Sass. The language server uses th

## Installing the Sass language server

### From Pub
See the contributing documentation for [how to build the language server](../../docs/contributing/building.md) so you can add it to your `PATH`.

<!--
<!-- Assuming this is how it will be -->
### From Pub
If you're a [Dart](https://dart.dev/get-dart) user, you can install the Sass language server globally using `pub global activate sass_language_server`, which will provide a `sass-language-server` executable.
-->

## Using the Sass language server

To use `sass-language-server` your editor needs a language client.
Expand Down
9 changes: 9 additions & 0 deletions pkgs/sass_language_server/lib/sass_language_server.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
/// The Sass language server.
///
/// Includes an executable `sass-language-server`. Run `sass-language-server --help` to see available options.
///
/// The server listens for incoming [JSON-RPC messages](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#languageServerProtocol). It handles [lifecycle messages](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#lifeCycleMessages) and [document synchronization](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#textDocument_synchronization) so the language server can keep track of the document and workspace state.
///
/// It has handlers for the different [language features](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#languageFeatures) and [workspace features](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#workspaceFeatures), but the implementation of those features are in `sass_language_services`.
library;

export 'src/local_file_system.dart' show LocalFileSystem;
export 'src/language_server.dart' show LanguageServer, Transport;
5 changes: 5 additions & 0 deletions pkgs/sass_language_server/lib/src/logger.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ int levelToRank(String level) {
}
}

/// An interface so send log messages to the client.
///
/// It's up to each individual editor how to display these log messages.
/// They may get shown in a status bar, in a dedicated output pane, or
/// not shown at all.
class Logger {
late RemoteConsole _console;
late int _level;
Expand Down
3 changes: 3 additions & 0 deletions pkgs/sass_language_services/lib/sass_language_services.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
/// if your language server is also written in Dart. Otherwise you may
/// want to use [the request forwarding pattern](https://code.visualstudio.com/api/language-extensions/embedded-languages#request-forwarding)
/// in your languages' client.
///
/// [LanguageServices] is the main public API.
library;

export 'src/configuration/configuration.dart' show LanguageServerConfiguration;
Expand All @@ -21,4 +23,5 @@ export 'src/file_system_provider.dart'
export 'src/language_services.dart' show LanguageServices;

export 'src/features/document_links/stylesheet_document_link.dart';
export 'src/features/document_symbols/scoped_symbols.dart';
export 'src/features/document_symbols/stylesheet_document_symbol.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'editor_configuration.dart';
import 'language_configuration.dart';
import 'workspace_configuration.dart';

/// User configuration for the different language server features.
class LanguageServerConfiguration {
late LanguageConfiguration css;
late LanguageConfiguration scss;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class EditorConfiguration {
colorDecoratorsLimit = config?['colorDecoratorsLimit'] as int? ?? 500;
insertSpaces = config?['insertSpaces'] as bool? ?? false;

// legacy reasons in VS Code
// legacy options in VS Code
var maybeIndentSize = config?['indentSize'];
if (maybeIndentSize is int) {
indentSize = maybeIndentSize;
Expand Down
Loading

0 comments on commit f896f67

Please sign in to comment.