Get Roslyn SyntaxToken from Visual Studio Text Selection (caret position)

I am trying to connect between the VSSDK and the Roslyn SDK in the Visual Studio expansion pack and this is hard to handle. ActivePoint.AbsoluteCharOffset given from Visual Studio does not match the element that I get from Roslyn when using FindToken (offset). I am sure that this is due to the way each side takes into account the EOL characters based on my current working hack, but I'm not 100% sure that my hack will be delayed in the long run.

My hack is a line: charOffset += point.Line;

I am adding the number of lines to the char offset, it seems to work, so I am assuming that I am adding to all the line break characters that are ignored by the active point count.

Assistants

 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>(); } 

Main part

 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); 
+4
c # visual-studio visual-studio-2015 roslyn visual-studio-extensions
source share
1 answer

I would recommend using Microsoft.VisualStudio.Text.SnapshotPoint from the Microsoft.VisualStudio.Text.Editor.IWpfTextView buffer instead of the EnvDTE interfaces for interacting with Roslyn.

The main code might look like this:

 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(); 

See Create a typed variable from the current method call for a complete example.

+10
source share

All Articles