Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion extensions/vscode/src/languageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ async function activateLc(

async function getInitializationOptions(context: vscode.ExtensionContext): Promise<VueInitializationOptions> {
return {
typescript: { tsdk: (await lsp.getTsdk(context))!.tsdk },
typescript: {
tsdk: (await lsp.getTsdk(context))!.tsdk,
requestForwardingCommand: 'forwardingTsRequest',
},
};
}
20 changes: 20 additions & 0 deletions extensions/vscode/src/nodeClientMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ export const { activate, deactivate } = defineExtension(async () => {

updateProviders(client);

client.onRequest('forwardingTsRequest', async ([command, args]) => {
const tsserver = (globalThis as any).__TSSERVER__?.semantic;
if (!tsserver) {
return;
}
const res = await tsserver.executeImpl(command, args, {
isAsync: true,
expectsResult: true,
lowPriority: true,
requireSemantic: true,
})[0];
return res.body;
});

return client;
}
);
Expand Down Expand Up @@ -140,6 +154,12 @@ try {
].join('')
);

// Expose tsserver process in SingleTsServer constructor
text = text.replace(
',this._callbacks.destroy("server errored")}))',
s => s + ',globalThis.__TSSERVER__||={},globalThis.__TSSERVER__[arguments[1]]=this'
);

/**
* VSCode < 1.87.0
*/
Expand Down
50 changes: 6 additions & 44 deletions packages/language-server/lib/hybridModeProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@ import type { Language, LanguagePlugin, LanguageServer, LanguageServerProject, P
import { createLanguageServiceEnvironment } from '@volar/language-server/lib/project/simpleProject';
import { createLanguage } from '@vue/language-core';
import { createLanguageService, createUriMap, LanguageService } from '@vue/language-service';
import { configuredServers, getBestServer, inferredServers, onServerReady } from '@vue/typescript-plugin/lib/utils';
import { URI } from 'vscode-uri';

export function createHybridModeProject(
create: (params: {
configFileName?: string;
asFileName: (scriptId: URI) => string;
}) => ProviderResult<{
create: () => ProviderResult<{
languagePlugins: LanguagePlugin<URI>[];
setup?(options: {
language: Language;
Expand All @@ -24,9 +20,6 @@ export function createHybridModeProject(
const project: LanguageServerProject = {
setup(_server) {
server = _server;
onServerReady.push(() => {
server.languageFeatures.requestRefresh(false);
});
server.fileWatcher.onDidChangeWatchedFiles(({ changes }) => {
for (const change of changes) {
const changeUri = URI.parse(change.uri);
Expand All @@ -36,34 +29,10 @@ export function createHybridModeProject(
}
}
});
const end = Date.now() + 60000;
const pipeWatcher = setInterval(() => {
for (const server of configuredServers) {
server.update();
}
for (const server of inferredServers) {
server.update();
}
if (Date.now() > end) {
clearInterval(pipeWatcher);
}
}, 2500);
},
async getLanguageService(uri) {
const fileName = asFileName(uri);
const namedPipeServer = await getBestServer(fileName);
if (namedPipeServer?.projectInfo?.kind === 1) {
const tsconfig = namedPipeServer.projectInfo.name;
const tsconfigUri = URI.file(tsconfig);
if (!tsconfigProjects.has(tsconfigUri)) {
tsconfigProjects.set(tsconfigUri, createLs(server, tsconfig));
}
return await tsconfigProjects.get(tsconfigUri)!;
}
else {
simpleLs ??= createLs(server, undefined);
return await simpleLs;
}
async getLanguageService() {
simpleLs ??= createLs(server);
return await simpleLs;
},
getExistingLanguageServices() {
return Promise.all([
Expand All @@ -85,15 +54,8 @@ export function createHybridModeProject(

return project;

function asFileName(uri: URI) {
return uri.fsPath.replace(/\\/g, '/');
}

async function createLs(server: LanguageServer, tsconfig: string | undefined) {
const { languagePlugins, setup } = await create({
configFileName: tsconfig,
asFileName,
});
async function createLs(server: LanguageServer) {
const { languagePlugins, setup } = await create();
const language = createLanguage([
{ getLanguageId: uri => server.documents.get(uri)?.languageId },
...languagePlugins,
Expand Down
1 change: 1 addition & 0 deletions packages/language-server/lib/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type VueInitializationOptions = {
typescript: {
tsdk: string;
requestForwardingCommand?: string;
};
};

Expand Down
55 changes: 44 additions & 11 deletions packages/language-server/node.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createConnection, createServer, loadTsdkByPath } from '@volar/language-server/node';
import { createParsedCommandLine, createVueLanguagePlugin, getDefaultCompilerOptions } from '@vue/language-core';
import { createVueLanguagePlugin, getDefaultCompilerOptions } from '@vue/language-core';
import { getHybridModeLanguageServicePlugins } from '@vue/language-service';
import * as namedPipeClient from '@vue/typescript-plugin/lib/client';
import { createHybridModeProject } from './lib/hybridModeProject';
import type { VueInitializationOptions } from './lib/types';

Expand All @@ -12,24 +11,30 @@ connection.listen();

connection.onInitialize(params => {
const options: VueInitializationOptions = params.initializationOptions;

if (!options.typescript?.tsdk) {
throw new Error('typescript.tsdk is required');
}
if (!options.typescript?.requestForwardingCommand) {
connection.console.warn('typescript.requestForwardingCommand is required since >= 3.0 for complete TS features');
}

const { typescript: ts } = loadTsdkByPath(options.typescript.tsdk, params.locale);
return server.initialize(
params,
createHybridModeProject(
({ asFileName, configFileName }) => {
const commandLine = configFileName
? createParsedCommandLine(ts, ts.sys, configFileName)
: {
vueOptions: getDefaultCompilerOptions(),
options: ts.getDefaultCompilerOptions(),
};
() => {
const commandLine = {
vueOptions: getDefaultCompilerOptions(),
options: ts.getDefaultCompilerOptions(),
};
return {
languagePlugins: [
createVueLanguagePlugin(
ts,
commandLine.options,
commandLine.vueOptions,
asFileName
uri => uri.fsPath.replace(/\\/g, '/')
),
],
setup({ project }) {
Expand All @@ -38,7 +43,35 @@ connection.onInitialize(params => {
};
}
),
getHybridModeLanguageServicePlugins(ts, namedPipeClient)
getHybridModeLanguageServicePlugins(ts, options.typescript.requestForwardingCommand ? {
collectExtractProps(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:collectExtractProps', args]);
},
getComponentDirectives(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getComponentDirectives', args]);
},
getComponentEvents(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getComponentEvents', args]);
},
getComponentNames(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getComponentNames', args]);
},
getComponentProps(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getComponentProps', args]);
},
getElementAttrs(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getElementAttrs', args]);
},
getImportPathForFile(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getImportPathForFile', args]);
},
getPropertiesAtLocation(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getPropertiesAtLocation', args]);
},
getQuickInfoAtPosition(...args) {
return connection.sendRequest(options.typescript.requestForwardingCommand!, ['vue:getQuickInfoAtPosition', args]);
},
} : undefined)
);
});

Expand Down
3 changes: 0 additions & 3 deletions packages/language-server/tests/completions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,6 @@ test('HTML tags and built-in components', async () => {
"component",
"slot",
"template",
"BaseTransition",
"Fixture",
"foo",
]
`);
});
Expand Down
Loading