Skip to content

Commit

Permalink
refactor(typescript): reuse existing snapshots for the syntax languag…
Browse files Browse the repository at this point in the history
…e service
  • Loading branch information
johnsoncodehk committed Mar 26, 2024
1 parent ce8eff4 commit c59f6ef
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 23 deletions.
6 changes: 3 additions & 3 deletions packages/typescript/lib/plugins/docCommentTemplate.ts
Expand Up @@ -2,8 +2,8 @@ import type * as vscode from '@volar/language-service';
import type { TextDocument } from 'vscode-languageserver-textdocument';
import * as nls from 'vscode-nls';
import { isTsDocument } from '../shared';
import { getLanguageService } from '../syntacticLanguageService';
import { getLineText } from '../utils/lspConverters';
import { getLanguageServiceByDocument } from './syntactic';

const localize = nls.loadMessageBundle(); // TODO: not working

Expand All @@ -13,7 +13,7 @@ export function create(ts: typeof import('typescript')): vscode.LanguageServiceP
return {
name: 'typescript-doc-comment-template',
triggerCharacters: ['*'],
create(): vscode.LanguageServicePluginInstance {
create(context): vscode.LanguageServicePluginInstance {

return {

Expand All @@ -27,7 +27,7 @@ export function create(ts: typeof import('typescript')): vscode.LanguageServiceP
return;
}

const { languageService, fileName } = getLanguageService(ts, document);
const { languageService, fileName } = getLanguageServiceByDocument(context, ts, document);
const offset = document.offsetAt(position);
const docCommentTemplate = languageService.getDocCommentTemplateAtPosition(fileName, offset);
if (!docCommentTemplate) {
Expand Down
29 changes: 24 additions & 5 deletions packages/typescript/lib/plugins/syntactic.ts
Expand Up @@ -42,7 +42,7 @@ export function create(
&& lastChange.text.endsWith('>')
&& await isAutoClosingTagsEnabled(document, context)
) {
const { languageService, fileName } = getLanguageService(ts, document);
const { languageService, fileName } = getLanguageServiceByDocument(context, ts, document);
const close = languageService.getJsxClosingTagAtPosition(fileName, document.offsetAt(position));
if (close) {
return '$0' + close.newText;
Expand All @@ -56,7 +56,7 @@ export function create(
return;
}

const { languageService, fileName } = getLanguageService(ts, document);
const { languageService, fileName } = getLanguageServiceByDocument(context, ts, document);
const outliningSpans = safeCall(() => languageService.getOutliningSpans(fileName));
if (!outliningSpans) {
return [];
Expand All @@ -70,7 +70,7 @@ export function create(
return;
}

const { languageService, fileName } = getLanguageService(ts, document);
const { languageService, fileName } = getLanguageServiceByDocument(context, ts, document);
const barItems = safeCall(() => languageService.getNavigationTree(fileName));
if (!barItems) {
return [];
Expand All @@ -97,7 +97,7 @@ export function create(
if (codeOptions) {
tsOptions.baseIndentSize = codeOptions.initialIndentLevel * options.tabSize;
}
const { languageService, fileName } = getLanguageService(ts, document);
const { languageService, fileName } = getLanguageServiceByDocument(context, ts, document);
const scriptEdits = range
? safeCall(() => languageService.getFormattingEditsForRange(
fileName,
Expand Down Expand Up @@ -126,7 +126,7 @@ export function create(
if (codeOptions) {
tsOptions.baseIndentSize = codeOptions.initialIndentLevel * options.tabSize;
}
const { languageService, fileName } = getLanguageService(ts, document);
const { languageService, fileName } = getLanguageServiceByDocument(context, ts, document);
const scriptEdits = safeCall(() => languageService.getFormattingEditsAfterKeystroke(fileName, document.offsetAt(position), key, tsOptions));
if (!scriptEdits) {
return [];
Expand All @@ -137,3 +137,22 @@ export function create(
},
};
}

export function getLanguageServiceByDocument(context: ServiceContext, ts: typeof import('typescript'), document: TextDocument) {
const decoded = context.decodeEmbeddedDocumentUri(document.uri);
if (decoded) {
const embeddedCode = context.language.scripts
.get(decoded[0])?.generated?.embeddedCodes
.get(decoded[1]);
if (embeddedCode) {
return getLanguageService(ts, embeddedCode.snapshot, document.languageId, true);
}
}
else {
const sourceScript = context.language.scripts.get(document.uri);
if (sourceScript) {
return getLanguageService(ts, sourceScript.snapshot, document.languageId, true);
}
}
throw new Error(`No language service for ${document.uri}`);
}
41 changes: 26 additions & 15 deletions packages/typescript/lib/syntacticLanguageService.ts
@@ -1,12 +1,10 @@
import type * as ts from 'typescript';
import type { TextDocument } from 'vscode-languageserver-textdocument';

let currentProjectVersion = -1;
let currentDocument: TextDocument | undefined;
let currentDocumentVersion: number | undefined;
let currentFileName = '';
let currentSnapshot: ts.IScriptSnapshot | undefined;
let languageService: ts.LanguageService | undefined;
let syntaxOnlyLanguageService: ts.LanguageService | undefined;

const host: ts.LanguageServiceHost = {
getProjectVersion: () => currentProjectVersion.toString(),
Expand All @@ -20,21 +18,34 @@ const host: ts.LanguageServiceHost = {
fileExists: fileName => fileName === currentFileName,
};

export function getLanguageService(ts: typeof import('typescript'), document: TextDocument) {
if (currentDocument !== document || currentDocumentVersion !== document.version) {
currentDocument = document;
export function getLanguageService(
ts: typeof import('typescript'),
snapshot: ts.IScriptSnapshot,
languageId: string,
syntaxOnly: boolean,
) {
if (currentSnapshot !== snapshot) {
currentSnapshot = snapshot;
currentFileName = '/tmp.' + (
document.languageId === 'javascript' ? 'js' :
document.languageId === 'typescriptreact' ? 'tsx' :
document.languageId === 'javascriptreact' ? 'jsx' :
languageId === 'javascript' ? 'js' :
languageId === 'typescriptreact' ? 'tsx' :
languageId === 'javascriptreact' ? 'jsx' :
'ts'
);
currentSnapshot = ts.ScriptSnapshot.fromString(document.getText());
currentProjectVersion++;
}
languageService ??= ts.createLanguageService(host, undefined, 2 satisfies ts.LanguageServiceMode.Syntactic);
return {
languageService,
fileName: currentFileName,
};
if (syntaxOnly) {
syntaxOnlyLanguageService ??= ts.createLanguageService(host, undefined, ts.LanguageServiceMode.Syntactic);
return {
languageService: syntaxOnlyLanguageService,
fileName: currentFileName,
};
}
else {
languageService ??= ts.createLanguageService(host);
return {
languageService,
fileName: currentFileName,
};
}
}

0 comments on commit c59f6ef

Please sign in to comment.