diff --git a/docs/src/language-server/configure-a-client.md b/docs/src/language-server/configure-a-client.md index aab5a8ca..eae2996f 100644 --- a/docs/src/language-server/configure-a-client.md +++ b/docs/src/language-server/configure-a-client.md @@ -18,10 +18,8 @@ For example, while we may document `"somesass.scss.workspace.loadPaths": []` (an { "settings": { "somesass": { - "scss": { - "workspace": { - "loadPaths": [] - } + "workspace": { + "loadPaths": [] } } } diff --git a/docs/src/user-guide/settings.md b/docs/src/user-guide/settings.md index 64aa3c4d..8030e574 100644 --- a/docs/src/user-guide/settings.md +++ b/docs/src/user-guide/settings.md @@ -37,7 +37,7 @@ Once you turn off the built-in language features you can configure Some Sass to Now that you disabled the built-in language features you need to turn on those language features in Some Sass. -Open your user settings JSON and paste this configuration. You may want to restart VS Code to make sure the changes apply. +Open your user settings JSON and paste this configuration. Restart VS Code to make sure the changes apply. ```json { @@ -82,6 +82,15 @@ Open your user settings JSON and paste this configuration. You may want to resta You can configure similar settings for both SCSS, Sass (indented) and CSS. There are also some settings that apply to the workspace regardless of syntax. +### Workspace + +| Id | Description | Default | +| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | +| `somesass.workspace.loadPaths` | A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included. Note that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path). | `[]` | +| `somesass.workspace.exclude` | List of glob patterns for directories that are excluded in the initial scan for Sass files. Files in the exclude list will still be processed if referenced by `@use`, `@forward` and `@import` (for example a depencendy you use from `node_modules`). | `["**/.git/**", "**/node_modules/**"]` | +| `somesass.workspace.logLevel` | Control how much gets logged to the Output window. Possible values are `"silent"`, `"fatal"`, `"error"`, `"warn"`, `"info"`, `"debug"` and `"trace"`. | `"info"` | +| `some-sass.trace.server` | Log the messages sent between VS Code and the Some Sass language server. Possible values are `"off"`, `"messages"` and `"verbose"` | `"off"` | + ### SCSS For brevity the ID column omits the `somesass.scss` prefix. For example, to use the setting `codeAction.enabled` use the ID `somesass.scss.codeAction.enabled`. @@ -171,11 +180,3 @@ For brevity the ID column omits the `somesass.css` prefix. For example, to use t | `signatureHelp.enabled` | Enable or disable signature help. | `false` | | `workspaceSymbol.enabled` | Enable or disable workspace symbol. | `false` | | `customData` | A list of relative file paths pointing to JSON files following the [custom data format](https://github.com/microsoft/vscode-css-languageservice/blob/master/docs/customData.md). Some Sass loads custom data on startup to enhance its CSS support for CSS custom properties (variables), at-rules, pseudo-classes, and pseudo-elements you specify in the JSON files. The file paths are relative to workspace and only workspace folder settings are considered. | `[]` | - -### Workspace - -| Id | Description | Default | -| ------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- | -| `somesass.workspace.loadPaths` | A list of paths relative to the workspace root where the language server should look for stylesheets loaded by `@use` and `@import`. `node_modules` is always included. Note that you will have to [configure your Sass compiler separately](https://sass-lang.com/documentation/cli/dart-sass/#load-path). | `[]` | -| `somesass.workspace.exclude` | List of glob patterns for directories that are excluded in the initial scan for Sass files. Files in the exclude list will still be processed if referenced by `@use`, `@forward` and `@import` (for example a depencendy you use from `node_modules`). | `["**/.git/**", "**/node_modules/**"]` | -| `somesass.workspace.logLevel` | Control how much gets logged to the Output window. | `"info"` | diff --git a/packages/language-server/src/configuration.ts b/packages/language-server/src/configuration.ts index 72f894c4..4dc2b281 100644 --- a/packages/language-server/src/configuration.ts +++ b/packages/language-server/src/configuration.ts @@ -1,13 +1,13 @@ import { defaultConfiguration, - type LanguageServiceConfiguration, + type LanguageServerConfiguration, } from "@somesass/language-services"; import { Logger } from "./logger"; export function toNewConfiguration( v1: Partial, log: Logger, -): LanguageServiceConfiguration { +): LanguageServerConfiguration { const newSettings = Object.assign({}, defaultConfiguration, v1); if (v1.loadPaths) { log.info("somesass.loadPaths is now somesass.workspace.loadPaths"); @@ -73,7 +73,7 @@ export function toNewConfiguration( } export function isOldConfiguration( - maybeV1: Partial, + maybeV1: Partial, ) { const asV1 = maybeV1 as Partial; if (typeof asV1.loadPaths !== "undefined") return true; diff --git a/packages/language-server/src/embedded.ts b/packages/language-server/src/embedded.ts index bd0bfc88..a11d35ec 100644 --- a/packages/language-server/src/embedded.ts +++ b/packages/language-server/src/embedded.ts @@ -7,7 +7,11 @@ type Region = { }; export function isFileWhereScssCanBeEmbedded(path: string) { - if (path.endsWith(".scss") || path.endsWith(".sass")) { + if ( + path.endsWith(".scss") || + path.endsWith(".sass") || + path.endsWith(".css") + ) { return false; } return true; diff --git a/packages/language-server/src/server.ts b/packages/language-server/src/server.ts index 8cb76139..b904ba73 100644 --- a/packages/language-server/src/server.ts +++ b/packages/language-server/src/server.ts @@ -2,7 +2,9 @@ import { defaultConfiguration, getLanguageService, LanguageService, - LanguageServiceConfiguration, + LanguageServerConfiguration, + LanguageConfiguration, + EditorConfiguration, } from "@somesass/language-services"; import { ClientCapabilities, @@ -31,17 +33,13 @@ import { import { getSassRegionsDocument } from "./embedded"; import WorkspaceScanner from "./workspace-scanner"; import { createLogger, type Logger } from "./logger"; -import { - EditorConfiguration, - LanguageConfiguration, -} from "@somesass/language-services/dist/language-services-types"; import merge from "lodash.merge"; export class SomeSassServer { private readonly connection: Connection; private readonly runtime: RuntimeEnvironment; private readonly log: Logger; - private configuration: LanguageServiceConfiguration = defaultConfiguration; + private configuration: LanguageServerConfiguration = defaultConfiguration; constructor(connection: Connection, runtime: RuntimeEnvironment) { this.connection = connection; @@ -72,7 +70,6 @@ export class SomeSassServer { logger: this.log, }); - // TODO: migrate to workspace folders workspaceRoot = URI.parse(params.rootUri!); this.log.info(`Workspace root ${workspaceRoot}`); @@ -131,9 +128,9 @@ export class SomeSassServer { }); const applyConfiguration = ( - somesass: Partial, + somesass: Partial, editor: Partial, - ): LanguageServiceConfiguration => { + ): LanguageServerConfiguration => { if (isOldConfiguration(somesass)) { this.log.warn( `Your somesass configuration uses old setting names. They will continue to work for some time, but it's recommended you change your settings to the new names. For all the available settings see https://wkillerud.github.io/some-sass/user-guide/settings.html`, @@ -149,7 +146,7 @@ export class SomeSassServer { ); } - const settings: LanguageServiceConfiguration = merge( + const settings: LanguageServerConfiguration = merge( defaultConfiguration, somesass, { @@ -158,17 +155,15 @@ export class SomeSassServer { }, }, ); - settings.workspace.workspaceRoot = workspaceRoot; - if (settings.workspace.logLevel) { - this.log.setLogLevel(settings.workspace.logLevel); - } + settings.workspace.workspaceRoot = workspaceRoot; this.configuration = settings; if (ls) { ls.configure(settings); } + this.log.setLogLevel(settings.workspace.logLevel); this.log.debug("Applied user configuration"); this.log.trace(JSON.stringify(this.configuration, null, 2)); @@ -199,7 +194,7 @@ export class SomeSassServer { } let [somesass, editor] = configs as [ - Partial, + Partial, Partial, ]; @@ -276,7 +271,9 @@ export class SomeSassServer { } await doDiagnostics(params); } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); } }); @@ -286,7 +283,9 @@ export class SomeSassServer { ls.onDocumentChanged(params.document); await doDiagnostics(params); } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); } }); @@ -314,7 +313,9 @@ export class SomeSassServer { await workspaceScanner.scan(newFiles); } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); } }); @@ -338,7 +339,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -360,7 +363,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -382,7 +387,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -404,7 +411,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -429,7 +438,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -453,7 +464,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -479,7 +492,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -490,7 +505,9 @@ export class SomeSassServer { const result = ls.findWorkspaceSymbols(params.query); return result; } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -543,7 +560,9 @@ export class SomeSassServer { return result; } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -568,7 +587,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -594,7 +615,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -618,7 +641,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -643,7 +668,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -664,7 +691,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); @@ -688,7 +717,9 @@ export class SomeSassServer { return null; } } catch (e) { - this.log.debug((e as Error).message); + const error = e as Error; + this.log.debug(String(error)); + if (error.stack) this.log.debug(error.stack); return null; } }); diff --git a/packages/language-server/src/workspace-scanner.ts b/packages/language-server/src/workspace-scanner.ts index a6b1c5d1..9125c274 100644 --- a/packages/language-server/src/workspace-scanner.ts +++ b/packages/language-server/src/workspace-scanner.ts @@ -9,27 +9,17 @@ import { getSassRegionsDocument } from "./embedded"; export default class WorkspaceScanner { #ls: LanguageService; #fs: FileSystemProvider; - #settings: { scannerDepth: number; scanImportedFiles: boolean }; - constructor( - ls: LanguageService, - fs: FileSystemProvider, - settings = { scannerDepth: 256, scanImportedFiles: true }, - ) { + constructor(ls: LanguageService, fs: FileSystemProvider) { this.#ls = ls; this.#fs = fs; - - this.#settings = settings; } public async scan(files: URI[]): Promise { // Populate the cache for the new language services return Promise.all( files.map((uri) => { - if ( - this.#settings.scanImportedFiles && - (uri.path.includes("/_") || uri.path.includes("\\_")) - ) { + if (uri.path.includes("/_") || uri.path.includes("\\_")) { // If we scan imported files (which we do by default), don't include partials in the initial scan. // This way we can be reasonably sure that we scan whatever index files there are _before_ we scan // partials which may or may not have been forwarded with a prefix. @@ -41,8 +31,8 @@ export default class WorkspaceScanner { } private async parse(file: URI, depth = 0) { - const maxDepth = this.#settings.scannerDepth ?? 30; - if (depth > maxDepth || !this.#settings.scanImportedFiles) { + const maxDepth = 256; + if (depth > maxDepth) { return; } @@ -65,7 +55,11 @@ export default class WorkspaceScanner { document = getSassRegionsDocument( TextDocument.create( uriString, - uriString.endsWith(".sass") ? "sass" : "scss", + uriString.endsWith(".sass") + ? "sass" + : uriString.endsWith(".css") + ? "css" + : "scss", 1, content, ), @@ -80,7 +74,7 @@ export default class WorkspaceScanner { for (const link of links) { if ( !link.target || - link.target.endsWith(".css") || + link.target.endsWith(".css") || // we'll get to it via our glob link.target.includes("#{") || link.target.startsWith("sass:") ) { diff --git a/packages/language-services/src/features/do-complete.ts b/packages/language-services/src/features/do-complete.ts index 5ea68f66..20614532 100644 --- a/packages/language-services/src/features/do-complete.ts +++ b/packages/language-services/src/features/do-complete.ts @@ -975,7 +975,6 @@ export class DoComplete extends LanguageFeature { config.completion.mixinStyle !== "nobracket" && document.languageId === "scss" ) { - // TODO: test if this works correctly with multiline, I think so from the spec text const insertSnippet = `${insert} {\n\t$0\n}`; items.push({ ...base, diff --git a/packages/language-services/src/features/find-symbols.ts b/packages/language-services/src/features/find-symbols.ts index 6521fba9..7e6bdebc 100644 --- a/packages/language-services/src/features/find-symbols.ts +++ b/packages/language-services/src/features/find-symbols.ts @@ -72,7 +72,6 @@ export class FindSymbols extends LanguageFeature { // This is the exception to the rule that this enabled check // should happen at the server edge. It's only at this point // we know if the document should be included or not. - // Maybe a sign that this method should be lifted out of language-services. const config = this.languageConfiguration(document); if (config.workspaceSymbol.enabled) { const symbols = this.findDocumentSymbols(document); diff --git a/packages/language-services/src/language-services.ts b/packages/language-services/src/language-services.ts index 24089120..6166d802 100644 --- a/packages/language-services/src/language-services.ts +++ b/packages/language-services/src/language-services.ts @@ -21,6 +21,8 @@ import { LanguageModelCache as LanguageServerCache } from "./language-model-cach import { CodeActionContext, LanguageService, + LanguageConfiguration, + EditorConfiguration, LanguageServerConfiguration, LanguageServiceOptions, Position, @@ -38,7 +40,9 @@ import { mapFsProviders } from "./utils/fs-provider"; export { defaultConfiguration, LanguageService, - LanguageServerConfiguration as LanguageServiceConfiguration, + LanguageServerConfiguration, + LanguageConfiguration, + EditorConfiguration, FileStat, FileSystemProvider, FileType, diff --git a/vscode-extension/package.json b/vscode-extension/package.json index 4bc23b8e..c2d24bac 100644 --- a/vscode-extension/package.json +++ b/vscode-extension/package.json @@ -1,7 +1,7 @@ { "name": "some-sass", "displayName": "Some Sass", - "description": "Full support for @use and @forward, including aliases, prefixes and hiding. Rich documentation through SassDoc. Workspace-wide code navigation and refactoring.", + "description": "Improved support for SCSS, Sass indented and SassDoc. Workspace awareness and full support for Sass modules.", "version": "3.9.3", "private": true, "publisher": "SomewhatStationery", @@ -1300,14 +1300,14 @@ "order": 81, "type": "boolean", "scope": "resource", - "default": false, + "default": true, "description": "Show property and value documentation in CSS hovers." }, "somesass.css.hover.references": { "order": 82, "type": "boolean", "scope": "resource", - "default": false, + "default": true, "description": "Show references to MDN in CSS hovers." }, "somesass.css.links.enabled": { diff --git a/vscode-extension/src/client.ts b/vscode-extension/src/client.ts index 0b958cb4..2135c066 100644 --- a/vscode-extension/src/client.ts +++ b/vscode-extension/src/client.ts @@ -36,9 +36,8 @@ export function log(message: string): void { export function createLanguageClientOptions( currentWorkspace?: WorkspaceFolder, ): LanguageClientOptions { - // TODO: also include CSS if opted in - let documentSelector: DocumentSelector = [ + { scheme: "untitled", language: "css" }, { scheme: "untitled", language: "scss" }, { scheme: "untitled", language: "sass" }, { scheme: "untitled", language: "vue" }, @@ -55,16 +54,19 @@ export function createLanguageClientOptions( const webPattern = `${currentWorkspace.uri.path}**`; documentSelector = [ + { scheme: "file", language: "css", pattern }, { scheme: "file", language: "scss", pattern }, { scheme: "file", language: "sass", pattern }, { scheme: "file", language: "vue", pattern }, { scheme: "file", language: "svelte", pattern }, { scheme: "file", language: "astro", pattern }, + { scheme: "vscode-vfs", language: "css", pattern }, { scheme: "vscode-vfs", language: "scss", pattern }, { scheme: "vscode-vfs", language: "sass", pattern }, { scheme: "vscode-vfs", language: "vue", pattern }, { scheme: "vscode-vfs", language: "svelte", pattern }, { scheme: "vscode-vfs", language: "astro", pattern }, + { scheme: "vscode-test-web", language: "css", pattern: webPattern }, { scheme: "vscode-test-web", language: "scss", pattern: webPattern }, { scheme: "vscode-test-web", language: "sass", pattern: webPattern }, { scheme: "vscode-test-web", language: "vue", pattern: webPattern }, @@ -81,7 +83,7 @@ export function createLanguageClientOptions( ? workspace.createFileSystemWatcher({ baseUri: currentWorkspace.uri, base: currentWorkspace.uri.fsPath, - pattern: "**/*.{scss,sass,vue,svelte,astro}", + pattern: "**/*.{css,scss,sass,vue,svelte,astro}", }) : undefined, }, diff --git a/vscode-extension/src/node-client.ts b/vscode-extension/src/node-client.ts index 7974d940..7e007905 100644 --- a/vscode-extension/src/node-client.ts +++ b/vscode-extension/src/node-client.ts @@ -74,6 +74,7 @@ export async function activate(context: ExtensionContext): Promise { document.uri.scheme !== "file" && document.uri.scheme !== "untitled" && document.uri.scheme !== "vscode-vfs" && + document.languageId !== "css" && document.languageId !== "scss" && document.languageId !== "sass" && document.languageId !== "vue" &&