0

我正在编写一个 Visual Studio 扩展,它为某种内容类型提供智能感知。我现在面临的问题是当用户键入字符时 Visual Studio 在空行上提供的“自动缩进”效果。

这里完成会话在一个空行开始(通过虚拟空间):

前

请注意其他行上的制表符符号,而带有插入符号的行上没有制表符。

现在,当使用开始输入时,VS 会自动正确地将必要的制表符添加到该行:

后

现在的问题是那些添加的选项卡显然成为用户输入的一部分,因此CurrentSession.SelectedCompletionSet.SelectBestMatch()Filter()方法无法在此处找到以“C”开头的当前项目(认为用户已键入 \t\tC 代替)。

如果我在其他不需要自动缩进的地方开始会话,一切正常。

任何的想法?

编辑(更多信息):我使用的代码流非常类似于:

在 Lua 和 Clojure 中,您不会遇到这个问题,因为它们从不在虚拟空间上提供智能感知(这意味着它们总是在特定字符集之后开始),并且如果您在字符虚拟空间已经变成真实空间之后开始。

好的,其他的也有同样的问题。

4

1 回答 1

2

修改后的答案:

啊,我明白了。我解释了您的问题,认为您指的是通过键入而不是通过显式命令触发完成。如果您为 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”无论如何都被视为您的跨度的一部分。

于 2013-02-01T17:43:05.600 回答