VS Code扩展开发:程序化获取指定语言活动代码片段及空白位置
解决方案
一、获取当前语言的所有活动代码片段
要覆盖用户自定义、内置及扩展提供的全部代码片段,可通过以下方式实现:
- 收集扩展提供的代码片段
遍历所有已激活扩展,提取其package.json中contributes.snippets字段里对应当前语言的片段:
async function getExtensionSnippets(langId: string): Promise<string[]> { const snippetNames: string[] = []; for (const ext of vscode.extensions.all) { const pkg = ext.packageJSON; if (pkg.contributes?.snippets) { for (const snippetDef of pkg.contributes.snippets) { if (snippetDef.language === langId && snippetDef.path) { const snippetPath = ext.asAbsolutePath(snippetDef.path); const snippetContent = await vscode.workspace.fs.readFile(vscode.Uri.file(snippetPath)); const snippets = JSON.parse(Buffer.from(snippetContent).toString()); snippetNames.push(...Object.keys(snippets)); } } } } return snippetNames; }
- 收集用户自定义代码片段
通过工作区配置获取用户针对当前语言的自定义片段:
function getUserSnippets(langId: string): string[] { const snippetConfig = vscode.workspace.getConfiguration('editor.snippets', vscode.Uri.parse(`file:///dummy.${langId}`)); const userSnippets = snippetConfig.get<Record<string, any>>(langId) || {}; return Object.keys(userSnippets); }
- 合并去重验证
将上述两部分结果合并去重,得到当前语言的完整代码片段名称列表,即可用来校验用户输入的<SNIPPET_NAME>是否合法。
另外,还可以通过触发临时补全请求获取实时片段列表(更适配动态注册的片段):
async function getSnippetsViaCompletion(document: vscode.TextDocument): Promise<string[]> { const validPosition = await getValidSnippetPosition(document); if (!validPosition) return []; const completions = await vscode.languages.getCompletionItems(document, validPosition); return completions .filter(item => item.kind === vscode.CompletionItemKind.Snippet) .map(item => item.label.toString()); }
二、获取语言无关的可触发片段提示的空白位置
要找到能触发所有代码片段提示的合法位置,需避开注释和字符串区域,步骤如下:
- 遍历文档寻找合法位置
通过语法分词判断每行token类型,找到第一个非注释、非字符串的空白位置:
async function getValidSnippetPosition(document: vscode.TextDocument): Promise<vscode.Position | undefined> { for (let line = 0; line < document.lineCount; line++) { const lineText = document.lineAt(line).text; if (lineText.trim() === '') { const tokens = await vscode.languages.tokenize(document.getText(new vscode.Range(line, 0, line, 1)), document.languageId); const tokenType = tokens[0]?.type; if (!tokenType?.includes('comment') && !tokenType?.includes('string')) { return new vscode.Position(line, 0); } } else { const firstNonWhitespace = lineText.search(/\S/); if (firstNonWhitespace > 0) { const tokens = await vscode.languages.tokenize(document.getText(new vscode.Range(line, 0, line, firstNonWhitespace)), document.languageId); const tokenType = tokens[0]?.type; if (!tokenType?.includes('comment') && !tokenType?.includes('string')) { return new vscode.Position(line, 0); } } } } // fallback:返回文档开头 return new vscode.Position(0, 0); }
内容的提问来源于stack exchange,提问作者Chrysaloid
相关产品推荐
相关产品推荐

