修改后的答案:
啊,我明白了。我解释了您的问题,认为您指的是通过键入而不是通过显式命令触发完成。如果您为 C# 编辑器启用“显示空白”,您可以在这里看到我们所做的:当您触发“显示完成”命令时,我们显式地实现了空白,因此您不再在虚拟空间中漂浮。您可能也应该这样做。(或者,您可以通过调整 ApplicableTo 跨度来检测场景并在第一次输入时修复它,但这可能不值得麻烦。)
您可以从 IEditorOperations 中获取应插入的空格。所以MEF导入一个IEditorOperationsFactoryService,然后做:
var editorOperations = editorOperationsFactoryService.GetEditorOperations(textView);
var whitespace = editorOperations.GetWhitespaceForVirtualSpace(textView.Caret.Position.VirtualBufferPosition);
if (whitespace.Length != 0)
{
textView.TextBuffer.Insert(textView.Caret.Position.BufferPosition, whitespace);
}
(有趣的是:当我回答这个问题时,我很想知道我们是如何在 Roslyn C# 和 VB 编辑器中处理这个问题的。答案是“不是”,但在代码的后面,过滤仍然靠运气。)
原答案:
根据您对问题的描述,我怀疑您正在像这样实现完成:您知道将要输入一个字符(通过键盘过滤器或IOleCommandTarget
),并且您触发了 ICompletionSession,其中跟踪跨度是当前插入符号位置。
解决此问题的最佳方法是在按键被按下并进入编辑器之前不触发会话,而是在它之后触发。这就是我们在 Roslyn 实现中为 C# 和 VB 完成所做的。然后,当您在 AugmentCompletionSession 调用并创建 CompletionSet 时,计算“适用于”跨度,该跨度由插入符号周围的非空白字符组成。计算它的最简单方法可能只是GetWordExtent
从文本结构导航器中调用。
这允许其他场景正常工作。考虑用户键入 C,按转义键,然后继续键入您的标识符的情况。如果您想再次触发完成,则必须进行数学运算以确保“C”无论如何都被视为您的跨度的一部分。