From 72b6502a2fc9d3c9757ceffc76ff690c9cf31a7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Kuklau?= Date: Thu, 1 Sep 2022 20:26:24 +0200 Subject: [PATCH 1/4] Syntax Visualizer: add tree nodes for ClassifiedSpans from embedded languages --- .../SyntaxVisualizerControl.xaml.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs index c1b586f67..16b298236 100644 --- a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs @@ -13,6 +13,7 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; +using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Classification; @@ -37,6 +38,7 @@ public enum SyntaxCategory SyntaxToken, SyntaxTrivia, Operation, + EmbeddedClassification, } // A control for visually displaying the contents of a SyntaxTree. @@ -518,6 +520,9 @@ private void ExpandPathTo(TreeViewItem? item) foreach (TreeViewItem item in current.Items) { + if (item == null) + continue; + if (category != SyntaxCategory.Operation && ((SyntaxTag)item.Tag).Category == SyntaxCategory.Operation) { // Do not prefer navigating to IOperation nodes when clicking in source code @@ -780,6 +785,20 @@ private void AddNode(TreeViewItem? parentItem, SyntaxNode? node) } } + private void AddEmbeddedClassification(TreeViewItem parentItem, ClassifiedSpan classifiedSpan) + { + var tag = new SyntaxTag + { + Category = SyntaxCategory.EmbeddedClassification, + Span = classifiedSpan.TextSpan, + ParentItem = parentItem + }; + + var item = CreateTreeViewItem(tag, $"{classifiedSpan.ClassificationType} {classifiedSpan.TextSpan}", false); + + parentItem.Items.Add(item); + } + private void AddToken(TreeViewItem parentItem, SyntaxToken token) { var kind = token.GetKind(); @@ -877,6 +896,19 @@ private void AddToken(TreeViewItem parentItem, SyntaxToken token) } } } + + if (token.GetKind().Contains("String") && item.Items.Count == 0 && classifiedSpans != null) // no child nodes and tokens + { + var embeddedClassifications = classifiedSpans.Where(cs => token.Span.Contains(cs.TextSpan)); + + if (embeddedClassifications.Count() > 1) + { + foreach (var classifiedSpan in embeddedClassifications) + { + AddEmbeddedClassification(item, classifiedSpan); + } + } + } } private void AddTrivia(TreeViewItem parentItem, SyntaxTrivia trivia, bool isLeadingTrivia) From 2ba5fb57b7f76137848a989a5fbe67bce393a477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Kuklau?= Date: Thu, 1 Sep 2022 20:29:46 +0200 Subject: [PATCH 2/4] 63664-visualize-embedded-language: skip the full span; only show nested ones --- .../SyntaxVisualizerControl.xaml.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs index 16b298236..c17afe328 100644 --- a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs @@ -903,8 +903,12 @@ private void AddToken(TreeViewItem parentItem, SyntaxToken token) if (embeddedClassifications.Count() > 1) { - foreach (var classifiedSpan in embeddedClassifications) + foreach (var classifiedSpan in embeddedClassifications.OrderBy(cs => cs.TextSpan.Start)) { + // skip the full span itself + if (classifiedSpan.TextSpan == token.Span) + continue; + AddEmbeddedClassification(item, classifiedSpan); } } From 5a08adc59290689514fc4e9fd2ba0e0aabf3ca09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Kuklau?= Date: Thu, 1 Sep 2022 20:42:48 +0200 Subject: [PATCH 3/4] 63664-visualize-embedded-language: selecting a node now shows its properties --- .../SyntaxVisualizerControl.xaml.cs | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs index c17afe328..a71f7e356 100644 --- a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs @@ -207,6 +207,10 @@ public SyntaxVisualizerControl() ClassifiedSpan = classifiedSpans.FirstOrDefault(s => s.TextSpan.Contains(trivia.Span)); break; + case ClassifiedSpan span: + ClassifiedSpan = span; + break; + default: ClassifiedSpan = null; break; @@ -795,7 +799,21 @@ private void AddEmbeddedClassification(TreeViewItem parentItem, ClassifiedSpan c }; var item = CreateTreeViewItem(tag, $"{classifiedSpan.ClassificationType} {classifiedSpan.TextSpan}", false); - + + item.Selected += new RoutedEventHandler((sender, e) => + { + _isNavigatingFromTreeToSource = true; + + typeTextLabel.Visibility = Visibility.Visible; + kindTextLabel.Visibility = Visibility.Hidden; + typeValueLabel.Content = classifiedSpan.GetType().Name; + kindValueLabel.Content = null; + _propertyGrid.SelectedObject = classifiedSpan; + + _isNavigatingFromTreeToSource = false; + e.Handled = true; + }); + parentItem.Items.Add(item); } From 4aebce63facf025c9ed09f35da2d1c1ca39578a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Kuklau?= Date: Thu, 1 Sep 2022 20:58:30 +0200 Subject: [PATCH 4/4] 63664-visualize-embedded-language: navigating between source and tree now works --- .../SyntaxVisualizerControl.xaml.cs | 10 +++++++++- .../SyntaxVisualizerContainer.xaml.cs | 1 + 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs index a71f7e356..9c72580e5 100644 --- a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Control/SyntaxVisualizerControl.xaml.cs @@ -13,7 +13,6 @@ using System.Windows.Input; using System.Windows.Media; using System.Windows.Shapes; -using System.Xml.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Classification; @@ -115,6 +114,9 @@ private class SyntaxTag public event SyntaxTokenDelegate? SyntaxTokenDirectedGraphRequested; public event SyntaxTokenDelegate? SyntaxTokenNavigationToSourceRequested; + public delegate void SyntaxClassifiedSpanDelegate(ClassifiedSpan span); + public event SyntaxClassifiedSpanDelegate? SyntaxClassifiedSpanNavigationToSourceRequested; + public delegate void SyntaxTriviaDelegate(SyntaxTrivia trivia); public event SyntaxTriviaDelegate? SyntaxTriviaDirectedGraphRequested; public event SyntaxTriviaDelegate? SyntaxTriviaNavigationToSourceRequested; @@ -794,6 +796,7 @@ private void AddEmbeddedClassification(TreeViewItem parentItem, ClassifiedSpan c var tag = new SyntaxTag { Category = SyntaxCategory.EmbeddedClassification, + FullSpan = classifiedSpan.TextSpan, Span = classifiedSpan.TextSpan, ParentItem = parentItem }; @@ -810,6 +813,11 @@ private void AddEmbeddedClassification(TreeViewItem parentItem, ClassifiedSpan c kindValueLabel.Content = null; _propertyGrid.SelectedObject = classifiedSpan; + if (!_isNavigatingFromSourceToTree && SyntaxClassifiedSpanNavigationToSourceRequested != null) + { + SyntaxClassifiedSpanNavigationToSourceRequested(classifiedSpan); + } + _isNavigatingFromTreeToSource = false; e.Handled = true; }); diff --git a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Extension/SyntaxVisualizerContainer.xaml.cs b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Extension/SyntaxVisualizerContainer.xaml.cs index f9bcd54b9..35edf2720 100644 --- a/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Extension/SyntaxVisualizerContainer.xaml.cs +++ b/src/VisualStudio.Roslyn.SDK/SyntaxVisualizer/Roslyn.SyntaxVisualizer.Extension/SyntaxVisualizerContainer.xaml.cs @@ -65,6 +65,7 @@ internal SyntaxVisualizerContainer(SyntaxVisualizerToolWindow parent) syntaxVisualizer.SyntaxNodeNavigationToSourceRequested += node => NavigateToSource(node?.Span); syntaxVisualizer.SyntaxTokenNavigationToSourceRequested += token => NavigateToSource(token.Span); + syntaxVisualizer.SyntaxClassifiedSpanNavigationToSourceRequested += span => NavigateToSource(span.TextSpan); syntaxVisualizer.SyntaxTriviaNavigationToSourceRequested += trivia => NavigateToSource(trivia.Span); }