From 6cb12ba992644c9241e2d62070f471ea1ff806d4 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Fri, 18 Nov 2022 02:42:38 +0300 Subject: [PATCH] fix(keywordsInsertText): when `return ` is accepted and then `Enter` or `;` typed remove redundant space fixes #57 --- package.json | 2 +- pnpm-lock.yaml | 9 ++-- src/extension.ts | 35 +------------ src/onCompletionAccepted.ts | 98 +++++++++++++++++++++++++++++++++++++ 4 files changed, 106 insertions(+), 38 deletions(-) create mode 100644 src/onCompletionAccepted.ts diff --git a/package.json b/package.json index 1b78fc87..28e0f460 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "@vscode/emmet-helper": "^2.8.4", "@vscode/test-electron": "^2.1.5", "@zardoy/utils": "^0.0.9", - "@zardoy/vscode-utils": "^0.0.41", + "@zardoy/vscode-utils": "^0.0.45", "chai": "^4.3.6", "chokidar": "^3.5.3", "chokidar-cli": "^3.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 82dec84c..ecb6022d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,7 +17,7 @@ importers: '@vscode/test-electron': ^2.1.5 '@zardoy/tsconfig': ^1.3.1 '@zardoy/utils': ^0.0.9 - '@zardoy/vscode-utils': ^0.0.41 + '@zardoy/vscode-utils': ^0.0.45 chai: ^4.3.6 chokidar: ^3.5.3 chokidar-cli: ^3.0.0 @@ -55,7 +55,7 @@ importers: '@vscode/emmet-helper': 2.8.4 '@vscode/test-electron': 2.1.5 '@zardoy/utils': 0.0.9 - '@zardoy/vscode-utils': 0.0.41_cq2imf3xlo2d7oce7kuqydjknm + '@zardoy/vscode-utils': 0.0.45_cq2imf3xlo2d7oce7kuqydjknm chai: 4.3.6 chokidar: 3.5.3 chokidar-cli: 3.0.0 @@ -838,8 +838,8 @@ packages: type-fest: 2.19.0 dev: false - /@zardoy/vscode-utils/0.0.41_cq2imf3xlo2d7oce7kuqydjknm: - resolution: {integrity: sha512-lieaSgIYFZCErFD2nJ5BvFISO3TvwSPtZoEqo23uUAb3k3oPGG+r6HhI9DUIXkS3xFuhX89P+P7BBQA/Goyl9A==} + /@zardoy/vscode-utils/0.0.45_cq2imf3xlo2d7oce7kuqydjknm: + resolution: {integrity: sha512-s90L2ctTxtQJGn9YEkSVxd1IjUhyc8Hzzyxu8CK2Ndt8UqZTgb2zXQfk1/Dds2aPZIswXrYtel+2sUGrKl7PMw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} hasBin: true peerDependencies: @@ -867,6 +867,7 @@ packages: fs-extra: 10.1.0 lodash.throttle: 4.1.1 modify-json-file: 1.2.2 + path-browserify: 1.0.1 rambda: 7.3.0 type-fest: 2.19.0 typed-jsonfile: 0.2.1 diff --git a/src/extension.ts b/src/extension.ts index eaee996a..0b312b81 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-require-imports */ import * as vscode from 'vscode' import { defaultJsSupersetLangs } from '@zardoy/vscode-utils/build/langs' -import { getActiveRegularEditor } from '@zardoy/vscode-utils' import { extensionCtx, getExtensionSettingId } from 'vscode-framework' import { pickObj } from '@zardoy/utils' import { Configuration } from './configurationType' @@ -12,6 +11,7 @@ import experimentalPostfixes from './experimentalPostfixes' import migrateSettings from './migrateSettings' import figIntegration from './figIntegration' import apiCommands from './apiCommands' +import onCompletionAccepted from './onCompletionAccepted' export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted }) => { let webWaitingForConfigSync = false @@ -46,38 +46,7 @@ export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted }) syncConfig() - tsApi.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 = //.exec(documentationString)?.[1] - console.debug('insertFuncArgs', insertFuncArgs) - 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 (!['(', '.'].includes(nextSymbol)) { - const snippet = new vscode.SnippetString('') - snippet.appendText('(') - const args = insertFuncArgs.split(',') - for (let [i, arg] of args.entries()) { - if (!arg) continue - // skip empty, but add tabstops if we explicitly want it! - if (arg === ' ') arg = '' - 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') - } - } - }) + onCompletionAccepted(tsApi) if (process.env.PLATFORM === 'web') { const possiblySyncConfig = async () => { diff --git a/src/onCompletionAccepted.ts b/src/onCompletionAccepted.ts new file mode 100644 index 00000000..ae71acb0 --- /dev/null +++ b/src/onCompletionAccepted.ts @@ -0,0 +1,98 @@ +import * as vscode from 'vscode' +import { getActiveRegularEditor } from '@zardoy/vscode-utils' +import { watchExtensionSettings } from '@zardoy/vscode-utils/build/settings' +import { getExtensionSetting, Settings } from 'vscode-framework' +import { oneOf } from '@zardoy/utils' + +export default (tsApi: { onCompletionAccepted }) => { + let justAcceptedReturnKeywordSuggestion = false + + tsApi.onCompletionAccepted((item: vscode.CompletionItem & { document: vscode.TextDocument }) => { + const enableMethodSnippets = vscode.workspace.getConfiguration(process.env.IDS_PREFIX, item.document).get('enableMethodSnippets') + const { insertText, documentation = '', kind } = item + if (kind === vscode.CompletionItemKind.Keyword && insertText === 'return ') { + justAcceptedReturnKeywordSuggestion = true + } + + const documentationString = documentation instanceof vscode.MarkdownString ? documentation.value : documentation + const insertFuncArgs = //.exec(documentationString)?.[1] + console.debug('insertFuncArgs', insertFuncArgs) + 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 (!['(', '.'].includes(nextSymbol)) { + const snippet = new vscode.SnippetString('') + snippet.appendText('(') + const args = insertFuncArgs.split(',') + for (let [i, arg] of args.entries()) { + if (!arg) continue + // skip empty, but add tabstops if we explicitly want it! + if (arg === ' ') arg = '' + 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') + } + } + } + }) + + conditionallyRegister( + 'suggestions.keywordsInsertText', + () => + vscode.workspace.onDidChangeTextDocument(({ document, contentChanges, reason }) => { + if (!justAcceptedReturnKeywordSuggestion) return + if (document !== vscode.window.activeTextEditor?.document) return + try { + if (oneOf(reason, vscode.TextDocumentChangeReason.Redo, vscode.TextDocumentChangeReason.Undo)) { + return + } + + const char = contentChanges[0]?.text + if (char?.length !== 1 || contentChanges.some(({ text }) => text !== char)) { + return + } + + if (char === ';') { + void vscode.window.activeTextEditor.edit(builder => { + for (const { range } of contentChanges) { + const pos = range.start + builder.delete(new vscode.Range(pos.translate(0, -1), pos)) + } + }) + } + } finally { + justAcceptedReturnKeywordSuggestion = false + } + }), + val => val !== 'none', + ) +} + +const conditionallyRegister = ( + settingKey: T, + registerFn: () => vscode.Disposable, + acceptSettingValue: (val: Settings[T]) => boolean = val => !!val, +) => { + let disposable: vscode.Disposable | undefined + const changeRegisterState = () => { + const registerState = acceptSettingValue(getExtensionSetting(settingKey)) + if (registerState) { + if (!disposable) disposable = registerFn() + } else { + disposable?.dispose() + disposable = undefined + } + } + + changeRegisterState() + watchExtensionSettings([settingKey], changeRegisterState) +}