Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Mar 9, 2024
1 parent bc5ff18 commit f11f08e
Show file tree
Hide file tree
Showing 12 changed files with 250 additions and 378 deletions.
193 changes: 161 additions & 32 deletions packages/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,56 @@ import type {
CancellationToken,
CompletionList,
CompletionTriggerKind,
DocumentHighlight,
FileChangeType,
Location,
ParameterInformation,
Result,
ServiceContext,
ServicePlugin,
ServicePluginInstance,
SignatureHelpTriggerKind,
SignatureInformation,
VirtualCode,
WorkspaceEdit
} from '@volar/language-service';
import { getDocumentRegistry } from '@volar/typescript';
import * as path from 'path-browserify';
import * as semver from 'semver';
import type * as ts from 'typescript';
import * as tsWithImportCache from 'typescript-auto-import-cache';
import type { TextDocument } from 'vscode-languageserver-textdocument';
import { getFormatCodeSettings } from './lib/configs/getFormatCodeSettings';
import { getUserPreferences } from './lib/configs/getUserPreferences';
import * as codeActions from './lib/features/codeAction';
import * as codeActionResolve from './lib/features/codeActionResolve';
import * as completions from './lib/features/completions/basic';
import * as directiveCommentCompletions from './lib/features/completions/directiveComment';
import * as jsDocCompletions from './lib/features/completions/jsDoc';
import * as completionResolve from './lib/features/completions/resolve';
import * as diagnostics from './lib/features/diagnostics';
import * as documentHighlight from './lib/features/documentHighlight';
import * as fileReferences from './lib/features/fileReferences';
import * as fileRename from './lib/features/fileRename';
import * as implementation from './lib/features/implementation';
import * as inlayHints from './lib/features/inlayHints';
import * as references from './lib/features/references';
import * as selectionRanges from './lib/features/selectionRanges';
import * as semanticTokens from './lib/features/semanticTokens';
import * as signatureHelp from './lib/features/signatureHelp';
import * as workspaceSymbols from './lib/features/workspaceSymbol';
import { getConfigTitle, isJsonDocument, isTsDocument, safeCall } from './lib/shared';
import { getConfigTitle, isJsonDocument, isTsDocument, notEmpty, safeCall } from './lib/shared';
import type { SharedContext } from './lib/types';
import {
convertCallHierarchyIncomingCall,
convertCallHierarchyItem,
convertCallHierarchyOutgoingCall,
convertDefinitionInfoAndBoundSpan,
convertDocumentSpanToLocation,
convertDocumentSpantoLocationLink,
convertFileTextChanges,
convertHighlightSpan,
convertInlayHint,
convertNavTree,
convertNavigateToItem,
convertOutliningSpan,
convertQuickInfo,
convertRenameLocations,
convertSelectionRange,
convertTextChange,
convertTextSpan,
} from './lib/utils/lspConverters';
import * as path from 'path-browserify';
import { getUserPreferences } from './lib/configs/getUserPreferences';

export * from '@volar/typescript';

Expand Down Expand Up @@ -223,21 +224,12 @@ export function create(
throw new Error(`getTextDocument: uri not found: ${uri}`);
},
};
const findReferences = references.register(ctx);
const findFileReferences = fileReferences.register(ctx);
const findImplementations = implementation.register(ctx);
const getEditsForFileRename = fileRename.register(ctx);
const getCodeActions = codeActions.register(ctx);
const doCodeActionResolve = codeActionResolve.register(ctx);
const getInlayHints = inlayHints.register(ctx);
const findDocumentHighlights = documentHighlight.register(ctx);
const findWorkspaceSymbols = workspaceSymbols.register(ctx);
const doComplete = completions.register(ctx);
const doCompletionResolve = completionResolve.register(ctx);
const doDirectiveCommentComplete = directiveCommentCompletions.register();
const doJsDocComplete = jsDocCompletions.register(ctx);
const getSignatureHelp = signatureHelp.register(ctx);
const getSelectionRanges = selectionRanges.register(ctx);
const doValidation = diagnostics.register(ctx);
const getDocumentSemanticTokens = semanticTokens.register(ctx);

