Skip to content

Expose completion entry symbol for plugins APIΒ #51936

Closed
@zardoy

Description

@zardoy

Suggestion

πŸ” Search Terms

languageService.getCompletionEntrySymbol

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

Hi! I don't have very deep knowledge of TS internals, but it seems very obvious that completion entries are coming from symbols and getting that symbol information per entry is not possible in any way (calling getCompletionEntrySymbol for every entry seems to be inefficient inside of getCompletionsAtPosition as it calles it).

πŸ“ƒ Motivating Example and πŸ’» Use Cases

plugin

Probably absolutely any plugin that wants to improve or change existing completions lists, so I can imagine hundreds of hundreds use cases. But I have a few real world cases that I really need sometimes. For example removing marking (or even removing some) global symbol completions:

const isLibCompletion = (symbol: ts.Symbol) => {
    const fileName = symbol.declarations?.[0]?.getSourceFile().fileName
    if (!fileName) return
    if (!fileName.includes('node_modules/typescript/lib/')) return
    return basename(fileName).slice(0, -'.d.ts'.length)
}

let prior = languageService.getCompletionsAtPosition(fileName, position, options)
if (!prior.isGlobalCompletion) return
entries.map(entry => {
    if (entry.sourceDisplay) return entry
    const symbol = entry['symbol'] as ts.Symbol | undefined
    if (!symbol) return entry
    const libCompletionEnding = isLibCompletion(symbol)
    if (!libCompletionEnding) return entry
    return {
        ...entry,
        labelDetails: {
            ...entry.labelDetails,
            description: libCompletionEnding,
        },
    }
})

With this patch I can get it (in my case it just adds symbol in %LOCALAPPDATA%\Programs\Microsoft VS Code\resources\app\extensions\node_modules\typescript\lib\tsserver.js at L135650):

before (lib.dom suggestions) after
Screenshot 2022-12-17 at 21 41 49 Screenshot 2022-12-17 at 21 42 03

Another (but more advanced) cases would be:

  1. Adding call signature (like objectLiteralMethodSnippets but for global / property access completions)
  2. Filter only jsx components completions in <Foo[||]>
  3. Change insertText of object literal property completion depending on JSDoc tags (for example @default)

... also changing sorting, insertText or even removing completions depending on contextual or declaration type or fileName (location) of where symbol is declared.

There are no workarounds known for me! (except of manually getting container and symbols of it), but it might become out of sync if manually maintained in plugin.

Metadata

Metadata

Assignees

No one assigned

    Labels

    APIRelates to the public API for TypeScriptAwaiting More FeedbackThis means we'd like to hear from more people who would be helped by this featureSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions