Visual Studio扩展场景下使用Roslyn跳转至SourceText的实现方法咨询
Visual Studio扩展中通过Roslyn Location跳转至源码位置的实现方案
存在已封装的跳转实现,不需要手动完成全流程操作,常见有两种实现路径:
路径一:直接使用EditorFeatures内置扩展方法(最简便)
在已经引用Microsoft.CodeAnalysis.EditorFeatures包的前提下,框架已经提供了封装好的跳转扩展,仅需少量代码即可完成操作:
using Microsoft.CodeAnalysis; using Microsoft.VisualStudio.LanguageServices; // 已通过MEF导入的VisualStudioWorkspace实例 private readonly VisualStudioWorkspace _workspace; public void JumpToSyntaxNodeLocation(SyntaxNode node) { var location = node.GetLocation(); // 直接调用扩展方法完成跳转,已封装打开文档、定位、选中逻辑 location.NavigateTo(_workspace); }
路径二:基于VS原生服务自定义实现(无需依赖EditorFeatures包)
如果不想引入额外的EditorFeatures依赖,也可以通过Visual Studio原生的SDK服务实现跳转,步骤如下:
- 先获取
SVsUIShellOpenDocument服务,调用OpenDocumentViaProject方法打开位置对应的源码文件 - 获取文件对应的
IVsTextView实例,设置光标位置与选中范围即可自动滚动到对应位置
示例代码:
using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Shell.Interop; using Microsoft.CodeAnalysis; using System.Runtime.InteropServices; public void NavigateToLocation(Location location) { ThreadHelper.ThrowIfNotOnUIThread(); if (!location.IsInSource) return; string filePath = location.SourceTree.FilePath; var span = location.GetLineSpan(); int startLine = span.StartLinePosition.Line; int startColumn = span.StartLinePosition.Character; int endLine = span.EndLinePosition.Line; int endColumn = span.EndLinePosition.Character; IVsUIShellOpenDocument openDoc = GetService<SVsUIShellOpenDocument, IVsUIShellOpenDocument>(); IVsWindowFrame frame; Guid logicalView = VSConstants.LOGVIEWID_Code; if (ErrorHandler.Succeeded(openDoc.OpenDocumentViaProject( filePath, ref logicalView, out _, out _, out _, out frame)) && frame != null) { frame.Show(); if (frame.GetProperty((int)__VSFPROPID.VSFPROPID_DocData, out object docData) == VSConstants.S_OK) { if (Marshal.QueryInterface(Marshal.GetIUnknownForObject(docData), ref typeof(IVsTextView).GUID, out IntPtr textViewPtr) >= 0) { IVsTextView textView = Marshal.GetObjectForIUnknown(textViewPtr) as IVsTextView; textView?.SetSelection(startLine, startColumn, endLine, endColumn); textView?.CenterLines(startLine, 1); Marshal.Release(textViewPtr); } } } }
注意事项
- 所有跳转相关操作必须在Visual Studio UI线程执行,可通过
ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync()切换线程上下文 - 跳转前需判断
Location.IsInSource为true,避免尝试跳转元数据、编译生成代码等非用户源码的位置 - 如果需要选中对应SyntaxNode的全部文本,直接传入
Location.SourceSpan作为选中范围即可
内容的提问来源于stack exchange,提问作者TWT
相关产品推荐
相关产品推荐

