diff --git a/package.json b/package.json index 9989b5ad..1df61b6e 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "@lerna-lite/cli": "latest", "@lerna-lite/exec": "latest", "@lerna-lite/publish": "latest", - "@volar/language-service": "~2.2.3", + "@volar/language-service": "~2.3.0-alpha.0", "@volar/tsl-config": "latest", "tsl": "latest", "typescript": "latest", diff --git a/packages/css/index.ts b/packages/css/index.ts index 6e1abf6d..2c30ad66 100644 --- a/packages/css/index.ts +++ b/packages/css/index.ts @@ -1,4 +1,4 @@ -import type { CodeAction, Diagnostic, Disposable, DocumentSelector, FormattingOptions, LocationLink, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; +import type { CodeAction, Diagnostic, Disposable, DocumentSelector, FormattingOptions, LocationLink, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; import * as css from 'vscode-css-languageservice'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { URI, Utils } from 'vscode-uri'; @@ -16,22 +16,22 @@ export function create({ getDocumentContext = context => { return { resolveReference(ref, base) { - const decoded = context.decodeEmbeddedDocumentUri(base); + let baseUri = URI.parse(base); + const decoded = context.decodeEmbeddedDocumentUri(baseUri); if (decoded) { - base = decoded[0]; + baseUri = decoded[0]; } if (ref.match(/^\w[\w\d+.-]*:/)) { // starts with a schema return ref; } - if (ref[0] === '/') { // resolve absolute path against the current workspace folder - let folderUri = context.env.workspaceFolder; + if (ref[0] === '/' && context.env.workspaceFolders.length) { // resolve absolute path against the current workspace folder + let folderUri = context.env.workspaceFolders[0].toString(); if (!folderUri.endsWith('/')) { folderUri += '/'; } return folderUri + ref.substring(1); } - const baseUri = URI.parse(base); const baseUriDir = baseUri.path.endsWith('/') ? baseUri : Utils.dirname(baseUri); return Utils.resolvePath(baseUriDir, ref).toString(true); }, @@ -53,15 +53,18 @@ export function create({ const customData: string[] = await context.env.getConfiguration?.('css.customData') ?? []; const newData: css.ICSSDataProvider[] = []; for (const customDataPath of customData) { - const uri = Utils.resolvePath(URI.parse(context.env.workspaceFolder), customDataPath); - const json = await context.env.fs?.readFile?.(uri.toString()); - if (json) { - try { - const data = JSON.parse(json); - newData.push(css.newCSSDataProvider(data)); - } - catch (error) { - console.error(error); + for (const workspaceFolder of context.env.workspaceFolders) { + const uri = Utils.resolvePath(workspaceFolder, customDataPath); + const json = await context.env.fs?.readFile?.(uri); + if (json) { + try { + const data = JSON.parse(json); + newData.push(css.newCSSDataProvider(data)); + } + catch (error) { + console.error(error); + } + break; } } } @@ -80,24 +83,43 @@ export function create({ scssDocumentSelector?: DocumentSelector, lessDocumentSelector?: DocumentSelector, useDefaultDataProvider?: boolean; - getDocumentContext?(context: ServiceContext): css.DocumentContext; - isFormattingEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: ServiceContext): ProviderResult; - getLanguageSettings?(document: TextDocument, context: ServiceContext): ProviderResult; - getCustomData?(context: ServiceContext): ProviderResult; - onDidChangeCustomData?(listener: () => void, context: ServiceContext): Disposable; + getDocumentContext?(context: LanguageServiceContext): css.DocumentContext; + isFormattingEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: LanguageServiceContext): ProviderResult; + getLanguageSettings?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getCustomData?(context: LanguageServiceContext): ProviderResult; + onDidChangeCustomData?(listener: () => void, context: LanguageServiceContext): Disposable; } = {}): LanguageServicePlugin { return { name: 'css', - // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/css-language-features/server/src/cssServer.ts#L97 - triggerCharacters: ['/', '-', ':'], + capabilities: { + completionProvider: { + // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/css-language-features/server/src/cssServer.ts#L97 + triggerCharacters: ['/', '-', ':'], + }, + renameProvider: { + prepareProvider: true, + }, + codeActionProvider: {}, + definitionProvider: true, + diagnosticProvider: true, + hoverProvider: true, + referencesProvider: true, + documentHighlightProvider: true, + documentLinkProvider: {}, + documentSymbolProvider: true, + colorProvider: true, + foldingRangeProvider: true, + selectionRangeProvider: true, + documentFormattingProvider: true, + }, create(context): LanguageServicePluginInstance { const stylesheets = new WeakMap(); const fileSystemProvider: css.FileSystemProvider = { - stat: async uri => await context.env.fs?.stat(uri) + stat: async uri => await context.env.fs?.stat(URI.parse(uri)) ?? { type: css.FileType.Unknown, ctime: 0, mtime: 0, size: 0 }, - readDirectory: async uri => await context.env.fs?.readDirectory(uri) ?? [], + readDirectory: async uri => await context.env.fs?.readDirectory(URI.parse(uri)) ?? [], }; const documentContext = getDocumentContext(context); const disposable = onDidChangeCustomData(() => initializing = undefined, context); diff --git a/packages/css/package.json b/packages/css/package.json index 71bf8e00..ba7186cd 100644 --- a/packages/css/package.json +++ b/packages/css/package.json @@ -32,7 +32,7 @@ "@types/node": "latest" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/emmet/empty.ts b/packages/emmet/empty.ts index 96131a28..cc78e88a 100644 --- a/packages/emmet/empty.ts +++ b/packages/emmet/empty.ts @@ -5,6 +5,7 @@ console.warn('[volar-service-emmet] this module is not yet supported for web.'); export function create(): LanguageServicePlugin { return { name: 'emmet (stub)', + capabilities: {}, create() { return {}; }, diff --git a/packages/emmet/index.ts b/packages/emmet/index.ts index f34af276..bfd516c7 100644 --- a/packages/emmet/index.ts +++ b/packages/emmet/index.ts @@ -1,9 +1,10 @@ import type * as vscode from '@volar/language-service'; import type * as helper from '@vscode/emmet-helper'; import type { Node, Stylesheet } from 'EmmetFlatNode'; +import { URI } from 'vscode-uri'; +import { getSyntaxFromArgs, isValidLocationForEmmetAbbreviation } from './lib/abbreviationActions'; import { getRootNode } from './lib/parseDocument'; import { allowedMimeTypesInScriptTag, getEmbeddedCssNodeIfAny, getEmmetConfiguration, getEmmetHelper, getEmmetMode, getFlatNode, getHtmlFlatNode, isStyleSheet, parsePartialStylesheet } from './lib/util'; -import { getSyntaxFromArgs, isValidLocationForEmmetAbbreviation } from './lib/abbreviationActions'; export function create({ mappedLanguages = {}, @@ -12,9 +13,12 @@ export function create({ } = {}): vscode.LanguageServicePlugin { return { name: 'emmet', - // https://docs.emmet.io/abbreviations/syntax/ - triggerCharacters: '>+^*()#.[]$@-{}'.split(''), - // @ts-expect-error Need to update @volar/language-service + capabilities: { + completionProvider: { + // https://docs.emmet.io/abbreviations/syntax/ + triggerCharacters: '>+^*()#.[]$@-{}'.split(''), + }, + }, create(context, languageService): vscode.LanguageServicePluginInstance { let lastCompletionType: string | undefined; @@ -182,7 +186,8 @@ export function create({ if (abbreviation.startsWith('this.') || /\[[^\]=]*\]/.test(abbreviation)) { isNoisePromise = Promise.resolve(true); } else { - const documentUri = context.decodeEmbeddedDocumentUri(document.uri)?.[0] ?? document.uri; + const uri = URI.parse(document.uri); + const documentUri = context.decodeEmbeddedDocumentUri(uri)?.[0] ?? uri; isNoisePromise = languageService.findDocumentSymbols(documentUri).then(symbols => { return !!symbols && symbols.some(x => abbreviation === x.name || (abbreviation.startsWith(x.name + '.') && !/>|\*|\+/.test(abbreviation))); }); diff --git a/packages/emmet/lib/abbreviationActions.ts b/packages/emmet/lib/abbreviationActions.ts index a7aaf296..0abdee3d 100644 --- a/packages/emmet/lib/abbreviationActions.ts +++ b/packages/emmet/lib/abbreviationActions.ts @@ -19,7 +19,7 @@ const hexColorRegex = /^#[\da-fA-F]{0,6}$/; * @param position position to validate * @param abbreviationRange The range of the abbreviation for which given position is being validated */ -export async function isValidLocationForEmmetAbbreviation(context: vscode.ServiceContext, document: vscode.TextDocument, rootNode: Node | undefined, currentNode: Node | undefined, syntax: string, offset: number, abbreviationRange: vscode.Range): Promise { +export async function isValidLocationForEmmetAbbreviation(context: vscode.LanguageServiceContext, document: vscode.TextDocument, rootNode: Node | undefined, currentNode: Node | undefined, syntax: string, offset: number, abbreviationRange: vscode.Range): Promise { if (isStyleSheet(syntax)) { const stylesheet = rootNode; if (stylesheet && (stylesheet.comments || []).some(x => offset >= x.start && offset <= x.end)) { @@ -203,7 +203,7 @@ export async function isValidLocationForEmmetAbbreviation(context: vscode.Servic return valid; } -export async function getSyntaxFromArgs(context: vscode.ServiceContext, args: { [x: string]: string; }): Promise { +export async function getSyntaxFromArgs(context: vscode.LanguageServiceContext, args: { [x: string]: string; }): Promise { const mappedModes = await getMappingForIncludedLanguages(context); const language: string = args['language']; const parentMode: string = args['parentMode']; diff --git a/packages/emmet/lib/util.ts b/packages/emmet/lib/util.ts index a3d91bfb..a07c101d 100644 --- a/packages/emmet/lib/util.ts +++ b/packages/emmet/lib/util.ts @@ -45,7 +45,7 @@ export function isStyleSheet(syntax: string): boolean { return stylesheetSyntaxes.includes(syntax); } -export async function getMappingForIncludedLanguages(context: vscode.ServiceContext): Promise> { +export async function getMappingForIncludedLanguages(context: vscode.LanguageServiceContext): Promise> { // Explicitly map languages that have built-in grammar in VS Code to their parent language // to get emmet completion support // For other languages, users will have to use `emmet.includeLanguages` or @@ -372,7 +372,7 @@ function setupCdataNodeSubtree(documentText: string, cdataNode: HtmlFlatNode): s return cdataBody; } -export async function getEmmetConfiguration(context: vscode.ServiceContext, syntax: string) { +export async function getEmmetConfiguration(context: vscode.LanguageServiceContext, syntax: string) { const emmetConfig = await context.env.getConfiguration?.('emmet') ?? {}; const syntaxProfiles = Object.assign({}, emmetConfig['syntaxProfiles'] || {}); const preferences = Object.assign({}, emmetConfig['preferences'] || {}); diff --git a/packages/emmet/package.json b/packages/emmet/package.json index 1e174734..6ce7a043 100644 --- a/packages/emmet/package.json +++ b/packages/emmet/package.json @@ -26,13 +26,14 @@ "dependencies": { "@emmetio/css-parser": "^0.4.0", "@emmetio/html-matcher": "^1.3.0", - "@vscode/emmet-helper": "^2.9.2" + "@vscode/emmet-helper": "^2.9.2", + "vscode-uri": "^3.0.8" }, "devDependencies": { "@types/node": "latest" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/html/index.ts b/packages/html/index.ts index cf7bb390..7cfafddf 100644 --- a/packages/html/index.ts +++ b/packages/html/index.ts @@ -1,4 +1,4 @@ -import type { Disposable, DocumentSelector, FormattingOptions, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; +import type { Disposable, DocumentSelector, FormattingOptions, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; import * as html from 'vscode-html-languageservice'; import { TextDocument } from 'vscode-languageserver-textdocument'; import { URI, Utils } from 'vscode-uri'; @@ -16,22 +16,22 @@ export function create({ getDocumentContext = context => { return { resolveReference(ref, base) { - const decoded = context.decodeEmbeddedDocumentUri(base); + let baseUri = URI.parse(base); + const decoded = context.decodeEmbeddedDocumentUri(baseUri); if (decoded) { - base = decoded[0]; + baseUri = decoded[0]; } if (ref.match(/^\w[\w\d+.-]*:/)) { // starts with a schema return ref; } - if (ref[0] === '/') { // resolve absolute path against the current workspace folder - let folderUri = context.env.workspaceFolder; + if (ref[0] === '/' && context.env.workspaceFolders.length) { // resolve absolute path against the current workspace folder + let folderUri = context.env.workspaceFolders[0].toString(); if (!folderUri.endsWith('/')) { folderUri += '/'; } return folderUri + ref.substring(1); } - const baseUri = URI.parse(base); const baseUriDir = baseUri.path.endsWith('/') ? baseUri : Utils.dirname(baseUri); return Utils.resolvePath(baseUriDir, ref).toString(true); }, @@ -40,12 +40,6 @@ export function create({ isFormattingEnabled = async (_document, context) => { return await context.env.getConfiguration?.('html.format.enable') ?? true; }, - isAutoCreateQuotesEnabled = async (_document, context) => { - return await context.env.getConfiguration?.('html.autoCreateQuotes') ?? true; - }, - isAutoClosingTagsEnabled = async (_document, context) => { - return await context.env.getConfiguration?.('html.autoClosingTags') ?? true; - }, getFormattingOptions = async (_document, options, context) => { const formatSettings: html.FormattingOptions = { ...options, @@ -70,15 +64,18 @@ export function create({ const customData: string[] = await context.env.getConfiguration?.('html.customData') ?? []; const newData: html.IHTMLDataProvider[] = []; for (const customDataPath of customData) { - const uri = Utils.resolvePath(URI.parse(context.env.workspaceFolder), customDataPath); - const json = await context.env.fs?.readFile?.(uri.toString()); - if (json) { - try { - const data = JSON.parse(json); - newData.push(html.newHTMLDataProvider(customDataPath, data)); - } - catch (error) { - console.error(error); + for (const workspaceFolder of context.env.workspaceFolders) { + const uri = Utils.resolvePath(workspaceFolder, customDataPath); + const json = await context.env.fs?.readFile?.(uri); + if (json) { + try { + const data = JSON.parse(json); + newData.push(html.newHTMLDataProvider(customDataPath, data)); + } + catch (error) { + console.error(error); + } + break; } } } @@ -95,27 +92,54 @@ export function create({ }: { documentSelector?: DocumentSelector; useDefaultDataProvider?: boolean; - isFormattingEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - isAutoCreateQuotesEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - isAutoClosingTagsEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - getDocumentContext?(context: ServiceContext): html.DocumentContext; - getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: ServiceContext): ProviderResult; - getCompletionConfiguration?(document: TextDocument, context: ServiceContext): ProviderResult; - getHoverSettings?(document: TextDocument, context: ServiceContext): ProviderResult; - getCustomData?(context: ServiceContext): ProviderResult; - onDidChangeCustomData?(listener: () => void, context: ServiceContext): Disposable; + isFormattingEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + isAutoCreateQuotesEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + isAutoClosingTagsEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getDocumentContext?(context: LanguageServiceContext): html.DocumentContext; + getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: LanguageServiceContext): ProviderResult; + getCompletionConfiguration?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getHoverSettings?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getCustomData?(context: LanguageServiceContext): ProviderResult; + onDidChangeCustomData?(listener: () => void, context: LanguageServiceContext): Disposable; } = {}): LanguageServicePlugin { + const configurationSections = { + autoCreateQuotes: 'html.autoCreateQuotes', + autoClosingTags: 'html.autoClosingTags', + }; return { name: 'html', - // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/html-language-features/server/src/htmlServer.ts#L183 - triggerCharacters: ['.', ':', '<', '"', '=', '/'], + capabilities: { + completionProvider: { + // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/html-language-features/server/src/htmlServer.ts#L183 + triggerCharacters: ['.', ':', '<', '"', '=', '/'], + }, + renameProvider: { + prepareProvider: true, + }, + hoverProvider: true, + documentHighlightProvider: true, + documentLinkProvider: {}, + documentSymbolProvider: true, + foldingRangeProvider: true, + selectionRangeProvider: true, + documentFormattingProvider: true, + linkedEditingRangeProvider: true, + autoInsertionProvider: { + triggerCharacters: ['=', '>', '/'], + configurationSections: [ + configurationSections.autoCreateQuotes, + configurationSections.autoClosingTags, + configurationSections.autoClosingTags, + ], + }, + }, create(context): LanguageServicePluginInstance { const htmlDocuments = new WeakMap(); const fileSystemProvider: html.FileSystemProvider = { - stat: async uri => await context.env.fs?.stat(uri) + stat: async uri => await context.env.fs?.stat(URI.parse(uri)) ?? { type: html.FileType.Unknown, ctime: 0, mtime: 0, size: 0 }, - readDirectory: async uri => await context.env.fs?.readDirectory(uri) ?? [], + readDirectory: async uri => await context.env.fs?.readDirectory(URI.parse(uri)) ?? [], }; const documentContext = getDocumentContext(context); const htmlLs = html.getLanguageService({ @@ -327,7 +351,7 @@ export function create({ }); }, - async provideAutoInsertionEdit(document, selection, change) { + async provideAutoInsertSnippet(document, selection, change) { // selection must at end of change if (document.offsetAt(selection) !== change.rangeOffset + change.text.length) { return; @@ -335,7 +359,7 @@ export function create({ return worker(document, async htmlDocument => { if (change.rangeLength === 0 && change.text.endsWith('=')) { - const enabled = await isAutoCreateQuotesEnabled(document, context); + const enabled = await context.env.getConfiguration?.('html.autoCreateQuotes') ?? true; if (enabled) { @@ -349,7 +373,7 @@ export function create({ } if (change.rangeLength === 0 && (change.text.endsWith('>') || change.text.endsWith('/'))) { - const enabled = await isAutoClosingTagsEnabled(document, context); + const enabled = await context.env.getConfiguration?.('html.autoClosingTags') ?? true; if (enabled) { diff --git a/packages/html/package.json b/packages/html/package.json index 65c07d26..8c9c4063 100644 --- a/packages/html/package.json +++ b/packages/html/package.json @@ -32,7 +32,7 @@ "@types/node": "latest" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/json/index.ts b/packages/json/index.ts index 8a07545b..7ef8f353 100644 --- a/packages/json/index.ts +++ b/packages/json/index.ts @@ -1,4 +1,4 @@ -import type { LanguageServicePlugin, LanguageServicePluginInstance, DocumentSelector, ServiceContext, Disposable, ProviderResult, FormattingOptions } from '@volar/language-service'; +import type { LanguageServicePlugin, LanguageServicePluginInstance, DocumentSelector, LanguageServiceContext, Disposable, ProviderResult, FormattingOptions } from '@volar/language-service'; import * as json from 'vscode-json-languageservice'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import { URI, Utils } from 'vscode-uri'; @@ -20,12 +20,13 @@ export function create({ getWorkspaceContextService = context => { return { resolveRelativePath(relativePath, resource) { - const decoded = context.decodeEmbeddedDocumentUri(resource); + const base = resource.substring(0, resource.lastIndexOf('/') + 1); + let baseUri = URI.parse(base); + const decoded = context.decodeEmbeddedDocumentUri(baseUri); if (decoded) { - resource = decoded[0]; + baseUri = decoded[0]; } - const base = resource.substring(0, resource.lastIndexOf('/') + 1); - return Utils.resolvePath(URI.parse(base), relativePath).toString(); + return Utils.resolvePath(baseUri, relativePath).toString(); }, }; }, @@ -73,22 +74,36 @@ export function create({ }, }: { documentSelector?: DocumentSelector; - getWorkspaceContextService?(context: ServiceContext): json.WorkspaceContextService; - isFormattingEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: ServiceContext): ProviderResult; - getLanguageSettings?(context: ServiceContext): ProviderResult; - getDocumentLanguageSettings?(document: TextDocument, context: ServiceContext): ProviderResult; - onDidChangeLanguageSettings?(listener: () => void, context: ServiceContext): Disposable; + getWorkspaceContextService?(context: LanguageServiceContext): json.WorkspaceContextService; + isFormattingEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: LanguageServiceContext): ProviderResult; + getLanguageSettings?(context: LanguageServiceContext): ProviderResult; + getDocumentLanguageSettings?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + onDidChangeLanguageSettings?(listener: () => void, context: LanguageServiceContext): Disposable; } = {}): LanguageServicePlugin { return { name: 'json', - // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/json-language-features/server/src/jsonServer.ts#L150 - triggerCharacters: ['"', ':'], + capabilities: { + completionProvider: { + // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/json-language-features/server/src/jsonServer.ts#L150 + triggerCharacters: ['"', ':'], + resolveProvider: true, + }, + definitionProvider: true, + diagnosticProvider: true, + hoverProvider: true, + documentLinkProvider: {}, + documentSymbolProvider: true, + colorProvider: true, + foldingRangeProvider: true, + selectionRangeProvider: true, + documentFormattingProvider: true, + }, create(context): LanguageServicePluginInstance { const jsonDocuments = new WeakMap(); const jsonLs = json.getLanguageService({ - schemaRequestService: async uri => await context.env.fs?.readFile(uri) ?? '', + schemaRequestService: async uri => await context.env.fs?.readFile(URI.parse(uri)) ?? '', workspaceContext: getWorkspaceContextService(context), clientCapabilities: context.env.clientCapabilities, }); diff --git a/packages/json/package.json b/packages/json/package.json index 1e49dfc6..74c52ca9 100644 --- a/packages/json/package.json +++ b/packages/json/package.json @@ -31,7 +31,7 @@ "vscode-languageserver-textdocument": "^1.0.11" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/markdown/index.ts b/packages/markdown/index.ts index 32caae71..53fc5348 100644 --- a/packages/markdown/index.ts +++ b/packages/markdown/index.ts @@ -1,4 +1,4 @@ -import { SourceScript, forEachEmbeddedCode, type DocumentSelector, type FileChangeType, type FileType, type LanguageServicePlugin, type LanguageServicePluginInstance, type LocationLink, type ProviderResult, type ServiceContext } from '@volar/language-service'; +import { SourceScript, forEachEmbeddedCode, type DocumentSelector, type FileChangeType, type FileType, type LanguageServicePlugin, type LanguageServicePluginInstance, type LocationLink, type ProviderResult, type LanguageServiceContext } from '@volar/language-service'; import { Emitter } from 'vscode-jsonrpc'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import type { DiagnosticOptions, ILogger, IMdLanguageService, IMdParser, ITextDocument, IWorkspace } from 'vscode-markdown-languageservice'; @@ -31,11 +31,32 @@ export function create({ }: { documentSelector?: DocumentSelector; fileExtensions?: string[]; - getDiagnosticOptions?(document: TextDocument, context: ServiceContext): ProviderResult; + getDiagnosticOptions?(document: TextDocument, context: LanguageServiceContext): ProviderResult; } = {}): LanguageServicePlugin { return { name: 'markdown', - triggerCharacters: ['.', '/', '#'], + capabilities: { + codeActionProvider: {}, + completionProvider: { + triggerCharacters: ['.', '/', '#'], + }, + definitionProvider: true, + diagnosticProvider: true, + documentHighlightProvider: true, + documentLinkProvider: { + resolveProvider: true, + }, + documentSymbolProvider: true, + // fileReferencesProvider: true + foldingRangeProvider: true, + hoverProvider: true, + referencesProvider: true, + renameProvider: { + prepareProvider: true, + }, + selectionRangeProvider: true, + workspaceSymbolProvider: true, + }, create(context): LanguageServicePluginInstance { const logger: ILogger = { level: LogLevel.Off, @@ -56,7 +77,7 @@ export function create({ workspace: workspace.workspace, }); const firedDocumentChanges = new Map(); - const fsSourceScripts = new Map(); + const fsSourceScripts = new Map | undefined>(); const fileWatcher = context.env.onDidChangeWatchedFiles?.(event => { for (const change of event.changes) { fsSourceScripts.delete(change.uri); @@ -222,14 +243,14 @@ export function create({ for (const change of event.changes) { switch (change.type) { case 2 satisfies typeof FileChangeType.Changed: { - const document = getTextDocument(change.uri); + const document = getTextDocument(URI.parse(change.uri)); if (document) { onDidChangeMarkdownDocument.fire(document); } break; } case 1 satisfies typeof FileChangeType.Created: { - const document = getTextDocument(change.uri); + const document = getTextDocument(URI.parse(change.uri)); if (document) { onDidCreateMarkdownDocument.fire(document); } @@ -248,21 +269,21 @@ export function create({ // const openTextDocumentResults = this.documents.all() // .filter(doc => this.isRelevantMarkdownDocument(doc)); - return await findMarkdownFilesInWorkspace(URI.parse(context.env.workspaceFolder)); + return (await Promise.all(context.env.workspaceFolders.map(findMarkdownFilesInWorkspace))).flat(); }, getContainingDocument(resource) { - const decoded = context.decodeEmbeddedDocumentUri(resource.toString()); + const decoded = context.decodeEmbeddedDocumentUri(resource); if (decoded) { return { - uri: URI.parse(decoded[0]), + uri: decoded[0], children: [], }; } }, hasMarkdownDocument(resource) { - const document = getTextDocument(resource.toString()); + const document = getTextDocument(resource); return Boolean(document && matchDocument(documentSelector, document)); }, @@ -273,11 +294,11 @@ export function create({ onDidDeleteMarkdownDocument: onDidDeleteMarkdownDocument.event, async openMarkdownDocument(resource) { - return getTextDocument(resource.toString()); + return getTextDocument(resource); }, async readDirectory(resource) { - const directory = await fs?.readDirectory(resource.toString()) ?? []; + const directory = await fs?.readDirectory(resource) ?? []; return directory .filter(file => file[1] !== 0 satisfies FileType.Unknown) .map(([fileName, fileType]) => [ @@ -287,14 +308,14 @@ export function create({ }, async stat(resource) { - const stat = await fs?.stat(resource.toString()); + const stat = await fs?.stat(resource); if (stat?.type === 0 satisfies FileType.Unknown) { return; } return { isDirectory: stat?.type === 2 satisfies FileType.Directory }; }, - workspaceFolders: [URI.parse(context.env.workspaceFolder)], + workspaceFolders: context.env.workspaceFolders, }; return { @@ -313,7 +334,7 @@ export function create({ async function findMarkdownFilesInWorkspace(folder: URI) { const { fs } = context.env; - const files = await fs?.readDirectory(folder.toString()) ?? []; + const files = await fs?.readDirectory(folder) ?? []; const docs: ITextDocument[] = []; await Promise.all( files.map(async ([fileName, fileType]) => { @@ -324,13 +345,13 @@ export function create({ } else if (fileExtensions.some(ext => fileName.endsWith('.' + ext))) { const fileUri = Utils.joinPath(folder, fileName); - let sourceScript = context.language.scripts.get(fileUri.toString()); + let sourceScript = context.language.scripts.get(fileUri); if (!sourceScript) { if (!fsSourceScripts.has(fileUri.toString())) { fsSourceScripts.set(fileUri.toString(), undefined); - const fileContent = await fs?.readFile(fileUri.toString()); + const fileContent = await fs?.readFile(fileUri); if (fileContent !== undefined) { - fsSourceScripts.set(fileUri.toString(), context.language.scripts.set(fileUri.toString(), { + fsSourceScripts.set(fileUri.toString(), context.language.scripts.set(fileUri, { getText(start, end) { return fileContent.substring(start, end); }, @@ -341,7 +362,7 @@ export function create({ return undefined; }, })); - context.language.scripts.delete(fileUri.toString()); + context.language.scripts.delete(fileUri); } } sourceScript = fsSourceScripts.get(fileUri.toString()); @@ -356,7 +377,7 @@ export function create({ } } else if (sourceScript) { - const doc = context.documents.get(fileName, sourceScript.languageId, sourceScript.snapshot); + const doc = context.documents.get(sourceScript.id, sourceScript.languageId, sourceScript.snapshot); if (doc && matchDocument(documentSelector, doc)) { docs.push(doc); } @@ -367,7 +388,7 @@ export function create({ return docs; } - function getTextDocument(uri: string) { + function getTextDocument(uri: URI) { const decoded = context.decodeEmbeddedDocumentUri(uri); if (decoded) { const sourceScript = context.language.scripts.get(decoded[0]); diff --git a/packages/markdown/package.json b/packages/markdown/package.json index df5936ff..c4ed2efd 100644 --- a/packages/markdown/package.json +++ b/packages/markdown/package.json @@ -34,7 +34,7 @@ "vscode-languageserver-textdocument": "^1.0.11" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/prettier/index.ts b/packages/prettier/index.ts index 847c8304..f7fc03fa 100644 --- a/packages/prettier/index.ts +++ b/packages/prettier/index.ts @@ -1,4 +1,4 @@ -import type { DocumentSelector, FormattingOptions, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; +import type { DocumentSelector, FormattingOptions, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; import type { Options } from 'prettier'; import { URI } from 'vscode-uri'; @@ -6,13 +6,13 @@ export function create( /** * Prettier instance or getter to use. */ - prettierInstanceOrGetter: typeof import('prettier') | ((context: ServiceContext) => ProviderResult), + prettierInstanceOrGetter: typeof import('prettier') | ((context: LanguageServiceContext) => ProviderResult), { html, documentSelector = ['html', 'css', 'scss', 'typescript', 'javascript'], isFormattingEnabled = async (prettier, document, context) => { - const documentUri = context.decodeEmbeddedDocumentUri(document.uri)?.[0] ?? document.uri; - const uri = URI.parse(documentUri); + const parsed = URI.parse(document.uri); + const uri = context.decodeEmbeddedDocumentUri(parsed)?.[0] ?? parsed; if (uri.scheme === 'file') { const fileInfo = await prettier.getFileInfo(uri.fsPath, { ignorePath: '.prettierignore', resolveConfig: false }); if (fileInfo.ignored) { @@ -22,12 +22,12 @@ export function create( return true; }, getFormattingOptions = async (prettier, document, formatOptions, context) => { - const documentUri = context.decodeEmbeddedDocumentUri(document.uri)?.[0] ?? document.uri; - const uri = URI.parse(documentUri); + const parsed = URI.parse(document.uri); + const uri = context.decodeEmbeddedDocumentUri(parsed)?.[0] ?? parsed; const configOptions = uri.scheme === 'file' ? await prettier.resolveConfig(uri.fsPath) : null; - const editorOptions = await context.env.getConfiguration?.('prettier', documentUri); + const editorOptions = await context.env.getConfiguration?.('prettier', uri.toString()); return { filepath: uri.scheme === 'file' ? uri.fsPath @@ -54,12 +54,15 @@ export function create( * ['html', 'css', 'scss', 'typescript', 'javascript'] */ documentSelector?: DocumentSelector; - isFormattingEnabled?(prettier: typeof import('prettier'), document: TextDocument, context: ServiceContext): ProviderResult; - getFormattingOptions?(prettier: typeof import('prettier'), document: TextDocument, formatOptions: FormattingOptions, context: ServiceContext): ProviderResult; + isFormattingEnabled?(prettier: typeof import('prettier'), document: TextDocument, context: LanguageServiceContext): ProviderResult; + getFormattingOptions?(prettier: typeof import('prettier'), document: TextDocument, formatOptions: FormattingOptions, context: LanguageServiceContext): ProviderResult; } = {}, ): LanguageServicePlugin { return { name: 'prettier', + capabilities: { + documentFormattingProvider: true, + }, create(context): LanguageServicePluginInstance { let prettierInstanceOrPromise: ProviderResult; diff --git a/packages/prettier/package.json b/packages/prettier/package.json index 48b6a953..7cf0f63f 100644 --- a/packages/prettier/package.json +++ b/packages/prettier/package.json @@ -32,7 +32,7 @@ "prettier": "^3.0.3" }, "peerDependencies": { - "@volar/language-service": "~2.2.3", + "@volar/language-service": "~2.3.0-alpha.0", "prettier": "^2.2 || ^3.0" }, "peerDependenciesMeta": { diff --git a/packages/prettyhtml/index.ts b/packages/prettyhtml/index.ts index ad40ff34..bd2060db 100644 --- a/packages/prettyhtml/index.ts +++ b/packages/prettyhtml/index.ts @@ -1,5 +1,5 @@ import * as prettyhtml from '@starptech/prettyhtml'; -import type { DocumentSelector, FormattingOptions, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; +import type { DocumentSelector, FormattingOptions, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; export type PrettyhtmlFormattingOptions = Parameters[1]; @@ -14,11 +14,14 @@ export function create({ }, }: { documentSelector?: DocumentSelector; - isFormattingEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: ServiceContext): ProviderResult; + isFormattingEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: LanguageServiceContext): ProviderResult; } = {}): LanguageServicePlugin { return { name: 'prettyhtml', + capabilities: { + documentFormattingProvider: true, + }, create(context): LanguageServicePluginInstance { return { async provideDocumentFormattingEdits(document, range, options) { diff --git a/packages/prettyhtml/package.json b/packages/prettyhtml/package.json index a9212da1..9dd9f39d 100644 --- a/packages/prettyhtml/package.json +++ b/packages/prettyhtml/package.json @@ -27,7 +27,7 @@ "@starptech/prettyhtml": "^0.10.0" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/pug-beautify/index.ts b/packages/pug-beautify/index.ts index a61c63e5..a0e32ed7 100644 --- a/packages/pug-beautify/index.ts +++ b/packages/pug-beautify/index.ts @@ -1,4 +1,4 @@ -import type { DocumentSelector, FormattingOptions, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; +import type { DocumentSelector, FormattingOptions, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; export function create({ documentSelector = ['jade'], @@ -11,11 +11,14 @@ export function create({ }, }: { documentSelector?: DocumentSelector; - isFormattingEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: ServiceContext): ProviderResult<{}>; + isFormattingEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getFormattingOptions?(document: TextDocument, options: FormattingOptions, context: LanguageServiceContext): ProviderResult<{}>; } = {}): LanguageServicePlugin { return { name: 'pug-beautify', + capabilities: { + documentFormattingProvider: true, + }, create(context): LanguageServicePluginInstance { return { async provideDocumentFormattingEdits(document, range, options) { diff --git a/packages/pug-beautify/package.json b/packages/pug-beautify/package.json index 72818455..e56c7533 100644 --- a/packages/pug-beautify/package.json +++ b/packages/pug-beautify/package.json @@ -27,7 +27,7 @@ "@johnsoncodehk/pug-beautify": "^0.2.2" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/pug/empty.ts b/packages/pug/empty.ts index 5cf35ccf..14b53c44 100644 --- a/packages/pug/empty.ts +++ b/packages/pug/empty.ts @@ -5,6 +5,7 @@ console.warn('[volar-service-pug] this module is not yet supported for web.'); export function create(): LanguageServicePlugin { return { name: 'pug (stub)', + capabilities: {}, create() { return {}; }, diff --git a/packages/pug/index.ts b/packages/pug/index.ts index fcac83b0..a1682d25 100644 --- a/packages/pug/index.ts +++ b/packages/pug/index.ts @@ -1,4 +1,4 @@ -import type { Diagnostic, DiagnosticSeverity, Disposable, DocumentSelector, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; +import type { Diagnostic, DiagnosticSeverity, Disposable, DocumentSelector, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; import { transformDocumentSymbol } from '@volar/language-service'; import { create as createHtmlService } from 'volar-service-html'; import type * as html from 'vscode-html-languageservice'; @@ -16,8 +16,8 @@ export function create({ onDidChangeCustomData, }: { documentSelector?: DocumentSelector; - getCustomData?(context: ServiceContext): ProviderResult; - onDidChangeCustomData?(listener: () => void, context: ServiceContext): Disposable; + getCustomData?(context: LanguageServiceContext): ProviderResult; + onDidChangeCustomData?(listener: () => void, context: LanguageServiceContext): Disposable; } = {}): LanguageServicePlugin { const _htmlService = createHtmlService({ getCustomData, @@ -26,9 +26,23 @@ export function create({ return { ..._htmlService, name: 'pug', - create(context): LanguageServicePluginInstance { + capabilities: { + completionProvider: {}, + diagnosticProvider: true, + hoverProvider: true, + documentHighlightProvider: true, + documentLinkProvider: {}, + documentSymbolProvider: true, + foldingRangeProvider: true, + selectionRangeProvider: true, + autoInsertionProvider: { + triggerCharacters: ['='], + configurationSections: ['html.autoCreateQuotes'], + }, + }, + create(context, languageService): LanguageServicePluginInstance { - const htmlService = _htmlService.create(context); + const htmlService = _htmlService.create(context, languageService); const pugDocuments = new WeakMap(); const pugLs = pug.getLanguageService(htmlService.provide['html/languageService']()); @@ -113,7 +127,7 @@ export function create({ }); }, - async provideAutoInsertionEdit(document, selection, change) { + async provideAutoInsertSnippet(document, selection, change) { // selection must at end of change if (document.offsetAt(selection) !== change.rangeOffset + change.text.length) { return; diff --git a/packages/pug/lib/services/completion.ts b/packages/pug/lib/services/completion.ts index 1730e720..8334038a 100644 --- a/packages/pug/lib/services/completion.ts +++ b/packages/pug/lib/services/completion.ts @@ -1,7 +1,7 @@ import type * as html from 'vscode-html-languageservice'; import { TextDocument } from 'vscode-html-languageservice'; import type { PugDocument } from '../pugDocument'; -import { ServiceContext, transformCompletionList } from '@volar/language-service'; +import { LanguageServiceContext, transformCompletionList } from '@volar/language-service'; export function register(htmlLs: html.LanguageService) { @@ -12,7 +12,7 @@ export function register(htmlLs: html.LanguageService) { return async ( pugDoc: PugDocument, pos: html.Position, - serviceContext: ServiceContext, + serviceContext: LanguageServiceContext, documentContext: html.DocumentContext | undefined, options?: html.CompletionConfiguration | undefined ) => { diff --git a/packages/pug/package.json b/packages/pug/package.json index 0b3a575f..d123bd52 100644 --- a/packages/pug/package.json +++ b/packages/pug/package.json @@ -24,7 +24,7 @@ "url": "https://github.com/johnsoncodehk" }, "dependencies": { - "@volar/language-service": "~2.2.3", + "@volar/language-service": "~2.3.0-alpha.0", "pug-lexer": "^5.0.1", "pug-parser": "^6.0.0", "volar-service-html": "0.0.47", diff --git a/packages/sass-formatter/index.ts b/packages/sass-formatter/index.ts index c7327de1..bc9cc5fd 100644 --- a/packages/sass-formatter/index.ts +++ b/packages/sass-formatter/index.ts @@ -1,4 +1,4 @@ -import type { DocumentSelector, FormattingOptions, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; +import type { DocumentSelector, FormattingOptions, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, TextDocument } from '@volar/language-service'; import { SassFormatter, SassFormatterConfig } from 'sass-formatter'; export function create({ @@ -7,11 +7,14 @@ export function create({ getFormatterConfig = (_document, options) => options, }: { documentSelector?: DocumentSelector; - isFormattingEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - getFormatterConfig?(document: TextDocument, options: FormattingOptions, context: ServiceContext): ProviderResult>; + isFormattingEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + getFormatterConfig?(document: TextDocument, options: FormattingOptions, context: LanguageServiceContext): ProviderResult>; } = {}): LanguageServicePlugin { return { name: 'sass-formatter', + capabilities: { + documentFormattingProvider: true, + }, create(context): LanguageServicePluginInstance { return { async provideDocumentFormattingEdits(document, range, options) { diff --git a/packages/sass-formatter/package.json b/packages/sass-formatter/package.json index c9e38b03..32a04f8b 100644 --- a/packages/sass-formatter/package.json +++ b/packages/sass-formatter/package.json @@ -27,7 +27,7 @@ "sass-formatter": "^0.7.8" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/typescript-twoslash-queries/index.ts b/packages/typescript-twoslash-queries/index.ts index 859aab45..51b34b10 100644 --- a/packages/typescript-twoslash-queries/index.ts +++ b/packages/typescript-twoslash-queries/index.ts @@ -1,16 +1,20 @@ import type { InlayHint, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; import type { Provide } from 'volar-service-typescript'; +import { URI } from 'vscode-uri'; export function create(ts: typeof import('typescript')): LanguageServicePlugin { return { name: 'typescript-twoslash-queries', + capabilities: { + inlayHintProvider: {}, + }, create(context): LanguageServicePluginInstance { return { provideInlayHints(document, range) { if (isTsDocument(document.languageId)) { const languageService = context.inject('typescript/languageService'); - const fileName = context.inject('typescript/documentFileName', document.uri); + const fileName = context.inject('typescript/documentFileName', URI.parse(document.uri)); if (!languageService || !fileName) { return; } diff --git a/packages/typescript-twoslash-queries/package.json b/packages/typescript-twoslash-queries/package.json index 42e5b959..c8ed6ce6 100644 --- a/packages/typescript-twoslash-queries/package.json +++ b/packages/typescript-twoslash-queries/package.json @@ -23,11 +23,14 @@ "email": "johnsoncodehk@gmail.com", "url": "https://github.com/johnsoncodehk" }, + "dependencies": { + "vscode-uri": "^3.0.8" + }, "devDependencies": { "volar-service-typescript": "0.0.47" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/typescript/lib/configs/getFormatCodeSettings.ts b/packages/typescript/lib/configs/getFormatCodeSettings.ts index c01363b4..27e7a3f4 100644 --- a/packages/typescript/lib/configs/getFormatCodeSettings.ts +++ b/packages/typescript/lib/configs/getFormatCodeSettings.ts @@ -1,10 +1,10 @@ -import type { FormattingOptions, ServiceContext } from '@volar/language-service'; +import type { FormattingOptions, LanguageServiceContext } from '@volar/language-service'; import type * as ts from 'typescript'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import { getConfigTitle } from '../shared'; export async function getFormatCodeSettings( - ctx: ServiceContext, + ctx: LanguageServiceContext, document: TextDocument, options: FormattingOptions | undefined, ): Promise { diff --git a/packages/typescript/lib/configs/getUserPreferences.ts b/packages/typescript/lib/configs/getUserPreferences.ts index f84ef021..879f8a91 100644 --- a/packages/typescript/lib/configs/getUserPreferences.ts +++ b/packages/typescript/lib/configs/getUserPreferences.ts @@ -2,17 +2,19 @@ import * as path from 'path-browserify'; import type * as ts from 'typescript'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import { getConfigTitle } from '../shared'; -import type { ServiceContext } from '@volar/language-service'; +import type { LanguageServiceContext } from '@volar/language-service'; +import { URI } from 'vscode-uri'; export async function getUserPreferences( - ctx: ServiceContext, + ctx: LanguageServiceContext, document: TextDocument, ): Promise { let currentDirectory = ''; if (ctx.language.typescript) { currentDirectory = ctx.language.typescript.languageServiceHost.getCurrentDirectory(); } - const documentUri = ctx.decodeEmbeddedDocumentUri(document.uri)?.[0] ?? document.uri; + const uri = URI.parse(document.uri); + const documentUri = ctx.decodeEmbeddedDocumentUri(uri)?.[0] ?? uri; const config = await ctx.env.getConfiguration?.(getConfigTitle(document)) ?? {}; const preferencesConfig = config?.preferences ?? {}; const preferences: ts.UserPreferences = { @@ -21,7 +23,7 @@ export async function getUserPreferences( importModuleSpecifierPreference: getImportModuleSpecifierPreference(preferencesConfig), importModuleSpecifierEnding: getImportModuleSpecifierEndingPreference(preferencesConfig), jsxAttributeCompletionStyle: getJsxAttributeCompletionStyle(preferencesConfig), - allowTextChangesInNewFiles: documentUri.startsWith('file://'), + allowTextChangesInNewFiles: documentUri.scheme === 'file', providePrefixAndSuffixTextForRename: (preferencesConfig.renameShorthandProperties ?? true) === false ? false : (preferencesConfig.useAliasesForRenames ?? true), allowRenameOfImportPath: true, includeAutomaticOptionalChainCompletions: config.suggest?.includeAutomaticOptionalChainCompletions ?? true, diff --git a/packages/typescript/lib/plugins/directiveComment.ts b/packages/typescript/lib/plugins/directiveComment.ts index a0f5d6c7..1511be70 100644 --- a/packages/typescript/lib/plugins/directiveComment.ts +++ b/packages/typescript/lib/plugins/directiveComment.ts @@ -36,7 +36,11 @@ const directives: Directive[] = [ export function create(): vscode.LanguageServicePlugin { return { name: 'typescript-directive-comment', - triggerCharacters: ['@'], + capabilities: { + completionProvider: { + triggerCharacters: ['@'], + }, + }, create(): vscode.LanguageServicePluginInstance { return { diff --git a/packages/typescript/lib/plugins/docCommentTemplate.ts b/packages/typescript/lib/plugins/docCommentTemplate.ts index 573abaff..fe70f64f 100644 --- a/packages/typescript/lib/plugins/docCommentTemplate.ts +++ b/packages/typescript/lib/plugins/docCommentTemplate.ts @@ -12,7 +12,11 @@ const defaultJsDoc = `/**\n * $0\n */`; export function create(ts: typeof import('typescript')): vscode.LanguageServicePlugin { return { name: 'typescript-doc-comment-template', - triggerCharacters: ['*'], + capabilities: { + completionProvider: { + triggerCharacters: ['*'], + }, + }, create(): vscode.LanguageServicePluginInstance { return { diff --git a/packages/typescript/lib/plugins/semantic.ts b/packages/typescript/lib/plugins/semantic.ts index 6d254e05..84cbe54d 100644 --- a/packages/typescript/lib/plugins/semantic.ts +++ b/packages/typescript/lib/plugins/semantic.ts @@ -7,14 +7,15 @@ import type { Location, ParameterInformation, ProviderResult, - ServiceContext, + LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance, SignatureHelpTriggerKind, SignatureInformation, VirtualCode, WorkspaceEdit, - FormattingOptions + FormattingOptions, + CodeActionKind, } from '@volar/language-service'; import * as path from 'path-browserify'; import * as semver from 'semver'; @@ -49,12 +50,13 @@ import * as codeActions from '../semanticFeatures/codeAction'; import * as codeActionResolve from '../semanticFeatures/codeActionResolve'; import * as semanticTokens from '../semanticFeatures/semanticTokens'; import type { SharedContext } from '../semanticFeatures/types'; +import { URI } from 'vscode-uri'; export interface Provide { 'typescript/languageService': () => ts.LanguageService; 'typescript/languageServiceHost': () => ts.LanguageServiceHost; - 'typescript/documentFileName': (uri: string) => string; - 'typescript/documentUri': (fileName: string) => string; + 'typescript/documentFileName': (uri: URI) => string; + 'typescript/documentUri': (fileName: string) => URI; } export interface CompletionItemData { @@ -90,21 +92,99 @@ export function create( return await context.env.getConfiguration?.(getConfigTitle(document) + '.suggest.enabled') ?? true; }, }: { - isValidationEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - isSuggestionsEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; + isValidationEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + isSuggestionsEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; } = {}, ): LanguageServicePlugin { return { name: 'typescript-semantic', - triggerCharacters: getBasicTriggerCharacters(ts.version), - signatureHelpTriggerCharacters: ['(', ',', '<'], - signatureHelpRetriggerCharacters: [')'], + capabilities: { + completionProvider: { + triggerCharacters: getBasicTriggerCharacters(ts.version), + resolveProvider: true, + }, + renameProvider: { + prepareProvider: true, + }, + codeActionProvider: { + codeActionKinds: [ + '' satisfies typeof CodeActionKind.Empty, + 'quickfix' satisfies typeof CodeActionKind.QuickFix, + 'refactor' satisfies typeof CodeActionKind.Refactor, + 'refactor.extract' satisfies typeof CodeActionKind.RefactorExtract, + 'refactor.inline' satisfies typeof CodeActionKind.RefactorInline, + 'refactor.rewrite' satisfies typeof CodeActionKind.RefactorRewrite, + 'source' satisfies typeof CodeActionKind.Source, + 'source.fixAll' satisfies typeof CodeActionKind.SourceFixAll, + 'source.organizeImports' satisfies typeof CodeActionKind.SourceOrganizeImports, + ], + resolveProvider: true, + }, + inlayHintProvider: {}, + callHierarchyProvider: true, + definitionProvider: true, + typeDefinitionProvider: true, + diagnosticProvider: true, + hoverProvider: true, + implementationProvider: true, + referencesProvider: true, + // fileReferencesProvider: true, + documentHighlightProvider: true, + semanticTokensProvider: { + // https://code.visualstudio.com/api/language-extensions/semantic-highlight-guide#standard-token-types-and-modifiers + legend: { + tokenTypes: [ + 'namespace', + 'class', + 'enum', + 'interface', + 'struct', + 'typeParameter', + 'type', + 'parameter', + 'variable', + 'property', + 'enumMember', + 'decorator', + 'event', + 'function', + 'method', + 'macro', + 'label', + 'comment', + 'string', + 'keyword', + 'number', + 'regexp', + 'operator', + ], + tokenModifiers: [ + 'declaration', + 'definition', + 'readonly', + 'static', + 'deprecated', + 'abstract', + 'async', + 'modification', + 'documentation', + 'defaultLibrary', + ], + }, + }, + workspaceSymbolProvider: true, + // fileRenameEdits: true, + selectionRangeProvider: true, + signatureHelpProvider: { + triggerCharacters: ['(', ',', '<'], + retriggerCharacters: [')'], + }, + }, create(context): LanguageServicePluginInstance { if (!context.language.typescript) { return {}; } - const { projectHost, languageServiceHost } = context.language.typescript; - const sys: ts.System | undefined = projectHost; + const { sys, languageServiceHost, asFileName, asScriptId } = context.language.typescript; const created = tsWithImportCache.createLanguageService( ts, sys, @@ -141,7 +221,7 @@ export function create( updateSourceScriptFileNames(); } for (const change of params.changes) { - const fileName = context.env.typescript!.uriToFileName(change.uri); + const fileName = asFileName(URI.parse(change.uri)); if (sourceScriptNames.has(normalizeFileName(fileName))) { created.projectUpdated?.(languageServiceHost.getCurrentDirectory()); } @@ -151,7 +231,7 @@ export function create( function updateSourceScriptFileNames() { sourceScriptNames.clear(); for (const fileName of languageServiceHost.getScriptFileNames()) { - const uri = context.env.typescript!.fileNameToUri(fileName); + const uri = asScriptId(fileName); const sourceScript = context.language.scripts.get(uri); if (sourceScript?.generated) { const tsCode = sourceScript.generated.languagePlugin.typescript?.getServiceScript(sourceScript.generated.root); @@ -175,10 +255,10 @@ export function create( if (virtualScript) { return virtualScript.fileName; } - return context.env.typescript!.uriToFileName(uri); + return asFileName(uri); }, fileNameToUri(fileName) { - const uri = context.env.typescript!.fileNameToUri(fileName); + const uri = asScriptId(fileName); const sourceScript = context.language.scripts.get(uri); const extraServiceScript = context.language.typescript!.getExtraServiceScript(fileName); @@ -247,7 +327,9 @@ export function create( async provideCompletionItems(document, position, completeContext, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } @@ -258,7 +340,7 @@ export function create( return await worker(token, async () => { const preferences = await getUserPreferences(ctx, document); - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const info = safeCall(() => ctx.languageService.getCompletionsAtPosition(fileName, offset, { ...preferences, @@ -294,7 +376,8 @@ export function create( return item; } const { fileName, offset } = data; - const document = ctx.getTextDocument(data.uri)!; + const uri = URI.parse(data.uri); + const document = ctx.getTextDocument(uri)!; const [formatOptions, preferences] = await Promise.all([ getFormatCodeSettings(ctx, document, formattingOptions), getUserPreferences(ctx, document), @@ -386,12 +469,14 @@ export function create( provideRenameRange(document, position, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const renameInfo = safeCall(() => ctx.languageService.getRenameInfo(fileName, offset, renameInfoOptions)); if (!renameInfo) { @@ -406,12 +491,14 @@ export function create( provideRenameEdits(document, position, newName, token) { - if (!isSemanticDocument(document, true)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document, true)) { return; } return worker(token, async () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const renameInfo = safeCall(() => ctx.languageService.getRenameInfo(fileName, offset, renameInfoOptions)); if (!renameInfo?.canRename) { @@ -454,8 +541,8 @@ export function create( } edits.documentChanges.push({ kind: 'rename', - oldUri: ctx.fileNameToUri(fileToRename), - newUri: ctx.fileNameToUri(newFilePath), + oldUri: ctx.fileNameToUri(fileToRename).toString(), + newUri: ctx.fileNameToUri(newFilePath).toString(), }); return edits; } @@ -464,12 +551,14 @@ export function create( provideCodeActions(document, range, context, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - return getCodeActions(document, range, context, formattingOptions); + return getCodeActions(uri, document, range, context, formattingOptions); }); }, @@ -481,13 +570,15 @@ export function create( provideInlayHints(document, range, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, async () => { const preferences = await getUserPreferences(ctx, document); - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const start = document.offsetAt(range.start); const end = document.offsetAt(range.end); const inlayHints = safeCall(() => @@ -504,12 +595,14 @@ export function create( provideCallHierarchyItems(document, position, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const calls = safeCall(() => ctx.languageService.prepareCallHierarchy(fileName, offset)); if (!calls) { @@ -522,8 +615,9 @@ export function create( async provideCallHierarchyIncomingCalls(item, token) { return await worker(token, () => { - const document = ctx.getTextDocument(item.uri)!; - const fileName = ctx.uriToFileName(item.uri); + const uri = URI.parse(item.uri); + const document = ctx.getTextDocument(uri)!; + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(item.selectionRange.start); const calls = safeCall(() => ctx.languageService.provideCallHierarchyIncomingCalls(fileName, offset)); if (!calls) { @@ -536,8 +630,9 @@ export function create( async provideCallHierarchyOutgoingCalls(item, token) { return await worker(token, () => { - const document = ctx.getTextDocument(item.uri)!; - const fileName = ctx.uriToFileName(item.uri); + const uri = URI.parse(item.uri); + const document = ctx.getTextDocument(uri)!; + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(item.selectionRange.start); const calls = safeCall(() => ctx.languageService.provideCallHierarchyOutgoingCalls(fileName, offset)); if (!calls) { @@ -550,12 +645,14 @@ export function create( provideDefinition(document, position, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const info = safeCall(() => ctx.languageService.getDefinitionAndBoundSpan(fileName, offset)); if (!info) { @@ -567,12 +664,14 @@ export function create( provideTypeDefinition(document, position, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const entries = safeCall(() => ctx.languageService.getTypeDefinitionAtPosition(fileName, offset)); if (!entries) { @@ -592,12 +691,14 @@ export function create( provideHover(document, position, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const info = safeCall(() => ctx.languageService.getQuickInfoAtPosition(fileName, offset)); if (!info) { @@ -609,12 +710,14 @@ export function create( provideImplementation(document, position, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const entries = safeCall(() => ctx.languageService.getImplementationAtPosition(fileName, offset)); if (!entries) { @@ -626,12 +729,14 @@ export function create( provideReferences(document, position, referenceContext, token) { - if (!isSemanticDocument(document, true)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document, true)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const references = safeCall(() => ctx.languageService.findReferences(fileName, offset)); if (!references) { @@ -658,12 +763,14 @@ export function create( provideFileReferences(document, token) { - if (!isSemanticDocument(document, true)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document, true)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const entries = safeCall(() => ctx.languageService.getFileReferences(fileName)); if (!entries) { return []; @@ -674,12 +781,14 @@ export function create( provideDocumentHighlights(document, position, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const highlights = safeCall(() => ctx.languageService.getDocumentHighlights(fileName, offset, [fileName])); if (!highlights) { @@ -697,12 +806,14 @@ export function create( provideDocumentSemanticTokens(document, range, legend, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { - return getDocumentSemanticTokens(document, range, legend); + return getDocumentSemanticTokens(uri, document, range, legend); }); }, @@ -740,14 +851,16 @@ export function create( provideSelectionRanges(document, positions, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } return worker(token, () => { return positions .map(position => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const range = safeCall(() => ctx.languageService.getSmartSelectionRange(fileName, offset)); if (!range) { @@ -761,7 +874,9 @@ export function create( provideSignatureHelp(document, position, context, token) { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } @@ -785,7 +900,7 @@ export function create( }; } - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const offset = document.offsetAt(position); const helpItems = safeCall(() => ctx.languageService.getSignatureHelpItems(fileName, offset, options)); if (!helpItems) { @@ -824,7 +939,9 @@ export function create( async function provideDiagnosticsWorker(document: TextDocument, token: CancellationToken, mode: 'syntactic' | 'semantic') { - if (!isSemanticDocument(document)) { + const uri = URI.parse(document.uri); + + if (!isSemanticDocument(uri, document)) { return; } @@ -833,7 +950,7 @@ export function create( } return await worker(token, () => { - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const program = ctx.languageService.getProgram(); const sourceFile = program?.getSourceFile(fileName); if (!program || !sourceFile) { @@ -870,8 +987,8 @@ export function create( return !!(compilerOptions.declaration || compilerOptions.composite); } - function isSemanticDocument(document: TextDocument, withJson = false) { - const virtualScript = getVirtualScriptByUri(document.uri); + function isSemanticDocument(uri: URI, document: TextDocument, withJson = false) { + const virtualScript = getVirtualScriptByUri(uri); if (virtualScript) { return true; } @@ -884,7 +1001,7 @@ export function create( async function worker(token: CancellationToken, fn: () => T): Promise | undefined> { let result: Awaited | undefined; let oldSysVersion: number | undefined; - let newSysVersion = await projectHost.syncSystem?.(); + let newSysVersion = await sys.sync?.(); do { oldSysVersion = newSysVersion; try { @@ -893,12 +1010,12 @@ export function create( console.warn(err); break; } - newSysVersion = await projectHost.syncSystem?.(); + newSysVersion = await sys.sync?.(); } while (newSysVersion !== oldSysVersion && !token.isCancellationRequested); return result; } - function getVirtualScriptByUri(uri: string): { + function getVirtualScriptByUri(uri: URI): { fileName: string; code: VirtualCode; } | undefined { @@ -907,7 +1024,7 @@ export function create( const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]); if (virtualCode && sourceScript?.generated?.languagePlugin.typescript) { const { getServiceScript, getExtraServiceScripts } = sourceScript.generated?.languagePlugin.typescript; - const sourceFileName = context.env.typescript!.uriToFileName(sourceScript.id); + const sourceFileName = asFileName(sourceScript.id); if (getServiceScript(sourceScript.generated.root)?.code === virtualCode) { return { fileName: sourceFileName, diff --git a/packages/typescript/lib/plugins/syntactic.ts b/packages/typescript/lib/plugins/syntactic.ts index d3616801..9f89cdf9 100644 --- a/packages/typescript/lib/plugins/syntactic.ts +++ b/packages/typescript/lib/plugins/syntactic.ts @@ -1,6 +1,6 @@ import type { ProviderResult, - ServiceContext, + LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; @@ -52,23 +52,31 @@ export function create( isFormattingEnabled = async (document, context) => { return await context.env.getConfiguration?.(getConfigTitle(document) + '.format.enable') ?? true; }, - isAutoClosingTagsEnabled = async (document, context) => { - return await context.env.getConfiguration?.(getConfigTitle(document) + '.autoClosingTags') ?? true; - }, }: { - isFormattingEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; - isAutoClosingTagsEnabled?(document: TextDocument, context: ServiceContext): ProviderResult; + isFormattingEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; + isAutoClosingTagsEnabled?(document: TextDocument, context: LanguageServiceContext): ProviderResult; } = {}, ): LanguageServicePlugin { return { name: 'typescript-syntactic', - // https://github.com/microsoft/vscode/blob/ce119308e8fd4cd3f992d42b297588e7abe33a0c/extensions/typescript-language-features/src/languageFeatures/formatting.ts#L99 - autoFormatTriggerCharacters: [';', '}', '\n'], + capabilities: { + autoInsertionProvider: { + triggerCharacters: ['>', '>'], + configurationSections: ['javascript.autoClosingTags', 'typescript.autoClosingTags'], + }, + foldingRangeProvider: true, + documentSymbolProvider: true, + documentFormattingProvider: true, + documentOnTypeFormattingProvider: { + // https://github.com/microsoft/vscode/blob/ce119308e8fd4cd3f992d42b297588e7abe33a0c/extensions/typescript-language-features/src/languageFeatures/formatting.ts#L99 + triggerCharacters: [';', '}', '\n'], + }, + }, create(context): LanguageServicePluginInstance { return { - async provideAutoInsertionEdit(document, selection, change) { + async provideAutoInsertSnippet(document, selection, change) { // selection must at end of change if (document.offsetAt(selection) !== change.rangeOffset + change.text.length) { return; @@ -76,7 +84,7 @@ export function create( if ( (document.languageId === 'javascriptreact' || document.languageId === 'typescriptreact') && change.text.endsWith('>') - && await isAutoClosingTagsEnabled(document, context) + && (await context.env.getConfiguration?.(getConfigTitle(document) + '.autoClosingTags') ?? true) ) { const { languageService, fileName } = getLanguageServiceByDocument(ts, document); const close = languageService.getJsxClosingTagAtPosition(fileName, document.offsetAt(selection)); diff --git a/packages/typescript/lib/semanticFeatures/codeAction.ts b/packages/typescript/lib/semanticFeatures/codeAction.ts index 3cdf8295..341b3e03 100644 --- a/packages/typescript/lib/semanticFeatures/codeAction.ts +++ b/packages/typescript/lib/semanticFeatures/codeAction.ts @@ -1,13 +1,14 @@ import type * as vscode from '@volar/language-service'; import type * as ts from 'typescript'; +import type { TextDocument } from 'vscode-languageserver-textdocument'; +import type { URI } from 'vscode-uri'; import { getFormatCodeSettings } from '../configs/getFormatCodeSettings'; import { getUserPreferences } from '../configs/getUserPreferences'; import { safeCall } from '../shared'; -import type { SharedContext } from './types'; import * as fixNames from '../utils/fixNames'; -import { resolveFixAllCodeAction, resolveOrganizeImportsCodeAction, resolveRefactorCodeAction } from './codeActionResolve'; -import type { TextDocument } from 'vscode-languageserver-textdocument'; import { convertFileTextChanges } from '../utils/lspConverters'; +import { resolveFixAllCodeAction, resolveOrganizeImportsCodeAction, resolveRefactorCodeAction } from './codeActionResolve'; +import type { SharedContext } from './types'; export interface FixAllData { type: 'fixAll'; @@ -61,13 +62,13 @@ export function register(ctx: SharedContext) { resolveEditSupport = true; } - return async (document: TextDocument, range: vscode.Range, context: vscode.CodeActionContext, formattingOptions: vscode.FormattingOptions | undefined) => { + return async (uri: URI, document: TextDocument, range: vscode.Range, context: vscode.CodeActionContext, formattingOptions: vscode.FormattingOptions | undefined) => { const [formatOptions, preferences] = await Promise.all([ getFormatCodeSettings(ctx, document, formattingOptions), getUserPreferences(ctx, document), ]); - const fileName = ctx.uriToFileName(document.uri); + const fileName = ctx.uriToFileName(uri); const start = document.offsetAt(range.start); const end = document.offsetAt(range.end); let result: vscode.CodeAction[] = []; diff --git a/packages/typescript/lib/semanticFeatures/codeActionResolve.ts b/packages/typescript/lib/semanticFeatures/codeActionResolve.ts index 71eee898..27075b60 100644 --- a/packages/typescript/lib/semanticFeatures/codeActionResolve.ts +++ b/packages/typescript/lib/semanticFeatures/codeActionResolve.ts @@ -7,12 +7,13 @@ import { safeCall } from '../shared'; import type { SharedContext } from './types'; import type { Data, FixAllData, RefactorData } from './codeAction'; import { convertFileTextChanges } from '../utils/lspConverters'; +import { URI } from 'vscode-uri'; export function register(ctx: SharedContext) { return async (codeAction: vscode.CodeAction, formattingOptions: vscode.FormattingOptions | undefined) => { const data: Data = codeAction.data; - const document = ctx.getTextDocument(data.uri)!; + const document = ctx.getTextDocument(URI.parse(data.uri))!; const [formatOptions, preferences] = await Promise.all([ getFormatCodeSettings(ctx, document, formattingOptions), getUserPreferences(ctx, document), diff --git a/packages/typescript/lib/semanticFeatures/semanticTokens.ts b/packages/typescript/lib/semanticFeatures/semanticTokens.ts index 187e2995..a7f94499 100644 --- a/packages/typescript/lib/semanticFeatures/semanticTokens.ts +++ b/packages/typescript/lib/semanticFeatures/semanticTokens.ts @@ -2,10 +2,11 @@ import type * as vscode from '@volar/language-service'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import { safeCall } from '../shared'; import type { SharedContext } from './types'; +import type { URI } from 'vscode-uri'; export function register(ts: typeof import('typescript'), ctx: SharedContext) { - return (document: TextDocument, range: vscode.Range, legend: vscode.SemanticTokensLegend) => { - const fileName = ctx.uriToFileName(document.uri); + return (uri: URI, document: TextDocument, range: vscode.Range, legend: vscode.SemanticTokensLegend) => { + const fileName = ctx.uriToFileName(uri); const start = range ? document.offsetAt(range.start) : 0; const length = range ? (document.offsetAt(range.end) - start) : document.getText().length; diff --git a/packages/typescript/lib/semanticFeatures/types.ts b/packages/typescript/lib/semanticFeatures/types.ts index 950f3e72..e63350da 100644 --- a/packages/typescript/lib/semanticFeatures/types.ts +++ b/packages/typescript/lib/semanticFeatures/types.ts @@ -1,11 +1,12 @@ -import type { ServiceContext } from '@volar/language-service'; +import type { LanguageServiceContext } from '@volar/language-service'; import type * as ts from 'typescript'; import type { TextDocument } from 'vscode-languageserver-textdocument'; +import type { URI } from 'vscode-uri'; -export type SharedContext = ServiceContext & { +export type SharedContext = LanguageServiceContext & { languageServiceHost: ts.LanguageServiceHost; languageService: ts.LanguageService; - getTextDocument: (uri: string) => TextDocument | undefined; - uriToFileName: (uri: string) => string; - fileNameToUri: (fileName: string) => string; + getTextDocument: (uri: URI) => TextDocument | undefined; + uriToFileName: (uri: URI) => string; + fileNameToUri: (fileName: string) => URI; }; diff --git a/packages/typescript/lib/utils/lspConverters.ts b/packages/typescript/lib/utils/lspConverters.ts index 21d35abf..7b97eaf8 100644 --- a/packages/typescript/lib/utils/lspConverters.ts +++ b/packages/typescript/lib/utils/lspConverters.ts @@ -1,22 +1,23 @@ import type * as vscode from '@volar/language-service'; import * as path from 'path-browserify'; +import * as semver from 'semver'; import type * as ts from 'typescript'; import type { TextDocument } from 'vscode-languageserver-textdocument'; +import type { URI } from 'vscode-uri'; import * as PConst from '../protocol.const'; -import { notEmpty } from '../shared'; import type { SharedContext } from '../semanticFeatures/types'; +import { notEmpty } from '../shared'; import { parseKindModifier } from '../utils/modifiers'; import * as previewer from '../utils/previewer'; import * as typeConverters from '../utils/typeConverters'; -import * as semver from 'semver'; // diagnostics export function convertDiagnostic( diag: ts.Diagnostic, document: TextDocument, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): vscode.Diagnostic | undefined { if (diag.start === undefined) { @@ -60,8 +61,8 @@ export function convertDiagnostic( function convertDiagnosticRelatedInformation( diag: ts.Diagnostic, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): vscode.DiagnosticRelatedInformation | undefined { if (diag.start === undefined) { @@ -128,8 +129,8 @@ export function applyCompletionEntryDetails( item: vscode.CompletionItem, data: ts.CompletionEntryDetails, document: TextDocument, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ) { const { sourceDisplay } = data; if (sourceDisplay) { @@ -612,8 +613,8 @@ export function convertSelectionRange(range: ts.SelectionRange, document: TextDo export function convertFileTextChanges( changes: readonly ts.FileTextChanges[], - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ) { const workspaceEdit: vscode.WorkspaceEdit = {}; for (const change of changes) { @@ -622,10 +623,10 @@ export function convertFileTextChanges( } const uri = fileNameToUri(change.fileName); if (change.isNewFile) { - workspaceEdit.documentChanges.push({ kind: 'create', uri }); + workspaceEdit.documentChanges.push({ kind: 'create', uri: uri.toString() }); workspaceEdit.documentChanges.push({ textDocument: { - uri, + uri: uri.toString(), version: null, // fix https://github.com/johnsoncodehk/volar/issues/2025 }, edits: change.textChanges.map(edit => ({ @@ -641,7 +642,7 @@ export function convertFileTextChanges( const doc = getTextDocument(uri); workspaceEdit.documentChanges.push({ textDocument: { - uri, + uri: uri.toString(), version: null, // fix https://github.com/johnsoncodehk/volar/issues/2025 }, edits: change.textChanges.map(edit => convertTextChange(edit, doc)), @@ -656,8 +657,8 @@ export function convertFileTextChanges( export function convertRenameLocations( newText: string, locations: readonly ts.RenameLocation[], - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ) { const workspaceEdit: vscode.WorkspaceEdit = {}; for (const location of locations) { @@ -666,8 +667,8 @@ export function convertRenameLocations( } const uri = fileNameToUri(location.fileName); const doc = getTextDocument(uri); - if (!workspaceEdit.changes[uri]) { - workspaceEdit.changes[uri] = []; + if (!workspaceEdit.changes[uri.toString()]) { + workspaceEdit.changes[uri.toString()] = []; } let _newText = newText; if (location.prefixText) { @@ -676,7 +677,7 @@ export function convertRenameLocations( if (location.suffixText) { _newText = _newText + location.suffixText; } - workspaceEdit.changes[uri].push({ + workspaceEdit.changes[uri.toString()].push({ newText: _newText, range: convertTextSpan(location.textSpan, doc), }); @@ -690,8 +691,8 @@ export function convertQuickInfo( ts: typeof import('typescript'), info: ts.QuickInfo, document: TextDocument, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): vscode.Hover { const parts: string[] = []; const displayString = ts.displayPartsToString(info.displayParts); @@ -875,7 +876,7 @@ export function convertCallHierarchyItem(item: ts.CallHierarchyItem, ctx: Shared kind: typeConverters.SymbolKind.fromProtocolScriptElementKind(item.kind), name, detail, - uri, + uri: uri.toString(), range: convertTextSpan(item.span, document), selectionRange: convertTextSpan(item.selectionSpan, document), }; @@ -898,7 +899,7 @@ export function convertDocumentSpanToLocation(documentSpan: ts.DocumentSpan, ctx const document = ctx.getTextDocument(uri); const range = convertTextSpan(documentSpan.textSpan, document); return { - uri, + uri: uri.toString(), range, }; } @@ -930,7 +931,7 @@ export function convertDocumentSpantoLocationLink(documentSpan: ts.DocumentSpan, ? convertTextSpan(documentSpan.originalTextSpan, document) : undefined; return { - targetUri, + targetUri: targetUri.toString(), targetRange, targetSelectionRange, originSelectionRange, diff --git a/packages/typescript/lib/utils/previewer.ts b/packages/typescript/lib/utils/previewer.ts index 94648f27..fd4fb954 100644 --- a/packages/typescript/lib/utils/previewer.ts +++ b/packages/typescript/lib/utils/previewer.ts @@ -5,6 +5,7 @@ import type * as ts from 'typescript'; import type { TextDocument } from 'vscode-languageserver-textdocument'; +import type { URI } from 'vscode-uri'; function replaceLinks(text: string): string { return text @@ -26,8 +27,8 @@ function processInlineTags(text: string): string { function getTagBodyText( tag: ts.server.protocol.JSDocTagInfo, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): string | undefined { if (!tag.text) { return undefined; @@ -69,8 +70,8 @@ function getTagBodyText( function getTagDocumentation( tag: ts.server.protocol.JSDocTagInfo, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): string | undefined { switch (tag.name) { case 'augments': @@ -100,8 +101,8 @@ function getTagDocumentation( export function plainWithLinks( parts: readonly ts.server.protocol.SymbolDisplayPart[] | string, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): string { return processInlineTags(convertLinkTags(parts, fileNameToUri, getTextDocument)); } @@ -111,8 +112,8 @@ export function plainWithLinks( */ function convertLinkTags( parts: readonly ts.server.protocol.SymbolDisplayPart[] | string | undefined, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): string { if (!parts) { return ''; @@ -206,8 +207,8 @@ function convertLinkTags( export function tagsMarkdownPreview( tags: readonly ts.JSDocTagInfo[], - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): string { return tags.map(tag => getTagDocumentation(tag, fileNameToUri, getTextDocument)).join(' \n\n'); } @@ -215,8 +216,8 @@ export function tagsMarkdownPreview( export function markdownDocumentation( documentation: ts.server.protocol.SymbolDisplayPart[] | string | undefined, tags: ts.JSDocTagInfo[] | undefined, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): string { return addMarkdownDocumentation('', documentation, tags, fileNameToUri, getTextDocument); } @@ -225,8 +226,8 @@ export function addMarkdownDocumentation( out: string, documentation: ts.server.protocol.SymbolDisplayPart[] | string | undefined, tags: ts.JSDocTagInfo[] | undefined, - fileNameToUri: (fileName: string) => string, - getTextDocument: (uri: string) => TextDocument | undefined, + fileNameToUri: (fileName: string) => URI, + getTextDocument: (uri: URI) => TextDocument | undefined, ): string { if (documentation) { out += plainWithLinks(documentation, fileNameToUri, getTextDocument); diff --git a/packages/typescript/package.json b/packages/typescript/package.json index 1902767b..f5f133ab 100644 --- a/packages/typescript/package.json +++ b/packages/typescript/package.json @@ -32,10 +32,11 @@ "semver": "^7.5.4", "typescript-auto-import-cache": "^0.3.1", "vscode-languageserver-textdocument": "^1.0.11", - "vscode-nls": "^5.2.0" + "vscode-nls": "^5.2.0", + "vscode-uri": "^3.0.8" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/vetur/index.ts b/packages/vetur/index.ts index 01fc0eaa..7cb98b56 100644 --- a/packages/vetur/index.ts +++ b/packages/vetur/index.ts @@ -1,17 +1,29 @@ -import type { SemanticToken, LanguageServicePluginInstance, LanguageServicePlugin } from '@volar/language-service'; +import type { LanguageServicePlugin, LanguageServicePluginInstance, SemanticToken } from '@volar/language-service'; import * as fs from 'fs'; import * as path from 'path'; import * as vls from 'vls'; import type { TextDocument } from 'vscode-html-languageservice'; import * as html from 'vscode-html-languageservice'; +import { URI } from 'vscode-uri'; import { getGlobalSnippetDir } from './lib/userSnippetDir'; export function create(): LanguageServicePlugin { return { name: 'vetur', - // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/html-language-features/server/src/htmlServer.ts#L183 - triggerCharacters: ['.', ':', '<', '"', '=', '/', /* vue event shorthand */'@'], - create(context): LanguageServicePluginInstance { + capabilities: { + completionProvider: { + // https://github.com/microsoft/vscode/blob/09850876e652688fb142e2e19fd00fd38c0bc4ba/extensions/html-language-features/server/src/htmlServer.ts#L183 + triggerCharacters: ['.', ':', '<', '"', '=', '/', /* vue event shorthand */'@'], + }, + hoverProvider: true, + semanticTokensProvider: { + legend: { + tokenTypes: ['function'], + tokenModifiers: [], + }, + }, + }, + create(): LanguageServicePluginInstance { const htmlDocuments = new WeakMap(); const uriToPackageJsonPath = new Map(); @@ -57,7 +69,7 @@ export function create(): LanguageServicePlugin { }); }, - provideDocumentSemanticTokens(document, range) { + provideDocumentSemanticTokens(document, range, legend) { return htmlWorker(document, () => { const packageJsonPath = getPackageJsonPath(document); @@ -95,7 +107,7 @@ export function create(): LanguageServicePlugin { const tokenPosition = document.positionAt(tokenOffset); if (components.has(tokenText)) { - result.push([tokenPosition.line, tokenPosition.character, tokenLength, 10/* 10: function, 12: component */, 0]); + result.push([tokenPosition.line, tokenPosition.character, tokenLength, legend.tokenTypes.indexOf('function'), 0]); } } } @@ -139,21 +151,26 @@ export function create(): LanguageServicePlugin { if (!packageJsonPath) { - let lastDirname = context.env.typescript!.uriToFileName(document.uri); + const uri = URI.parse(document.uri); - while (true) { + if (uri.scheme === 'file') { - const dirname = path.dirname(lastDirname); - if (dirname === lastDirname) { - break; - } + let lastDirname = uri.fsPath.replace(/\\/g, '/'); - if (fs.existsSync(dirname + '/package.json')) { - packageJsonPath = dirname + '/package.json'; - break; - } + while (true) { - lastDirname = dirname; + const dirname = path.dirname(lastDirname); + if (dirname === lastDirname) { + break; + } + + if (fs.existsSync(dirname + '/package.json')) { + packageJsonPath = dirname + '/package.json'; + break; + } + + lastDirname = dirname; + } } uriToPackageJsonPath.set(document.uri, packageJsonPath); diff --git a/packages/vetur/package.json b/packages/vetur/package.json index a75c0f65..709bb9ff 100644 --- a/packages/vetur/package.json +++ b/packages/vetur/package.json @@ -25,10 +25,11 @@ }, "dependencies": { "vls": "^0.8.5", - "vscode-html-languageservice": "npm:@johnsoncodehk/vscode-html-languageservice@5.2.0-34a5462" + "vscode-html-languageservice": "npm:@johnsoncodehk/vscode-html-languageservice@5.2.0-34a5462", + "vscode-uri": "^3.0.8" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/packages/yaml/index.ts b/packages/yaml/index.ts index 7ea75fe3..37e9d6fa 100644 --- a/packages/yaml/index.ts +++ b/packages/yaml/index.ts @@ -1,4 +1,4 @@ -import type { Disposable, DocumentSelector, ProviderResult, ServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; +import type { Disposable, DocumentSelector, ProviderResult, LanguageServiceContext, LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import { URI, Utils } from 'vscode-uri'; import * as yaml from 'yaml-language-server'; @@ -17,12 +17,13 @@ export function create({ getWorkspaceContextService = context => { return { resolveRelativePath(relativePath, resource) { - const decoded = context.decodeEmbeddedDocumentUri(resource); + const base = resource.substring(0, resource.lastIndexOf('/') + 1); + let baseUri = URI.parse(base); + const decoded = context.decodeEmbeddedDocumentUri(baseUri); if (decoded) { - resource = decoded[0]; + baseUri = decoded[0]; } - const base = resource.substring(0, resource.lastIndexOf('/') + 1); - return Utils.resolvePath(URI.parse(base), relativePath).toString(); + return Utils.resolvePath(baseUri, relativePath).toString(); }, }; }, @@ -42,17 +43,32 @@ export function create({ }, }: { documentSelector?: DocumentSelector; - getWorkspaceContextService?(context: ServiceContext): yaml.WorkspaceContextService; - getLanguageSettings?(context: ServiceContext): ProviderResult; - onDidChangeLanguageSettings?(listener: () => void, context: ServiceContext): Disposable; + getWorkspaceContextService?(context: LanguageServiceContext): yaml.WorkspaceContextService; + getLanguageSettings?(context: LanguageServiceContext): ProviderResult; + onDidChangeLanguageSettings?(listener: () => void, context: LanguageServiceContext): Disposable; } = {}): LanguageServicePlugin { return { name: 'yaml', - triggerCharacters: [' ', ':'], + capabilities: { + codeActionProvider: {}, + codeLensProvider: { + resolveProvider: true, + }, + completionProvider: { + triggerCharacters: [' ', ':'], + }, + definitionProvider: true, + diagnosticProvider: true, + documentSymbolProvider: true, + hoverProvider: true, + documentLinkProvider: {}, + foldingRangeProvider: true, + selectionRangeProvider: true, + }, create(context): LanguageServicePluginInstance { const ls = yaml.getLanguageService({ - schemaRequestService: async uri => await context.env.fs?.readFile(uri) ?? '', + schemaRequestService: async uri => await context.env.fs?.readFile(URI.parse(uri)) ?? '', telemetry: { send: noop, sendError: noop, diff --git a/packages/yaml/package.json b/packages/yaml/package.json index 0150836c..396d5738 100644 --- a/packages/yaml/package.json +++ b/packages/yaml/package.json @@ -31,7 +31,7 @@ "vscode-languageserver-textdocument": "^1.0.11" }, "peerDependencies": { - "@volar/language-service": "~2.2.3" + "@volar/language-service": "~2.3.0-alpha.0" }, "peerDependenciesMeta": { "@volar/language-service": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 23f0fbc1..9d8aaf1a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -18,8 +18,8 @@ importers: specifier: latest version: 3.4.0(@lerna-lite/exec@3.4.0)(typescript@5.4.5) '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 '@volar/tsl-config': specifier: latest version: 0.0.0-20240315.2(tsl@0.0.10(typescript@5.4.5)) @@ -36,8 +36,8 @@ importers: packages/css: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 vscode-css-languageservice: specifier: ^6.2.10 version: 6.2.14 @@ -61,11 +61,14 @@ importers: specifier: ^1.3.0 version: 1.3.0 '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 '@vscode/emmet-helper': specifier: ^2.9.2 version: 2.9.3 + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 devDependencies: '@types/node': specifier: latest @@ -74,8 +77,8 @@ importers: packages/html: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 vscode-html-languageservice: specifier: npm:@johnsoncodehk/vscode-html-languageservice@5.2.0-34a5462 version: '@johnsoncodehk/vscode-html-languageservice@5.2.0-34a5462' @@ -93,8 +96,8 @@ importers: packages/json: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 vscode-json-languageservice: specifier: ^5.3.7 version: 5.3.11 @@ -109,8 +112,8 @@ importers: packages/markdown: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 markdown-it: specifier: ^13.0.2 version: 13.0.2 @@ -134,8 +137,8 @@ importers: packages/prettier: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 vscode-uri: specifier: ^3.0.8 version: 3.0.8 @@ -153,14 +156,14 @@ importers: specifier: ^0.10.0 version: 0.10.0 '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 packages/pug: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 pug-lexer: specifier: ^5.0.1 version: 5.0.1 @@ -187,8 +190,8 @@ importers: specifier: ^0.2.2 version: 0.2.2 '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 devDependencies: '@types/node': specifier: latest @@ -197,8 +200,8 @@ importers: packages/sass-formatter: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 sass-formatter: specifier: ^0.7.8 version: 0.7.9 @@ -206,8 +209,8 @@ importers: packages/typescript: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 path-browserify: specifier: ^1.0.1 version: 1.0.1 @@ -223,6 +226,9 @@ importers: vscode-nls: specifier: ^5.2.0 version: 5.2.0 + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 devDependencies: '@types/path-browserify': specifier: latest @@ -234,8 +240,11 @@ importers: packages/typescript-twoslash-queries: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 devDependencies: volar-service-typescript: specifier: 0.0.47 @@ -244,14 +253,17 @@ importers: packages/vetur: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 vls: specifier: ^0.8.5 version: 0.8.5 vscode-html-languageservice: specifier: npm:@johnsoncodehk/vscode-html-languageservice@5.2.0-34a5462 version: '@johnsoncodehk/vscode-html-languageservice@5.2.0-34a5462' + vscode-uri: + specifier: ^3.0.8 + version: 3.0.8 devDependencies: '@types/node': specifier: latest @@ -260,8 +272,8 @@ importers: packages/yaml: dependencies: '@volar/language-service': - specifier: ~2.2.3 - version: 2.2.3 + specifier: ~2.3.0-alpha.0 + version: 2.3.0-alpha.0 vscode-uri: specifier: ^3.0.8 version: 3.0.8 @@ -799,14 +811,14 @@ packages: '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - '@volar/language-core@2.2.3': - resolution: {integrity: sha512-8GT6QiWJMdiU4k/PStcGYLGYjoaQnN/hbFNtHvturzdIiK2tJRmZuub4tBrwGS4AeklhkvA32E6fPdGMQkMPLA==} + '@volar/language-core@2.3.0-alpha.0': + resolution: {integrity: sha512-k7eAxGIZZz2G0zBfV6yM/btuE78eYxq04G/uvbK7/GEBo4ZApKw6DJpnPjh6sS8cE/NjY9C48Nd9pn7tD23VzA==} - '@volar/language-service@2.2.3': - resolution: {integrity: sha512-hqIUdrODcmyddHsK6hqqcBJc6pJN6BZ86uD7r+ka77iN70zcVMNdymqlMeSPCPSPkC2Ar2rhCGhNoVvEDyim/g==} + '@volar/language-service@2.3.0-alpha.0': + resolution: {integrity: sha512-+U1oqropMIzIMS0s8HVNVSkBlsWYVPUg44Yhagz5Nah79XN3i3Aa5dRrx/cOgM7EEfdQOtX9BFM6JrdNwGeBvw==} - '@volar/source-map@2.2.3': - resolution: {integrity: sha512-Be1rBnC0yvLprcCaoNxU+hLUguYQt4jp/IBnwdMbCXLDWIU0fXHgPPIBWmYSiGe0uu0ns5cQMEqzNsGwiX/mGw==} + '@volar/source-map@2.3.0-alpha.0': + resolution: {integrity: sha512-UU68C+c9e0jLCg6KKYOQaq8n3QYwcscVRCh8BbPimXALaHIFr06WE7BbW3BAD+pSnDtYfJQc7pmAlHG1pQT9MA==} '@volar/tsl-config@0.0.0-20240315.2': resolution: {integrity: sha512-bv57xhmegLkfjW0/FZL/sberfmUch7yLAkXlRXj5KxHPYCjIU4T1ciPuLWrtVzCa+o0q7ykQ6aR+Q/z7MSMf6w==} @@ -4155,18 +4167,18 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@volar/language-core@2.2.3': + '@volar/language-core@2.3.0-alpha.0': dependencies: - '@volar/source-map': 2.2.3 + '@volar/source-map': 2.3.0-alpha.0 - '@volar/language-service@2.2.3': + '@volar/language-service@2.3.0-alpha.0': dependencies: - '@volar/language-core': 2.2.3 + '@volar/language-core': 2.3.0-alpha.0 vscode-languageserver-protocol: 3.17.5 vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 - '@volar/source-map@2.2.3': + '@volar/source-map@2.3.0-alpha.0': dependencies: muggle-string: 0.4.1