diff --git a/ExpandRegions/ExpandRegions.Vsix/source.extension.vsixmanifest b/ExpandRegions/ExpandRegions.Vsix/source.extension.vsixmanifest
index 3efc9fb..6e6e025 100644
--- a/ExpandRegions/ExpandRegions.Vsix/source.extension.vsixmanifest
+++ b/ExpandRegions/ExpandRegions.Vsix/source.extension.vsixmanifest
@@ -3,7 +3,7 @@
ExpandRegions
- This extension expands all regions in C# and Visual Basic when a file is opened. It's a slimmed down version of "I Hate #Regions" for VS2017.
+ This extension expands all regions in C# and Visual Basic when a file is opened. It's a slimmed down version of \"I Hate #Regions\" for VS2017.
license.txt
diff --git a/ExpandRegions/ExpandRegions/Classifications/ActiveRegionClassification.cs b/ExpandRegions/ExpandRegions/Classifications/ActiveRegionClassification.cs
new file mode 100644
index 0000000..c41b763
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Classifications/ActiveRegionClassification.cs
@@ -0,0 +1,27 @@
+using System.ComponentModel.Composition;
+using System.Windows.Media;
+
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Utilities;
+
+namespace ExpandRegions.Classifications
+{
+ [Export(typeof(EditorFormatDefinition))]
+ [ClassificationType(ClassificationTypeNames = Constants.ActiveRegionClassificationTypeNames)]
+ [Name(Constants.ActiveRegionName)]
+ [DisplayName(Constants.ActiveRegionName)]
+ [UserVisible(true)]
+ [Order(After = Constants.OrderAfterPriority, Before = Constants.OrderBeforePriority)]
+ internal sealed class ActiveRegionClassification : ClassificationFormatDefinition
+ {
+ #region Initialization
+
+ // Methods
+ public ActiveRegionClassification()
+ {
+ ForegroundColor = Colors.DarkGray;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/Classifications/ClassificationFormatDefinition.cs b/ExpandRegions/ExpandRegions/Classifications/ClassificationFormatDefinition.cs
new file mode 100644
index 0000000..ca20f2d
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Classifications/ClassificationFormatDefinition.cs
@@ -0,0 +1,166 @@
+using System.Globalization;
+using System.Windows;
+using System.Windows.Media;
+
+using Microsoft.VisualStudio.Text.Classification;
+
+namespace ExpandRegions.Classifications
+{
+ internal abstract class ClassificationFormatDefinition : EditorFormatDefinition
+ {
+ #region Protected Methods
+
+ protected override ResourceDictionary CreateResourceDictionaryFromDefinition()
+ {
+ ResourceDictionary resourceDictionary = new ResourceDictionary();
+ AddOverridableProperties(resourceDictionary);
+ if (ForegroundBrush != null)
+ {
+ resourceDictionary["Foreground"] = ForegroundBrush;
+ if (ForegroundBrush.Opacity != 1.0)
+ {
+ resourceDictionary["ForegroundOpacity"] = ForegroundBrush.Opacity;
+ }
+ }
+ if (BackgroundBrush != null)
+ {
+ resourceDictionary["Background"] = BackgroundBrush;
+ if (BackgroundBrush.Opacity != 1.0)
+ {
+ resourceDictionary["BackgroundOpacity"] = BackgroundBrush.Opacity;
+ }
+ }
+ if (FontTypeface != null)
+ {
+ resourceDictionary.Add("Typeface", FontTypeface);
+ if (FontTypeface.Weight == FontWeights.Bold)
+ {
+ resourceDictionary["IsBold"] = true;
+ }
+ if (FontTypeface.Style == FontStyles.Italic)
+ {
+ resourceDictionary["IsItalic"] = true;
+ }
+ }
+ if (FontRenderingSize.HasValue)
+ {
+ resourceDictionary.Add("FontRenderingSize", FontRenderingSize.Value);
+ }
+ if (FontHintingSize.HasValue)
+ {
+ resourceDictionary.Add("FontHintingSize", FontHintingSize.Value);
+ }
+ if (TextDecorations != null)
+ {
+ resourceDictionary.Add("TextDecorations", TextDecorations);
+ }
+ if (TextEffects != null)
+ {
+ resourceDictionary.Add("TextEffects", TextEffects);
+ }
+ if (CultureInfo != null)
+ {
+ resourceDictionary.Add("CultureInfo", CultureInfo);
+ }
+ return resourceDictionary;
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private void AddOverridableProperties(ResourceDictionary resourceDictionary)
+ {
+ if (ForegroundOpacity.HasValue)
+ {
+ resourceDictionary.Add("ForegroundOpacity", ForegroundOpacity.Value);
+ }
+ if (BackgroundOpacity.HasValue)
+ {
+ resourceDictionary.Add("BackgroundOpacity", BackgroundOpacity.Value);
+ }
+ if (IsBold.HasValue)
+ {
+ resourceDictionary.Add("IsBold", IsBold.Value);
+ }
+ if (IsItalic.HasValue)
+ {
+ resourceDictionary.Add("IsItalic", IsItalic.Value);
+ }
+ if (ForegroundColor.HasValue)
+ {
+ resourceDictionary["Foreground"] = new SolidColorBrush(ForegroundColor.Value);
+ }
+ if (BackgroundColor.HasValue)
+ {
+ resourceDictionary["Background"] = new SolidColorBrush(BackgroundColor.Value);
+ }
+ }
+
+ #endregion
+
+ #region Public Properties
+
+ public double? BackgroundOpacity
+ {
+ get;
+ protected set;
+ }
+
+ public CultureInfo CultureInfo
+ {
+ get;
+ protected set;
+ }
+
+ public double? FontHintingSize
+ {
+ get;
+ protected set;
+ }
+
+ public double? FontRenderingSize
+ {
+ get;
+ protected set;
+ }
+
+ public Typeface FontTypeface
+ {
+ get;
+ protected set;
+ }
+
+ public double? ForegroundOpacity
+ {
+ get;
+ protected set;
+ }
+
+ public bool? IsBold
+ {
+ get;
+ protected set;
+ }
+
+ public bool? IsItalic
+ {
+ get;
+ protected set;
+ }
+
+ public TextDecorationCollection TextDecorations
+ {
+ get;
+ protected set;
+ }
+
+ public TextEffectCollection TextEffects
+ {
+ get;
+ protected set;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/Classifications/ClassifierProvider.cs b/ExpandRegions/ExpandRegions/Classifications/ClassifierProvider.cs
new file mode 100644
index 0000000..8d7af3c
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Classifications/ClassifierProvider.cs
@@ -0,0 +1,22 @@
+using System.ComponentModel.Composition;
+
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Utilities;
+
+namespace ExpandRegions.Classifications
+{
+ internal sealed class ClassifierProvider
+ {
+ #region Internal Fields
+
+ [Export]
+ [Name(Constants.ActiveRegionClassificationTypeNames)]
+ internal static ClassificationTypeDefinition ActiveRegionDefinition;
+
+ [Export]
+ [Name(Constants.InactiveRegionClassificationTypeNames)]
+ internal static ClassificationTypeDefinition InactiveRegionDefinition;
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/Classifications/InactiveRegionClassification.cs b/ExpandRegions/ExpandRegions/Classifications/InactiveRegionClassification.cs
new file mode 100644
index 0000000..5af3411
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Classifications/InactiveRegionClassification.cs
@@ -0,0 +1,29 @@
+using System.ComponentModel.Composition;
+using System.Windows.Media;
+
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Utilities;
+
+namespace ExpandRegions.Classifications
+{
+ [Export(typeof(EditorFormatDefinition))]
+ [ClassificationType(ClassificationTypeNames = Constants.InactiveRegionClassificationTypeNames)]
+ [Name(Constants.InactiveRegionName)]
+ [DisplayName(Constants.InactiveRegionName)]
+ [UserVisible(true)]
+ [Order(After =Constants.OrderAfterPriority, Before = Constants.OrderBeforePriority)]
+ internal sealed class InactiveRegionClassification : ClassificationFormatDefinition
+ {
+ #region Initialization
+
+ // Methods
+ public InactiveRegionClassification()
+ {
+ ForegroundColor = Colors.Gray;
+ FontRenderingSize = 10;
+ ForegroundOpacity = 0.5;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/Constants.cs b/ExpandRegions/ExpandRegions/Constants.cs
new file mode 100644
index 0000000..cd1aa37
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Constants.cs
@@ -0,0 +1,25 @@
+namespace ExpandRegions
+{
+ internal static class Constants
+ {
+ #region Internal Fields
+
+ internal const char RegionIndicatorCharacter = '#';
+ internal const string RegionIndicator = "#region";
+
+ internal const string CSharpContentType = "CSharp";
+ internal const string BasicContentType = "Basic";
+
+ internal const string TextViewRole = "DOCUMENT";
+
+ internal const string ActiveRegionName = "Active Region";
+ internal const string InactiveRegionName = "Inactive Region";
+ internal const string ActiveRegionClassificationTypeNames = "activeRegion";
+ internal const string InactiveRegionClassificationTypeNames = "inactiveRegion";
+
+ internal const string OrderAfterPriority = "Default Priority";
+ internal const string OrderBeforePriority = "High Priority";
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/ExpandRegions.csproj b/ExpandRegions/ExpandRegions/ExpandRegions.csproj
index 2630064..6116f9a 100644
--- a/ExpandRegions/ExpandRegions/ExpandRegions.csproj
+++ b/ExpandRegions/ExpandRegions/ExpandRegions.csproj
@@ -50,17 +50,29 @@
..\..\packages\Microsoft.VisualStudio.Text.UI.Wpf.15.0.26201\lib\net45\Microsoft.VisualStudio.Text.UI.Wpf.dll
True
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ExpandRegions/ExpandRegions/RegionTextViewHandler.cs b/ExpandRegions/ExpandRegions/RegionTextViewHandler.cs
index b45b1a0..f724512 100644
--- a/ExpandRegions/ExpandRegions/RegionTextViewHandler.cs
+++ b/ExpandRegions/ExpandRegions/RegionTextViewHandler.cs
@@ -1,56 +1,82 @@
using System;
+using System.Diagnostics.CodeAnalysis;
+
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Outlining;
namespace ExpandRegions
{
- class RegionTextViewHandler
+ public class RegionTextViewHandler
{
+ #region Private Fields
+
private IWpfTextView _textView;
private IOutliningManager _outliningManager;
- public static void CreateHandler(IWpfTextView textView, IOutliningManagerService outliningManagerService)
- {
- new RegionTextViewHandler(textView, outliningManagerService);
- }
+ #endregion
+
+ #region Initialization
private RegionTextViewHandler(IWpfTextView textView, IOutliningManagerService outliningManagerService)
{
-
_outliningManager = outliningManagerService.GetOutliningManager(textView);
+
if (_outliningManager == null)
{
return;
}
+
_textView = textView;
_outliningManager.RegionsCollapsed += OnRegionsCollapsed;
_textView.Closed += OnClosed;
+ }
+
+ #endregion
+ #region Public Methods
+
+ [SuppressMessage("ReSharper", "ObjectCreationAsStatement")]
+ public static void CreateHandler(IWpfTextView textView, IOutliningManagerService outliningManagerService)
+ {
+ new RegionTextViewHandler(textView, outliningManagerService);
}
+ #endregion
+
+ #region Private Methods
+
private void OnClosed(object sender, EventArgs e)
{
if (_outliningManager != null)
{
_outliningManager.RegionsCollapsed -= OnRegionsCollapsed;
}
+
if (_textView != null)
{
_textView.Closed -= OnClosed;
}
+
_textView = null;
_outliningManager = null;
}
-
+
private void OnRegionsCollapsed(object sender, RegionsCollapsedEventArgs e)
{
- foreach (var cr in e.CollapsedRegions)
+ foreach (ICollapsed collapsed in e.CollapsedRegions)
{
- _outliningManager.Expand(cr);
+ try
+ {
+ _outliningManager.Expand(collapsed);
+ }
+ catch (InvalidOperationException)
+ {
+ }
}
+
_outliningManager.RegionsCollapsed -= OnRegionsCollapsed;
}
-
+ #endregion
}
-}
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/Tags/RegionTag.cs b/ExpandRegions/ExpandRegions/Tags/RegionTag.cs
new file mode 100644
index 0000000..186b4d5
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Tags/RegionTag.cs
@@ -0,0 +1,17 @@
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace ExpandRegions.Tags
+{
+ public sealed class RegionTag : ClassificationTag
+ {
+ #region Initialization
+
+ public RegionTag(IClassificationType type)
+ : base(type)
+ {
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/Tags/RegionTagger.cs b/ExpandRegions/ExpandRegions/Tags/RegionTagger.cs
new file mode 100644
index 0000000..3f9c257
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Tags/RegionTagger.cs
@@ -0,0 +1,141 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+
+namespace ExpandRegions.Tags
+{
+ public class RegionTagger : ITagger
+ {
+ #region Private Fields
+
+ private int _oldLineNumber = -1;
+ private SnapshotSpan _oldSnapshotSpan;
+
+ private static readonly object _lock = new object();
+
+ #endregion
+
+ #region Initialization
+
+ public RegionTagger(ITextView view, ITextBuffer sourceBuffer, IClassificationTypeRegistryService classificationTypeRegistryService)
+ {
+ View = view;
+ SourceBuffer = sourceBuffer;
+ ClassificationTypeRegistryService = classificationTypeRegistryService;
+
+ view.Caret.PositionChanged += CaretPositionChanged;
+ view.LayoutChanged += ViewLayoutChanged;
+ }
+
+ #endregion
+
+ #region Private Methods
+
+ private void CaretPositionChanged(object sender, CaretPositionChangedEventArgs e)
+ {
+ UpdateAtCaretPosition(e.NewPosition);
+ }
+
+
+ private static bool IsRegionOrEndRegion(SnapshotSpan snapshotSpan)
+ {
+ return Regex.IsMatch(snapshotSpan.GetText().Trim().ToLower(), @"^#\W*(end\W*)*region");
+ }
+
+ private void UpdateAtCaretPosition(CaretPosition newPosition)
+ {
+ SnapshotPoint? point = newPosition.Point.GetPoint(SourceBuffer, newPosition.Affinity);
+
+ if (!point.HasValue)
+ return;
+
+ ITextSnapshotLine lineFromPosition = point.Value.Snapshot.GetLineFromPosition(point.Value.Position);
+
+ lock (_lock)
+ {
+ if (lineFromPosition.LineNumber != _oldLineNumber)
+ {
+ SnapshotSpan snapshotSpan = new SnapshotSpan(lineFromPosition.Snapshot, lineFromPosition.Start.Position, lineFromPosition.Length);
+ bool isRegionOrEndRegion = IsRegionOrEndRegion(snapshotSpan);
+
+ EventHandler tagsChanged = TagsChanged;
+ if (tagsChanged != null)
+ {
+ if (isRegionOrEndRegion)
+ {
+ tagsChanged(this, new SnapshotSpanEventArgs(snapshotSpan));
+ }
+ if (!_oldSnapshotSpan.IsEmpty)
+ {
+ tagsChanged(this, new SnapshotSpanEventArgs(_oldSnapshotSpan));
+ }
+ }
+
+ _oldSnapshotSpan = snapshotSpan;
+ _oldLineNumber = lineFromPosition.LineNumber;
+ }
+ }
+ }
+
+ private void ViewLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
+ {
+ if (e.NewViewState.EditSnapshot != e.OldViewState.EditSnapshot)
+ {
+ UpdateAtCaretPosition(View.Caret.Position);
+ }
+ }
+
+ #endregion
+
+ #region Private Properties
+
+ private IClassificationTypeRegistryService ClassificationTypeRegistryService
+ {
+ get;
+ }
+
+ private ITextBuffer SourceBuffer
+ {
+ get;
+ }
+
+ private ITextView View
+ {
+ get;
+ }
+
+ #endregion
+
+ #region Interface Implementation: ITagger
+
+ public event EventHandler TagsChanged;
+
+ public IEnumerable> GetTags(NormalizedSnapshotSpanCollection snapShotSpans)
+ {
+ foreach (SnapshotSpan snapshotSpan in snapShotSpans.Where(IsRegionOrEndRegion))
+ {
+ SnapshotPoint? point = View.Caret.Position.Point.GetPoint(SourceBuffer, View.Caret.Position.Affinity);
+
+ int pointPosition = point.HasValue ? snapshotSpan.Snapshot.GetLineNumberFromPosition(point.Value) : -1;
+ int lineNumberFromPosition = snapshotSpan.Snapshot.GetLineNumberFromPosition(snapshotSpan.Start);
+ int index = snapshotSpan.GetText().IndexOf(Constants.RegionIndicatorCharacter);
+
+ SnapshotSpan newSpan = new SnapshotSpan(snapshotSpan.Snapshot, (int)snapshotSpan.Start + index, snapshotSpan.Length - index);
+
+ string classificationTypeNames = lineNumberFromPosition != pointPosition
+ ? Constants.InactiveRegionClassificationTypeNames
+ : Constants.ActiveRegionClassificationTypeNames;
+
+ yield return new TagSpan(newSpan, new RegionTag(ClassificationTypeRegistryService.GetClassificationType(classificationTypeNames)));
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/Tags/RegionTaggerProvider.cs b/ExpandRegions/ExpandRegions/Tags/RegionTaggerProvider.cs
new file mode 100644
index 0000000..9c61a30
--- /dev/null
+++ b/ExpandRegions/ExpandRegions/Tags/RegionTaggerProvider.cs
@@ -0,0 +1,42 @@
+using System.ComponentModel.Composition;
+
+using Microsoft.VisualStudio.Text;
+using Microsoft.VisualStudio.Text.Classification;
+using Microsoft.VisualStudio.Text.Editor;
+using Microsoft.VisualStudio.Text.Tagging;
+using Microsoft.VisualStudio.Utilities;
+
+namespace ExpandRegions.Tags
+{
+ [Export(typeof(IViewTaggerProvider))]
+ [ContentType(Constants.CSharpContentType)]
+ [ContentType(Constants.BasicContentType)]
+ [TagType(typeof(RegionTag))]
+ public class RegionTaggerProvider : IViewTaggerProvider
+ {
+ #region Internal Properties
+
+ [Import]
+ internal IClassificationTypeRegistryService ClassificationTypeRegistryService
+ {
+ get;
+ set;
+ }
+
+ #endregion
+
+ #region Interface Implementation: IViewTaggerProvider
+
+ public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag
+ {
+ if (textView.TextBuffer != buffer)
+ {
+ return null;
+ }
+
+ return new RegionTagger(textView, buffer, ClassificationTypeRegistryService) as ITagger;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/ExpandRegions/ExpandRegions/TextViewCreationListener.cs b/ExpandRegions/ExpandRegions/TextViewCreationListener.cs
index 69f5366..6f91425 100644
--- a/ExpandRegions/ExpandRegions/TextViewCreationListener.cs
+++ b/ExpandRegions/ExpandRegions/TextViewCreationListener.cs
@@ -1,19 +1,18 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel.Composition;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+using System.ComponentModel.Composition;
+
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Outlining;
using Microsoft.VisualStudio.Utilities;
namespace ExpandRegions
{
- [TextViewRole("DOCUMENT"), ContentType("CSharp"), ContentType("Basic"), Export(typeof(IWpfTextViewCreationListener))]
+ [TextViewRole(Constants.TextViewRole)]
+ [ContentType(Constants.CSharpContentType)]
+ [ContentType(Constants.BasicContentType)]
+ [Export(typeof(IWpfTextViewCreationListener))]
public class TextViewCreationListener : IWpfTextViewCreationListener
{
-
+ #region Public Properties
[Import(typeof(IOutliningManagerService))]
public IOutliningManagerService OutliningManagerService
@@ -22,13 +21,20 @@ public IOutliningManagerService OutliningManagerService
set;
}
+ #endregion
+
+ #region Interface Implementation: IWpfTextViewCreationListener
+
public void TextViewCreated(IWpfTextView textView)
{
if (textView == null || OutliningManagerService == null)
{
return;
}
+
RegionTextViewHandler.CreateHandler(textView, OutliningManagerService);
}
+
+ #endregion
}
-}
+}
\ No newline at end of file