Skip to content

Commit

Permalink
refactor: prepare ls for customData
Browse files Browse the repository at this point in the history
  • Loading branch information
wkillerud committed Dec 8, 2024
1 parent 9bb800b commit 4bc952a
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 75 deletions.
67 changes: 19 additions & 48 deletions packages/language-services/src/language-feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,11 @@ import {
Scanner,
SassScanner,
} from "@somesass/vscode-css-languageservice";
import merge from "lodash.merge";
import { defaultConfiguration } from "./configuration";
import { LanguageModelCache } from "./language-model-cache";
import {
LanguageServiceOptions,
TextDocument,
LanguageService,
LanguageServerConfiguration,
NodeType,
Range,
SassDocumentSymbol,
Expand All @@ -22,14 +19,13 @@ import {
VariableDeclaration,
URI,
Utils,
ClientCapabilities,
RecursivePartial,
LanguageConfiguration,
LanguageServerConfiguration,
ClientCapabilities,
} from "./language-services-types";
import { asDollarlessVariable } from "./utils/sass";

export type LanguageFeatureInternal = {
cache: LanguageModelCache;
cssLs: VSCodeLanguageService;
sassLs: VSCodeLanguageService;
scssLs: VSCodeLanguageService;
Expand All @@ -52,13 +48,19 @@ type FindOptions = {
export abstract class LanguageFeature {
protected ls;
protected options;
protected clientCapabilities: ClientCapabilities;
protected configuration: LanguageServerConfiguration = defaultConfiguration;

private _internal: LanguageFeatureInternal;

protected get cache(): LanguageModelCache {
return this._internal.cache;
return this.ls.cache;
}

protected get configuration(): LanguageServerConfiguration {
return this.ls.configuration;
}

protected get clientCapabilities(): ClientCapabilities {
return this.ls.clientCapabilities;
}

constructor(
Expand All @@ -68,59 +70,25 @@ export abstract class LanguageFeature {
) {
this.ls = ls;
this.options = options;
this.clientCapabilities = options.clientCapabilities;
this._internal = _internal;
}

languageConfiguration(document: TextDocument): LanguageConfiguration {
switch (document.languageId) {
case "css": {
return this.configuration.css;
return this.ls.configuration.css;
}
case "sass": {
return this.configuration.sass;
return this.ls.configuration.sass;
}
case "scss": {
return this.configuration.scss;
return this.ls.configuration.scss;
}
}

throw new Error(`Unsupported language ${document.languageId}`);
}

configure(
configuration: RecursivePartial<LanguageServerConfiguration>,
): void {
this.configuration = merge(defaultConfiguration, configuration);

this._internal.sassLs.configure({
validate: this.configuration.sass.diagnostics.enabled,
lint: this.configuration.sass.diagnostics.lint,
completion: this.configuration.sass.completion,
hover: this.configuration.sass.hover,
importAliases: this.configuration.workspace.importAliases,
loadPaths: this.configuration.workspace.loadPaths,
});

this._internal.scssLs.configure({
validate: this.configuration.scss.diagnostics.enabled,
lint: this.configuration.scss.diagnostics.lint,
completion: this.configuration.scss.completion,
hover: this.configuration.scss.hover,
importAliases: this.configuration.workspace.importAliases,
loadPaths: this.configuration.workspace.loadPaths,
});

this._internal.cssLs.configure({
validate: this.configuration.css.diagnostics.enabled,
lint: this.configuration.css.diagnostics.lint,
completion: this.configuration.css.completion,
hover: this.configuration.css.hover,
importAliases: this.configuration.workspace.importAliases,
loadPaths: this.configuration.workspace.loadPaths,
});
}

protected getUpstreamLanguageServer(
document: TextDocument,
): VSCodeLanguageService {
Expand All @@ -140,9 +108,12 @@ export abstract class LanguageFeature {
* @returns The resolved path
*/
resolveReference: (ref: string, base: string) => {
if (ref.startsWith("/") && this.configuration.workspace.workspaceRoot) {
if (
ref.startsWith("/") &&
this.ls.configuration.workspace.workspaceRoot
) {
return Utils.joinPath(
this.configuration.workspace.workspaceRoot,
this.ls.configuration.workspace.workspaceRoot,
ref,
).toString(true);
}
Expand Down
20 changes: 20 additions & 0 deletions packages/language-services/src/language-services-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
FoldingRange,
FoldingRangeKind,
SelectionRange,
ICSSDataProvider,
} from "@somesass/vscode-css-languageservice";
import type { ParseResult } from "sassdoc-parser";
import { TextDocument } from "vscode-languageserver-textdocument";
Expand Down Expand Up @@ -63,6 +64,7 @@ import {
} from "vscode-languageserver-types";
import { URI, Utils } from "vscode-uri";
import { FoldingRangeContext } from "./features/folding-ranges";
import { LanguageModelCache } from "./language-model-cache";

/**
* The root of the abstract syntax tree.
Expand All @@ -83,6 +85,11 @@ export type RecursivePartial<T> = {
};

export interface LanguageService {
readonly cache: LanguageModelCache;
readonly clientCapabilities: ClientCapabilities;
readonly configuration: LanguageServerConfiguration;
readonly fs: FileSystemProvider;

/**
* Clears all cached documents, forcing everything to be reparsed the next time a feature is used.
*/
Expand Down Expand Up @@ -179,8 +186,21 @@ export interface LanguageService {
): Promise<
null | { defaultBehavior: boolean } | { range: Range; placeholder: string }
>;
/**
* Load custom data sets, for example custom at-rules, for use in completions and diagnostics.
*
* @see https://github.com/microsoft/vscode-css-languageservice/blob/main/docs/customData.md
*/
setDataProviders(
customDataProviders: ICSSDataProvider[],
options?: SetDataProvidersOptions,
): void;
}

export type SetDataProvidersOptions = {
useDefaultProviders: boolean;
};

export type Rename =
| { range: Range; placeholder: string }
| { defaultBehavior: boolean };
Expand Down
112 changes: 85 additions & 27 deletions packages/language-services/src/language-services.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import {
getCSSLanguageService,
getSassLanguageService,
ICSSDataProvider,
LanguageService as UpstreamLanguageService,
} from "@somesass/vscode-css-languageservice";
import merge from "lodash.merge";
import { defaultConfiguration } from "./configuration";
import { CodeActions } from "./features/code-actions";
import { DoComplete } from "./features/do-complete";
Expand All @@ -17,7 +20,7 @@ import { FindReferences } from "./features/find-references";
import { FindSymbols } from "./features/find-symbols";
import { FoldingRangeContext, FoldingRanges } from "./features/folding-ranges";
import { SelectionRanges } from "./features/selection-ranges";
import { LanguageModelCache as LanguageServerCache } from "./language-model-cache";
import { LanguageModelCache } from "./language-model-cache";
import {
CodeActionContext,
LanguageService,
Expand All @@ -34,6 +37,9 @@ import {
Range,
ReferenceContext,
URI,
SetDataProvidersOptions,
RecursivePartial,
ClientCapabilities,
} from "./language-services-types";
import { mapFsProviders } from "./utils/fs-provider";

Expand All @@ -55,7 +61,6 @@ export function getLanguageService(
}

class LanguageServiceImpl implements LanguageService {
#cache: LanguageServerCache;
#codeActions: CodeActions;
#doComplete: DoComplete;
#doDiagnostics: DoDiagnostics;
Expand All @@ -71,27 +76,55 @@ class LanguageServiceImpl implements LanguageService {
#foldingRanges: FoldingRanges;
#selectionRanges: SelectionRanges;

#configuration = defaultConfiguration;
get configuration(): LanguageServerConfiguration {
return this.#configuration;
}

#cache: LanguageModelCache;
get cache(): LanguageModelCache {
return this.#cache;
}

#clientCapabilities: ClientCapabilities;
get clientCapabilities(): ClientCapabilities {
return this.#clientCapabilities;
}

#fs: FileSystemProvider;
get fs(): FileSystemProvider {
return this.#fs;
}

#cssLs: UpstreamLanguageService;
#sassLs: UpstreamLanguageService;
#scssLs: UpstreamLanguageService;

constructor(options: LanguageServiceOptions) {
this.#clientCapabilities = options.clientCapabilities;
this.#fs = options.fileSystemProvider;

const vscodeLsOptions = {
clientCapabilities: options.clientCapabilities,
clientCapabilities: this.clientCapabilities,
fileSystemProvider: mapFsProviders(options.fileSystemProvider),
};
const sassLs = getSassLanguageService(vscodeLsOptions);

const cache = new LanguageServerCache({
sassLs,
this.#cssLs = getCSSLanguageService(vscodeLsOptions);
this.#sassLs = getSassLanguageService(vscodeLsOptions);
// The server code is the same as sassLs, but separate on syntax in case the user has different settings
this.#scssLs = getSassLanguageService(vscodeLsOptions);

this.#cache = new LanguageModelCache({
sassLs: this.#sassLs,
...options.languageModelCache,
});

const internal = {
cache,
sassLs,
cssLs: getCSSLanguageService(vscodeLsOptions),
// The server code is the same as sassLs, but separate on syntax in case the user has different settings
scssLs: getSassLanguageService(vscodeLsOptions),
cssLs: this.#cssLs,
sassLs: this.#sassLs,
scssLs: this.#scssLs,
};

this.#cache = cache;
this.#codeActions = new CodeActions(this, options, internal);
this.#doComplete = new DoComplete(this, options, internal);
this.#doDiagnostics = new DoDiagnostics(this, options, internal);
Expand All @@ -112,21 +145,46 @@ class LanguageServiceImpl implements LanguageService {
this.#selectionRanges = new SelectionRanges(this, options, internal);
}

configure(configuration: LanguageServerConfiguration): void {
this.#codeActions.configure(configuration);
this.#doComplete.configure(configuration);
this.#doDiagnostics.configure(configuration);
this.#doHover.configure(configuration);
this.#doRename.configure(configuration);
this.#doSignatureHelp.configure(configuration);
this.#findColors.configure(configuration);
this.#findDefinition.configure(configuration);
this.#findDocumentHighlights.configure(configuration);
this.#findDocumentLinks.configure(configuration);
this.#findReferences.configure(configuration);
this.#findSymbols.configure(configuration);
this.#foldingRanges.configure(configuration);
this.#selectionRanges.configure(configuration);
configure(
configuration: RecursivePartial<LanguageServerConfiguration>,
): void {
this.#configuration = merge(defaultConfiguration, configuration);

this.#sassLs.configure({
validate: this.configuration.sass.diagnostics.enabled,
lint: this.configuration.sass.diagnostics.lint,
completion: this.configuration.sass.completion,
hover: this.configuration.sass.hover,
importAliases: this.configuration.workspace.importAliases,
loadPaths: this.configuration.workspace.loadPaths,
});

this.#scssLs.configure({
validate: this.configuration.scss.diagnostics.enabled,
lint: this.configuration.scss.diagnostics.lint,
completion: this.configuration.scss.completion,
hover: this.configuration.scss.hover,
importAliases: this.configuration.workspace.importAliases,
loadPaths: this.configuration.workspace.loadPaths,
});

this.#cssLs.configure({
validate: this.configuration.css.diagnostics.enabled,
lint: this.configuration.css.diagnostics.lint,
completion: this.configuration.css.completion,
hover: this.configuration.css.hover,
importAliases: this.configuration.workspace.importAliases,
loadPaths: this.configuration.workspace.loadPaths,
});
}

setDataProviders(
providers: ICSSDataProvider[],
options: SetDataProvidersOptions = { useDefaultProviders: true },
): void {
this.#cssLs.setDataProviders(options.useDefaultProviders, providers);
this.#sassLs.setDataProviders(options.useDefaultProviders, providers);
this.#scssLs.setDataProviders(options.useDefaultProviders, providers);
}

parseStylesheet(document: TextDocument) {
Expand Down

0 comments on commit 4bc952a

Please sign in to comment.