diff --git a/packages/language-core/src/languageContext.ts b/packages/language-core/src/languageContext.ts index 512995068..f4f6f3cf7 100644 --- a/packages/language-core/src/languageContext.ts +++ b/packages/language-core/src/languageContext.ts @@ -136,6 +136,7 @@ export function createLanguageContext( // delete virtualFiles.delete(fileName); shouldUpdateTsProject = true; + virtualFilesUpdatedNum++; continue; } diff --git a/packages/language-server/src/common/project.ts b/packages/language-server/src/common/project.ts index 7c5ad1622..87c257496 100644 --- a/packages/language-server/src/common/project.ts +++ b/packages/language-server/src/common/project.ts @@ -8,11 +8,11 @@ import * as vscode from 'vscode-languageserver'; import { URI } from 'vscode-uri'; import { FileSystem, LanguageServerPlugin } from '../types'; import { createUriMap } from './utils/uriMap'; -import { WorkspaceParams } from './workspace'; +import { WorkspaceContext } from './workspace'; import { LanguageServicePlugin } from '@volar/language-service'; -export interface ProjectParams { - workspace: WorkspaceParams; +export interface ProjectContext { + workspace: WorkspaceContext; rootUri: URI; tsConfig: path.PosixPath | ts.CompilerOptions, documentRegistry: ts.DocumentRegistry, @@ -21,19 +21,15 @@ export interface ProjectParams { export type Project = ReturnType; -export async function createProject(params: ProjectParams) { +export async function createProject(context: ProjectContext) { - const { tsConfig, documentRegistry, rootUri } = params; - const { ts, fileSystemHost, documents, cancelTokenHost, tsLocalized, initOptions, configurationHost } = params.workspace.workspaces; - const { plugins } = params.workspace.workspaces; - const { runtimeEnv } = params.workspace.workspaces.server; - const sys = fileSystemHost.getWorkspaceFileSystem(rootUri); + const sys = context.workspace.workspaces.fileSystemHost.getWorkspaceFileSystem(context.rootUri); let typeRootVersion = 0; let projectVersion = 0; - let projectVersionUpdateTime = cancelTokenHost.getMtime(); - let vueLs: embeddedLS.LanguageService | undefined; - let parsedCommandLine = createParsedCommandLine(ts, sys, shared.getPathOfUri(rootUri.toString()), tsConfig, plugins); + let projectVersionUpdateTime = context.workspace.workspaces.cancelTokenHost.getMtime(); + let languageService: embeddedLS.LanguageService | undefined; + let parsedCommandLine = createParsedCommandLine(context.workspace.workspaces.ts, sys, shared.getPathOfUri(context.rootUri.toString()), context.tsConfig, context.workspace.workspaces.plugins); const scripts = createUriMap<{ version: number, @@ -42,65 +38,64 @@ export async function createProject(params: ProjectParams) { snapshotVersion: number | undefined, }>(); const languageServiceHost = createLanguageServiceHost(); - - const disposeWatchEvent = fileSystemHost.onDidChangeWatchedFiles(params => { + const disposeWatchEvent = context.workspace.workspaces.fileSystemHost.onDidChangeWatchedFiles(params => { onWorkspaceFilesChanged(params.changes); }); - const disposeDocChange = documents.onDidChangeContent(() => { + const disposeDocChange = context.workspace.workspaces.documents.onDidChangeContent(() => { projectVersion++; - projectVersionUpdateTime = cancelTokenHost.getMtime(); + projectVersionUpdateTime = context.workspace.workspaces.cancelTokenHost.getMtime(); }); return { - tsConfig, + tsConfig: context.tsConfig, scripts, languageServiceHost, getLanguageService, - getLanguageServiceDontCreate: () => vueLs, + getLanguageServiceDontCreate: () => languageService, getParsedCommandLine: () => parsedCommandLine, tryAddFile: (fileName: string) => { if (!parsedCommandLine.fileNames.includes(fileName)) { parsedCommandLine.fileNames.push(fileName); projectVersion++; - projectVersionUpdateTime = cancelTokenHost.getMtime(); + projectVersionUpdateTime = context.workspace.workspaces.cancelTokenHost.getMtime(); } }, dispose, }; function getLanguageService() { - if (!vueLs) { + if (!languageService) { - const languageModules = plugins.map(plugin => plugin.semanticService?.getLanguageModules?.(languageServiceHost) ?? []).flat(); + const languageModules = context.workspace.workspaces.plugins.map(plugin => plugin.semanticService?.getLanguageModules?.(languageServiceHost) ?? []).flat(); const languageContext = embedded.createLanguageContext(languageServiceHost, languageModules); const languageServiceContext = embeddedLS.createLanguageServiceContext({ host: languageServiceHost, context: languageContext, getPlugins() { return [ - ...params.workspacePlugins, - ...plugins.map(plugin => plugin.semanticService?.getServicePlugins?.(languageServiceHost, vueLs!) ?? []).flat(), + ...context.workspacePlugins, + ...context.workspace.workspaces.plugins.map(plugin => plugin.semanticService?.getServicePlugins?.(languageServiceHost, languageService!) ?? []).flat(), ]; }, env: { - rootUri, - configurationHost: configurationHost, - fileSystemProvider: runtimeEnv.fileSystemProvide, - documentContext: getHTMLDocumentContext(ts, languageServiceHost), + rootUri: context.rootUri, + configurationHost: context.workspace.workspaces.configurationHost, + fileSystemProvider: context.workspace.workspaces.server.runtimeEnv.fileSystemProvide, + documentContext: getHTMLDocumentContext(context.workspace.workspaces.ts, languageServiceHost), schemaRequestService: async uri => { const protocol = uri.substring(0, uri.indexOf(':')); - const builtInHandler = runtimeEnv.schemaRequestHandlers[protocol]; + const builtInHandler = context.workspace.workspaces.server.runtimeEnv.schemaRequestHandlers[protocol]; if (builtInHandler) { return await builtInHandler(uri); } return ''; }, }, - documentRegistry, + documentRegistry: context.documentRegistry, }); - vueLs = embeddedLS.createLanguageService(languageServiceContext); + languageService = embeddedLS.createLanguageService(languageServiceContext); } - return vueLs; + return languageService; } async function onWorkspaceFilesChanged(changes: vscode.FileEvent[]) { @@ -131,20 +126,20 @@ export async function createProject(params: ProjectParams) { const deletes = changes.filter(change => change.type === vscode.FileChangeType.Deleted); if (creates.length || deletes.length) { - parsedCommandLine = createParsedCommandLine(ts, sys, shared.getPathOfUri(rootUri.toString()), tsConfig, plugins); + parsedCommandLine = createParsedCommandLine(context.workspace.workspaces.ts, sys, shared.getPathOfUri(context.rootUri.toString()), context.tsConfig, context.workspace.workspaces.plugins); projectVersion++; typeRootVersion++; } if (_projectVersion !== projectVersion) { - projectVersionUpdateTime = cancelTokenHost.getMtime(); + projectVersionUpdateTime = context.workspace.workspaces.cancelTokenHost.getMtime(); } } function createLanguageServiceHost() { const token: ts.CancellationToken = { isCancellationRequested() { - return cancelTokenHost.getMtime() !== projectVersionUpdateTime; + return context.workspace.workspaces.cancelTokenHost.getMtime() !== projectVersionUpdateTime; }, throwIfCancellationRequested() { }, }; @@ -159,16 +154,16 @@ export async function createProject(params: ProjectParams) { readDirectory: sys.readDirectory, realpath: sys.realpath, fileExists: sys.fileExists, - getCurrentDirectory: () => shared.getPathOfUri(rootUri.toString()), + getCurrentDirectory: () => shared.getPathOfUri(context.rootUri.toString()), getProjectReferences: () => parsedCommandLine.projectReferences, // if circular, broken with provide `getParsedCommandLine: () => parsedCommandLine` getCancellationToken: () => token, // custom getDefaultLibFileName: options => { try { - return ts.getDefaultLibFilePath(options); + return context.workspace.workspaces.ts.getDefaultLibFilePath(options); } catch { // web - return initOptions.typescript.tsdk + '/' + ts.getDefaultLibFileName(options); + return context.workspace.workspaces.initOptions.typescript.tsdk + '/' + context.workspace.workspaces.ts.getDefaultLibFileName(options); } }, getProjectVersion: () => projectVersion.toString(), @@ -177,10 +172,10 @@ export async function createProject(params: ProjectParams) { getCompilationSettings: () => parsedCommandLine.options, getScriptVersion, getScriptSnapshot, - getTypeScriptModule: () => ts, + getTypeScriptModule: () => context.workspace.workspaces.ts, }; - if (initOptions.noProjectReferences) { + if (context.workspace.workspaces.initOptions.noProjectReferences) { host.getProjectReferences = undefined; host.getCompilationSettings = () => ({ ...parsedCommandLine.options, @@ -189,13 +184,13 @@ export async function createProject(params: ProjectParams) { }); } - if (tsLocalized) { - host.getLocalizedDiagnosticMessages = () => tsLocalized; + if (context.workspace.workspaces.tsLocalized) { + host.getLocalizedDiagnosticMessages = () => context.workspace.workspaces.tsLocalized; } - for (const plugin of plugins) { + for (const plugin of context.workspace.workspaces.plugins) { if (plugin.semanticService?.resolveLanguageServiceHost) { - host = plugin.semanticService.resolveLanguageServiceHost(ts, sys, tsConfig, host); + host = plugin.semanticService.resolveLanguageServiceHost(context.workspace.workspaces.ts, sys, context.tsConfig, host); } } @@ -203,7 +198,7 @@ export async function createProject(params: ProjectParams) { function getScriptVersion(fileName: string) { - const doc = documents.data.pathGet(fileName); + const doc = context.workspace.workspaces.documents.data.pathGet(fileName); if (doc) { return doc.version.toString(); } @@ -212,7 +207,7 @@ export async function createProject(params: ProjectParams) { } function getScriptSnapshot(fileName: string) { - const doc = documents.data.pathGet(fileName); + const doc = context.workspace.workspaces.documents.data.pathGet(fileName); if (doc) { return doc.getSnapshot(); } @@ -223,16 +218,16 @@ export async function createProject(params: ProjectParams) { } if (sys.fileExists(fileName)) { - if (initOptions.maxFileSize) { + if (context.workspace.workspaces.initOptions.maxFileSize) { const fileSize = sys.getFileSize?.(fileName); - if (fileSize !== undefined && fileSize > initOptions.maxFileSize) { - console.warn(`IGNORING "${fileName}" because it is too large (${fileSize}bytes > ${initOptions.maxFileSize}bytes)`); - return ts.ScriptSnapshot.fromString(''); + if (fileSize !== undefined && fileSize > context.workspace.workspaces.initOptions.maxFileSize) { + console.warn(`IGNORING "${fileName}" because it is too large (${fileSize}bytes > ${context.workspace.workspaces.initOptions.maxFileSize}bytes)`); + return context.workspace.workspaces.ts.ScriptSnapshot.fromString(''); } } const text = sys.readFile(fileName, 'utf8'); if (text !== undefined) { - const snapshot = ts.ScriptSnapshot.fromString(text); + const snapshot = context.workspace.workspaces.ts.ScriptSnapshot.fromString(text); if (script) { script.snapshot = snapshot; script.snapshotVersion = script.version; @@ -251,7 +246,7 @@ export async function createProject(params: ProjectParams) { } } function dispose() { - vueLs?.dispose(); + languageService?.dispose(); scripts.clear(); disposeWatchEvent(); disposeDocChange(); diff --git a/packages/language-server/src/common/server.ts b/packages/language-server/src/common/server.ts index bacb79013..e51759582 100644 --- a/packages/language-server/src/common/server.ts +++ b/packages/language-server/src/common/server.ts @@ -8,15 +8,13 @@ import { createSyntaxServicesHost } from './syntaxServicesHost'; import { setupSemanticCapabilities, setupSyntacticCapabilities } from './utils/registerFeatures'; import { createWorkspaces } from './workspaces'; -export interface ServerParams { +export interface ServerContext { connection: vscode.Connection, runtimeEnv: RuntimeEnvironment, plugins: LanguageServerPlugin[], } -export function createCommonLanguageServer(params: ServerParams) { - - const { connection, runtimeEnv, plugins: _plugins } = params; +export function createCommonLanguageServer(context: ServerContext) { let initParams: vscode.InitializeParams; let options: LanguageServerInitializationOptions; @@ -27,13 +25,13 @@ export function createCommonLanguageServer(params: ServerParams) { let configurationHost: ReturnType | undefined; let plugins: ReturnType[]; - const documents = createDocuments(connection); + const documents = createDocuments(context.connection); - connection.onInitialize(async _params => { + context.connection.onInitialize(async _params => { initParams = _params; options = initParams.initializationOptions; - plugins = _plugins.map(plugin => plugin(options)); + plugins = context.plugins.map(plugin => plugin(options)); if (initParams.capabilities.workspace?.workspaceFolders && initParams.workspaceFolders) { roots = initParams.workspaceFolders.map(folder => URI.parse(folder.uri)); @@ -51,7 +49,7 @@ export function createCommonLanguageServer(params: ServerParams) { }, }; - configurationHost = initParams.capabilities.workspace?.configuration ? createConfigurationHost(initParams, connection) : undefined; + configurationHost = initParams.capabilities.workspace?.configuration ? createConfigurationHost(initParams, context.connection) : undefined; const serverMode = options.serverMode ?? ServerMode.Semantic; @@ -74,13 +72,13 @@ export function createCommonLanguageServer(params: ServerParams) { return result; }); - connection.onInitialized(() => { + context.connection.onInitialized(() => { - fsHost?.ready(connection); + fsHost?.ready(context.connection); configurationHost?.ready(); if (initParams.capabilities.workspace?.workspaceFolders) { - connection.workspace.onDidChangeWorkspaceFolders(e => { + context.connection.workspace.onDidChangeWorkspaceFolders(e => { for (const folder of e.added) { documentServiceHost?.add(URI.parse(folder.uri)); @@ -99,7 +97,7 @@ export function createCommonLanguageServer(params: ServerParams) { && !options.disableFileWatcher && initParams.capabilities.workspace?.didChangeWatchedFiles?.dynamicRegistration ) { - connection.client.register(vscode.DidChangeWatchedFilesNotification.type, { + context.connection.client.register(vscode.DidChangeWatchedFilesNotification.type, { watchers: [ { globPattern: `**/*.{${[ @@ -119,14 +117,14 @@ export function createCommonLanguageServer(params: ServerParams) { }); } }); - connection.listen(); + context.connection.listen(); async function _createDocumentServiceHost() { - const ts = runtimeEnv.loadTypescript(options.typescript.tsdk); + const ts = context.runtimeEnv.loadTypescript(options.typescript.tsdk); documentServiceHost = createSyntaxServicesHost( - runtimeEnv, + context.runtimeEnv, plugins, ts, configurationHost, @@ -138,25 +136,25 @@ export function createCommonLanguageServer(params: ServerParams) { } (await import('./features/documentFeatures')).register( - connection, + context.connection, documents, documentServiceHost, ); for (const plugin of plugins) { - plugin.syntacticService?.onInitialize?.(connection); + plugin.syntacticService?.onInitialize?.(context.connection); } } async function createLanguageServiceHost() { - const ts = runtimeEnv.loadTypescript(options.typescript.tsdk); - fsHost = runtimeEnv.createFileSystemHost(ts, initParams.capabilities); + const ts = context.runtimeEnv.loadTypescript(options.typescript.tsdk); + fsHost = context.runtimeEnv.createFileSystemHost(ts, initParams.capabilities); - const tsLocalized = initParams.locale ? await runtimeEnv.loadTypescriptLocalized(options.typescript.tsdk, initParams.locale) : undefined; + const tsLocalized = initParams.locale ? await context.runtimeEnv.loadTypescriptLocalized(options.typescript.tsdk, initParams.locale) : undefined; const cancelTokenHost = createCancellationTokenHost(options.cancellationPipeName); const _projects = createWorkspaces({ - server: params, + server: context, fileSystemHost: fsHost, configurationHost, ts, @@ -173,11 +171,11 @@ export function createCommonLanguageServer(params: ServerParams) { projects.add(root); } - (await import('./features/customFeatures')).register(connection, projects); - (await import('./features/languageFeatures')).register(connection, projects, initParams, cancelTokenHost, getSemanticTokensLegend()); + (await import('./features/customFeatures')).register(context.connection, projects); + (await import('./features/languageFeatures')).register(context.connection, projects, initParams, cancelTokenHost, getSemanticTokensLegend()); for (const plugin of plugins) { - plugin.semanticService?.onInitialize?.(connection, getLanguageService as any); + plugin.semanticService?.onInitialize?.(context.connection, getLanguageService as any); } async function getLanguageService(uri: string) { diff --git a/packages/language-server/src/common/workspace.ts b/packages/language-server/src/common/workspace.ts index 9ba681103..8535ac2a1 100644 --- a/packages/language-server/src/common/workspace.ts +++ b/packages/language-server/src/common/workspace.ts @@ -7,33 +7,29 @@ import { createProject, Project } from './project'; import { getInferredCompilerOptions } from './utils/inferredCompilerOptions'; import { loadCustomPlugins } from './utils/serverConfig'; import { createUriMap } from './utils/uriMap'; -import { WorkspacesParams } from './workspaces'; +import { WorkspacesContext } from './workspaces'; export const rootTsConfigNames = ['tsconfig.json', 'jsconfig.json']; -export interface WorkspaceParams { - workspaces: WorkspacesParams; +export interface WorkspaceContext { + workspaces: WorkspacesContext; rootUri: URI, } -export async function createWorkspace(params: WorkspaceParams) { - - const { rootUri } = params; - const { ts, fileSystemHost, initOptions, configurationHost } = params.workspaces; +export async function createWorkspace(context: WorkspaceContext) { let inferredProject: Project | undefined; - const workspacePlugins = loadCustomPlugins(shared.getPathOfUri(rootUri.toString()), initOptions.configFilePath); - const sys = fileSystemHost.getWorkspaceFileSystem(rootUri); - const documentRegistry = ts.createDocumentRegistry(sys.useCaseSensitiveFileNames, shared.getPathOfUri(rootUri.toString())); + const workspacePlugins = loadCustomPlugins(shared.getPathOfUri(context.rootUri.toString()), context.workspaces.initOptions.configFilePath); + const sys = context.workspaces.fileSystemHost.getWorkspaceFileSystem(context.rootUri); + const documentRegistry = context.workspaces.ts.createDocumentRegistry(sys.useCaseSensitiveFileNames, shared.getPathOfUri(context.rootUri.toString())); const projects = createUriMap(); - const rootTsConfigs = new Set(sys.readDirectory(shared.getPathOfUri(rootUri.toString()), rootTsConfigNames, undefined, ['**/*']).map(fileName => shared.normalizeFileName(fileName))); - const disposeWatch = fileSystemHost.onDidChangeWatchedFiles(async (params) => { - const disposes: Promise[] = []; - for (const change of params.changes) { + const rootTsConfigs = new Set(sys.readDirectory(shared.getPathOfUri(context.rootUri.toString()), rootTsConfigNames, undefined, ['**/*']).map(fileName => shared.normalizeFileName(fileName))); + const disposeTsConfigWatch = context.workspaces.fileSystemHost.onDidChangeWatchedFiles(({ changes }) => { + for (const change of changes) { if (rootTsConfigNames.includes(change.uri.substring(change.uri.lastIndexOf('/') + 1))) { if (change.type === vscode.FileChangeType.Created) { - if (shared.isFileInDir(shared.getPathOfUri(change.uri), shared.getPathOfUri(rootUri.toString()))) { + if (shared.isFileInDir(shared.getPathOfUri(change.uri), shared.getPathOfUri(context.rootUri.toString()))) { rootTsConfigs.add(shared.getPathOfUri(change.uri)); } } @@ -41,15 +37,12 @@ export async function createWorkspace(params: WorkspaceParams) { if (change.type === vscode.FileChangeType.Deleted) { rootTsConfigs.delete(shared.getPathOfUri(change.uri)); } - const _project = projects.uriGet(change.uri); + const project = projects.uriGet(change.uri); projects.uriDelete(change.uri); - disposes.push((async () => { - (await _project)?.dispose(); - })()); + project?.then(project => project.dispose()); } } } - return Promise.all(disposes); }); return { @@ -61,7 +54,7 @@ export async function createWorkspace(params: WorkspaceParams) { reload: clearProjects, dispose() { clearProjects(); - disposeWatch(); + disposeTsConfigWatch(); }, }; @@ -90,11 +83,11 @@ export async function createWorkspace(params: WorkspaceParams) { function getInferredProject() { if (!inferredProject) { inferredProject = (async () => { - const inferOptions = await getInferredCompilerOptions(ts, configurationHost); + const inferOptions = await getInferredCompilerOptions(context.workspaces.ts, context.workspaces.configurationHost); return createProject({ - workspace: params, + workspace: context, workspacePlugins, - rootUri, + rootUri: context.rootUri, tsConfig: inferOptions, documentRegistry, }); @@ -153,7 +146,7 @@ export async function createWorkspace(params: WorkspaceParams) { let chains = await getReferencesChains(project.getParsedCommandLine(), rootTsConfig, []); - if (initOptions.reverseConfigFilePriority) { + if (context.workspaces.initOptions.reverseConfigFilePriority) { chains = chains.reverse(); } @@ -224,7 +217,7 @@ export async function createWorkspace(params: WorkspaceParams) { let project = projects.pathGet(tsConfig); if (!project) { project = createProject({ - workspace: params, + workspace: context, workspacePlugins, rootUri: URI.parse(shared.getUriByPath(path.dirname(tsConfig))), tsConfig, diff --git a/packages/language-server/src/common/workspaces.ts b/packages/language-server/src/common/workspaces.ts index 964ecc106..73ea27809 100644 --- a/packages/language-server/src/common/workspaces.ts +++ b/packages/language-server/src/common/workspaces.ts @@ -6,11 +6,11 @@ import { URI } from 'vscode-uri'; import { DiagnosticModel, FileSystemHost, LanguageServerInitializationOptions, LanguageServerPlugin } from '../types'; import { CancellationTokenHost } from './cancellationPipe'; import { createDocuments } from './documents'; -import { ServerParams } from './server'; +import { ServerContext } from './server'; import { createWorkspace, rootTsConfigNames, sortTsConfigs } from './workspace'; -export interface WorkspacesParams { - server: ServerParams; +export interface WorkspacesContext { + server: ServerContext; initParams: vscode.InitializeParams, initOptions: LanguageServerInitializationOptions, plugins: ReturnType[], @@ -24,43 +24,40 @@ export interface WorkspacesParams { export interface Workspaces extends ReturnType { } -export function createWorkspaces(params: WorkspacesParams) { +export function createWorkspaces(context: WorkspacesContext) { - const { fileSystemHost, configurationHost, initParams, initOptions, documents, cancelTokenHost } = params; - const { connection, runtimeEnv } = params.server; + const workspaces = new Map>(); let semanticTokensReq = 0; let documentUpdatedReq = 0; - const workspaces = new Map>(); - - documents.onDidChangeContent(params => { - updateDiagnostics(params.textDocument.uri); + context.documents.onDidChangeContent(({ textDocument }) => { + updateDiagnostics(textDocument.uri); }); - documents.onDidClose(params => { - connection.sendDiagnostics({ uri: params.textDocument.uri, diagnostics: [] }); + context.documents.onDidClose(({ textDocument }) => { + context.server.connection.sendDiagnostics({ uri: textDocument.uri, diagnostics: [] }); }); - fileSystemHost.onDidChangeWatchedFiles(params => { - const tsConfigChanges = params.changes.filter(change => rootTsConfigNames.includes(change.uri.substring(change.uri.lastIndexOf('/') + 1))); + context.fileSystemHost.onDidChangeWatchedFiles(({ changes }) => { + const tsConfigChanges = changes.filter(change => rootTsConfigNames.includes(change.uri.substring(change.uri.lastIndexOf('/') + 1))); if (tsConfigChanges.length) { reloadDiagnostics(); } else { - onDriveFileUpdated(); + updateDiagnosticsAndSemanticTokens(); } }); - runtimeEnv.onDidChangeConfiguration?.(async () => { - onDriveFileUpdated(); + context.server.runtimeEnv.onDidChangeConfiguration?.(async () => { + updateDiagnosticsAndSemanticTokens(); }); return { workspaces, - getProject, + getProject: getProjectAndTsConfig, reloadProject, add: (rootUri: URI) => { if (!workspaces.has(rootUri.toString())) { workspaces.set(rootUri.toString(), createWorkspace({ - workspaces: params, + workspaces: context, rootUri, })); } @@ -76,7 +73,7 @@ export function createWorkspaces(params: WorkspacesParams) { async function reloadProject() { - fileSystemHost.reload(); + context.fileSystemHost.reload(); for (const [_, workspace] of workspaces) { (await workspace).reload(); @@ -86,89 +83,89 @@ export function createWorkspaces(params: WorkspacesParams) { } function reloadDiagnostics() { - for (const doc of documents.data.values()) { - connection.sendDiagnostics({ uri: doc.uri, diagnostics: [] }); + for (const doc of context.documents.data.values()) { + context.server.connection.sendDiagnostics({ uri: doc.uri, diagnostics: [] }); } - onDriveFileUpdated(); + updateDiagnosticsAndSemanticTokens(); } - async function onDriveFileUpdated() { + async function updateDiagnosticsAndSemanticTokens() { const req = ++semanticTokensReq; await updateDiagnostics(); + const delay = await context.configurationHost?.getConfiguration('volar.diagnostics.delay') ?? 200; + await shared.sleep(delay); + if (req === semanticTokensReq) { - if (initParams.capabilities.textDocument?.semanticTokens) { - connection.languages.semanticTokens.refresh(); + if (context.initParams.capabilities.textDocument?.semanticTokens) { + context.server.connection.languages.semanticTokens.refresh(); } - if (initParams.capabilities.textDocument?.inlayHint) { - connection.languages.inlayHint.refresh(); + if (context.initParams.capabilities.textDocument?.inlayHint) { + context.server.connection.languages.inlayHint.refresh(); } } } + async function updateDiagnostics(docUri?: string) { - if ((initOptions.diagnosticModel ?? DiagnosticModel.Push) !== DiagnosticModel.Push) + if ((context.initOptions.diagnosticModel ?? DiagnosticModel.Push) !== DiagnosticModel.Push) return; const req = ++documentUpdatedReq; - const delay = await configurationHost?.getConfiguration('volar.diagnostics.delay') ?? 200; - const cancel = cancelTokenHost.createCancellationToken({ + const delay = await context.configurationHost?.getConfiguration('volar.diagnostics.delay') ?? 200; + const cancel = context.cancelTokenHost.createCancellationToken({ get isCancellationRequested() { return req !== documentUpdatedReq; }, onCancellationRequested: vscode.Event.None, }); - const changeDoc = docUri ? documents.data.uriGet(docUri) : undefined; - const otherDocs = [...documents.data.values()].filter(doc => doc !== changeDoc); + const changeDoc = docUri ? context.documents.data.uriGet(docUri) : undefined; + const otherDocs = [...context.documents.data.values()].filter(doc => doc !== changeDoc); if (changeDoc) { - await shared.sleep(delay); - + if (cancel.isCancellationRequested) { + return; + } await sendDocumentDiagnostics(changeDoc.uri, changeDoc.version, cancel); } for (const doc of otherDocs) { - await shared.sleep(delay); - - await sendDocumentDiagnostics(doc.uri, doc.version, cancel); - if (cancel.isCancellationRequested) { break; } + await sendDocumentDiagnostics(doc.uri, doc.version, cancel); } + } - async function sendDocumentDiagnostics(uri: string, version: number, cancel: vscode.CancellationToken) { - - if (cancel.isCancellationRequested) - return; + async function sendDocumentDiagnostics(uri: string, version: number, cancel: vscode.CancellationToken) { - const project = (await getProject(uri))?.project; - if (!project) return; + const project = (await getProjectAndTsConfig(uri))?.project; + if (!project) return; - const languageService = project.getLanguageService(); - const errors = await languageService.doValidation(uri, cancel, result => { - connection.sendDiagnostics({ uri: uri, diagnostics: result.map(addVersion), version }); - }); + const languageService = project.getLanguageService(); + const errors = await languageService.doValidation(uri, cancel, result => { + context.server.connection.sendDiagnostics({ uri: uri, diagnostics: result.map(addVersion), version }); + }); - connection.sendDiagnostics({ uri: uri, diagnostics: errors.map(addVersion), version }); + context.server.connection.sendDiagnostics({ uri: uri, diagnostics: errors.map(addVersion), version }); - function addVersion(error: vscode.Diagnostic) { - if (error.data === undefined) { - error.data = { version }; - } - else if (typeof error.data === 'object') { - error.data.version = version; - } - return error; + function addVersion(error: vscode.Diagnostic) { + if (error.data === undefined) { + error.data = { version }; } + else if (typeof error.data === 'object') { + error.data.version = version; + } + return error; } } - async function getProject(uri: string) { + + async function getProjectAndTsConfig(uri: string) { const rootUris = [...workspaces.keys()] .filter(rootUri => shared.isFileInDir(shared.getPathOfUri(uri), shared.getPathOfUri(rootUri))) @@ -176,9 +173,9 @@ export function createWorkspaces(params: WorkspacesParams) { for (const rootUri of rootUris) { const workspace = await workspaces.get(rootUri); - const project = await workspace?.getProjectAndTsConfig(uri); - if (project) { - return project; + const projectAndTsConfig = await workspace?.getProjectAndTsConfig(uri); + if (projectAndTsConfig) { + return projectAndTsConfig; } }