我正在开发一个使用外部程序格式化Visual Studio内部代码的扩展程序。
如果我使用 ITextEdit.Replace(...)替换文件的内容,则插入符号将放在文档的末尾,这是错误的。
我要做的是在替换文件内容之前保存textbuffer中当前插入符号位置的快照,然后将插入符号位置设置为之前的位置。替换内容之前的textbuffer。
然而, ITextEdit.Apply()正在生成一个新的快照,导致 _textView.Caret.MoveTo(指向)引发异常:
System.ArgumentException: The supplied SnapshotPoint is on an incorrect snapshot.
Parameter name: bufferPosition
at Microsoft.VisualStudio.Text.Editor.Implementation.CaretElement.InternalMoveTo(VirtualSnapshotPoint bufferPosition, PositionAffinity caretAffinity, Boolean captureHorizontalPosition, Boolean captureVerticalPosition, Boolean raiseEvent)
at Microsoft.VisualStudio.Text.Editor.Implementation.CaretElement.MoveTo(SnapshotPoint bufferPosition)
我也尝试过创建一个新的快照点而不是使用_textView.Caret.Position.BufferPosition,如下所示:
var point = new SnapshotPoint(_textView.TextSnapshot, 0);
抛出相同的“提供的SnapshotPoint位于不正确的快照上”。异常。
public class MyCommand
{
private readonly IWpfTextView _textView;
private readonly MyFormatter _formatter;
private readonly ITextDocument _document;
public MyCommand(IWpfTextView textView, MyFormatter formatter, ITextDocument document)
{
_textView = textView;
_formatter = formatter;
_document = document;
}
public void Format()
{
var input = _document.TextBuffer.CurrentSnapshot.GetText();
var output = _formatter.format(input);
// get caret snapshot point
var point = _textView.Caret.Position.BufferPosition;
using (var edit = _document.TextBuffer.CreateEdit())
{
edit.Replace(0, _document.TextBuffer.CurrentSnapshot.Length, output);
edit.Apply();
}
// set caret position
_textView.Caret.MoveTo(point);
}
}
我不想实现一些自定义插入符号“历史记录”,我希望按照它的意图来实现。 此外,我希望将移动的插入符号视为编辑的一部分,保持“ctrl + z”功能不变。
一如既往,非常感谢任何帮助!
答案 0 :(得分:1)
您可以检索点的位置,然后创建一个新的SnapshotPoint并移动到它。
像这样:var point = _textView.Caret.Position.BufferPosition;
int position = point.Position;
using (var edit = _document.TextBuffer.CreateEdit())
{
edit.Replace(0, _document.TextBuffer.CurrentSnapshot.Length, output);
edit.Apply();
}
// set caret position
_textView.Caret.MoveTo(new SnapshotPoint(_textView.TextSnapshot, position));
此外,您可以创建和使用这样的扩展程序: https://github.com/jaredpar/EditorUtils/blob/master/Src/EditorUtils/Extensions.cs
答案 1 :(得分:0)
尽管Cole Wu - MSFT对我的问题的回答帮助我解决了我的问题,但它并没有完全符合我的要求:
使用提供的代码可以移动插入符号,但是由于我替换了文档的整个内容,因此即使插入符号位于文档的下方,它也会将滚动位置重置为顶部。
另外:这仍然生成“multiple undos”而不只是一个:即替换文档的内容并移动插入符是两个单独的“undos”,其中要求用户点击 CTRL + Z两次而不是仅一次撤消替换。
要解决此问题,我将代码更改为以下内容:
public class MyCommand
{
private readonly IWpfTextView _textView;
private readonly MyFormatter _formatter;
private readonly ITextDocument _document;
private readonly ITextBufferUndoManager _undoManager;
public MyCommand(IWpfTextView textView, MyFormatter formatter, ITextDocument document, ITextBufferUndoManager undoManager)
{
_textView = textView;
_formatter = formatter;
_document = document;
_undoManager = undoManager;
}
public void Format()
{
var input = _textView.TextSnapshot.GetText();
var output = _formatter.format(input);
using (var undo = _undoManager.TextBufferUndoHistory.CreateTransaction("Format"))
using (var edit = _undoManager.TextBuffer.CreateEdit(EditOptions.DefaultMinimalChange, 0, null))
{
edit.Replace(0, _textView.TextSnapshot.Length, output);
edit.Apply();
undo.Complete();
}
}
}
这不能正常按照我想要的方式,因为插入符号有时(当位于尾随空格时)跳转到下一行的开头而不是当前行的结尾。
然而,它足够接近!