From 453e0d4577f1a0f8da12a8e3c113e2ab522a4052 Mon Sep 17 00:00:00 2001 From: SerKo Date: Tue, 11 Nov 2025 23:34:22 +0800 Subject: [PATCH] feat(kit): add `createAutoInserter` function --- packages/kit/index.ts | 1 + packages/kit/lib/createAutoInserter.ts | 54 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 packages/kit/lib/createAutoInserter.ts diff --git a/packages/kit/index.ts b/packages/kit/index.ts index dd099971..dbc20796 100644 --- a/packages/kit/index.ts +++ b/packages/kit/index.ts @@ -1,3 +1,4 @@ export * from '@volar/language-service'; +export * from './lib/createAutoInserter'; export * from './lib/createChecker'; export * from './lib/createFormatter'; diff --git a/packages/kit/lib/createAutoInserter.ts b/packages/kit/lib/createAutoInserter.ts new file mode 100644 index 00000000..09d3e029 --- /dev/null +++ b/packages/kit/lib/createAutoInserter.ts @@ -0,0 +1,54 @@ +import { + createLanguage, + createLanguageService, + createUriMap, + type LanguagePlugin, + type LanguageServicePlugin, +} from '@volar/language-service'; +import * as ts from 'typescript'; +import { URI } from 'vscode-uri'; +import { createServiceEnvironment } from './createServiceEnvironment'; + +export function createAutoInserter( + languages: LanguagePlugin[], + services: LanguageServicePlugin[], +) { + let settings = {}; + + const fakeUri = URI.parse('file:///dummy.txt'); + const env = createServiceEnvironment(() => settings); + const language = createLanguage(languages, createUriMap(false), () => {}); + const languageService = createLanguageService(language, services, env, {}); + + return { + env, + autoInsert, + get settings() { + return settings; + }, + set settings(v) { + settings = v; + }, + }; + + async function autoInsert(textWithCursor: string, insertedText: string, languageId: string, cursor = '|') { + const cursorIndex = textWithCursor.indexOf(cursor); + if (cursorIndex === -1) { + throw new Error('Cursor marker not found in input text.'); + } + const content = textWithCursor.slice(0, cursorIndex) + insertedText + + textWithCursor.slice(cursorIndex + cursor.length); + const snapshot = ts.ScriptSnapshot.fromString(content); + language.scripts.set(fakeUri, snapshot, languageId); + const document = languageService.context.documents.get(fakeUri, languageId, snapshot); + return await languageService.getAutoInsertSnippet( + fakeUri, + document.positionAt(cursorIndex + insertedText.length), + { + rangeOffset: cursorIndex, + rangeLength: 0, + text: insertedText, + }, + ); + } +}