Skip to content

Commit

Permalink
wip [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Mar 19, 2024
1 parent a7ad6da commit b16d556
Show file tree
Hide file tree
Showing 18 changed files with 482 additions and 350 deletions.
65 changes: 29 additions & 36 deletions extensions/vscode/src/features/doctor.ts
Expand Up @@ -134,30 +134,6 @@ export async function register(context: vscode.ExtensionContext, client: BaseLan
});
}

// check should use @volar-plugins/vetur instead of vetur
const vetur = vscode.extensions.getExtension('octref.vetur');
if (vetur?.isActive) {
problems.push({
title: 'Use volar-service-vetur instead of Vetur',
message: 'Detected Vetur enabled. Consider disabling Vetur and use [volar-service-vetur](https://github.com/volarjs/services/tree/master/packages/vetur) instead.',
});
}

// #3942, https://github.com/microsoft/TypeScript/issues/57633
for (const extId of ['svelte.svelte-vscode', 'styled-components.vscode-styled-components']) {
const ext = vscode.extensions.getExtension(extId);
if (ext) {
problems.push({
title: `Recommended to disable "${ext.packageJSON.displayName || extId}" in Vue workspace`,
message: [
`This extension's TypeScript Plugin and Vue's TypeScript Plugin are known to cause some conflicts. Until the problem is resolved, it is recommended that you temporarily disable the this extension in the Vue workspace.`,
'',
'Issues: https://github.com/vuejs/language-tools/issues/3942, https://github.com/microsoft/TypeScript/issues/57633',
].join('\n'),
});
}
}

// check using pug but don't install @vue/language-plugin-pug
if (
sfc?.descriptor.template?.lang === 'pug'
Expand Down Expand Up @@ -236,18 +212,35 @@ export async function register(context: vscode.ExtensionContext, client: BaseLan
});
}

