diff --git a/extensions/html-language-features/server/src/browser/htmlServerMain.ts b/extensions/html-language-features/server/src/browser/htmlServerMain.ts
index 1a3041aad688e..309c629f08f0d 100644
--- a/extensions/html-language-features/server/src/browser/htmlServerMain.ts
+++ b/extensions/html-language-features/server/src/browser/htmlServerMain.ts
@@ -4,9 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { createServer, createConnection, createSimpleProjectProvider } from '@volar/language-server/node';
-import { create as createCssServicePlugin } from 'volar-service-css';
-import { create as createHtmlServicePlugin } from 'volar-service-html';
import { htmlLanguagePlugin } from '../modes/languagePlugin';
+import { getLanguageServices } from '../modes/servicePlugins';
const connection = createConnection();
const server = createServer(connection);
@@ -17,10 +16,7 @@ connection.onInitialize(params => {
return [htmlLanguagePlugin];
},
getServicePlugins() {
- return [
- createCssServicePlugin(),
- createHtmlServicePlugin(),
- ];
+ return getLanguageServices(server.modules.typescript!);
},
});
});
diff --git a/extensions/html-language-features/server/src/modes/project.ts b/extensions/html-language-features/server/src/modes/project.ts
new file mode 100644
index 0000000000000..5b278f35b0706
--- /dev/null
+++ b/extensions/html-language-features/server/src/modes/project.ts
@@ -0,0 +1,68 @@
+import { ServerProject } from '@volar/language-server';
+import { ServerContext, ServerOptions } from '@volar/language-server/lib/server';
+import { LanguageService, ServiceEnvironment, ServicePlugin, createLanguageService } from '@volar/language-service';
+import type { SnapshotDocument } from '@volar/snapshot-document';
+import { createLanguage, createSys } from '@volar/typescript';
+import { createProjectHost } from './projectHost';
+
+export async function createProject(
+ context: ServerContext,
+ serviceEnv: ServiceEnvironment,
+ getLanguagePlugins: ServerOptions['getLanguagePlugins'],
+ servicePlugins: ServicePlugin[],
+ getCurrentTextDocument: () => SnapshotDocument,
+): Promise {
+
+ let languageService: LanguageService | undefined;
+
+ const ts = context.ts!;
+ const sys = createSys(ts, serviceEnv, '');
+ const host = createProjectHost(
+ serviceEnv.typescript!,
+ fileName => sys.readFile(fileName),
+ getCurrentTextDocument,
+ () => getCurrentTextDocument().getSnapshot(),
+ context.tsLocalized,
+ )
+ const languagePlugins = await getLanguagePlugins(serviceEnv, {
+ typescript: {
+ configFileName: undefined,
+ host,
+ sys,
+ },
+ });
+
+ return {
+ serviceEnv,
+ getLanguageService,
+ getLanguageServiceDontCreate: () => languageService,
+ dispose,
+ };
+
+ function getLanguageService() {
+ if (!languageService) {
+ const language = createLanguage(
+ ts,
+ sys,
+ languagePlugins,
+ undefined,
+ host,
+ {
+ fileNameToFileId: serviceEnv.typescript!.fileNameToUri,
+ fileIdToFileName: serviceEnv.typescript!.uriToFileName,
+ },
+ );
+ languageService = createLanguageService(
+ language,
+ servicePlugins,
+ serviceEnv,
+ );
+ }
+ return languageService;
+ }
+
+ function dispose() {
+ sys.dispose();
+ languageService?.dispose();
+ }
+}
diff --git a/extensions/html-language-features/server/src/modes/projectHost.ts b/extensions/html-language-features/server/src/modes/projectHost.ts
new file mode 100644
index 0000000000000..0b897ae4fea5d
--- /dev/null
+++ b/extensions/html-language-features/server/src/modes/projectHost.ts
@@ -0,0 +1,48 @@
+import { ServiceEnvironment, TypeScriptProjectHost, resolveCommonLanguageId, TextDocument } from '@volar/language-service';
+import type * as ts from 'typescript';
+import { JQUERY_PATH } from './javascriptLibs';
+
+export function createProjectHost(
+ { uriToFileName, fileNameToUri }: NonNullable,
+ readFile: (fileName: string) => string | undefined,
+ getCurrentTextDocument: () => TextDocument,
+ getCurrentDocumentSnapshot: () => ts.IScriptSnapshot,
+ tsLocalized?: ts.MapLike,
+) {
+ const libSnapshots = new Map();
+ const compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es2020.full.d.ts'], target: 99 satisfies ts.ScriptTarget.Latest, moduleResolution: 1 satisfies ts.ModuleResolutionKind.Classic, experimentalDecorators: false };
+ const host: TypeScriptProjectHost = {
+ getCompilationSettings: () => compilerOptions,
+ getScriptFileNames: () => [uriToFileName(getCurrentTextDocument().uri), JQUERY_PATH],
+ getCurrentDirectory: () => '',
+ getProjectVersion: () => getCurrentTextDocument().uri + ',' + getCurrentTextDocument().version.toString(),
+ getScriptSnapshot: fileName => {
+ if (fileNameToUri(fileName) === getCurrentTextDocument().uri) {
+ return getCurrentDocumentSnapshot();
+ }
+ else {
+ let snapshot = libSnapshots.get(fileName);
+ if (!snapshot) {
+ const text = readFile(fileName);
+ if (text !== undefined) {
+ snapshot = {
+ getText: (start, end) => text.substring(start, end),
+ getLength: () => text.length,
+ getChangeRange: () => undefined,
+ };
+ }
+ libSnapshots.set(fileName, snapshot);
+ }
+ return snapshot;
+ }
+ },
+ getLocalizedDiagnosticMessages: tsLocalized ? () => tsLocalized : undefined,
+ getLanguageId: uri => {
+ if (uri === getCurrentTextDocument().uri) {
+ return getCurrentTextDocument().languageId;
+ }
+ return resolveCommonLanguageId(uri)
+ },
+ };
+ return host;
+}
diff --git a/extensions/html-language-features/server/src/modes/projectProvider.ts b/extensions/html-language-features/server/src/modes/projectProvider.ts
index e9c6039e74815..e35a4efb6bc7b 100644
--- a/extensions/html-language-features/server/src/modes/projectProvider.ts
+++ b/extensions/html-language-features/server/src/modes/projectProvider.ts
@@ -1,12 +1,8 @@
import { ServerProject, ServerProjectProviderFactory } from '@volar/language-server';
-import { ServerContext, ServerOptions } from '@volar/language-server/lib/server';
import { createServiceEnvironment, getWorkspaceFolder } from '@volar/language-server/node';
-import { LanguageService, ServiceEnvironment, ServicePlugin, TypeScriptProjectHost, createLanguageService, resolveCommonLanguageId } from '@volar/language-service';
-import { createLanguage, createSys } from '@volar/typescript';
-import type * as ts from 'typescript';
+import type { SnapshotDocument } from '@volar/snapshot-document';
import { URI } from 'vscode-uri';
-import type { SnapshotDocument } from '@volar/snapshot-document'
-import { JQUERY_PATH } from './javascriptLibs';
+import { createProject } from './project';
export const serverProjectProviderFactory: ServerProjectProviderFactory = (context, serverOptions, servicePlugins) => {
@@ -38,93 +34,15 @@ export const serverProjectProviderFactory: ServerProjectProviderFactory = (conte
if (!inferredProject) {
inferredProject = (async () => {
const serviceEnv = createServiceEnvironment(context, workspaceFolder);
- return createProject(context, serviceEnv, serverOptions.getLanguagePlugins, servicePlugins);
- })();
- }
- return await inferredProject;
- }
-
- async function createProject(
- context: ServerContext,
- serviceEnv: ServiceEnvironment,
- getLanguagePlugins: ServerOptions['getLanguagePlugins'],
- servicePlugins: ServicePlugin[],
- ): Promise {
-
- let languageService: LanguageService | undefined;
-
- const libSnapshots = new Map();
- const { fileNameToUri } = context.runtimeEnv;
- const ts = context.ts!;
- const compilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, allowJs: true, lib: ['lib.es2020.full.d.ts'], target: ts.ScriptTarget.Latest, moduleResolution: ts.ModuleResolutionKind.Classic, experimentalDecorators: false };
- const sys = createSys(ts, serviceEnv, '');
- const host: TypeScriptProjectHost = {
- getCompilationSettings: () => compilerOptions,
- getScriptFileNames: () => [uriToFileName(currentTextDocument!.uri), JQUERY_PATH],
- getCurrentDirectory: () => '',
- getProjectVersion: () => currentTextDocument!.uri + ',' + currentTextDocument!.version.toString() + ',' + sys.version,
- getScriptSnapshot: fileName => {
- if (fileNameToUri(fileName) === currentTextDocument!.uri) {
- const document = context.documents.get(fileNameToUri(fileName));
- if (document) {
- return document.getSnapshot();
- }
- }
- else {
- let snapshot = libSnapshots.get(fileName);
- if (!snapshot) {
- const text = sys.readFile?.(fileName);
- if (text !== undefined) {
- snapshot = ts.ScriptSnapshot.fromString(text);
- }
- libSnapshots.set(fileName, snapshot);
- }
- return snapshot;
- }
- return undefined;
- },
- getLocalizedDiagnosticMessages: context.tsLocalized ? () => context.tsLocalized : undefined,
- getLanguageId: uri => context.documents.get(uri)?.languageId ?? resolveCommonLanguageId(uri),
- };
- const languagePlugins = await getLanguagePlugins(serviceEnv, {
- typescript: {
- configFileName: undefined,
- host,
- sys,
- },
- });
-
- return {
- serviceEnv,
- getLanguageService,
- getLanguageServiceDontCreate: () => languageService,
- dispose,
- };
-
- function getLanguageService() {
- if (!languageService) {
- const language = createLanguage(
- ts,
- sys,
- languagePlugins,
- undefined,
- host,
- {
- fileNameToFileId: serviceEnv.typescript!.fileNameToUri,
- fileIdToFileName: serviceEnv.typescript!.uriToFileName,
- },
- );
- languageService = createLanguageService(
- language,
- servicePlugins,
+ return createProject(
+ context,
serviceEnv,
+ serverOptions.getLanguagePlugins,
+ servicePlugins,
+ () => currentTextDocument!,
);
- }
- return languageService;
- }
- function dispose() {
- sys.dispose();
- languageService?.dispose();
+ })();
}
+ return await inferredProject;
}
};
diff --git a/extensions/html-language-features/server/src/modes/servicePlugins.ts b/extensions/html-language-features/server/src/modes/servicePlugins.ts
new file mode 100644
index 0000000000000..abb71fe67e64c
--- /dev/null
+++ b/extensions/html-language-features/server/src/modes/servicePlugins.ts
@@ -0,0 +1,25 @@
+import type { ServicePlugin } from '@volar/language-service';
+import { create as createCssServicePlugin } from 'volar-service-css';
+import { create as createHtmlServicePlugin } from 'volar-service-html';
+import { create as createTypeScriptServicePlugin } from 'volar-service-typescript';
+
+export function getLanguageServices(ts: typeof import('typescript')) {
+ const html1ServicePlugins: ServicePlugin[] = [
+ createCssServicePlugin(),
+ createHtmlServicePlugin(),
+ createTypeScriptServicePlugin(ts),
+ {
+ create() {
+ return {
+ resolveEmbeddedCodeFormattingOptions(code, options) {
+ if (code.id.startsWith('css_')) {
+ options.initialIndentLevel++;
+ }
+ return options;
+ },
+ };
+ },
+ },
+ ];
+ return html1ServicePlugins;
+}
diff --git a/extensions/html-language-features/server/src/node/htmlServerMain.ts b/extensions/html-language-features/server/src/node/htmlServerMain.ts
index 56eb997bb902e..1717eca9eb5e0 100644
--- a/extensions/html-language-features/server/src/node/htmlServerMain.ts
+++ b/extensions/html-language-features/server/src/node/htmlServerMain.ts
@@ -4,11 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import { createServer, createConnection } from '@volar/language-server/node';
-import { create as createCssServicePlugin } from 'volar-service-css';
-import { create as createHtmlServicePlugin } from 'volar-service-html';
-import { create as createTypeScriptServicePlugin } from 'volar-service-typescript';
import { htmlLanguagePlugin } from '../modes/languagePlugin';
import { serverProjectProviderFactory } from '../modes/projectProvider';
+import { getLanguageServices } from '../modes/servicePlugins';
const connection = createConnection();
const server = createServer(connection);
@@ -19,23 +17,7 @@ connection.onInitialize(params => {
return [htmlLanguagePlugin];
},
getServicePlugins() {
- return [
- createCssServicePlugin(),
- createHtmlServicePlugin(),
- createTypeScriptServicePlugin(server.modules.typescript!),
- {
- create() {
- return {
- resolveEmbeddedCodeFormattingOptions(code, options) {
- if (code.id.startsWith('css_')) {
- options.initialIndentLevel++;
- }
- return options;
- },
- };
- },
- },
- ];
+ return getLanguageServices(server.modules.typescript!);
},
});
});