From 8f3280ffcbd956eb7f7fc03fcb525fbd019e6a6f Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky <vital2580@icloud.com> Date: Sun, 11 Sep 2022 12:02:52 +0300 Subject: [PATCH] feat: big feature! Args snippets for simple arrow callbacks (enabled by default). Feature is experimental and doesn't support aliases for now --- src/configurationType.ts | 5 +++++ src/extension.ts | 32 ++++++++++++++++++++++++++++++++ typescript/src/index.ts | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/src/configurationType.ts b/src/configurationType.ts index d5bdf73d..45f24a41 100644 --- a/src/configurationType.ts +++ b/src/configurationType.ts @@ -153,4 +153,9 @@ export type Configuration = { * @default false */ changeDtsFileDefinitionToJs: boolean + /** + * Experimental. Also includes optional args + * @default true + */ + enableMethodSnippets: boolean } diff --git a/src/extension.ts b/src/extension.ts index 30e31a66..f876f9e5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,4 +1,6 @@ import * as vscode from 'vscode' +import { getActiveRegularEditor } from '@zardoy/vscode-utils' +import {} from 'vscode-framework' export const activate = async () => { const tsExtension = vscode.extensions.getExtension('vscode.typescript-language-features') @@ -21,4 +23,34 @@ export const activate = async () => { if (affectsConfiguration(process.env.IDS_PREFIX!)) syncConfig() }) syncConfig() + + api.onCompletionAccepted((item: vscode.CompletionItem & { document: vscode.TextDocument }) => { + const enableMethodSnippets = vscode.workspace.getConfiguration(process.env.IDS_PREFIX, item.document).get('enableMethodSnippets') + const { documentation = '' } = item + const documentationString = documentation instanceof vscode.MarkdownString ? documentation.value : documentation + const insertFuncArgs = /<!-- insert-func: (.*)-->/.exec(documentationString)?.[1] + if (enableMethodSnippets && insertFuncArgs !== undefined) { + const editor = getActiveRegularEditor()! + const startPos = editor.selection.start + const nextSymbol = editor.document.getText(new vscode.Range(startPos, startPos.translate(0, 1))) + if (nextSymbol !== '(') { + const snippet = new vscode.SnippetString('') + snippet.appendText('(') + const args = insertFuncArgs.split(',') + for (const [i, arg] of args.entries()) { + if (!arg) continue + snippet.appendPlaceholder(arg) + if (i !== args.length - 1) snippet.appendText(', ') + } + + snippet.appendText(')') + void editor.insertSnippet(snippet, undefined, { + undoStopAfter: false, + undoStopBefore: false, + }) + if (vscode.workspace.getConfiguration('editor.parameterHints').get('enabled')) + void vscode.commands.executeCommand('editor.action.triggerParameterHints') + } + } + }) } diff --git a/typescript/src/index.ts b/typescript/src/index.ts index 0cbf1368..4f849629 100644 --- a/typescript/src/index.ts +++ b/typescript/src/index.ts @@ -6,6 +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' const thisPluginMarker = Symbol('__essentialPluginsMarker__') @@ -83,6 +86,35 @@ export = function ({ typescript }: { typescript: typeof import('typescript/lib/t data, ) if (!prior) return + if (c('enableMethodSnippets') && oneOf(prior.kind as string, ts.ScriptElementKind.constElement, 'property')) { + const punctuationIndex = prior.displayParts.findIndex(({ kind }) => kind === 'punctuation') + if (punctuationIndex !== 1) { + const isParsableMethod = prior.displayParts + // next is space + .slice(punctuationIndex + 2) + .map(({ text }) => text) + .join('') + .match(/\((.*)\) => /) + if (isParsableMethod) { + let firstArgMeet = false + const args = prior.displayParts + .filter(({ kind }, index, array) => { + if (kind !== 'parameterName') return false + if (array[index - 1]!.text === '(') { + if (!firstArgMeet) { + // bad parsing, as doesn't take second and more args + firstArgMeet = true + return true + } + return false + } + return true + }) + .map(({ text }) => text) + prior.documentation = [...(prior.documentation ?? []), { kind: 'text', text: `<!-- insert-func: ${args.join(',')}-->` }] + } + } + } // if (prior.kind === typescript.ScriptElementKind.constElement && prior.displayParts.map(item => item.text).join('').match(/: \(.+\) => .+/)) prior.codeActions?.push({ // description: '', // changes: []