// #3942
const namedPipe = await client.sendRequest(GetConnectedNamedPipeServerRequest.type, fileUri.fsPath.replace(/\\/g, '/'));
if (namedPipe?.serverKind === 0) {
problems.push({
title: 'Missing jsconfig/tsconfig',
message: [
'The current file does not have a matching tsconfig/jsconfig, and extension version 2.0 will not work properly for this at the moment.',
'To avoid this problem, you can create a jsconfig in the project root, or downgrade to 1.8.27.',
'',
'Issue: https://github.com/vuejs/language-tools/issues/3942',
].join('\n'),
});
if (config.server.hybridMode) {
// #3942
const namedPipe = await client.sendRequest(GetConnectedNamedPipeServerRequest.type, fileUri.fsPath.replace(/\\/g, '/'));
if (namedPipe?.serverKind === 0) {
problems.push({
title: 'Missing jsconfig/tsconfig',
message: [
'The current file does not have a matching tsconfig/jsconfig, and extension version 2.0 will not work properly for this at the moment.',
'To avoid this problem, you can create a jsconfig in the project root, or downgrade to 1.8.27.',
'',
'Issue: https://github.com/vuejs/language-tools/issues/3942',
].join('\n'),
});
}

// #3942, https://github.com/microsoft/TypeScript/issues/57633
for (const extId of ['svelte.svelte-vscode', 'styled-components.vscode-styled-components']) {
const ext = vscode.extensions.getExtension(extId);
if (ext) {
problems.push({
title: `Recommended to disable "${ext.packageJSON.displayName || extId}" in Vue workspace`,
message: [
`This extension's TypeScript Plugin and Vue's TypeScript Plugin are known to cause some conflicts. Until the problem is resolved, it is recommended that you temporarily disable the this extension in the Vue workspace.`,
'',
'Issues: https://github.com/vuejs/language-tools/issues/3942, https://github.com/microsoft/TypeScript/issues/57633',
].join('\n'),
});
}
}
}

// check outdated vue language plugins
Expand Down
15 changes: 11 additions & 4 deletions packages/language-server/node.ts
Expand Up @@ -5,6 +5,7 @@ import { ServiceEnvironment, convertAttrName, convertTagName, createVueServicePl
import { DetectNameCasingRequest, GetConvertAttrCasingEditsRequest, GetConvertTagCasingEditsRequest, ParseSFCRequest } from './lib/protocol';
import type { VueInitializationOptions } from './lib/types';
import * as tsPluginClient from '@vue/typescript-plugin/lib/client';
import { searchNamedPipeServerForFile } from '@vue/typescript-plugin/lib/utils';
import { GetConnectedNamedPipeServerRequest } from './lib/protocol';

export const connection: Connection = createConnection();
Expand Down Expand Up @@ -39,7 +40,11 @@ connection.onInitialize(async params => {
{
watchFileExtensions: ['js', 'cjs', 'mjs', 'ts', 'cts', 'mts', 'jsx', 'tsx', 'json', ...vueFileExtensions],
getServicePlugins() {
return createVueServicePlugins(tsdk.typescript, env => envToVueOptions.get(env)!, options.vue.hybridMode, tsPluginClient);
return createVueServicePlugins(
tsdk.typescript,
env => envToVueOptions.get(env)!,
options.vue.hybridMode ? () => tsPluginClient : undefined,
);
},
async getLanguagePlugins(serviceEnv, projectContext) {
const commandLine = await parseCommandLine();
Expand Down Expand Up @@ -101,8 +106,10 @@ connection.onInitialize(async params => {
},
);

// handle by tsserver + @vue/typescript-plugin
result.capabilities.semanticTokensProvider = undefined;
if (options.vue.hybridMode) {
// handle by tsserver + @vue/typescript-plugin
result.capabilities.semanticTokensProvider = undefined;
}

return result;
});
Expand Down Expand Up @@ -141,7 +148,7 @@ connection.onRequest(GetConvertAttrCasingEditsRequest.type, async params => {
});

connection.onRequest(GetConnectedNamedPipeServerRequest.type, async fileName => {
const server = await tsPluginClient.searchNamedPipeServerForFile(fileName);
const server = await searchNamedPipeServerForFile(fileName);
if (server) {
return server;
}
Expand Down
108 changes: 79 additions & 29 deletions packages/language-service/index.ts
Expand Up @@ -3,14 +3,13 @@ export * from '@vue/language-core';
export * from './lib/ideFeatures/nameCasing';
export * from './lib/types';

import type { ServiceEnvironment, ServicePlugin } from '@volar/language-service';
import type { ServiceContext, ServiceEnvironment, ServicePlugin } from '@volar/language-service';
import type { VueCompilerOptions } from './lib/types';

import { decorateLanguageServiceForVue } from '@vue/typescript-plugin/lib/common';
import { create as createEmmetServicePlugin } from 'volar-service-emmet';
import { create as createJsonServicePlugin } from 'volar-service-json';
import { create as createPugFormatServicePlugin } from 'volar-service-pug-beautify';
import { create as createTypeScriptServicePlugin } from 'volar-service-typescript';
import { create as createTypeScriptServicePlugins } from 'volar-service-typescript';
import { create as createTypeScriptTwoslashQueriesServicePlugin } from 'volar-service-typescript-twoslash-queries';
import { create as createTypeScriptDocCommentTemplateServicePlugin } from 'volar-service-typescript/lib/plugins/docCommentTemplate';
import { create as createTypeScriptSyntacticServicePlugin } from 'volar-service-typescript/lib/plugins/syntactic';
Expand All @@ -28,53 +27,104 @@ import { create as createVueToggleVBindServicePlugin } from './lib/plugins/vue-t
import { create as createVueTwoslashQueriesServicePlugin } from './lib/plugins/vue-twoslash-queries';
import { create as createVueVisualizeHiddenCallbackParamServicePlugin } from './lib/plugins/vue-visualize-hidden-callback-param';

import { decorateLanguageServiceForVue } from '@vue/typescript-plugin/lib/common';
import { collectExtractProps } from '@vue/typescript-plugin/lib/requests/collectExtractProps';
import { getComponentEvents, getComponentNames, getComponentProps, getElementAttrs, getTemplateContextProps } from '@vue/typescript-plugin/lib/requests/componentInfos';
import { getPropertiesAtLocation } from '@vue/typescript-plugin/lib/requests/getPropertiesAtLocation';
import { getQuickInfoAtPosition } from '@vue/typescript-plugin/lib/requests/getQuickInfoAtPosition';

export function createVueServicePlugins(
ts: typeof import('typescript'),
getVueOptions: (env: ServiceEnvironment) => VueCompilerOptions,
hybridMode = true,
tsPluginClient?: typeof import('@vue/typescript-plugin/lib/client'),
getTsPluginClient?: (context: ServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined,
): ServicePlugin[] {
const plugins: ServicePlugin[] = [
createTypeScriptTwoslashQueriesServicePlugin(ts),
createCssServicePlugin(),
createPugFormatServicePlugin(),
createJsonServicePlugin(),
createVueTemplateServicePlugin('html', ts, getVueOptions, tsPluginClient),
createVueTemplateServicePlugin('pug', ts, getVueOptions, tsPluginClient),
createVueSfcServicePlugin(),
createVueTwoslashQueriesServicePlugin(ts, tsPluginClient),
createVueReferencesCodeLensServicePlugin(),
createVueDocumentDropServicePlugin(ts),
createVueAutoDotValueServicePlugin(ts, tsPluginClient),
createVueAutoWrapParenthesesServicePlugin(ts),
createVueAutoAddSpaceServicePlugin(),
createVueVisualizeHiddenCallbackParamServicePlugin(),
createVueDirectiveCommentsServicePlugin(),
createVueExtractFileServicePlugin(ts, tsPluginClient),
createVueToggleVBindServicePlugin(ts),
createEmmetServicePlugin(),
];
const plugins: ServicePlugin[] = [];
const hybridMode = !!getTsPluginClient;
if (!hybridMode) {
plugins.push(...createTypeScriptServicePlugin(ts));
plugins.push(...createTypeScriptServicePlugins(ts));
for (let i = 0; i < plugins.length; i++) {
const plugin = plugins[i];
if (plugin.name === 'typescript-semantic') {
plugins[i] = {
...plugin,
create(context) {
const created = plugin.create(context);
if (!context.language.typescript) {
return created;
}
const languageService = (created.provide as import('volar-service-typescript').Provide)['typescript/languageService']();
const vueOptions = getVueOptions(context.env);
decorateLanguageServiceForVue(context.language.files, languageService, vueOptions, ts);
decorateLanguageServiceForVue(context.language.files, languageService, vueOptions, ts, false);
return created;
},
};
break;
}
}
getTsPluginClient = context => {
if (!context.language.typescript) {
return;
}
const requestContext = {
typescript: ts,
files: context.language.files,
languageService: context.inject<(import('volar-service-typescript').Provide), 'typescript/languageService'>('typescript/languageService'),
vueOptions: getVueOptions(context.env),
isTsPlugin: false,
};
return {
async collectExtractProps(...args) {
return await collectExtractProps.apply(requestContext, args);
},
async getPropertiesAtLocation(...args) {
return await getPropertiesAtLocation.apply(requestContext, args);
},
async getComponentEvents(...args) {
return await getComponentEvents.apply(requestContext, args);
},
async getComponentNames(...args) {
return await getComponentNames.apply(requestContext, args);
},
async getComponentProps(...args) {
return await getComponentProps.apply(requestContext, args);
},
async getElementAttrs(...args) {
return await getElementAttrs.apply(requestContext, args);
},
async getTemplateContextProps(...args) {
return await getTemplateContextProps.apply(requestContext, args);
},
async getQuickInfoAtPosition(...args) {
return await getQuickInfoAtPosition.apply(requestContext, args);
},
};
};
}
else {
plugins.push(createTypeScriptSyntacticServicePlugin(ts));
plugins.push(createTypeScriptDocCommentTemplateServicePlugin(ts));
plugins.push(
createTypeScriptSyntacticServicePlugin(ts),
createTypeScriptDocCommentTemplateServicePlugin(ts),
);
}
plugins.push(
createTypeScriptTwoslashQueriesServicePlugin(ts),
createCssServicePlugin(),
createPugFormatServicePlugin(),
createJsonServicePlugin(),
createVueTemplateServicePlugin('html', ts, getVueOptions, getTsPluginClient),
createVueTemplateServicePlugin('pug', ts, getVueOptions, getTsPluginClient),
createVueSfcServicePlugin(),
createVueTwoslashQueriesServicePlugin(ts, getTsPluginClient),
createVueReferencesCodeLensServicePlugin(),
createVueDocumentDropServicePlugin(ts),
createVueAutoDotValueServicePlugin(ts, getTsPluginClient),
createVueAutoWrapParenthesesServicePlugin(ts),
createVueAutoAddSpaceServicePlugin(),
createVueVisualizeHiddenCallbackParamServicePlugin(),
createVueDirectiveCommentsServicePlugin(),
createVueExtractFileServicePlugin(ts, getTsPluginClient),
createVueToggleVBindServicePlugin(ts),
createEmmetServicePlugin(),
);
return plugins;
}
@@ -1,4 +1,4 @@
import type { ServicePlugin, ServicePluginInstance } from '@volar/language-service';
import type { ServiceContext, ServicePlugin, ServicePluginInstance } from '@volar/language-service';
import { hyphenateAttr } from '@vue/language-core';
import type * as ts from 'typescript';
import type * as vscode from 'vscode-languageserver-protocol';
Expand All @@ -17,11 +17,12 @@ function getAst(ts: typeof import('typescript'), fileName: string, snapshot: ts.

export function create(
ts: typeof import('typescript'),
tsPluginClient?: typeof import('@vue/typescript-plugin/lib/client'),
getTsPluginClient?: (context: ServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined,
): ServicePlugin {
return {
name: 'vue-autoinsert-dotvalue',
create(context): ServicePluginInstance {
const tsPluginClient = getTsPluginClient?.(context);
let currentReq = 0;
return {
async provideAutoInsertionEdit(document, position, lastChange) {
Expand Down
5 changes: 3 additions & 2 deletions packages/language-service/lib/plugins/vue-extract-file.ts
@@ -1,4 +1,4 @@
import type { CreateFile, ServicePlugin, TextDocumentEdit, TextEdit } from '@volar/language-service';
import type { CreateFile, ServiceContext, ServicePlugin, TextDocumentEdit, TextEdit } from '@volar/language-service';
import type { ExpressionNode, TemplateChildNode } from '@vue/compiler-dom';
import { Sfc, VueGeneratedCode, scriptRanges } from '@vue/language-core';
import type * as ts from 'typescript';
Expand All @@ -14,11 +14,12 @@ const unicodeReg = /\\u/g;

export function create(
ts: typeof import('typescript'),
tsPluginClient?: typeof import('@vue/typescript-plugin/lib/client'),
getTsPluginClient?: (context: ServiceContext) => typeof import('@vue/typescript-plugin/lib/client') | undefined,
): ServicePlugin {
return {
name: 'vue-extract-file',
create(context) {
const tsPluginClient = getTsPluginClient?.(context);
return {
async provideCodeActions(document, range, _context) {

Expand Down

0 comments on commit b16d556

Please sign in to comment.