Skip to content

Commit

Permalink
annotate syntax visualizer
Browse files Browse the repository at this point in the history
  • Loading branch information
jmarolf committed Jan 26, 2021
1 parent 6f39a9c commit ca7a08b
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 117 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ private void UpdateColorComponents()
}

#region NotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public event PropertyChangedEventHandler? PropertyChanged;
private bool SetProperty<T>(ref T backingField, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer<T>.Default.Equals(backingField, value))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ internal static Color GetColorAtOffset(this GradientStopCollection collection, d
}

GradientStop left = stops[0];
GradientStop right = null;
GradientStop? right = null;

foreach (GradientStop stop in stops)
{
Expand All @@ -42,6 +42,11 @@ internal static Color GetColorAtOffset(this GradientStopCollection collection, d
left = stop;
}

if (right is null)
{
return left.Color;
}

double percent = Math.Round((offset - left.Offset) / (right.Offset - left.Offset), 3);
byte a = (byte)((right.Color.A - left.Color.A) * percent + left.Color.A);
byte r = (byte)((right.Color.R - left.Color.R) * percent + left.Color.R);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ internal abstract class BasePropertyGridAdapter : ICustomTypeDescriptor
public virtual string GetComponentName() => TypeDescriptor.GetClassName(this, true);
public virtual TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, true);
public virtual EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, true);
public virtual PropertyDescriptor GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true);
public virtual PropertyDescriptor? GetDefaultProperty() => TypeDescriptor.GetDefaultProperty(this, true);
public virtual object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, true);
public virtual EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, true);
public virtual EventDescriptorCollection GetEvents(Attribute[] attributes) => TypeDescriptor.GetEvents(this, attributes, true);
public virtual PropertyDescriptorCollection GetProperties() => TypeDescriptor.GetProperties(this, true);
public virtual PropertyDescriptorCollection GetProperties(Attribute[] attributes) => TypeDescriptor.GetProperties(this, attributes, true);
public virtual object GetPropertyOwner(PropertyDescriptor pd) => null;
public virtual object? GetPropertyOwner(PropertyDescriptor pd) => null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ public static string GetKind(this SyntaxNodeOrToken nodeOrToken)
{
var kind = string.Empty;

if (nodeOrToken.IsNode)
if (nodeOrToken.IsNode && nodeOrToken.AsNode() is SyntaxNode node)
{
kind = nodeOrToken.AsNode().GetKind();
kind = node.GetKind();
}
else
{
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ namespace Roslyn.SyntaxVisualizer.Control
internal class TabStopPanel : Panel
{
private readonly HwndHost _wpfHost;
private PropertyGrid _propertyGrid;
private PropertyGrid? _propertyGrid;
public TabStopPanel(HwndHost wpfHost)
{
_wpfHost = wpfHost;
}

public PropertyGrid PropertyGrid
public PropertyGrid? PropertyGrid
{
get => _propertyGrid;
set
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace Roslyn.SyntaxVisualizer.Extension
{
internal static class HelperExtensionMethods
{
internal static IWpfTextView ToWpfTextView(this IVsWindowFrame vsWindowFrame)
internal static IWpfTextView? ToWpfTextView(this IVsWindowFrame vsWindowFrame)
{
IWpfTextView wpfTextView = null;
IWpfTextView? wpfTextView = null;
var vsTextView = VsShellUtilities.GetTextView(vsWindowFrame);

if (vsTextView != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Windows.Controls;
using System.Windows.Threading;
using System.Xml.Linq;

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Classification;
using Microsoft.CodeAnalysis.Text;
Expand All @@ -17,6 +18,7 @@
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;

using Roslyn.SyntaxVisualizer.DgmlHelper;

namespace Roslyn.SyntaxVisualizer.Extension
Expand All @@ -26,11 +28,11 @@ namespace Roslyn.SyntaxVisualizer.Extension
internal partial class SyntaxVisualizerContainer : UserControl, IVsRunningDocTableEvents, IVsSolutionEvents, IDisposable
{
private readonly SyntaxVisualizerToolWindow parent;
private IWpfTextView activeWpfTextView;
private IClassificationFormatMap activeClassificationFormatMap;
private IEditorFormatMap activeEditorFormatMap;
private SyntaxTree activeSyntaxTree;
private DispatcherTimer typingTimer;
private IWpfTextView? activeWpfTextView;
private IClassificationFormatMap? activeClassificationFormatMap;
private IEditorFormatMap? activeEditorFormatMap;
private SyntaxTree? activeSyntaxTree;
private DispatcherTimer? typingTimer;

private const string CSharpContentType = "CSharp";
private const string VisualBasicContentType = "Basic";
Expand Down Expand Up @@ -62,7 +64,7 @@ internal SyntaxVisualizerContainer(SyntaxVisualizerToolWindow parent)

UpdateThemedColors();

syntaxVisualizer.SyntaxNodeNavigationToSourceRequested += node => NavigateToSource(node.Span);
syntaxVisualizer.SyntaxNodeNavigationToSourceRequested += node => NavigateToSource(node?.Span);
syntaxVisualizer.SyntaxTokenNavigationToSourceRequested += token => NavigateToSource(token.Span);
syntaxVisualizer.SyntaxTriviaNavigationToSourceRequested += trivia => NavigateToSource(trivia.Span);
}
Expand All @@ -78,7 +80,10 @@ internal void UpdateThemedColors()
if (activeClassificationFormatMap != null && activeEditorFormatMap != null)
{
var classificationTypeRegistryService = GetMefService<IClassificationTypeRegistryService>();
syntaxVisualizer.SetTreeViewColors(classificationTypeRegistryService, activeClassificationFormatMap, activeEditorFormatMap);
if (classificationTypeRegistryService is not null)
{
syntaxVisualizer.SetTreeViewColors(classificationTypeRegistryService, activeClassificationFormatMap, activeEditorFormatMap);
}
}
}

Expand Down Expand Up @@ -121,7 +126,7 @@ internal void Clear()
}

#region Helpers - GetService
private static Microsoft.VisualStudio.OLE.Interop.IServiceProvider globalServiceProvider;
private static Microsoft.VisualStudio.OLE.Interop.IServiceProvider? globalServiceProvider;
private static Microsoft.VisualStudio.OLE.Interop.IServiceProvider GlobalServiceProvider
{
get
Expand All @@ -138,11 +143,11 @@ private static Microsoft.VisualStudio.OLE.Interop.IServiceProvider GlobalService
}
}

private TServiceInterface GetService<TServiceInterface, TService>()
private TServiceInterface? GetService<TServiceInterface, TService>()
where TServiceInterface : class
where TService : class
{
TServiceInterface service = null;
TServiceInterface? service = null;

if (parent != null)
{
Expand All @@ -152,12 +157,12 @@ private TServiceInterface GetService<TServiceInterface, TService>()
return service;
}

private static object GetService(
private static object? GetService(
Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider, Guid guidService, bool unique)
{
var guidInterface = VSConstants.IID_IUnknown;
var ptr = IntPtr.Zero;
object service = null;
object? service = null;

#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
if (serviceProvider.QueryService(ref guidService, ref guidInterface, out ptr) == 0 &&
Expand All @@ -184,17 +189,17 @@ private static object GetService(
return service;
}

private static TServiceInterface GetService<TServiceInterface, TService>(
private static TServiceInterface? GetService<TServiceInterface, TService>(
Microsoft.VisualStudio.OLE.Interop.IServiceProvider serviceProvider)
where TServiceInterface : class
where TService : class
{
return (TServiceInterface)GetService(serviceProvider, typeof(TService).GUID, false);
return (TServiceInterface?)GetService(serviceProvider, typeof(TService).GUID, false);
}

private static TServiceInterface GetMefService<TServiceInterface>() where TServiceInterface : class
private static TServiceInterface? GetMefService<TServiceInterface>() where TServiceInterface : class
{
TServiceInterface service = null;
TServiceInterface? service = null;
var componentModel = GetService<IComponentModel, SComponentModel>(GlobalServiceProvider);

if (componentModel != null)
Expand All @@ -209,8 +214,8 @@ private static TServiceInterface GetMefService<TServiceInterface>() where TServi
#region Helpers - Initialize and Dispose IVsRunningDocumentTable
private uint runningDocumentTableCookie;

private IVsRunningDocumentTable runningDocumentTable;
private IVsRunningDocumentTable RunningDocumentTable
private IVsRunningDocumentTable? runningDocumentTable;
private IVsRunningDocumentTable? RunningDocumentTable
{
get
{
Expand Down Expand Up @@ -238,7 +243,7 @@ void IDisposable.Dispose()
if (runningDocumentTableCookie != 0)
{
#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
runningDocumentTable.UnadviseRunningDocTableEvents(runningDocumentTableCookie);
runningDocumentTable?.UnadviseRunningDocTableEvents(runningDocumentTableCookie);
#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread
runningDocumentTableCookie = 0;
}
Expand Down Expand Up @@ -268,7 +273,7 @@ private void RefreshSyntaxVisualizer()
var activeSemanticModel = ThreadHelper.JoinableTaskFactory.Run(() => document.GetSemanticModelAsync());

// Display the SyntaxTree.
if (contentType.IsOfType(VisualBasicContentType) || contentType.IsOfType(CSharpContentType))
if (( contentType.IsOfType(VisualBasicContentType) || contentType.IsOfType(CSharpContentType) ) && activeSyntaxTree is not null)
{
syntaxVisualizer.DisplaySyntaxTree(activeSyntaxTree, activeSemanticModel, workspace: document.Project.Solution.Workspace);
}
Expand All @@ -290,11 +295,11 @@ private void NavigateFromSource()
}

// When user clicks on a particular item in the treeview select the corresponding text in the editor.
private void NavigateToSource(TextSpan span)
private void NavigateToSource(TextSpan? span)
{
if (IsVisible && activeWpfTextView != null)
if (IsVisible && activeWpfTextView != null && span is TextSpan nonNullableSpan)
{
var snapShotSpan = span.ToSnapshotSpan(activeWpfTextView.TextBuffer.CurrentSnapshot);
var snapShotSpan = nonNullableSpan.ToSnapshotSpan(activeWpfTextView.TextBuffer.CurrentSnapshot);

// See SyntaxVisualizerToolWindow_GotFocus and SyntaxVisualizerToolWindow_LostFocus
// for some notes about selection opacity and why it needs to be manipulated.
Expand Down Expand Up @@ -337,7 +342,7 @@ private void HandleTextViewLostFocus(object sender, EventArgs e)

private void HandleTypingTimerTimeout(object sender, EventArgs e)
{
typingTimer.Stop();
typingTimer?.Stop();
RefreshSyntaxVisualizer();
}

Expand All @@ -361,10 +366,16 @@ int IVsRunningDocTableEvents.OnBeforeDocumentWindowShow(uint docCookie, int isFi

var classificationFormatMapService = GetMefService<IClassificationFormatMapService>();
var editorFormatMapService = GetMefService<IEditorFormatMapService>();
activeClassificationFormatMap = classificationFormatMapService.GetClassificationFormatMap(activeWpfTextView);
activeClassificationFormatMap.ClassificationFormatMappingChanged += HandleFormatMappingChanged;
activeEditorFormatMap = editorFormatMapService.GetEditorFormatMap(activeWpfTextView);
activeEditorFormatMap.FormatMappingChanged += HandleFormatMappingChanged;
activeClassificationFormatMap = classificationFormatMapService?.GetClassificationFormatMap(activeWpfTextView);
if (activeClassificationFormatMap is not null)
{
activeClassificationFormatMap.ClassificationFormatMappingChanged += HandleFormatMappingChanged;
}
activeEditorFormatMap = editorFormatMapService?.GetEditorFormatMap(activeWpfTextView);
if (activeEditorFormatMap is not null)
{
activeEditorFormatMap.FormatMappingChanged += HandleFormatMappingChanged;
}

UpdateThemedColors();
RefreshSyntaxVisualizer();
Expand Down Expand Up @@ -414,9 +425,9 @@ int IVsRunningDocTableEvents.OnAfterSave(uint docCookie)
#endregion

#region Event Handlers - Directed Syntax Graph / IVsSolutionEvents Events
private string dgmlFilePath;
private IVsFileChangeEx fileChangeService;
private IVsFileChangeEx FileChangeService
private string? dgmlFilePath;
private IVsFileChangeEx? fileChangeService;
private IVsFileChangeEx? FileChangeService
{
get
{
Expand All @@ -429,8 +440,8 @@ private IVsFileChangeEx FileChangeService
}
}

private IVsSolution solutionService;
private IVsSolution SolutionService
private IVsSolution? solutionService;
private IVsSolution? SolutionService
{
get
{
Expand All @@ -443,7 +454,7 @@ private IVsSolution SolutionService
}
}

private void DisplayDgml(XElement dgml)
private void DisplayDgml(XElement? dgml)
{
uint cookie;
const int TRUE = -1;
Expand All @@ -466,8 +477,9 @@ private void DisplayDgml(XElement dgml)
#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread
out var docUIHierarchy, out var docItemId, out var docWindowFrame) && docWindowFrame != null)
{
if (RunningDocumentTable is not null &&
#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
if (RunningDocumentTable.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, dgmlFilePath,
RunningDocumentTable.FindAndLockDocument((uint)_VSRDTFLAGS.RDT_NoLock, dgmlFilePath,
#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread
out var docHierarchy, out docItemId,
out var docDataIUnknownPointer,
Expand All @@ -490,16 +502,16 @@ private void DisplayDgml(XElement dgml)
// The below call ensures that there are no pop-ups from Visual Studio
// prompting the user to reload the file each time it is changed.
#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
FileChangeService.IgnoreFile(0, dgmlFilePath, TRUE);
FileChangeService?.IgnoreFile(0, dgmlFilePath, TRUE);
#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread

// Update the file on disk with the new directed syntax graph.
dgml.Save(dgmlFilePath);
dgml?.Save(dgmlFilePath);

// The below calls ensure that the file is refreshed inside Visual Studio
// so that the latest contents are displayed to the user.
#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
FileChangeService.SyncFile(dgmlFilePath);
FileChangeService?.SyncFile(dgmlFilePath);
persistDocDataService.ReloadDocData((uint)_VSRELOADDOCDATA.RDD_IgnoreNextFileChange);
#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread

Expand All @@ -519,7 +531,7 @@ private void DisplayDgml(XElement dgml)
else
{
// Update the file on disk with the new directed syntax graph.
dgml.Save(dgmlFilePath);
dgml?.Save(dgmlFilePath);

// Open the new directed syntax graph in the 'design' view.
VsShellUtilities.OpenDocument(
Expand All @@ -532,18 +544,18 @@ private void DisplayDgml(XElement dgml)
// This ensures that the file won't be persisted in the .suo file and that it therefore won't get re-opened
// when the solution is re-opened.
#pragma warning disable VSTHRD010 // Invoke single-threaded types on Main thread
SolutionService.AdviseSolutionEvents(this, out cookie);
SolutionService?.AdviseSolutionEvents(this, out cookie);
#pragma warning restore VSTHRD010 // Invoke single-threaded types on Main thread
}
}

private void DisplaySyntaxNodeDgml(SyntaxNode node)
private void DisplaySyntaxNodeDgml(SyntaxNode? node)
{
if (activeWpfTextView != null)
{
var snapshot = activeWpfTextView.TextBuffer.CurrentSnapshot;
var contentType = snapshot.ContentType;
XElement dgml = null;
XElement? dgml = null;

if (contentType.IsOfType(CSharpContentType) || contentType.IsOfType(VisualBasicContentType))
{
Expand All @@ -560,7 +572,7 @@ private void DisplaySyntaxTokenDgml(SyntaxToken token)
{
var snapshot = activeWpfTextView.TextBuffer.CurrentSnapshot;
var contentType = snapshot.ContentType;
XElement dgml = null;
XElement? dgml = null;

if (contentType.IsOfType(CSharpContentType) || contentType.IsOfType(VisualBasicContentType))
{
Expand All @@ -577,7 +589,7 @@ private void DisplaySyntaxTriviaDgml(SyntaxTrivia trivia)
{
var snapshot = activeWpfTextView.TextBuffer.CurrentSnapshot;
var contentType = snapshot.ContentType;
XElement dgml = null;
XElement? dgml = null;

if (contentType.IsOfType(CSharpContentType) || contentType.IsOfType(VisualBasicContentType))
{
Expand Down
Loading

0 comments on commit ca7a08b

Please sign in to comment.