From 722e2c8325f761946ca2f913ffc41d5a43fa9e79 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Fri, 9 Aug 2019 18:53:12 +0200 Subject: [PATCH] Add bracket highlighting to ILSpy. --- ILSpy/ILSpy.csproj | 2 ++ .../CSharpHighlightingTokenWriter.cs | 20 ++++++++++++++++++- ILSpy/Languages/CSharpLanguage.cs | 5 +++++ ILSpy/Languages/Language.cs | 6 ++++++ ILSpy/Options/DisplaySettings.cs | 13 ++++++++++++ ILSpy/Options/DisplaySettingsPanel.xaml | 1 + ILSpy/Options/DisplaySettingsPanel.xaml.cs | 2 ++ ILSpy/Properties/Resources.Designer.cs | 9 +++++++++ ILSpy/Properties/Resources.resx | 3 +++ ILSpy/TextView/DecompilerTextView.cs | 15 ++++++++++++++ 10 files changed, 75 insertions(+), 1 deletion(-) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 2338940e6..ea4846842 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -140,6 +140,7 @@ + @@ -206,6 +207,7 @@ + diff --git a/ILSpy/Languages/CSharpHighlightingTokenWriter.cs b/ILSpy/Languages/CSharpHighlightingTokenWriter.cs index 827e774b3..cf0464067 100644 --- a/ILSpy/Languages/CSharpHighlightingTokenWriter.cs +++ b/ILSpy/Languages/CSharpHighlightingTokenWriter.cs @@ -1,4 +1,22 @@ -using System; +// Copyright (c) 2018 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; using System.Collections.Generic; using System.Linq; using ICSharpCode.AvalonEdit.Highlighting; diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 35f614764..e952647e1 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -37,6 +37,7 @@ using ICSharpCode.Decompiler.Output; using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.Util; +using ICSharpCode.ILSpy.TextView; using ICSharpCode.ILSpy.TreeNodes; namespace ICSharpCode.ILSpy @@ -634,5 +635,9 @@ namespace ICSharpCode.ILSpy { return CSharpDecompiler.GetCodeMappingInfo(module, member); } + + CSharpBracketSearcher bracketSearcher = new CSharpBracketSearcher(); + + public override IBracketSearcher BracketSearcher => bracketSearcher; } } diff --git a/ILSpy/Languages/Language.cs b/ILSpy/Languages/Language.cs index e97696fea..701399c70 100644 --- a/ILSpy/Languages/Language.cs +++ b/ILSpy/Languages/Language.cs @@ -102,6 +102,12 @@ namespace ICSharpCode.ILSpy } } + public virtual TextView.IBracketSearcher BracketSearcher { + get { + return TextView.DefaultBracketSearcher.DefaultInstance; + } + } + public virtual void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) { WriteCommentLine(output, TypeToString(method.DeclaringTypeDefinition, includeNamespace: true) + "." + method.Name); diff --git a/ILSpy/Options/DisplaySettings.cs b/ILSpy/Options/DisplaySettings.cs index 3d6053961..a887e2913 100644 --- a/ILSpy/Options/DisplaySettings.cs +++ b/ILSpy/Options/DisplaySettings.cs @@ -215,6 +215,18 @@ namespace ICSharpCode.ILSpy.Options } } + bool highlightMatchingBraces = true; + + public bool HighlightMatchingBraces { + get { return highlightMatchingBraces; } + set { + if (highlightMatchingBraces != value) { + highlightMatchingBraces = value; + OnPropertyChanged(); + } + } + } + public void CopyValues(DisplaySettings s) { this.SelectedFont = s.selectedFont; @@ -231,6 +243,7 @@ namespace ICSharpCode.ILSpy.Options this.IndentationUseTabs = s.indentationUseTabs; this.IndentationTabSize = s.indentationTabSize; this.IndentationSize = s.indentationSize; + this.HighlightMatchingBraces = s.highlightMatchingBraces; } } } diff --git a/ILSpy/Options/DisplaySettingsPanel.xaml b/ILSpy/Options/DisplaySettingsPanel.xaml index ab2ad7398..13d149e6d 100644 --- a/ILSpy/Options/DisplaySettingsPanel.xaml +++ b/ILSpy/Options/DisplaySettingsPanel.xaml @@ -80,6 +80,7 @@ + diff --git a/ILSpy/Options/DisplaySettingsPanel.xaml.cs b/ILSpy/Options/DisplaySettingsPanel.xaml.cs index b08a139fb..56ff2622d 100644 --- a/ILSpy/Options/DisplaySettingsPanel.xaml.cs +++ b/ILSpy/Options/DisplaySettingsPanel.xaml.cs @@ -114,6 +114,7 @@ namespace ICSharpCode.ILSpy.Options s.IndentationUseTabs = (bool?)e.Attribute("IndentationUseTabs") ?? true; s.IndentationSize = (int?)e.Attribute("IndentationSize") ?? 4; s.IndentationTabSize = (int?)e.Attribute("IndentationTabSize") ?? 4; + s.HighlightMatchingBraces = (bool?)e.Attribute("HighlightMatchingBraces") ?? true; return s; } @@ -136,6 +137,7 @@ namespace ICSharpCode.ILSpy.Options section.SetAttributeValue("IndentationUseTabs", s.IndentationUseTabs); section.SetAttributeValue("IndentationSize", s.IndentationSize); section.SetAttributeValue("IndentationTabSize", s.IndentationTabSize); + section.SetAttributeValue("HighlightMatchingBraces", s.HighlightMatchingBraces); XElement existingElement = root.Element("DisplaySettings"); if (existingElement != null) diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs index c2c607198..9cb673c88 100644 --- a/ILSpy/Properties/Resources.Designer.cs +++ b/ILSpy/Properties/Resources.Designer.cs @@ -1152,6 +1152,15 @@ namespace ICSharpCode.ILSpy.Properties { } } + /// + /// Looks up a localized string similar to Highlight matching braces. + /// + public static string HighlightMatchingBraces { + get { + return ResourceManager.GetString("HighlightMatchingBraces", resourceCulture); + } + } + /// /// Looks up a localized string similar to ILSpy version . /// diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx index 6ef64ac91..08bb57a15 100644 --- a/ILSpy/Properties/Resources.resx +++ b/ILSpy/Properties/Resources.resx @@ -742,4 +742,7 @@ Are you sure you want to continue? Project Directory not empty + + Highlight matching braces + \ No newline at end of file diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 8a4f05152..a370e4984 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -65,6 +65,7 @@ namespace ICSharpCode.ILSpy.TextView readonly UIElementGenerator uiElementGenerator; List activeCustomElementGenerators = new List(); RichTextColorizer activeRichTextColorizer; + BracketHighlightRenderer bracketHighlightRenderer; FoldingManager foldingManager; ILSpyTreeNode[] decompiledNodes; @@ -103,12 +104,14 @@ namespace ICSharpCode.ILSpy.TextView this.referenceElementGenerator = new ReferenceElementGenerator(this.JumpToReference, this.IsLink); textEditor.TextArea.TextView.ElementGenerators.Add(referenceElementGenerator); this.uiElementGenerator = new UIElementGenerator(); + this.bracketHighlightRenderer = new BracketHighlightRenderer(textEditor.TextArea.TextView); textEditor.TextArea.TextView.ElementGenerators.Add(uiElementGenerator); textEditor.Options.RequireControlModifierForHyperlinkClick = false; textEditor.TextArea.TextView.MouseHover += TextViewMouseHover; textEditor.TextArea.TextView.MouseHoverStopped += TextViewMouseHoverStopped; textEditor.TextArea.PreviewMouseDown += TextAreaMouseDown; textEditor.TextArea.PreviewMouseUp += TextAreaMouseUp; + textEditor.TextArea.Caret.PositionChanged += HighlightBrackets; textEditor.SetBinding(Control.FontFamilyProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFont") }); textEditor.SetBinding(Control.FontSizeProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("SelectedFontSize") }); textEditor.SetBinding(TextEditor.WordWrapProperty, new Binding { Source = DisplaySettingsPanel.CurrentDisplaySettings, Path = new PropertyPath("EnableWordWrap") }); @@ -245,6 +248,18 @@ namespace ICSharpCode.ILSpy.TextView } #endregion + #region Highlight brackets + void HighlightBrackets(object sender, EventArgs e) + { + if (DisplaySettingsPanel.CurrentDisplaySettings.HighlightMatchingBraces) { + var result = MainWindow.Instance.CurrentLanguage.BracketSearcher.SearchBracket(textEditor.Document, textEditor.CaretOffset); + bracketHighlightRenderer.SetHighlight(result); + } else { + bracketHighlightRenderer.SetHighlight(null); + } + } + #endregion + #region RunWithCancellation /// /// Switches the GUI into "waiting" mode, then calls to create