Skip to content

Add API option to getCompletionsAtPosition to expose completion symbol information #52560

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Feb 16, 2023
13 changes: 10 additions & 3 deletions src/services/completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,7 @@ export function getCompletionsAtPosition(
completionKind: CompletionTriggerKind | undefined,
cancellationToken: CancellationToken,
formatContext?: formatting.FormatContext,
includeSymbol = false
): CompletionInfo | undefined {
const { previousToken } = getRelevantTokens(position, sourceFile);
if (triggerCharacter && !isInString(sourceFile, position, previousToken) && !isValidTrigger(sourceFile, triggerCharacter, previousToken, position)) {
Expand Down Expand Up @@ -675,7 +676,7 @@ export function getCompletionsAtPosition(
incompleteCompletionsCache?.clear();
}

const stringCompletions = StringCompletions.getStringLiteralCompletions(sourceFile, position, previousToken, compilerOptions, host, program, log, preferences);
const stringCompletions = StringCompletions.getStringLiteralCompletions(sourceFile, position, previousToken, compilerOptions, host, program, log, preferences, includeSymbol);
if (stringCompletions) {
return stringCompletions;
}
Expand All @@ -692,7 +693,7 @@ export function getCompletionsAtPosition(

switch (completionData.kind) {
case CompletionDataKind.Data:
const response = completionInfoFromData(sourceFile, host, program, compilerOptions, log, completionData, preferences, formatContext, position);
const response = completionInfoFromData(sourceFile, host, program, compilerOptions, log, completionData, preferences, formatContext, position, includeSymbol);
if (response?.isIncomplete) {
incompleteCompletionsCache?.set(response);
}
Expand Down Expand Up @@ -866,7 +867,8 @@ function completionInfoFromData(
completionData: CompletionData,
preferences: UserPreferences,
formatContext: formatting.FormatContext | undefined,
position: number
position: number,
includeSymbol: boolean | undefined,
): CompletionInfo | undefined {
const {
symbols,
Expand Down Expand Up @@ -951,6 +953,7 @@ function completionInfoFromData(
symbolToSortTextMap,
isJsxIdentifierExpected,
isRightOfOpenTag,
includeSymbol
);

if (keywordFilters !== KeywordCompletionFilters.None) {
Expand Down Expand Up @@ -1339,6 +1342,7 @@ function createCompletionEntry(
formatContext: formatting.FormatContext | undefined,
isJsxIdentifierExpected: boolean | undefined,
isRightOfOpenTag: boolean | undefined,
includeSymbol: boolean
): CompletionEntry | undefined {
let insertText: string | undefined;
let replacementSpan = getReplacementSpanForContextToken(replacementToken);
Expand Down Expand Up @@ -1492,6 +1496,7 @@ function createCompletionEntry(
isPackageJsonImport: originIsPackageJsonImport(origin) || undefined,
isImportStatementCompletion: !!importStatementCompletion || undefined,
data,
...includeSymbol ? { symbol } : undefined
};
}

Expand Down Expand Up @@ -2119,6 +2124,7 @@ export function getCompletionEntriesFromSymbols(
symbolToSortTextMap?: SymbolSortTextMap,
isJsxIdentifierExpected?: boolean,
isRightOfOpenTag?: boolean,
includeSymbol = false
): UniqueNameSet {
const start = timestamp();
const variableDeclaration = getVariableDeclaration(location);
Expand Down Expand Up @@ -2164,6 +2170,7 @@ export function getCompletionEntriesFromSymbols(
formatContext,
isJsxIdentifierExpected,
isRightOfOpenTag,
includeSymbol
);
if (!entry) {
continue;
Expand Down
3 changes: 2 additions & 1 deletion src/services/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1990,7 +1990,8 @@ export function createLanguageService(
options.triggerCharacter,
options.triggerKind,
cancellationToken,
formattingSettings && formatting.getFormatContext(formattingSettings, host));
formattingSettings && formatting.getFormatContext(formattingSettings, host),
options.includeSymbol);
}

function getCompletionEntryDetails(fileName: string, position: number, name: string, formattingOptions: FormatCodeSettings | undefined, source: string | undefined, preferences: UserPreferences = emptyOptions, data?: CompletionEntryData): CompletionEntryDetails | undefined {
Expand Down
17 changes: 15 additions & 2 deletions src/services/stringCompletions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,15 +190,16 @@ export function getStringLiteralCompletions(
host: LanguageServiceHost,
program: Program,
log: Log,
preferences: UserPreferences): CompletionInfo | undefined {
preferences: UserPreferences,
includeSymbol: boolean): CompletionInfo | undefined {
if (isInReferenceComment(sourceFile, position)) {
const entries = getTripleSlashReferenceCompletion(sourceFile, position, options, host);
return entries && convertPathCompletions(entries);
}
if (isInString(sourceFile, position, contextToken)) {
if (!contextToken || !isStringLiteralLike(contextToken)) return undefined;
const entries = getStringLiteralCompletionEntries(sourceFile, contextToken, position, program.getTypeChecker(), options, host, preferences);
return convertStringLiteralCompletions(entries, contextToken, sourceFile, host, program, log, options, preferences, position);
return convertStringLiteralCompletions(entries, contextToken, sourceFile, host, program, log, options, preferences, position, includeSymbol);
}
}

Expand All @@ -212,6 +213,7 @@ function convertStringLiteralCompletions(
options: CompilerOptions,
preferences: UserPreferences,
position: number,
includeSymbol: boolean,
): CompletionInfo | undefined {
if (completion === undefined) {
return undefined;
Expand Down Expand Up @@ -239,6 +241,17 @@ function convertStringLiteralCompletions(
preferences,
options,
/*formatContext*/ undefined,
/*isTypeOnlyLocation */ undefined,
/*propertyAccessToConvert*/ undefined,
/*jsxIdentifierExpected*/ undefined,
/*isJsxInitializer*/ undefined,
/*importStatementCompletion*/ undefined,
/*recommendedCompletion*/ undefined,
/*symbolToOriginInfoMap*/ undefined,
/*symbolToSortTextMap*/ undefined,
/*isJsxIdentifierExpected*/ undefined,
/*isRightOfOpenTag*/ undefined,
includeSymbol
); // Target will not be used, so arbitrary
return { isGlobalCompletion: false, isMemberCompletion: true, isNewIdentifierLocation: completion.hasIndexSignature, optionalReplacementSpan, entries };
}
Expand Down
13 changes: 13 additions & 0 deletions src/services/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,13 @@ export interface GetCompletionsAtPositionOptions extends UserPreferences {
*/
triggerCharacter?: CompletionsTriggerCharacter;
triggerKind?: CompletionTriggerKind;
/**
* Include a `symbol` property on each completion entry object.
* Symbols reference cyclic data structures and sometimes an entire TypeChecker instance,
* so use caution when serializing or retaining completion entries retrieved with this option.
* @default false
*/
includeSymbol?: boolean
/** @deprecated Use includeCompletionsForModuleExports */
includeExternalModuleExports?: boolean;
/** @deprecated Use includeCompletionsWithInsertText */
Expand Down Expand Up @@ -1379,6 +1386,12 @@ export interface CompletionEntry {
isFromUncheckedFile?: true;
isPackageJsonImport?: true;
isImportStatementCompletion?: true;
/**
* For API purposes.
* Included for non-string completions only when `includeSymbol: true` option is passed to `getCompletionsAtPosition`.
* @example Get declaration of completion: `symbol.valueDeclaration`
*/
symbol?: Symbol
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@andrewbranch All done, but decided to also add jsdoc on symbol property itself (since its always visible to user even if option is off). Anyway, don't see anything bad in extra documentation 😄

/**
* A property to be sent back to TS Server in the CompletionDetailsRequest, along with `name`,
* that allows TS Server to look up the symbol represented by the completion item, disambiguating
Expand Down
13 changes: 13 additions & 0 deletions tests/baselines/reference/api/tsserverlibrary.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10072,6 +10072,13 @@ declare namespace ts {
*/
triggerCharacter?: CompletionsTriggerCharacter;
triggerKind?: CompletionTriggerKind;
/**
* Include a `symbol` property on each completion entry object.
* Symbols reference cyclic data structures and sometimes an entire TypeChecker instance,
* so use caution when serializing or retaining completion entries retrieved with this option.
* @default false
*/
includeSymbol?: boolean;
/** @deprecated Use includeCompletionsForModuleExports */
includeExternalModuleExports?: boolean;
/** @deprecated Use includeCompletionsWithInsertText */
Expand Down Expand Up @@ -10629,6 +10636,12 @@ declare namespace ts {
isFromUncheckedFile?: true;
isPackageJsonImport?: true;
isImportStatementCompletion?: true;
/**
* For API purposes.
* Included for non-string completions only when `includeSymbol: true` option is passed to `getCompletionsAtPosition`.
* @example Get declaration of completion: `symbol.valueDeclaration`
*/
symbol?: Symbol;
/**
* A property to be sent back to TS Server in the CompletionDetailsRequest, along with `name`,
* that allows TS Server to look up the symbol represented by the completion item, disambiguating
Expand Down
13 changes: 13 additions & 0 deletions tests/baselines/reference/api/typescript.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6170,6 +6170,13 @@ declare namespace ts {
*/
triggerCharacter?: CompletionsTriggerCharacter;
triggerKind?: CompletionTriggerKind;
/**
* Include a `symbol` property on each completion entry object.
* Symbols reference cyclic data structures and sometimes an entire TypeChecker instance,
* so use caution when serializing or retaining completion entries retrieved with this option.
* @default false
*/
includeSymbol?: boolean;
/** @deprecated Use includeCompletionsForModuleExports */
includeExternalModuleExports?: boolean;
/** @deprecated Use includeCompletionsWithInsertText */
Expand Down Expand Up @@ -6727,6 +6734,12 @@ declare namespace ts {
isFromUncheckedFile?: true;
isPackageJsonImport?: true;
isImportStatementCompletion?: true;
/**
* For API purposes.
* Included for non-string completions only when `includeSymbol: true` option is passed to `getCompletionsAtPosition`.
* @example Get declaration of completion: `symbol.valueDeclaration`
*/
symbol?: Symbol;
/**
* A property to be sent back to TS Server in the CompletionDetailsRequest, along with `name`,
* that allows TS Server to look up the symbol represented by the completion item, disambiguating
Expand Down