Expand Down Expand Up @@ -407,8 +399,20 @@ export function create(
if (!isSemanticDocument(document))
return;

return worker(token, () => {
return getInlayHints(document, range);
return worker(token, async () => {
const preferences = await getUserPreferences(ctx, document);
const fileName = ctx.uriToFileName(document.uri);
const start = document.offsetAt(range.start);
const end = document.offsetAt(range.end);
const inlayHints = safeCall(() =>
'provideInlayHints' in ctx.languageService
? ctx.languageService.provideInlayHints(fileName, { start, length: end - start }, preferences)
: []
);
if (!inlayHints) {
return [];
}
return inlayHints.map(hint => convertInlayHint(hint, document));
});
},

Expand Down Expand Up @@ -537,7 +541,13 @@ export function create(
return;

return worker(token, () => {
return findImplementations(document, position);
const fileName = ctx.uriToFileName(document.uri);
const offset = document.offsetAt(position);
const entries = safeCall(() => ctx.languageService.getImplementationAtPosition(fileName, offset));
if (!entries) {
return [];
}
return entries.map(entry => convertDocumentSpantoLocationLink(entry, ctx));
});
},

Expand All @@ -547,7 +557,28 @@ export function create(
return;

return worker(token, () => {
return findReferences(document, position, referenceContext);
const fileName = ctx.uriToFileName(document.uri);
const offset = document.offsetAt(position);
const references = safeCall(() => ctx.languageService.findReferences(fileName, offset));
if (!references) {
return [];
}
const result: Location[] = [];
for (const reference of references) {
if (referenceContext.includeDeclaration) {
const definition = convertDocumentSpanToLocation(reference.definition, ctx);
if (definition) {
result.push(definition);
}
}
for (const referenceEntry of reference.references) {
const reference = convertDocumentSpanToLocation(referenceEntry, ctx);
if (reference) {
result.push(reference);
}
}
}
return result;
});
},

Expand All @@ -557,7 +588,12 @@ export function create(
return;

return worker(token, () => {
return findFileReferences(document);
const fileName = ctx.uriToFileName(document.uri);
const entries = safeCall(() => ctx.languageService.getFileReferences(fileName));
if (!entries) {
return [];
}
return entries.map(entry => convertDocumentSpanToLocation(entry, ctx));
});
},

Expand All @@ -567,7 +603,19 @@ export function create(
return;

return worker(token, () => {
return findDocumentHighlights(document, position);
const fileName = ctx.uriToFileName(document.uri);
const offset = document.offsetAt(position);
const highlights = safeCall(() => ctx.languageService.getDocumentHighlights(fileName, offset, [fileName]));
if (!highlights) {
return [];
}
const results: DocumentHighlight[] = [];
for (const highlight of highlights) {
for (const span of highlight.highlightSpans) {
results.push(convertHighlightSpan(span, document));
}
}
return results;
});
},

Expand All @@ -583,13 +631,33 @@ export function create(

provideWorkspaceSymbols(query, token) {
return worker(token, () => {
return findWorkspaceSymbols(query);
const items = safeCall(() => ctx.languageService.getNavigateToItems(query));
if (!items) {
return [];
}
return items
.filter(item => item.containerName || item.kind !== 'alias')
.map(item => convertNavigateToItem(item, ctx.getTextDocument(ctx.fileNameToUri(item.fileName))))
.filter(notEmpty);
});
},

provideFileRenameEdits(oldUri, newUri, token) {
return worker(token, () => {
return getEditsForFileRename(oldUri, newUri);
return worker(token, async () => {
const document = ctx.getTextDocument(oldUri);
const [formatOptions, preferences] = await Promise.all([
getFormatCodeSettings(ctx, document),
getUserPreferences(ctx, document),
]);

const fileToRename = ctx.uriToFileName(oldUri);
const newFilePath = ctx.uriToFileName(newUri);
const response = safeCall(() => ctx.languageService.getEditsForFileRename(fileToRename, newFilePath, formatOptions, preferences));
if (!response?.length) {
return;
}

return convertFileTextChanges(response, ctx.fileNameToUri, ctx.getTextDocument);
});
},

Expand All @@ -599,7 +667,17 @@ export function create(
return;

return worker(token, () => {
return getSelectionRanges(document, positions);
return positions
.map(position => {
const fileName = ctx.uriToFileName(document.uri);
const offset = document.offsetAt(position);
const range = safeCall(() => ctx.languageService.getSmartSelectionRange(fileName, offset));
if (!range) {
return;
}
return convertSelectionRange(range, document);
})
.filter(notEmpty);
});
},

Expand All @@ -609,7 +687,58 @@ export function create(
return;

return worker(token, () => {
return getSignatureHelp(document, position, context);
const options: ts.SignatureHelpItemsOptions = {};
if (context?.triggerKind === 1 satisfies typeof SignatureHelpTriggerKind.Invoked) {
options.triggerReason = {
kind: 'invoked'
};
}
else if (context?.triggerKind === 2 satisfies typeof SignatureHelpTriggerKind.TriggerCharacter) {
options.triggerReason = {
kind: 'characterTyped',
triggerCharacter: context.triggerCharacter as ts.SignatureHelpTriggerCharacter,
};
}
else if (context?.triggerKind === 3 satisfies typeof SignatureHelpTriggerKind.ContentChange) {
options.triggerReason = {
kind: 'retrigger',
triggerCharacter: context.triggerCharacter as ts.SignatureHelpRetriggerCharacter,
};
}

const fileName = ctx.uriToFileName(document.uri);
const offset = document.offsetAt(position);
const helpItems = safeCall(() => ctx.languageService.getSignatureHelpItems(fileName, offset, options));
if (!helpItems) {
return;
}

return {
activeSignature: helpItems.selectedItemIndex,
activeParameter: helpItems.argumentIndex,
signatures: helpItems.items.map(item => {
const signature: SignatureInformation = {
label: '',
documentation: undefined,
parameters: []
};
signature.label += ts.displayPartsToString(item.prefixDisplayParts);
item.parameters.forEach((p, i, a) => {
const label = ts.displayPartsToString(p.displayParts);
const parameter: ParameterInformation = {
label,
documentation: ts.displayPartsToString(p.documentation)
};
signature.label += label;
signature.parameters!.push(parameter);
if (i < a.length - 1) {
signature.label += ts.displayPartsToString(item.separatorDisplayParts);
}
});
signature.label += ts.displayPartsToString(item.suffixDisplayParts);
return signature;
}),
};
});
},
};
Expand Down
32 changes: 0 additions & 32 deletions packages/typescript/lib/features/documentHighlight.ts

This file was deleted.

15 changes: 0 additions & 15 deletions packages/typescript/lib/features/fileReferences.ts

This file was deleted.

25 changes: 0 additions & 25 deletions packages/typescript/lib/features/fileRename.ts

This file was deleted.

Loading

0 comments on commit f11f08e

Please sign in to comment.