如何在Visual Studio 2022菜单命令扩展中移动文本插入点至新行末尾?
如何在Visual Studio 2022扩展中将文本插入点移到新历史行末尾?
我正在开发Visual Studio 2022扩展,用于帮开发者在源文件顶部添加历史行,扩展会自动填充当前日期、开发者姓名、问题报告编号等信息。已完成菜单和命令配置,能找到历史行栈的末尾位置并插入新历史行的开头部分,但目前插入点仍停留在之前的位置,需要实现将插入点移到新历史行的末尾,方便开发者直接输入变更描述。
internal sealed class AddHistoryLine : BaseCommand<AddHistoryLine> { //------------------------------------------------------------------------------------------ protected override Task ExecuteAsync( OleMenuCmdEventArgs e ) { _ = AddHistoryLineAsync(); return Task.CompletedTask; } //------------------------------------------------------------------------------------------ public async Task AddHistoryLineAsync() { await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); DocumentView docView = await VS.Documents.GetActiveDocumentViewAsync(); if (docView == null) return; ITextSnapshot snapshot = docView.TextBuffer.CurrentSnapshot; if (snapshot == null) return; // Insert the $HISTORY$ line. int historyLineNumber = FindHistoryLineNumber( snapshot ); if (historyLineNumber == -1 || historyLineNumber == 0) return; // Build the history line using the previous history line and the author's name. ITextSnapshotLine previousHistoryLineSnapShot = snapshot.GetLineFromLineNumber( historyLineNumber - 1 ); string previousHistoryLine = previousHistoryLineSnapShot.GetText(); string authorName = GetAuthorName(); string newHistoryLine = BuildHistoryLine( previousHistoryLine, authorName ); // Insert the new history line right before the $HISTORY$ line. ITextSnapshotLine historyLine = snapshot.GetLineFromLineNumber( historyLineNumber ); docView.TextBuffer.Insert( historyLine.Start, newHistoryLine ); // #TODO: Move the cursor to the end of the new history line so the developer can just start typing. } }
实现方案
要将插入点移动到新历史行末尾,可通过以下步骤修改代码:
- 获取插入后的文本快照:插入新行后,
TextBuffer的CurrentSnapshot会更新,需用新快照定位新行位置。 - 定位新历史行并计算结束位置:新插入的行位于原
$HISTORY$行之前,插入后原$HISTORY$行号会+1,因此新行对应原来的historyLineNumber位置;计算行结束位置时需减去换行符长度,避免光标跳到下一行。 - 设置光标位置并滚动视图:通过
TextView.Caret设置新位置,同时确保视图滚动到光标所在处。
修改后的关键代码如下:
// Insert the new history line right before the $HISTORY$ line. ITextSnapshotLine historyLine = snapshot.GetLineFromLineNumber( historyLineNumber ); docView.TextBuffer.Insert( historyLine.Start, newHistoryLine ); // 获取插入后的新快照 ITextSnapshot newSnapshot = docView.TextBuffer.CurrentSnapshot; // 新插入的行位于原historyLineNumber位置(原HISTORY行已下移) ITextSnapshotLine newHistoryLineSnapshot = newSnapshot.GetLineFromLineNumber( historyLineNumber ); // 计算行结束位置(排除换行符) int endPosition = newHistoryLineSnapshot.End.Position - newHistoryLineSnapshot.LineBreakLength; // 移动光标到新行末尾 docView.TextView.Caret.MoveTo( newSnapshot.CreateTrackingPoint( endPosition, PointTrackingMode.Positive ) ); // 确保视图滚动到光标位置 docView.TextView.ViewScroller.EnsureSpanVisible( newSnapshot.CreateSpan( endPosition, 0 ), EnsureSpanVisibleOptions.AlwaysCenter );
注意事项
- 代码已通过
SwitchToMainThreadAsync切换到主线程,无需额外处理线程问题。 - 使用
TrackingPoint可保证文本后续变更时光标位置的准确性。
内容的提问来源于stack exchange,提问作者Erratic Badger
相关产品推荐
相关产品推荐

