From 46a158712600c0ab754f8d6efeea7537c61ee66d Mon Sep 17 00:00:00 2001 From: WMJ Date: Sun, 4 Feb 2018 19:30:38 +0800 Subject: [PATCH] - Fixed issue #3 + Shows method parameter of current expression in quick info, optionally - Fixed an issue of code formatting in Super Quick Info which was causing VS to crash - Fixed an issue that empty Enum type could crash VS in Super Quick Info --- Codist/Classifiers/CodeTagger.cs | 52 +++++++++--- Codist/Config.cs | 57 +++++++++++-- Codist/Margins/CodeMargin.cs | 25 +++--- Codist/Margins/CodeMarginElement.cs | 106 ++++++++++++++++-------- Codist/Options/CSharpPage.Designer.cs | 55 +++++++----- Codist/Options/CSharpPage.cs | 10 +-- Codist/Options/ConfigPage.cs | 21 ++++- Codist/Options/MiscPage.cs | 2 +- Codist/Options/SyntaxStyleOptionPage.cs | 6 +- Codist/Options/UiLock.cs | 2 + Codist/Properties/AssemblyInfo.cs | 2 +- Codist/Views/CSharpTooltip.cs | 95 ++++++++++++++++----- Codist/Views/CodeViewDecorator.cs | 28 +++---- Codist/source.extension.vsixmanifest | 2 +- 14 files changed, 328 insertions(+), 135 deletions(-) diff --git a/Codist/Classifiers/CodeTagger.cs b/Codist/Classifiers/CodeTagger.cs index 87ed3d69..dd32f7a6 100644 --- a/Codist/Classifiers/CodeTagger.cs +++ b/Codist/Classifiers/CodeTagger.cs @@ -23,14 +23,25 @@ public class CodeTaggerProvider : IViewTaggerProvider [Import] internal IBufferTagAggregatorFactoryService Aggregator = null; + ITagAggregator _Tagger; + ITextView _TextView; + CodeTagger _CodeTagger; + public ITagger CreateTagger(ITextView textView, ITextBuffer buffer) where T : ITag { - var tagger = Aggregator.CreateTagAggregator(buffer); - textView.Closed += (s, args) => { tagger.Dispose(); }; + _Tagger = Aggregator.CreateTagAggregator(buffer); + _TextView = textView; + textView.Closed += TextViewClosed; var tags = textView.Properties.GetOrCreateSingletonProperty(() => new TaggerResult()); - var codeTagger = new CodeTagger(ClassificationRegistry, tagger, tags, CodeTagger.GetCodeType(textView.TextBuffer.ContentType)); - return codeTagger as ITagger; + _CodeTagger = new CodeTagger(ClassificationRegistry, _Tagger, tags, CodeTagger.GetCodeType(textView.TextBuffer.ContentType)); + return _CodeTagger as ITagger; } + + void TextViewClosed(object sender, EventArgs args) { + _Tagger.Dispose(); + _TextView.Closed -= TextViewClosed; + _CodeTagger.Dispose(); + } } enum CodeType @@ -38,7 +49,7 @@ enum CodeType None, CSharp, Markup } - sealed class CodeTagger : ITagger + sealed class CodeTagger : ITagger, IDisposable { static ClassificationTag[] __CommentClassifications; //static ClassificationTag _exitClassification; @@ -78,11 +89,7 @@ internal CodeTagger(IClassificationTypeRegistryService registry, ITagAggregator< _Aggregator = aggregator; _Tags = tags; _CodeType = codeType; - _Aggregator.BatchedTagsChanged += (s, args) => { - if (Margin != null) { - Margin.InvalidateVisual(); - } - }; + _Aggregator.BatchedTagsChanged += AggregateorBatchedTagsChanged; } internal FrameworkElement Margin { get; set; } @@ -290,6 +297,29 @@ static bool Matches(SnapshotSpan span, string text) { } return true; } - } + + void AggregateorBatchedTagsChanged(object sender, EventArgs args) { + if (Margin != null) { + Margin.InvalidateVisual(); + } + } + + #region IDisposable Support + private bool disposedValue = false; + + void Dispose(bool disposing) { + if (!disposedValue) { + if (disposing) { + _Aggregator.BatchedTagsChanged -= AggregateorBatchedTagsChanged; + } + disposedValue = true; + } + } + + public void Dispose() { + Dispose(true); + } + #endregion + } } diff --git a/Codist/Config.cs b/Codist/Config.cs index 4118bbfd..f359db54 100644 --- a/Codist/Config.cs +++ b/Codist/Config.cs @@ -7,12 +7,14 @@ using System.Text.RegularExpressions; using System.Reflection; using System.ComponentModel; +using System.Threading; namespace Codist { sealed class Config { - static DateTime LastSaved; + static DateTime _LastSaved, _LastLoaded; + static int _LoadingConfig; public static readonly string ConfigPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\" + Constants.NameOfMe + "\\Config.json"; public static Config Instance = InitConfig(); @@ -30,7 +32,7 @@ sealed class Config [DefaultValue(true)] public bool MarkLineNumbers { get; set; } = true; - [DefaultValue(true)] + [DefaultValue(QuickInfoOptions.Attributes | QuickInfoOptions.BaseType | QuickInfoOptions.Interfaces | QuickInfoOptions.NumericValues)] public QuickInfoOptions QuickInfoOptions { get; set; } = QuickInfoOptions.Attributes | QuickInfoOptions.BaseType | QuickInfoOptions.Interfaces | QuickInfoOptions.NumericValues; public double TopSpace { @@ -67,9 +69,23 @@ public static Config InitConfig() { } public static void LoadConfig(string configPath) { - Instance = InternalLoadConfig(configPath); - ConfigLoaded?.Invoke(Instance, EventArgs.Empty); - ConfigUpdated?.Invoke(Instance, EventArgs.Empty); + //HACK: prevent redundant load operations issued by configuration pages + if (_LastLoaded.AddSeconds(2) > DateTime.Now + || Interlocked.Exchange(ref _LoadingConfig, 1) != 0) { + return; + } + try { + Instance = InternalLoadConfig(configPath); + ConfigLoaded?.Invoke(Instance, EventArgs.Empty); + ConfigUpdated?.Invoke(Instance, EventArgs.Empty); + } + catch(Exception ex) { + Debug.WriteLine(ex.ToString()); + Instance = GetDefaultConfig(); + } + finally { + _LoadingConfig = 0; + } } static Config InternalLoadConfig(string configPath) { @@ -108,6 +124,8 @@ static Config InternalLoadConfig(string configPath) { } } MergeDefaultXmlCodeStyles(xcs); + _LastLoaded = DateTime.Now; + Debug.WriteLine("Config loaded"); return config; } @@ -124,7 +142,7 @@ public void Reset() { public void SaveConfig(string path) { //HACK: prevent redundant save operations issued by configuration pages - if (LastSaved.AddSeconds(2) > DateTime.Now) { + if (_LastSaved.AddSeconds(2) > DateTime.Now) { return; } path = path ?? ConfigPath; @@ -135,7 +153,8 @@ public void SaveConfig(string path) { } File.WriteAllText(path, JsonConvert.SerializeObject(this, Formatting.Indented, new Newtonsoft.Json.Converters.StringEnumConverter())); if (path == ConfigPath) { - LastSaved = DateTime.Now; + _LastSaved = _LastLoaded = DateTime.Now; + Debug.WriteLine("Config saved"); ConfigUpdated?.Invoke(this, EventArgs.Empty); } } @@ -148,6 +167,7 @@ internal void FireConfigChangedEvent() { ConfigUpdated?.Invoke(this, EventArgs.Empty); } static Config GetDefaultConfig() { + _LastLoaded = DateTime.Now; var c = new Config(); InitDefaultLabels(c.Labels); c.CommentStyles.AddRange(GetDefaultCommentStyles()); @@ -290,6 +310,18 @@ internal Color BackColor { internal StyleBase Clone() { return (StyleBase)MemberwiseClone(); } + internal void CopyTo(StyleBase style) { + style.Bold = Bold; + style.Italic = Italic; + style.OverLine = OverLine; + style.Underline = Underline; + style.StrikeThrough = StrikeThrough; + style.FontSize = FontSize; + style.BackgroundEffect = BackgroundEffect; + style.Font = Font; + style._foreColor = _foreColor; + style._backColor = _backColor; + } internal void Reset() { Bold = Italic = OverLine = Underline = StrikeThrough = null; FontSize = 0; @@ -432,6 +464,14 @@ public bool IgnoreCase { public CommentLabel Clone() { return (CommentLabel)MemberwiseClone(); } + public void CopyTo(CommentLabel label) { + label.AllowPunctuationDelimiter = AllowPunctuationDelimiter; + label.StyleApplication = StyleApplication; + label.StyleID = StyleID; + label._label = _label; + label._labelLength = _labelLength; + label._stringComparison = _stringComparison; + } } public enum BrushEffect @@ -455,6 +495,7 @@ public enum QuickInfoOptions Interfaces = 1 << 5, InterfacesInheritence = 1 << 6, NumericValues = 1 << 7, - String = 1 << 8 + String = 1 << 8, + Parameter = 1 << 9 } } diff --git a/Codist/Margins/CodeMargin.cs b/Codist/Margins/CodeMargin.cs index 81634078..36ab319f 100644 --- a/Codist/Margins/CodeMargin.cs +++ b/Codist/Margins/CodeMargin.cs @@ -17,8 +17,9 @@ class CodeMargin : Canvas, IWpfTextViewMargin /// public const string MarginName = nameof(CodeMargin); - readonly CodeMarginElement _commentMarginElement; - readonly ITagAggregator _commentTagAggregator; + readonly CodeMarginElement _CodeMarginElement; + readonly ITagAggregator _CodeTagAggregator; + readonly IWpfTextViewHost _TextView; bool isDisposed; /// @@ -26,14 +27,15 @@ class CodeMargin : Canvas, IWpfTextViewMargin /// /// The to attach the margin to. public CodeMargin(IWpfTextViewHost textView, IVerticalScrollBar scrollBar, CodeMarginFactory container) { - if (textView == null) - throw new ArgumentNullException("textView"); + _TextView = textView ?? throw new ArgumentNullException("textView"); + _CodeTagAggregator = container.ViewTagAggregatorFactoryService.CreateTagAggregator(textView.TextView); + _CodeMarginElement = new CodeMarginElement(textView.TextView, container, _CodeTagAggregator, scrollBar); + textView.Closed += TextView_Closed; + } - _commentTagAggregator = container.ViewTagAggregatorFactoryService.CreateTagAggregator(textView.TextView); - _commentMarginElement = new CodeMarginElement(textView.TextView, container, _commentTagAggregator, scrollBar); - textView.Closed += (sender, e) => { - _commentTagAggregator.Dispose(); - }; + private void TextView_Closed(object sender, EventArgs e) { + _CodeTagAggregator.Dispose(); + _CodeMarginElement.Dispose(); } #region IWpfTextViewMargin @@ -46,7 +48,7 @@ public FrameworkElement VisualElement { // the margin. get { ThrowIfDisposed(); - return _commentMarginElement; + return _CodeMarginElement; } } @@ -68,7 +70,7 @@ public double MarginSize { get { ThrowIfDisposed(); - return _commentMarginElement.ActualHeight; + return _CodeMarginElement.ActualHeight; } } @@ -104,6 +106,7 @@ public ITextViewMargin GetTextViewMargin(string marginName) { /// public void Dispose() { if (!isDisposed) { + _TextView.Closed -= TextView_Closed; GC.SuppressFinalize(this); isDisposed = true; } diff --git a/Codist/Margins/CodeMarginElement.cs b/Codist/Margins/CodeMarginElement.cs index 45cb08a9..b6ec1457 100644 --- a/Codist/Margins/CodeMarginElement.cs +++ b/Codist/Margins/CodeMarginElement.cs @@ -14,7 +14,7 @@ namespace Codist.Margins { - sealed class CodeMarginElement : FrameworkElement + sealed class CodeMarginElement : FrameworkElement, IDisposable { readonly IWpfTextView _TextView; readonly IEditorFormatMap _EditorFormatMap; @@ -74,46 +74,48 @@ public CodeMarginElement(IWpfTextView textView, CodeMarginFactory factory, ITagA _TextView.Options.OptionChanged += OnOptionChanged; //subscribe to change events and use them to update the markers - _TextView.TextBuffer.Changed += (s, args) => { - if (args.Changes.Count == 0) { - return; - } - Debug.WriteLine($"snapshot version: {args.AfterVersion.VersionNumber}"); - var tags = _Tags.Tags; - foreach (var change in args.Changes) { - Debug.WriteLine($"change:{change.OldPosition}->{change.NewPosition}"); - for (int i = tags.Count - 1; i >= 0; i--) { - var t = tags[i]; - if (!(t.Start > change.OldEnd || t.End < change.OldPosition)) { - // remove tags within the updated range - Debug.WriteLine($"Removed [{t.Start}..{t.End}) {t.Tag.ClassificationType}"); - tags.RemoveAt(i); - } - else if (t.Start > change.OldEnd) { - // shift positions of remained items - t.Start += change.Delta; - } - } - } - try { - _Tags.Version = args.AfterVersion.VersionNumber; - _Tags.LastParsed = args.Before.GetLineFromPosition(args.Changes[0].OldPosition).Start.Position; - } - catch (ArgumentOutOfRangeException) { - MessageBox.Show(String.Join("\n", - "Code margin exception:", args.Changes[0].OldPosition, - "Before length:", args.Before.Length, - "After length:", args.After.Length - )); - } - InvalidateVisual(); - }; + _TextView.TextBuffer.Changed += TextView_TextBufferChanged; IsVisibleChanged += OnViewOrMarginVisiblityChanged; _TextView.VisualElement.IsVisibleChanged += OnViewOrMarginVisiblityChanged; OnOptionChanged(null, null); } + private void TextView_TextBufferChanged(object sender, TextContentChangedEventArgs args) { + if (args.Changes.Count == 0) { + return; + } + Debug.WriteLine($"snapshot version: {args.AfterVersion.VersionNumber}"); + var tags = _Tags.Tags; + foreach (var change in args.Changes) { + Debug.WriteLine($"change:{change.OldPosition}->{change.NewPosition}"); + for (int i = tags.Count - 1; i >= 0; i--) { + var t = tags[i]; + if (!(t.Start > change.OldEnd || t.End < change.OldPosition)) { + // remove tags within the updated range + Debug.WriteLine($"Removed [{t.Start}..{t.End}) {t.Tag.ClassificationType}"); + tags.RemoveAt(i); + } + else if (t.Start > change.OldEnd) { + // shift positions of remained items + t.Start += change.Delta; + } + } + } + try { + _Tags.Version = args.AfterVersion.VersionNumber; + _Tags.LastParsed = args.Before.GetLineFromPosition(args.Changes[0].OldPosition).Start.Position; + } + catch (ArgumentOutOfRangeException) { + MessageBox.Show(String.Join("\n", + "Code margin exception:", args.Changes[0].OldPosition, + "Before length:", args.Before.Length, + "After length:", args.After.Length + )); + } + InvalidateVisual(); + } + private void OnViewOrMarginVisiblityChanged(object sender, DependencyPropertyChangedEventArgs e) { //There is no need to update event handlers if the visibility change is the result of an options change (since we will //update the event handlers after changing all the options). @@ -316,5 +318,39 @@ static void DrawMark(DrawingContext dc, Brush brush, double y, int style) { static void DrawKeywordMark(DrawingContext dc, Brush brush, double y) { dc.DrawEllipse(brush, null, new Point(HalfMarkSize, y - HalfMarkSize * 0.5), HalfMarkSize, HalfMarkSize); } + + #region IDisposable Support + private bool disposedValue = false; // 要检测冗余调用 + + void Dispose(bool disposing) { + if (!disposedValue) { + if (disposing) { + _TextView.Options.OptionChanged -= OnOptionChanged; + _TextView.TextBuffer.Changed -= TextView_TextBufferChanged; + IsVisibleChanged -= OnViewOrMarginVisiblityChanged; + _TextView.VisualElement.IsVisibleChanged -= OnViewOrMarginVisiblityChanged; + } + + // TODO: 释放未托管的资源(未托管的对象)并在以下内容中替代终结器。 + // TODO: 将大型字段设置为 null。 + + disposedValue = true; + } + } + + // TODO: 仅当以上 Dispose(bool disposing) 拥有用于释放未托管资源的代码时才替代终结器。 + // ~CodeMarginElement() { + // // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + // Dispose(false); + // } + + // 添加此代码以正确实现可处置模式。 + public void Dispose() { + // 请勿更改此代码。将清理代码放入以上 Dispose(bool disposing) 中。 + Dispose(true); + // TODO: 如果在以上内容中替代了终结器,则取消注释以下行。 + // GC.SuppressFinalize(this); + } + #endregion } } diff --git a/Codist/Options/CSharpPage.Designer.cs b/Codist/Options/CSharpPage.Designer.cs index 76a894f2..c9ec6441 100644 --- a/Codist/Options/CSharpPage.Designer.cs +++ b/Codist/Options/CSharpPage.Designer.cs @@ -32,6 +32,7 @@ private void InitializeComponent() { this._CodeAbstractionsBox = new System.Windows.Forms.CheckBox(); this._TypeDeclarationBox = new System.Windows.Forms.CheckBox(); this.groupBox3 = new System.Windows.Forms.GroupBox(); + this._CSharpDeclarationQuickInfoBox = new System.Windows.Forms.CheckBox(); this._CSharpStringQuickInfoBox = new System.Windows.Forms.CheckBox(); this._CSharpNumberQuickInfoBox = new System.Windows.Forms.CheckBox(); this._CSharpInterfaceInheritenceQuickInfoBox = new System.Windows.Forms.CheckBox(); @@ -40,7 +41,7 @@ private void InitializeComponent() { this._CSharpInterfacesQuickInfoBox = new System.Windows.Forms.CheckBox(); this._CSharpBaseTypeQuickInfoBox = new System.Windows.Forms.CheckBox(); this._CSharpAttributesQuickInfoBox = new System.Windows.Forms.CheckBox(); - this._CSharpDeclarationQuickInfoBox = new System.Windows.Forms.CheckBox(); + this._CSharpParameterQuickInfoBox = new System.Windows.Forms.CheckBox(); this.groupBox2.SuspendLayout(); this.groupBox3.SuspendLayout(); this.SuspendLayout(); @@ -52,10 +53,10 @@ private void InitializeComponent() { this.groupBox2.Controls.Add(this._SpecialCommentsBox); this.groupBox2.Controls.Add(this._CodeAbstractionsBox); this.groupBox2.Controls.Add(this._TypeDeclarationBox); - this.groupBox2.Location = new System.Drawing.Point(3, 3); + this.groupBox2.Location = new System.Drawing.Point(3, 162); this.groupBox2.Name = "groupBox2"; - this.groupBox2.Size = new System.Drawing.Size(200, 237); - this.groupBox2.TabIndex = 0; + this.groupBox2.Size = new System.Drawing.Size(495, 134); + this.groupBox2.TabIndex = 1; this.groupBox2.TabStop = false; this.groupBox2.Text = "Scrollbar markers"; // @@ -72,7 +73,7 @@ private void InitializeComponent() { // _LineNumbersBox // this._LineNumbersBox.AutoSize = true; - this._LineNumbersBox.Location = new System.Drawing.Point(9, 136); + this._LineNumbersBox.Location = new System.Drawing.Point(220, 24); this._LineNumbersBox.Name = "_LineNumbersBox"; this._LineNumbersBox.Size = new System.Drawing.Size(125, 19); this._LineNumbersBox.TabIndex = 4; @@ -111,6 +112,7 @@ private void InitializeComponent() { // // groupBox3 // + this.groupBox3.Controls.Add(this._CSharpParameterQuickInfoBox); this.groupBox3.Controls.Add(this._CSharpDeclarationQuickInfoBox); this.groupBox3.Controls.Add(this._CSharpStringQuickInfoBox); this.groupBox3.Controls.Add(this._CSharpNumberQuickInfoBox); @@ -120,17 +122,27 @@ private void InitializeComponent() { this.groupBox3.Controls.Add(this._CSharpInterfacesQuickInfoBox); this.groupBox3.Controls.Add(this._CSharpBaseTypeQuickInfoBox); this.groupBox3.Controls.Add(this._CSharpAttributesQuickInfoBox); - this.groupBox3.Location = new System.Drawing.Point(209, 3); + this.groupBox3.Location = new System.Drawing.Point(3, 3); this.groupBox3.Name = "groupBox3"; - this.groupBox3.Size = new System.Drawing.Size(200, 258); - this.groupBox3.TabIndex = 1; + this.groupBox3.Size = new System.Drawing.Size(495, 153); + this.groupBox3.TabIndex = 0; this.groupBox3.TabStop = false; this.groupBox3.Text = "Super Quick info"; // + // _CSharpDeclarationQuickInfoBox + // + this._CSharpDeclarationQuickInfoBox.AutoSize = true; + this._CSharpDeclarationQuickInfoBox.Location = new System.Drawing.Point(220, 99); + this._CSharpDeclarationQuickInfoBox.Name = "_CSharpDeclarationQuickInfoBox"; + this._CSharpDeclarationQuickInfoBox.Size = new System.Drawing.Size(197, 19); + this._CSharpDeclarationQuickInfoBox.TabIndex = 8; + this._CSharpDeclarationQuickInfoBox.Text = "Declaration modifiers"; + this._CSharpDeclarationQuickInfoBox.UseVisualStyleBackColor = true; + // // _CSharpStringQuickInfoBox // this._CSharpStringQuickInfoBox.AutoSize = true; - this._CSharpStringQuickInfoBox.Location = new System.Drawing.Point(9, 199); + this._CSharpStringQuickInfoBox.Location = new System.Drawing.Point(220, 74); this._CSharpStringQuickInfoBox.Name = "_CSharpStringQuickInfoBox"; this._CSharpStringQuickInfoBox.Size = new System.Drawing.Size(181, 19); this._CSharpStringQuickInfoBox.TabIndex = 7; @@ -140,7 +152,7 @@ private void InitializeComponent() { // _CSharpNumberQuickInfoBox // this._CSharpNumberQuickInfoBox.AutoSize = true; - this._CSharpNumberQuickInfoBox.Location = new System.Drawing.Point(9, 174); + this._CSharpNumberQuickInfoBox.Location = new System.Drawing.Point(220, 49); this._CSharpNumberQuickInfoBox.Name = "_CSharpNumberQuickInfoBox"; this._CSharpNumberQuickInfoBox.Size = new System.Drawing.Size(133, 19); this._CSharpNumberQuickInfoBox.TabIndex = 6; @@ -170,11 +182,11 @@ private void InitializeComponent() { // _CSharpExtensionMethodQuickInfoBox // this._CSharpExtensionMethodQuickInfoBox.AutoSize = true; - this._CSharpExtensionMethodQuickInfoBox.Location = new System.Drawing.Point(9, 149); + this._CSharpExtensionMethodQuickInfoBox.Location = new System.Drawing.Point(220, 24); this._CSharpExtensionMethodQuickInfoBox.Name = "_CSharpExtensionMethodQuickInfoBox"; - this._CSharpExtensionMethodQuickInfoBox.Size = new System.Drawing.Size(157, 19); + this._CSharpExtensionMethodQuickInfoBox.Size = new System.Drawing.Size(229, 19); this._CSharpExtensionMethodQuickInfoBox.TabIndex = 5; - this._CSharpExtensionMethodQuickInfoBox.Text = "Extension method"; + this._CSharpExtensionMethodQuickInfoBox.Text = "Extension method location"; this._CSharpExtensionMethodQuickInfoBox.UseVisualStyleBackColor = true; // // _CSharpInterfacesQuickInfoBox @@ -207,15 +219,15 @@ private void InitializeComponent() { this._CSharpAttributesQuickInfoBox.Text = "Attributes"; this._CSharpAttributesQuickInfoBox.UseVisualStyleBackColor = true; // - // _CSharpDeclarationQuickInfoBox + // _CSharpParameterQuickInfoBox // - this._CSharpDeclarationQuickInfoBox.AutoSize = true; - this._CSharpDeclarationQuickInfoBox.Location = new System.Drawing.Point(9, 224); - this._CSharpDeclarationQuickInfoBox.Name = "_CSharpDeclarationQuickInfoBox"; - this._CSharpDeclarationQuickInfoBox.Size = new System.Drawing.Size(189, 19); - this._CSharpDeclarationQuickInfoBox.TabIndex = 8; - this._CSharpDeclarationQuickInfoBox.Text = "Declaration keywords"; - this._CSharpDeclarationQuickInfoBox.UseVisualStyleBackColor = true; + this._CSharpParameterQuickInfoBox.AutoSize = true; + this._CSharpParameterQuickInfoBox.Location = new System.Drawing.Point(220, 124); + this._CSharpParameterQuickInfoBox.Name = "_CSharpParameterQuickInfoBox"; + this._CSharpParameterQuickInfoBox.Size = new System.Drawing.Size(101, 19); + this._CSharpParameterQuickInfoBox.TabIndex = 9; + this._CSharpParameterQuickInfoBox.Text = "Parameter"; + this._CSharpParameterQuickInfoBox.UseVisualStyleBackColor = true; // // CSharpPage // @@ -251,5 +263,6 @@ private void InitializeComponent() { private System.Windows.Forms.CheckBox _CSharpNumberQuickInfoBox; private System.Windows.Forms.CheckBox _CSharpStringQuickInfoBox; private System.Windows.Forms.CheckBox _CSharpDeclarationQuickInfoBox; + private System.Windows.Forms.CheckBox _CSharpParameterQuickInfoBox; } } diff --git a/Codist/Options/CSharpPage.cs b/Codist/Options/CSharpPage.cs index 15080e06..f990dab4 100644 --- a/Codist/Options/CSharpPage.cs +++ b/Codist/Options/CSharpPage.cs @@ -1,11 +1,5 @@ using System; -using System.Collections.Generic; using System.ComponentModel; -using System.Drawing; -using System.Data; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Forms; using AppHelpers; @@ -21,7 +15,7 @@ public CSharpPage() { InitializeComponent(); } internal CSharpPage(ConfigPage page) : this() { - + _UI.CommonAction += Config.Instance.FireConfigChangedEvent; } private void CSharpPage_Load(object sender, EventArgs e) { if (_Loaded) { @@ -43,6 +37,7 @@ private void CSharpPage_Load(object sender, EventArgs e) { _CSharpInterfaceInheritenceQuickInfoBox.CheckedChanged += _UI.HandleEvent(() => Config.Instance.Set(QuickInfoOptions.InterfacesInheritence, _CSharpInterfaceInheritenceQuickInfoBox.Checked)); _CSharpNumberQuickInfoBox.CheckedChanged += _UI.HandleEvent(() => Config.Instance.Set(QuickInfoOptions.NumericValues, _CSharpNumberQuickInfoBox.Checked)); _CSharpStringQuickInfoBox.CheckedChanged += _UI.HandleEvent(() => Config.Instance.Set(QuickInfoOptions.String, _CSharpStringQuickInfoBox.Checked)); + _CSharpParameterQuickInfoBox.CheckedChanged += _UI.HandleEvent(() => Config.Instance.Set(QuickInfoOptions.Parameter, _CSharpParameterQuickInfoBox.Checked)); Config.ConfigUpdated += (s, args) => LoadConfig(s as Config); _Loaded = true; @@ -64,6 +59,7 @@ void LoadConfig(Config config) { _CSharpExtensionMethodQuickInfoBox.Checked = config.QuickInfoOptions.MatchFlags(QuickInfoOptions.ExtensionMethod); _CSharpNumberQuickInfoBox.Checked = config.QuickInfoOptions.MatchFlags(QuickInfoOptions.NumericValues); _CSharpStringQuickInfoBox.Checked = config.QuickInfoOptions.MatchFlags(QuickInfoOptions.String); + _CSharpParameterQuickInfoBox.Checked = config.QuickInfoOptions.MatchFlags(QuickInfoOptions.Parameter); }); } } diff --git a/Codist/Options/ConfigPage.cs b/Codist/Options/ConfigPage.cs index 097bec10..5cfa176e 100644 --- a/Codist/Options/ConfigPage.cs +++ b/Codist/Options/ConfigPage.cs @@ -13,6 +13,14 @@ namespace Codist.Options [Browsable(false)] class ConfigPage : DialogPage { + int _version, _oldVersion; + + protected override void OnActivate(CancelEventArgs e) { + base.OnActivate(e); + _oldVersion = _version; + Config.ConfigUpdated += UpdateVersion; + } + internal FontInfo GetFontSettings(Guid category) { var storage = (IVsFontAndColorStorage)GetService(typeof(SVsFontAndColorStorage)); var pLOGFONT = new LOGFONTW[1]; @@ -63,7 +71,14 @@ internal static Brush GetPreviewBrush(BrushEffect effect, System.Windows.Media.C } } - + protected override void OnClosed(EventArgs e) { + base.OnClosed(e); + if (_version != _oldVersion) { + Config.LoadConfig(Config.ConfigPath); + _oldVersion = _version; + Config.ConfigUpdated -= UpdateVersion; + } + } protected override void OnApply(PageApplyEventArgs e) { base.OnApply(e); @@ -71,6 +86,10 @@ protected override void OnApply(PageApplyEventArgs e) { Config.Instance.SaveConfig(null); } } + + void UpdateVersion(object sender, EventArgs e) { + _version++; + } } [Browsable(false)] diff --git a/Codist/Options/MiscPage.cs b/Codist/Options/MiscPage.cs index 47a0e50d..6756d0ca 100644 --- a/Codist/Options/MiscPage.cs +++ b/Codist/Options/MiscPage.cs @@ -19,7 +19,7 @@ public MiscPage() { InitializeComponent(); } internal MiscPage(ConfigPage page) : this() { - + _UI.CommonAction += Config.Instance.FireConfigChangedEvent; } private void MiscPage_Load(object sender, EventArgs e) { if (_Loaded) { diff --git a/Codist/Options/SyntaxStyleOptionPage.cs b/Codist/Options/SyntaxStyleOptionPage.cs index 039e54d9..40404e92 100644 --- a/Codist/Options/SyntaxStyleOptionPage.cs +++ b/Codist/Options/SyntaxStyleOptionPage.cs @@ -70,13 +70,13 @@ protected override void OnLoad(EventArgs e) { _loaded = true; } - static void RenderPreview(Bitmap bmp, FontInfo fs, StyleBase style) { - var fontSize = (float)(fs.wPointSize + style.FontSize); + static void RenderPreview(Bitmap bmp, FontInfo fontInfo, StyleBase style) { + var fontSize = (float)(fontInfo.wPointSize + style.FontSize); if (fontSize < 2) { return; } using (var g = Graphics.FromImage(bmp)) - using (var f = new Font(String.IsNullOrEmpty(style.Font) ? fs.bstrFaceName : style.Font, fontSize, ConfigPage.GetFontStyle(style))) + using (var f = new Font(String.IsNullOrEmpty(style.Font) ? fontInfo.bstrFaceName : style.Font, fontSize, ConfigPage.GetFontStyle(style))) using (var b = style.ForeColor.A == 0 ? (Brush)Brushes.Black.Clone() : new SolidBrush(style.ForeColor.ToGdiColor())) { const string t = "Preview 01ioIOlLWM"; var m = g.MeasureString(t, f, bmp.Size); diff --git a/Codist/Options/UiLock.cs b/Codist/Options/UiLock.cs index c5712072..5e030610 100644 --- a/Codist/Options/UiLock.cs +++ b/Codist/Options/UiLock.cs @@ -11,6 +11,7 @@ sealed class UiLock int _locked; public bool IsLocked => _locked != 0; + public Action CommonAction { get; set; } public bool Lock() { return Interlocked.CompareExchange(ref _locked, 1, 0) == 0; } @@ -21,6 +22,7 @@ public EventHandler HandleEvent (Action action) { return (sender, args) => { if (Lock()) { try { + CommonAction(); action(); } finally { diff --git a/Codist/Properties/AssemblyInfo.cs b/Codist/Properties/AssemblyInfo.cs index aae5a2b8..0540bcab 100644 --- a/Codist/Properties/AssemblyInfo.cs +++ b/Codist/Properties/AssemblyInfo.cs @@ -30,4 +30,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("2.4.0.0")] -[assembly: AssemblyFileVersion("2.4.1.406")] +[assembly: AssemblyFileVersion("2.4.2.435")] diff --git a/Codist/Views/CSharpTooltip.cs b/Codist/Views/CSharpTooltip.cs index de02bc20..f73dc2b3 100644 --- a/Codist/Views/CSharpTooltip.cs +++ b/Codist/Views/CSharpTooltip.cs @@ -24,7 +24,7 @@ namespace Codist.Views { sealed class CSharpQuickInfoSource : IQuickInfoSource { - static Brush _InterfaceBrush, _ClassBrush, _StructBrush, _TextBrush, _NumberBrush, _EnumBrush, _KeywordBrush; + static Brush _InterfaceBrush, _ClassBrush, _StructBrush, _TextBrush, _NumberBrush, _EnumBrush, _KeywordBrush, _MethodBrush, _ParameterBrush; readonly IEditorFormatMapService _FormatMapService; IEditorFormatMap _FormatMap; @@ -66,11 +66,14 @@ public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiC //look for occurrences of our QuickInfo words in the span var navigator = _QuickInfoSourceProvider.NavigatorService.GetTextStructureNavigator(_TextBuffer); - var extent = navigator.GetExtentOfWord(subjectTriggerPoint.Value); - var node = unitCompilation.FindNode(new Microsoft.CodeAnalysis.Text.TextSpan(extent.Span.Start, extent.Span.Length), true); - if (node == null) { + var extent = navigator.GetSpanOfEnclosing(new SnapshotSpan(subjectTriggerPoint.Value, 0)); + var node = unitCompilation.FindNode(new Microsoft.CodeAnalysis.Text.TextSpan(extent.Span.Start, extent.Span.Length), false, true); + if (node == null || node.Span.Contains(subjectTriggerPoint.Value.Position) == false) { goto EXIT; } + if (Config.Instance.QuickInfoOptions.MatchFlags(QuickInfoOptions.Parameter)) { + ShowParameterInfo(qiContent, node); + } node = node.Kind() == SyntaxKind.Argument ? (node as ArgumentSyntax).Expression : node; var symbol = GetSymbol(node, semanticModel); if (symbol == null) { @@ -82,11 +85,8 @@ public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiC else if (nodeKind == SyntaxKind.SwitchStatement) { infoBox = new TextBlock { Text = (node as SwitchStatementSyntax).Sections.Count + " sections" }; } - else if (Config.Instance.QuickInfoOptions.MatchFlags(QuickInfoOptions.String)) { - var token = node.GetFirstToken(); - if (token.Kind() == SyntaxKind.StringLiteralToken) { - infoBox = ShowStringInfo(token.ValueText); - } + else if (nodeKind == SyntaxKind.StringLiteralExpression) { + infoBox = ShowStringInfo(node.ToString()); } if (infoBox != null) { qiContent.Add(infoBox); @@ -96,6 +96,9 @@ public void AugmentQuickInfoSession(IQuickInfoSession session, IList qiC goto EXIT; } + if (node is PredefinedTypeSyntax) { + goto EXIT; + } var formatMap = _FormatMapService.GetEditorFormatMap(session.TextView); if (_FormatMap != formatMap) { _FormatMap = formatMap; @@ -186,7 +189,7 @@ void IDisposable.Dispose() { } static Brush GetFormatBrush(string name, IEditorFormatMap formatMap) { - return formatMap.GetProperties(name)[EditorFormatDefinition.ForegroundBrushId] as Brush; + return formatMap.GetProperties(name)?[EditorFormatDefinition.ForegroundBrushId] as Brush; } static ISymbol GetSymbol(SyntaxNode node, SemanticModel semanticModel) { @@ -316,6 +319,32 @@ static StackPanel ShowNumericForms(object value, NumericForm form) { return null; } + void ShowParameterInfo(IList qiContent, SyntaxNode node) { + var argument = node; + int depth = 0; + do { + var n = argument as ArgumentSyntax; + if (n != null) { + var al = n.Parent as BaseArgumentListSyntax; + var ap = al.Arguments.IndexOf(n); + if (ap != -1) { + var symbol = _SemanticModel.GetSymbolInfo(al.Parent).Symbol; + if (symbol == null) { + qiContent.Add("Argument " + ap); + } + else { + qiContent.Add(ToUIText(symbol.ToMinimalDisplayParts(_SemanticModel, node.SpanStart), "Argument of ", false, ap)); + } + } + return; + } + else if (depth > 3) { + return; + } + ++depth; + } while ((argument = argument.Parent) != null); + } + void ShowPropertyDeclaration(IList qiContent, IPropertySymbol property, int position) { var info = new StackPanel().MakeHorizontal().AddText("Property declaration: ", true); if (property.IsAbstract) { @@ -382,10 +411,12 @@ static StackPanel ToUIText(string dec, byte[] bytes) { } static StackPanel ToUIText(ImmutableArray parts) { - return ToUIText(parts, null, false); + return ToUIText(parts, null, false, Int32.MinValue); } - static StackPanel ToUIText(ImmutableArray parts, string title, bool bold) { + return ToUIText(parts, title, bold, Int32.MinValue); + } + static StackPanel ToUIText(ImmutableArray parts, string title, bool bold, int argumentIndex) { var stack = new StackPanel { Orientation = Orientation.Horizontal }; if (title != null) { stack.AddText(title, bold); @@ -393,10 +424,27 @@ static StackPanel ToUIText(ImmutableArray parts, string title foreach (var part in parts) { switch (part.Kind) { case SymbolDisplayPartKind.ClassName: - stack.AddText(part.Symbol.Name, true, false, _ClassBrush); + stack.AddText(part.Symbol.Name, argumentIndex == Int32.MinValue, false, _ClassBrush); + break; + case SymbolDisplayPartKind.EnumName: + stack.AddText(part.Symbol.Name, argumentIndex == Int32.MinValue, false, _EnumBrush); break; case SymbolDisplayPartKind.InterfaceName: - stack.AddText(part.Symbol.Name, true, false, _InterfaceBrush); + stack.AddText(part.Symbol.Name, argumentIndex == Int32.MinValue, false, _InterfaceBrush); + break; + case SymbolDisplayPartKind.MethodName: + stack.AddText(part.Symbol.Name, argumentIndex != Int32.MinValue, false, _MethodBrush); + break; + case SymbolDisplayPartKind.ParameterName: + if ((part.Symbol as IParameterSymbol).Ordinal == argumentIndex) { + stack.AddText(part.Symbol.Name, true, true, _ParameterBrush); + } + else { + stack.AddText(part.Symbol.Name, false, false, _ParameterBrush); + } + break; + case SymbolDisplayPartKind.StructName: + stack.AddText(part.Symbol.Name, argumentIndex == Int32.MinValue, false, _StructBrush); break; case SymbolDisplayPartKind.StringLiteral: stack.AddText(part.ToString(), false, false, _TextBrush); @@ -420,6 +468,8 @@ static void UpdateSyntaxHighlights(IEditorFormatMap formatMap) { _NumberBrush = GetFormatBrush(Constants.CodeNumber, formatMap); _StructBrush = GetFormatBrush(Constants.CodeStructName, formatMap); _KeywordBrush = GetFormatBrush(Constants.CodeKeyword, formatMap); + _MethodBrush = GetFormatBrush(Constants.CSharpMethodName, formatMap); + _ParameterBrush = GetFormatBrush(Constants.CSharpParameterName, formatMap); } private void _ConfigUpdated(object sender, EventArgs e) { @@ -570,17 +620,22 @@ void TextBuffer_Changing(object sender, TextContentChangingEventArgs e) { void ToUIText(StackPanel attrStack, TypedConstant v, int position) { switch (v.Kind) { case TypedConstantKind.Primitive: - attrStack.AddText(v.ToCSharpString(), _NumberBrush); + if (v.Value is bool) { + attrStack.AddText((bool)v.Value ? "true" : "false", _KeywordBrush); + } + else { + attrStack.AddText(v.ToCSharpString(), _NumberBrush); + } break; case TypedConstantKind.Enum: var en = v.ToCSharpString(); if (en.IndexOf('|') != -1) { var items = v.Type.GetMembers().Where(i => { var field = i as IFieldSymbol; - if (field == null || field.HasConstantValue == false) { - return false; - } - return UnsafeArithmeticHelper.Equals(UnsafeArithmeticHelper.And(v.Value, field.ConstantValue), field.ConstantValue) && UnsafeArithmeticHelper.IsZero(field.ConstantValue) == false; + return field != null + && field.HasConstantValue != false + && UnsafeArithmeticHelper.Equals(UnsafeArithmeticHelper.And(v.Value, field.ConstantValue), field.ConstantValue) + && UnsafeArithmeticHelper.IsZero(field.ConstantValue) == false; }); var flags = items.ToArray(); for (int i = 0; i < flags.Length; i++) { @@ -595,7 +650,7 @@ void ToUIText(StackPanel attrStack, TypedConstant v, int position) { } break; case TypedConstantKind.Type: - attrStack.AddText("typeof("); + attrStack.AddText("typeof", _KeywordBrush).AddText("("); attrStack.Children.Add(ToUIText((v.Value as ITypeSymbol).ToMinimalDisplayParts(_SemanticModel, position))); attrStack.AddText(")"); break; diff --git a/Codist/Views/CodeViewDecorator.cs b/Codist/Views/CodeViewDecorator.cs index 7d1665f2..8d2d5290 100644 --- a/Codist/Views/CodeViewDecorator.cs +++ b/Codist/Views/CodeViewDecorator.cs @@ -20,6 +20,7 @@ sealed class CodeViewDecorator readonly IEditorFormatMap _FormatMap; Color _BackColor, _ForeColor; + TextFormattingRunProperties _EditorTextProperties; bool _IsDecorating; public CodeViewDecorator(ITextView view, IClassificationFormatMap map, IClassificationTypeRegistryService service, IEditorFormatMap formatMap) { @@ -68,14 +69,14 @@ static void InitStyleClassificationCache(IClassification } } - private void SettingsSaved(object sender, EventArgs eventArgs) { + void SettingsSaved(object sender, EventArgs eventArgs) { if (!_IsDecorating) { CacheStyles(_RegService); Decorate(); } } - private void Decorate() { + void Decorate() { try { _IsDecorating = true; var c = _FormatMap.GetProperties(Constants.EditorProperties.Text)?[EditorFormatDefinition.ForegroundColorId]; @@ -98,8 +99,9 @@ private void Decorate() { } } - private void DecorateClassificationTypes() { + void DecorateClassificationTypes() { _Map.BeginBatchUpdate(); + _EditorTextProperties = _Map.GetTextProperties(_RegService.GetClassificationType("text")); foreach (var item in _Map.CurrentPriorityOrder) { if (item == null) { continue; @@ -129,28 +131,27 @@ private void DecorateClassificationTypes() { _Map.EndBatchUpdate(); } - private double GetEditorTextSize() { - return _Map.GetTextProperties(_RegService.GetClassificationType("text")).FontRenderingEmSize; - } - - private TextFormattingRunProperties SetProperties(TextFormattingRunProperties properties, StyleBase styleOption) { + TextFormattingRunProperties SetProperties(TextFormattingRunProperties properties, StyleBase styleOption) { var settings = styleOption; - var fontSize = GetEditorTextSize() + settings.FontSize; + var fontSize = _EditorTextProperties.FontRenderingEmSize + settings.FontSize; if (fontSize < 2) { fontSize = 1; } if (string.IsNullOrWhiteSpace(settings.Font) == false) { properties = properties.SetTypeface(new Typeface(settings.Font)); } - if (Math.Abs(fontSize - properties.FontRenderingEmSize) > 0.0) { + if (settings.FontSize != 0) { properties = properties.SetFontRenderingEmSize(fontSize); } + if (settings.Bold.HasValue) { + properties = properties.SetBold(settings.Bold.Value); + } if (settings.Italic.HasValue) { properties = properties.SetItalic(settings.Italic.Value); } if (settings.ForeColor.A > 0) { - properties = properties.SetForegroundOpacity(settings.ForeColor.A / 255.0); - properties = properties.SetForeground(settings.ForeColor); + properties = properties.SetForegroundOpacity(settings.ForeColor.A / 255.0) + .SetForeground(settings.ForeColor); } if (settings.BackColor.A > 0) { properties = properties.SetBackgroundOpacity(settings.BackColor.A / 255.0); @@ -174,9 +175,6 @@ private TextFormattingRunProperties SetProperties(TextFormattingRunProperties pr break; } } - if (settings.Bold.HasValue) { - properties = properties.SetBold(settings.Bold.Value); - } if (settings.Underline.HasValue || settings.StrikeThrough.HasValue || settings.OverLine.HasValue) { var tdc = new TextDecorationCollection(); if (settings.Underline.GetValueOrDefault()) { diff --git a/Codist/source.extension.vsixmanifest b/Codist/source.extension.vsixmanifest index e42dadef..0857ab1c 100644 --- a/Codist/source.extension.vsixmanifest +++ b/Codist/source.extension.vsixmanifest @@ -1,7 +1,7 @@  - + Codist A plugin which enhances coding experience with advanced syntax highlighting and scrollbar marking.