From 88b0d983839ab8ed464ee8eb06790eb9373e922d Mon Sep 17 00:00:00 2001 From: johnsoncodehk Date: Sun, 18 Dec 2022 14:24:05 +0800 Subject: [PATCH] feat: auto `{{}}` -> `{{ | }}` close #2088 --- .../vscode-vue-language-features/package.json | 5 +++ .../language-server/src/registerFeatures.ts | 6 ++- .../src/features/autoInsertion.ts | 37 ++++++++++--------- .../src/documentService.ts | 3 ++ .../src/plugins/vue-autoinsert-space.ts | 37 +++++++++++++++++++ 5 files changed, 69 insertions(+), 19 deletions(-) create mode 100644 vue-language-tools/vue-language-service/src/plugins/vue-autoinsert-space.ts diff --git a/extensions/vscode-vue-language-features/package.json b/extensions/vscode-vue-language-features/package.json index 3bf769081..092f35c49 100644 --- a/extensions/vscode-vue-language-features/package.json +++ b/extensions/vscode-vue-language-features/package.json @@ -406,6 +406,11 @@ "default": false, "description": "Auto-complete Ref value with `.value`." }, + "volar.addSpaceBetweenDoubleCurlyBrackets": { + "type": "boolean", + "default": true, + "description": "Auto add space between double curly brackets: {{|}} -> {{ | }}" + }, "volar.format.initialIndent": { "type": "object", "description": "Whether to have initial indent.", diff --git a/packages/language-server/src/registerFeatures.ts b/packages/language-server/src/registerFeatures.ts index e1cc1df4d..da491079f 100644 --- a/packages/language-server/src/registerFeatures.ts +++ b/packages/language-server/src/registerFeatures.ts @@ -74,7 +74,11 @@ export function setupSyntacticCapabilities( // https://github.com/microsoft/vscode/blob/ce119308e8fd4cd3f992d42b297588e7abe33a0c/extensions/typescript-language-features/src/languageFeatures/formatting.ts#L99 server.documentOnTypeFormattingProvider = { firstTriggerCharacter: ';', - moreTriggerCharacter: ['}', '\n'], + moreTriggerCharacter: [ + '}', + '\n', + '{', // addSpaceBetweenDoubleCurlyBrackets + ], }; } } diff --git a/packages/vscode-language-client/src/features/autoInsertion.ts b/packages/vscode-language-client/src/features/autoInsertion.ts index 603f23fb9..de72ae216 100644 --- a/packages/vscode-language-client/src/features/autoInsertion.ts +++ b/packages/vscode-language-client/src/features/autoInsertion.ts @@ -79,32 +79,33 @@ export async function register( lastChange: vscode.TextDocumentContentChangeEvent, provider: (document: vscode.TextDocument, position: vscode.Position, lastChange: vscode.TextDocumentContentChangeEvent, isCancel: () => boolean) => Thenable, ) { - const rangeStart = lastChange.range.start; const version = document.version; timeout = setTimeout(() => { - const position = new vscode.Position(rangeStart.line, rangeStart.character + lastChange.text.length); - provider(document, position, lastChange, () => vscode.window.activeTextEditor?.document.version !== version).then(text => { - if (text && isEnabled) { - const activeEditor = vscode.window.activeTextEditor; - if (activeEditor) { - const activeDocument = activeEditor.document; - if (document === activeDocument && activeDocument.version === version) { - if (typeof text === 'string') { - const selections = activeEditor.selections; - if (selections.length && selections.some(s => s.active.isEqual(position))) { - activeEditor.insertSnippet(new vscode.SnippetString(text), selections.map(s => s.active)); + const position = vscode.window.activeTextEditor?.selections.length === 1 && vscode.window.activeTextEditor.selections[0].active; + if (position) { + provider(document, position, lastChange, () => vscode.window.activeTextEditor?.document.version !== version).then(text => { + if (text && isEnabled) { + const activeEditor = vscode.window.activeTextEditor; + if (activeEditor) { + const activeDocument = activeEditor.document; + if (document === activeDocument && activeDocument.version === version) { + if (typeof text === 'string') { + const selections = activeEditor.selections; + if (selections.length && selections.some(s => s.active.isEqual(position))) { + activeEditor.insertSnippet(new vscode.SnippetString(text), selections.map(s => s.active)); + } + else { + activeEditor.insertSnippet(new vscode.SnippetString(text), position); + } } else { - activeEditor.insertSnippet(new vscode.SnippetString(text), position); + activeEditor.insertSnippet(new vscode.SnippetString(text.newText), text.range); } } - else { - activeEditor.insertSnippet(new vscode.SnippetString(text.newText), text.range); - } } } - } - }); + }); + } timeout = undefined; }, 100); } diff --git a/vue-language-tools/vue-language-service/src/documentService.ts b/vue-language-tools/vue-language-service/src/documentService.ts index 383c01e7d..570288d48 100644 --- a/vue-language-tools/vue-language-service/src/documentService.ts +++ b/vue-language-tools/vue-language-service/src/documentService.ts @@ -7,6 +7,7 @@ import useTsPlugin from '@volar-plugins/typescript'; import { DocumentServiceRuntimeContext } from '@volar/language-service'; import useVuePlugin from './plugins/vue'; import useAutoWrapParenthesesPlugin from './plugins/vue-autoinsert-parentheses'; +import useAutoAddSpacePlugin from './plugins/vue-autoinsert-space'; import * as embeddedLS from '@volar/language-service'; import * as vue from '@volar/vue-language-core'; import * as shared from '@volar/shared'; @@ -29,6 +30,7 @@ export function getDocumentServicePlugins( const autoWrapParenthesesPlugin = useAutoWrapParenthesesPlugin({ getVueDocument: doc => context.getSourceFileDocument(doc)?.[0], }); + const autoAddSpacePlugin = useAutoAddSpacePlugin(); const pugFormatPlugin = usePugFormatPlugin(); return [ @@ -40,6 +42,7 @@ export function getDocumentServicePlugins( jsonPlugin, tsPlugin, autoWrapParenthesesPlugin, + autoAddSpacePlugin, ]; } diff --git a/vue-language-tools/vue-language-service/src/plugins/vue-autoinsert-space.ts b/vue-language-tools/vue-language-service/src/plugins/vue-autoinsert-space.ts new file mode 100644 index 000000000..114e3b603 --- /dev/null +++ b/vue-language-tools/vue-language-service/src/plugins/vue-autoinsert-space.ts @@ -0,0 +1,37 @@ +import { LanguageServicePlugin, LanguageServicePluginContext } from '@volar/language-service'; + +export default function (): LanguageServicePlugin { + + let context: LanguageServicePluginContext; + + return { + + setup(_context) { + context = _context; + }, + + async doAutoInsert(document, position) { + + if (document.languageId === 'html' || document.languageId === 'jade') { + + const enabled = await context.env.configurationHost?.getConfiguration('volar.addSpaceBetweenDoubleCurlyBrackets') ?? true; + if (!enabled) + return; + + const prev = document.getText({ + start: { line: position.line, character: position.character - 2 }, + end: position, + }); + if (prev === '{{') { + const next = document.getText({ + start: position, + end: { line: position.line, character: position.character + 2 }, + }); + if (next === '}}') { + return ` $0 `; + } + } + } + }, + }; +}