VSCode语言服务端/客户端:如何前置格式化内嵌补全结果?
解决VS Code Inline补全幽灵文本预格式化问题
要在inline补全显示为幽灵文本前完成格式化,无需创建可见的临时编辑器,直接利用VS Code的executeFormatRangeProviderAPI对内存中的临时文档处理即可,具体实现如下:
改进的格式化函数
export async function prettifyInlineCompletion( originalDoc: vscode.TextDocument, position: vscode.Position, completionText: string ): Promise<string> { // 1. 构建包含补全内容的临时文档:原文档到补全位置的内容 + 补全文本 const originalText = originalDoc.getText(); const textBeforeCompletion = originalText.substring(0, originalDoc.offsetAt(position)); const tempDocContent = textBeforeCompletion + completionText; // 2. 创建内存临时文档,不会显示给用户 const tempDoc = await vscode.workspace.openTextDocument({ content: tempDocContent, language: originalDoc.languageId }); // 3. 计算补全文本在临时文档中的范围 const completionStartOffset = textBeforeCompletion.length; const completionEndOffset = completionStartOffset + completionText.length; const completionRange = new vscode.Range( tempDoc.positionAt(completionStartOffset), tempDoc.positionAt(completionEndOffset) ); // 4. 调用格式化提供者执行格式化 const formatEdits = await vscode.commands.executeCommand<vscode.TextEdit[]>( 'vscode.executeFormatRangeProvider', tempDoc.uri, completionRange, originalDoc.options // 复用原文档的格式化配置 ); if (!formatEdits || formatEdits.length === 0) { return completionText; // 无格式化操作则返回原文本 } // 5. 逆序应用编辑操作,避免偏移量错乱 let formattedContent = tempDocContent; formatEdits.sort((a, b) => b.range.start.compareTo(a.range.start)); for (const edit of formatEdits) { const startOffset = tempDoc.offsetAt(edit.range.start); const endOffset = tempDoc.offsetAt(edit.range.end); formattedContent = formattedContent.substring(0, startOffset) + edit.newText + formattedContent.substring(endOffset); } // 提取格式化后的补全文本 const formattedCompletion = formattedContent.substring(completionStartOffset); return formattedCompletion; }
在Inline补全中间件中集成
修改provideInlineCompletionItems中间件,对每个补全项应用格式化:
async provideInlineCompletionItems( document: vscode.TextDocument, position: vscode.Position, context: vscode.InlineCompletionContext, token: vscode.CancellationToken, next: ProvideInlineCompletionItemsSignature, ) { const result = await next(document, position, context, token); if (!result || token.isCancellationRequested) { return result; } // 处理单个补全项或补全列表 const processCompletion = async (item: vscode.InlineCompletionItem) => { if (typeof item.insertText === 'string') { const formattedText = await prettifyInlineCompletion(document, position, item.insertText); return { ...item, insertText: formattedText }; } return item; // 如需支持SnippetString可扩展此处逻辑 }; let prettifiedResult: vscode.InlineCompletionItem[] | vscode.InlineCompletionList | undefined; if (Array.isArray(result)) { prettifiedResult = await Promise.all(result.map(processCompletion)); } else if (result instanceof vscode.InlineCompletionList) { prettifiedResult = new vscode.InlineCompletionList( await Promise.all(result.items.map(processCompletion)), result.incomplete ); } return prettifiedResult; }
核心优势
- 无临时标签页:内存文档不会在编辑器中显示,完全后台处理
- 配置一致性:复用原文档的格式化选项,和用户当前编辑环境保持一致
- 上下文兼容:临时文档包含补全位置前的原内容,保证格式化工具能识别正确的语法结构(如缩进、代码块)
内容的提问来源于stack exchange,提问作者Olena Horal
相关产品推荐
相关产品推荐

