【问题标题】:Get Roslyn SyntaxToken from Visual Studio Text Selection (caret position)从 Visual Studio 文本选择(插入符号位置)获取 Roslyn SyntaxToken
【发布时间】:2016-05-26 19:55:07
【问题描述】:

我试图在 Visual Studio 扩展包中的 VSSDK 和 Roslyn SDK 之间架起一座桥梁,但我一直很难做到这一点。 Visual Studio 提供的 ActivePoint.AbsoluteCharOffset 与我在使用 FindToken(offset) 时从 Roslyn 获得的元素不匹配。我相当确定这与每一方如何根据我当前的工作技巧计算 EOL 字符有关,但我并不是 100% 地认为我的技巧能够长期坚持下去。

我的 hack 是这一行:charOffset += point.Line;

我将行数添加到 char 偏移量上,这似乎可行,所以我猜我正在添加所有被活动点计数忽略的换行符。

帮手

private VisualStudioWorkspace workspace = null;
public RoslynUtilities(VisualStudioWorkspace workspace)
{
    this.workspace = workspace;
}
public Solution Solution { get { return workspace.CurrentSolution; } }
public Document GetDocumentFromPath(string fullPath)
{
    foreach (Project proj in this.Solution.Projects)
    {               
        foreach (Document doc in proj.Documents)
        {
            if (doc.FilePath == fullPath)
                return doc;                   
        }
    }
    return null;
}
public SyntaxTree GetSyntaxTreeFromDocumentPath(string fullPath)
{
    Document doc = GetDocumentFromPath(fullPath);
    if (doc != null)
        return doc.GetSyntaxTreeAsync().Result;
    else
        return null;
}
public SyntaxNode GetNodeByFilePosition(string fullPath, int absoluteChar)
{
    SyntaxTree tree = GetSyntaxTreeFromDocumentPath(fullPath);
    if(tree != null)
    {
        var compUnit = tree.GetCompilationUnitRoot();
        if(compUnit != null)
        {
            return compUnit.FindToken(absoluteChar, true).Parent;
        }
    }
    return null;                        
}
private VisualStudioWorkspace GetRoslynWorkspace()
    {
        var componentModel = (IComponentModel)GetGlobalService(typeof(SComponentModel));
        return componentModel.GetService<VisualStudioWorkspace>();
    }

主要部分

EnvDTE80.DTE2 applicationObject = (EnvDTE80.DTE2)GetService(typeof(SDTE));
EnvDTE.TextSelection ts = applicationObject.ActiveWindow.Selection as EnvDTE.TextSelection;
if (ts == null)
    return;

EnvDTE.VirtualPoint point = ts.ActivePoint;
int charOffset = point.AbsoluteCharOffset;
charOffset += point.Line;//HACK ALERT

Parse.Roslyn.RoslynUtilities roslyn = new Parse.Roslyn.RoslynUtilities(GetRoslynWorkspace());
SyntaxNode node = roslyn.GetNodeByFilePosition(applicationObject.ActiveDocument.FullName, charOffset);

【问题讨论】:

    标签: c# visual-studio visual-studio-2015 roslyn visual-studio-extensions


    【解决方案1】:

    我强烈建议使用 Microsoft.VisualStudio.Text.Editor.IWpfTextView 缓冲区中的 Microsoft.VisualStudio.Text.SnapshotPoint 而不是 EnvDTE 接口与 Roslyn 交互。

    主代码可能如下所示:

    Microsoft.VisualStudio.Text.Editor.IWpfTextView textView =
        GetTextView();
    
    Microsoft.VisualStudio.Text.SnapshotPoint caretPosition =
        textView.Caret.Position.BufferPosition;
    
    Microsoft.CodeAnalysis.Document document =
        caretPosition.Snapshot.GetOpenDocumentInCurrentContextWithChanges();
    
    Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax invocationExpressionNode = 
        document.GetSyntaxRootAsync().Result.
            FindToken(caretPosition).Parent.AncestorsAndSelf().
            OfType<Microsoft.CodeAnalysis.CSharp.Syntax.InvocationExpressionSyntax>().
            FirstOrDefault();
    

    完整示例请参见Create a typed variable from the current method invocation

    【讨论】:

    • 谢谢!我将其切换并编辑了最后一行,只需删除以 .AncestorsAndSelf 开头的所有内容,它就完成了我想要的。无论出于何种原因,我的旧方法总是比这个返回的内容多 2 个字符,但这个是正确的。
    • 为了拯救其他人我刚刚开始的疯狂追逐:在 Microsoft 中使用 GetOpenDocumentInCurrentContextWithChanges 扩展方法。代码分析 2.0 将引入(据我所知未记录)对 Microsoft 的依赖.VisualStudio 15.0,导致插件在 Visual Studio 2015 上不起作用。因此,如果您想使用此方法并且不想限制自己使用 Visual Studio 2017,您似乎需要针对 Microsoft.CodeAnalysis 进行构建1.3.2.
    • @DanielMcLaury 我还没有找到任何官方文档(虽然没有花很多时间寻找),但是这个 SO 答案谈到了每个 CodeAnalysis 版本支持的 VS 版本。看起来 1.3.2 适用于 VS2015 Update 3 及更高版本:stackoverflow.com/questions/45678861/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多