Skip to content

Commit db4cd19

Browse files
authored
feat: add two settings to tweak completions in other editors (#224)
Testing in Helix, which uses a different grammar for SCSS than Code, revealed a few annoying nits with compleitons. This version adds two new settings that can be useful for maintainers of language clients and editor configurations: - `somesass.completion.afterModule` - `somesass.completion.beforeVariable` `afterModule` lets you control whether or not to insert a `.` when accepting a suggestion from modules. If you see for instance `module..$variable` then try setting `afterModule` to an empty string. `beforeVariable` is for non-module variables. If you see double dollars (`$$variable`) then set `beforeVariable` to the empty string.
1 parent 396d342 commit db4cd19

File tree

12 files changed

+160
-25
lines changed

12 files changed

+160
-25
lines changed

docs/src/SUMMARY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
- [Getting started](language-server/getting-started.md)
1818
- [Configure a client](language-server/configure-a-client.md)
1919
- [Existing clients](language-server/existing-clients.md)
20+
- [Helix](language-server/helix.md)
2021
- [Kate](language-server/kate.md)
2122
- [Neovim](language-server/neovim.md)
23+
<!-- Sort alphabetically. Add new pages to existing-clients.md as well. -->
2224

2325
# Contributing to Some Sass
2426

@@ -27,6 +29,7 @@
2729
- [Extensions for VS Code](contributing/extensions-for-vs-code.md)
2830
- [Language Server Protocol](contributing/language-server-protocol.md)
2931
- [Development environment](contributing/development-environment.md)
32+
- [Testing in other editors](contributing/testing-other-editors.md)
3033
- [Architecture](contributing/architecture.md)
3134
- [Building](contributing/building.md)
3235
- [Automated tests](contributing/automated-tests.md)

docs/src/contributing/development-environment.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Development environment
22

3-
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.
3+
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 or VSCodium for development.
44

55
You need:
66

77
- A current long-term support version of [Node.js](https://nodejs.org/en)
8-
- [Visual Studio Code](https://code.visualstudio.com/)
8+
- [Visual Studio Code](https://code.visualstudio.com/) or [VSCodium](https://vscodium.com)
99

1010
Recommended extensions:
1111

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Testing in other editors
2+
3+
While it's recommended to use Visual Studio Code or VSCodium, you can use other editors to test and debug the language server.
4+
5+
In this document we'll look at how we can test our local development build in the Helix editor.
6+
7+
## Install the local version globally
8+
9+
To make the local version of `some-sass-language-server` available on `PATH`, go to its directory and run `npm install --global .`.
10+
11+
```sh
12+
cd packages/language-server/
13+
npm install --global .
14+
```
15+
16+
Editors using Some Sass from `PATH` now use your local build.
17+
18+
## Check the logs
19+
20+
In Helix, run the `hx` command with the `-v` verbose flag. Do your test, and then run the `:log-open` command to see the traffic between server and client.

docs/src/language-server/configure-a-client.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,32 @@ To configure a client for an editor that doesn't have one yet, check the documen
66

77
## Settings
88

9-
The language server requests [settings](../user-guide/settings.md) via the [`workspace/configuration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration), on the `somesass` key. All fields are optional.
9+
The language server requests settings via the [`workspace/configuration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration), on the `somesass` key. All fields are optional.
10+
11+
You can also configure the language server by sending the [`workspace/didChangeConfiguration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_didChangeConfiguration).
12+
13+
While settings keys are documented with dot-notation, the shape of the settings is a nested object.
14+
15+
For example, while we may document `"somesass.loadPaths": []` (and write it this way in `settings.json` in Code), the actual shape of the settings object sent to the server looks like this.
16+
17+
```json
18+
{
19+
"settings": {
20+
"somesass": {
21+
"loadPaths": []
22+
}
23+
}
24+
}
25+
```
26+
27+
### Server-only settings
28+
29+
In addition to [the user settings](../user-guide/settings.md), language clients may want to configure these server-only settings to tweak how certain features interact with your specific editor and its grammar for Sass.
30+
31+
| Key | Description |
32+
| ------------------------------------ | ----------------------------------------------------------------------------------------------------------- |
33+
| `somesass.completion.afterModule` | Set this to the empty string if you end up with `module..$variable` after accepting a code suggestion item. |
34+
| `somesass.completion.beforeVariable` | Set this to the empty string if you end up with `$$variable` after accepting a code suggestion item. |
1035

1136
## Existing clients
1237

docs/src/language-server/existing-clients.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

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

5+
<!-- Sort alphabetically. Add new pages to SUMMARY.md as well. -->
6+
- [Helix](./helix.md)
57
- [Kate](./kate.md)
68
- [Neovim](./neovim.md)
79

8-
<!-- Sort alphabetically. Add new pages to SUMMARY.md as well. -->

docs/src/language-server/getting-started.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,9 @@ some-sass-language-server --stdio
2222

2323
`--debug` – runs the development build of the language server, helpful to get more context if the server crashes
2424

25-
### Settings
25+
## Configure your editor's client
2626

27-
The language server requests [settings](../user-guide/settings.md) via the [`workspace/configuration` message](https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#workspace_configuration), on the `somesass` key. All fields are optional.
28-
29-
## Configure a client
30-
31-
The next step is to [configure a language client](./configure-a-client.md).
27+
The next step is to [configure your editor's language client](./configure-a-client.md).
3228

3329
[lsp]: https://microsoft.github.io/language-server-protocol/
3430
[npm]: https://www.npmjs.com/package/some-sass-language-server

docs/src/language-server/helix.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Helix
2+
3+
You can configure new language servers in [`.config/helix/languages.toml`](https://docs.helix-editor.com/guides/adding_languages.html).
4+
5+
[Install the language server if you haven't already](./getting-started.md), then add this config you `languages.toml`.
6+
7+
```toml
8+
[language-server.some-sass-language-server]
9+
command = "some-sass-language-server"
10+
args = ["--stdio"]
11+
config = { somesass = { completion = { afterModule = "", beforeVariable = "" } } }
12+
13+
[[language]]
14+
name = "scss"
15+
scope = "source.scss"
16+
injection-regex = "scss"
17+
file-types = ["scss"]
18+
block-comment-tokens = { start = "/*", end = "*/" }
19+
language-servers = [ "some-sass-language-server" ]
20+
auto-format = true
21+
indent = { tab-width = 2, unit = " " }
22+
```
23+
24+
The language server will start once you open an SCSS file.
25+
26+
At time of writing there doesn't seem to be a grammar for Sass indented available in Helix.

packages/language-server/src/server.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ export class SomeSassServer {
180180
suggestionStyle: settings.suggestionStyle,
181181
suggestFunctionsInStringContextAfterSymbols:
182182
settings.suggestFunctionsInStringContextAfterSymbols,
183+
afterModule: settings.completion?.afterModule,
184+
beforeVariable: settings.completion?.beforeVariable,
183185
},
184186
});
185187

@@ -282,6 +284,8 @@ export class SomeSassServer {
282284
suggestionStyle: settings.suggestionStyle,
283285
suggestFunctionsInStringContextAfterSymbols:
284286
settings.suggestFunctionsInStringContextAfterSymbols,
287+
afterModule: settings.completion?.afterModule,
288+
beforeVariable: settings.completion?.beforeVariable,
285289
},
286290
});
287291
});

packages/language-server/src/settings.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ export interface ISettings {
88
readonly suggestFromUseOnly: boolean;
99
readonly suggestFunctionsInStringContextAfterSymbols: " (+-*%";
1010
readonly triggerPropertyValueCompletion: boolean;
11+
readonly completion?: {
12+
afterModule?: string;
13+
beforeVariable?: string;
14+
};
1115
}
1216

1317
export interface IEditorSettings {

packages/language-services/src/features/do-complete.ts

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -848,14 +848,26 @@ export class DoComplete extends LanguageFeature {
848848
let filterText: string | undefined;
849849

850850
if (namespace && namespace !== "*") {
851+
const noDot =
852+
isEmbedded ||
853+
dotExt === ".sass" ||
854+
this.configuration.completionSettings?.afterModule === "";
855+
856+
const noDollar = isEmbedded;
857+
851858
insertText = currentWord.endsWith(".")
852-
? `${isEmbedded || dotExt === ".sass" ? "" : "."}${label}`
853-
: isEmbedded
859+
? `${noDot ? "" : "."}${label}`
860+
: noDollar
854861
? asDollarlessVariable(label)
855862
: label;
856863

857864
filterText = currentWord.endsWith(".") ? `${namespace}.${label}` : label;
858-
} else if (dotExt === ".vue" || dotExt === ".astro" || dotExt === ".sass") {
865+
} else if (
866+
dotExt === ".vue" ||
867+
dotExt === ".astro" ||
868+
dotExt === ".sass" ||
869+
this.configuration.completionSettings?.beforeVariable === ""
870+
) {
859871
// In these languages the $ does not get replaced by the suggestion,
860872
// so exclude it from the insertText.
861873
insertText = asDollarlessVariable(label);
@@ -907,12 +919,17 @@ export class DoComplete extends LanguageFeature {
907919
: symbol.name;
908920

909921
const isEmbedded = this.isEmbedded(initialDocument);
910-
const includeDot =
911-
namespace !== "*" && !isEmbedded && initialDocument.languageId !== "sass";
922+
923+
const noDot =
924+
namespace === "*" ||
925+
isEmbedded ||
926+
initialDocument.languageId === ".sass" ||
927+
this.configuration.completionSettings?.afterModule === "";
928+
912929
const insertText = namespace
913-
? includeDot
914-
? `.${prefix}${symbol.name}`
915-
: `${prefix}${symbol.name}`
930+
? noDot
931+
? `${prefix}${symbol.name}`
932+
: `.${prefix}${symbol.name}`
916933
: symbol.name;
917934

918935
const sortText = isPrivate ? label.replace(/^$[_]/, "") : undefined;
@@ -1035,12 +1052,17 @@ export class DoComplete extends LanguageFeature {
10351052
}
10361053

10371054
const isEmbedded = this.isEmbedded(initialDocument);
1038-
const includeDot =
1039-
namespace !== "*" && !isEmbedded && initialDocument.languageId !== "sass";
1055+
1056+
const noDot =
1057+
namespace === "*" ||
1058+
isEmbedded ||
1059+
initialDocument.languageId === ".sass" ||
1060+
this.configuration.completionSettings?.afterModule === "";
1061+
10401062
const insertText = namespace
1041-
? includeDot
1042-
? `.${prefix}${symbol.name}`
1043-
: `${prefix}${symbol.name}`
1063+
? noDot
1064+
? `${prefix}${symbol.name}`
1065+
: `.${prefix}${symbol.name}`
10441066
: symbol.name;
10451067

10461068
const sortText = isPrivate ? label.replace(/^$[_]/, "") : undefined;
@@ -1130,9 +1152,14 @@ export class DoComplete extends LanguageFeature {
11301152
// be replaced (except when we're embedded in Vue, Svelte or Astro).
11311153
// Example result: .floor(${1:number})
11321154
const isEmbedded = this.isEmbedded(document);
1133-
const includeDot = !isEmbedded && document.languageId !== "sass";
1155+
1156+
const noDot =
1157+
isEmbedded ||
1158+
document.languageId === ".sass" ||
1159+
this.configuration.completionSettings?.afterModule === "";
1160+
11341161
const insertText = context.currentWord.includes(".")
1135-
? `${includeDot ? "." : ""}${label}${
1162+
? `${noDot ? "" : "."}${label}${
11361163
signature ? `(${parameterSnippet})` : ""
11371164
}`
11381165
: label;

0 commit comments

Comments
 (0)