From f96835e70db6b36c7ad52bea9bd2ada9591b697b Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 11 Sep 2022 12:53:21 +0300 Subject: [PATCH] feat: include fix for builtin `typescript.suggest.completeFunctionCalls` in some positions out of the box fix: don't insert method snippet in some positions, inclusing const assigning --- typescript/src/completionsAtPosition.ts | 6 ++++ typescript/src/index.ts | 5 +-- .../src/isGootPositionMethodCompletion.ts | 32 +++++++++++++++++++ typescript/src/utils.ts | 7 +++- 4 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 typescript/src/isGootPositionMethodCompletion.ts diff --git a/typescript/src/completionsAtPosition.ts b/typescript/src/completionsAtPosition.ts index d56af65a..4ccc1a3e 100644 --- a/typescript/src/completionsAtPosition.ts +++ b/typescript/src/completionsAtPosition.ts @@ -4,6 +4,7 @@ import * as emmet from '@vscode/emmet-helper' import isInBannedPosition from './isInBannedPosition' import { GetConfig } from './types' import { findChildContainingPosition } from './utils' +import { isGoodPositionBuiltinMethodCompletion } from './isGootPositionMethodCompletion' export type PrevCompletionMap = Record @@ -225,6 +226,11 @@ export const getCompletionsAtPosition = ( if (rule.patch?.insertText) suggestion.isSnippet = true } + // prevent vscode-builtin wrong insertText with methods snippets enabled + if (!isGoodPositionBuiltinMethodCompletion(ts, sourceFile, position)) { + prior.entries = prior.entries.map(item => ({ ...item, insertText: item.insertText ?? item.name, isSnippet: true })) + } + if (c('correctSorting.enable')) prior.entries = prior.entries.map((entry, index) => ({ ...entry, sortText: `${entry.sortText ?? ''}${index}` })) // console.log('signatureHelp', JSON.stringify(info.languageService.getSignatureHelpItems(fileName, position, {}))) diff --git a/typescript/src/index.ts b/typescript/src/index.ts index 4f849629..f01590aa 100644 --- a/typescript/src/index.ts +++ b/typescript/src/index.ts @@ -6,9 +6,9 @@ import type { Configuration } from '../../src/configurationType' import _ from 'lodash' import { GetConfig } from './types' import { getCompletionsAtPosition, PrevCompletionMap } from './completionsAtPosition' -import { CompletionEntry } from 'typescript/lib/tsserverlibrary' import { getParameterListParts } from './completionGetMethodParameters' import { oneOf } from '@zardoy/utils' +import { isGoodPositionMethodCompletion } from './isGootPositionMethodCompletion' const thisPluginMarker = Symbol('__essentialPluginsMarker__') @@ -87,8 +87,9 @@ export = function ({ typescript }: { typescript: typeof import('typescript/lib/t ) if (!prior) return if (c('enableMethodSnippets') && oneOf(prior.kind as string, ts.ScriptElementKind.constElement, 'property')) { + const goodPosition = isGoodPositionMethodCompletion(ts, fileName, sourceFile, position, info.languageService) const punctuationIndex = prior.displayParts.findIndex(({ kind }) => kind === 'punctuation') - if (punctuationIndex !== 1) { + if (goodPosition && punctuationIndex !== 1) { const isParsableMethod = prior.displayParts // next is space .slice(punctuationIndex + 2) diff --git a/typescript/src/isGootPositionMethodCompletion.ts b/typescript/src/isGootPositionMethodCompletion.ts new file mode 100644 index 00000000..2fbf0cb5 --- /dev/null +++ b/typescript/src/isGootPositionMethodCompletion.ts @@ -0,0 +1,32 @@ +import type tslib from 'typescript/lib/tsserverlibrary' +import { findChildContainingPosition } from './utils' + +export const isGoodPositionBuiltinMethodCompletion = (ts: typeof tslib, sourceFile: tslib.SourceFile, position: number) => { + const importClauseCandidate = findChildContainingPosition(ts, sourceFile, position, 2) + if (importClauseCandidate?.kind === 266) return false + const currentNode = findChildContainingPosition(ts, sourceFile, position) + // const obj = { method() {}, arrow: () => {} } + // type A = typeof obj["|"] + if (currentNode && ts.isStringLiteralLike(currentNode)) return false + return true +} + +export const isGoodPositionMethodCompletion = ( + ts: typeof tslib, + fileName: string, + sourceFile: tslib.SourceFile, + position: number, + languageService: tslib.LanguageService, +) => { + if (!isGoodPositionBuiltinMethodCompletion(ts, sourceFile, position)) return false + const { kind } = languageService.getQuickInfoAtPosition(fileName, position) ?? {} + switch (kind) { + case 'var': + case 'let': + case 'const': + case 'alias': + return false + } + // TODO check for brace here + return true +} diff --git a/typescript/src/utils.ts b/typescript/src/utils.ts index 97f97238..c35a79bd 100644 --- a/typescript/src/utils.ts +++ b/typescript/src/utils.ts @@ -4,9 +4,14 @@ export function findChildContainingPosition( typescript: typeof import('typescript/lib/tsserverlibrary'), sourceFile: tslib.SourceFile, position: number, + maxDepth?: number, ): tslib.Node | undefined { + let currentDepth = 0 function find(node: ts.Node): ts.Node | undefined { - if (position >= node.getStart() && position < node.getEnd()) return typescript.forEachChild(node, find) || node + if (position >= node.getStart() && position < node.getEnd()) { + if (++currentDepth === maxDepth) return node + return typescript.forEachChild(node, find) || node + } return }