diff --git a/src/VisualStudio/LanguageService/Commands/GotoDefinition.cs b/src/VisualStudio/LanguageService/Commands/GotoDefinition.cs index f9601af87a..fbdec2e884 100644 --- a/src/VisualStudio/LanguageService/Commands/GotoDefinition.cs +++ b/src/VisualStudio/LanguageService/Commands/GotoDefinition.cs @@ -54,11 +54,17 @@ internal static void GotoDefn(ITextView TextView) var result = TextView.GetSymbolUnderCursor(out var state,out _, out _); // ThreadHelper.ThrowIfNotOnUIThread(); - if (result.Count > 0) + if (result.Count == 1) { Goto(result[0], TextView, state); return; } + if (result.Count > 1) + { + var window = new GotoDefinitionResultsWindow(result, TextView, state); + window.Show(); + return; + } } catch (Exception ex) { @@ -148,7 +154,15 @@ private static XSourceEntity FindElementInFile(XFile file, XPETypeSymbol petype, { if (entity.Name == element.Name) { - return entity; + if (entity is IXMemberSymbol m1 && element is IXMemberSymbol m2) + { + if (m1.Prototype == m2.Prototype) + return entity; + } + else if (entity.FullName == element.FullName) + { + return entity; + } } } } diff --git a/src/VisualStudio/LanguageService/Completion/CompletionHelpers.cs b/src/VisualStudio/LanguageService/Completion/CompletionHelpers.cs index 550867eb02..6812dabc26 100644 --- a/src/VisualStudio/LanguageService/Completion/CompletionHelpers.cs +++ b/src/VisualStudio/LanguageService/Completion/CompletionHelpers.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Microsoft.VisualStudio.Imaging; using Microsoft.VisualStudio.Language.Intellisense; using Microsoft.VisualStudio.Text; using XSharpModel; @@ -19,14 +20,12 @@ namespace XSharp.LanguageService { internal class CompletionHelpers { - internal IGlyphService _glyphService = null; private XDialect _dialect; private XFile _file; private bool _settingIgnoreCase; - internal CompletionHelpers(XDialect dialect, IGlyphService glyphService, XFile file, bool ignoreCase) + internal CompletionHelpers(XDialect dialect, XFile file, bool ignoreCase) { _dialect = dialect; - _glyphService = glyphService; _file = file; _settingIgnoreCase = ignoreCase; } @@ -94,7 +93,7 @@ internal void AddPETypeNamesLike(XCompletionList compList, XSharpSearchLocation continue; var typeAnalysis = new XTypeAnalysis(type); - ImageSource icon = _glyphService.GetGlyph(type.getGlyphGroup(), type.getGlyphItem()); + ImageSource icon = type.Kind.GetImageMoniker(type.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(displayName, displayName, typeAnalysis.Prototype, icon, null, Kind.Class, ""))) break; } @@ -120,7 +119,7 @@ internal void AddSourceTypeNamesLike(XCompletionList compList, XSharpSearchLocat continue; var typeAnalysis = new XTypeAnalysis(type); - ImageSource icon = _glyphService.GetGlyph(type.getGlyphGroup(), type.getGlyphItem()); + ImageSource icon = type.Kind.GetImageMoniker(type.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(displayName, displayName, typeAnalysis.Prototype, icon, null, Kind.Class, ""))) break; } @@ -182,7 +181,7 @@ internal void AddXSharpKeywordsLike(XCompletionList compList, string startWith) { foreach (var kw in XSharpSyntax.GetKeywords().Where(ti => nameStartsWith(ti.Name, startWith))) { - ImageSource icon = _glyphService.GetGlyph(kw.getGlyphGroup(), kw.getGlyphItem()); + ImageSource icon = kw.Kind.GetImageMoniker(kw.Visibility).GetImageSource(); var item = new XSCompletion(kw.Name, kw.Name, kw.Prototype, icon, null, Kind.Keyword, ""); compList.Add(item); } @@ -192,7 +191,7 @@ internal void AddSnippets(XCompletionList compList, string startWith) var snippets = SnippetHelpers.FindSnippets(startWith); foreach (var snippet in snippets) { - ImageSource icon = _glyphService.GetGlyph(StandardGlyphGroup.GlyphCSharpExpansion, StandardGlyphItem.GlyphItemPublic); + ImageSource icon = KnownMonikers.Snippet.GetImageSource(); var item = new XSCompletion(snippet.title, "", snippet.description, icon, null, Kind.Snippet, snippet.shortcut); item.Properties.AddProperty(typeof(VsExpansion), snippet); compList.Add(item,false, true); @@ -210,7 +209,7 @@ internal void AddXSharpTypeNamesLike(XCompletionList compList, XSharpSearchLocat continue; // Then remove it - ImageSource icon = _glyphService.GetGlyph(typeInfo.getGlyphGroup(), typeInfo.getGlyphItem()); + ImageSource icon = typeInfo.Kind.GetImageMoniker(typeInfo.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(typeInfo.Name, typeInfo.Name, typeInfo.FullName, icon, null, typeInfo.Kind, ""))) break; } @@ -237,7 +236,7 @@ internal void AddXSharpKeywordTypeNamesLike(XCompletionList compList, string sta // Then remove it if (dotPos > 0) realTypeName = realTypeName.Substring(0, dotPos); - ImageSource icon = _glyphService.GetGlyph(typeInfo.getGlyphGroup(), typeInfo.getGlyphItem()); + ImageSource icon = typeInfo.Kind.GetImageMoniker(typeInfo.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(realTypeName, realTypeName, typeInfo.Prototype, icon, null, Kind.Class, ""))) break; } @@ -334,8 +333,8 @@ internal void AddNamespacesLike(XCompletionList compList, XSharpSearchLocation l int dotPos = startWith.LastIndexOf('.'); if (dotPos != -1) startLen = dotPos + 1; - ImageSource icon = _glyphService.GetGlyph(StandardGlyphGroup.GlyphGroupNamespace, StandardGlyphItem.GlyphItemPublic); - ImageSource iconClass = _glyphService.GetGlyph(StandardGlyphGroup.GlyphGroupClass, StandardGlyphItem.GlyphItemPublic); + ImageSource icon = KnownMonikers.Namespace.GetImageSource(); + ImageSource iconClass = KnownMonikers.ClassPublic.GetImageSource(); foreach (string nameSpace in namespaces.Where(ns => nameStartsWith(ns, startWith))) { string displayName = nameSpace; @@ -408,7 +407,7 @@ internal void AddGenericLocalsLike(XCompletionList compList, XSharpSearchLocatio // First, look after Parameters foreach (var paramVar in location.Member.Parameters.Where(p => nameStartsWith(p.Name, startWith))) { - ImageSource icon = _glyphService.GetGlyph(paramVar.getGlyphGroup(), paramVar.getGlyphItem()); + ImageSource icon = paramVar.Kind.GetImageMoniker(paramVar.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(paramVar.Name, paramVar.Name, paramVar.Prototype, icon, null, Kind.Parameter, ""))) break; } @@ -416,7 +415,7 @@ internal void AddGenericLocalsLike(XCompletionList compList, XSharpSearchLocatio // line numbers in the range are 1 based. currentLine = 0 based ! foreach (var localVar in location.Member.GetLocals(location).Where(l => nameStartsWith(l.Name, startWith) && l.Range.StartLine <= location.LineNumber)) { - ImageSource icon = _glyphService.GetGlyph(localVar.getGlyphGroup(), localVar.getGlyphItem()); + ImageSource icon = localVar.Kind.GetImageMoniker(localVar.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(localVar.Name, localVar.Name, localVar.Prototype, icon, null, Kind.Local, ""))) break; @@ -440,7 +439,7 @@ internal void AddGenericSelfMembersLike(XCompletionList compList, XSharpSearchLo return; foreach (var member in type.GetMembers(startWith)) { - ImageSource icon = _glyphService.GetGlyph(member.getGlyphGroup(), member.getGlyphItem()); + ImageSource icon = member.Kind.GetImageMoniker(member.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(member.Name, member.Name, member.Prototype, icon, null, Kind.Field, ""))) break; } @@ -465,7 +464,7 @@ internal void AddGenericInheritedMembersLike(XCompletionList compList, XSharpSea return; foreach (var member in baseType.GetMembers(startWith)) { - ImageSource icon = _glyphService.GetGlyph(member.getGlyphGroup(), member.getGlyphItem()); + ImageSource icon = member.Kind.GetImageMoniker(member.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(member.Name, member.Name, member.Prototype, icon, null, Kind.Field, ""))) break; } @@ -578,7 +577,7 @@ internal void FillEnumMembers(XSharpSearchLocation location, XCompletionList com continue; if (elt is XPESymbol peSym && peSym.IsSpecialName) continue; - ImageSource icon = _glyphService.GetGlyph(elt.getGlyphGroup(), elt.getGlyphItem()); + ImageSource icon = elt.Kind.GetImageMoniker(elt.Visibility).GetImageSource(); if (!compList.Add(new XSCompletion(elt.Name, elt.Name, elt.Prototype, icon, null, elt.Kind, elt.Value))) break; } @@ -638,7 +637,7 @@ internal void FillMembers(XSharpSearchLocation location, XCompletionList compLis if (!add) continue; // - ImageSource icon = _glyphService.GetGlyph(elt.getGlyphGroup(), elt.getGlyphItem()); + ImageSource icon = elt.Kind.GetImageMoniker(elt.Visibility).GetImageSource(); string toAdd = AddOpenParen(elt.Kind); if (!compList.Add(new XSCompletion(elt.Name, elt.Name + toAdd, elt.Prototype, icon, null, elt.Kind, elt.Value))) break; diff --git a/src/VisualStudio/LanguageService/Completion/XSharpCompletionSource.cs b/src/VisualStudio/LanguageService/Completion/XSharpCompletionSource.cs index 45567b7310..cc903309a4 100644 --- a/src/VisualStudio/LanguageService/Completion/XSharpCompletionSource.cs +++ b/src/VisualStudio/LanguageService/Completion/XSharpCompletionSource.cs @@ -42,7 +42,7 @@ public XSharpCompletionSource(XSharpCompletionSourceProvider provider, ITextBuff _file = file; var prj = _file.Project.ProjectNode; _dialect = _file.Project.Dialect; - helpers = new CompletionHelpers(_dialect, provider.GlyphService, file, !prj.ParseOptions.CaseSensitive); + helpers = new CompletionHelpers(_dialect, file, !prj.ParseOptions.CaseSensitive); this._tagAggregator = aggregator.CreateTagAggregator(_buffer); } diff --git a/src/VisualStudio/LanguageService/Completion/XSharpCompletionSourceProvider.cs b/src/VisualStudio/LanguageService/Completion/XSharpCompletionSourceProvider.cs index 5e297fe8b9..5d7ecdeee8 100644 --- a/src/VisualStudio/LanguageService/Completion/XSharpCompletionSourceProvider.cs +++ b/src/VisualStudio/LanguageService/Completion/XSharpCompletionSourceProvider.cs @@ -12,7 +12,6 @@ using Microsoft.VisualStudio.Utilities; using XSharpModel; using Microsoft.VisualStudio.Shell; -using System.Windows.Media; using LanguageService.SyntaxTree; using LanguageService.CodeAnalysis.XSharp.SyntaxParser; using Microsoft.VisualStudio; @@ -29,9 +28,6 @@ class XSharpCompletionSourceProvider : ICompletionSourceProvider [Import] internal SVsServiceProvider ServiceProvider = null; - [Import] - internal IGlyphService GlyphService = null; - [Import] IBufferTagAggregatorFactoryService aggregator = null; diff --git a/src/VisualStudio/LanguageService/DocumentOutline/DocumentOutlineControl.cs b/src/VisualStudio/LanguageService/Controls/DocumentOutlineControl.cs similarity index 75% rename from src/VisualStudio/LanguageService/DocumentOutline/DocumentOutlineControl.cs rename to src/VisualStudio/LanguageService/Controls/DocumentOutlineControl.cs index 581429b738..54713d84b0 100644 --- a/src/VisualStudio/LanguageService/DocumentOutline/DocumentOutlineControl.cs +++ b/src/VisualStudio/LanguageService/Controls/DocumentOutlineControl.cs @@ -3,17 +3,12 @@ // See License.txt in the project root for license information. // using Community.VisualStudio.Toolkit; - +using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Shell; - using System; using System.Collections.Generic; -using System.Data.Common; -using System.IO; using System.Windows; using System.Windows.Controls; -using System.Windows.Media; -using System.Windows.Media.Imaging; using Microsoft.VisualStudio.TextManager.Interop; using XSharpModel; @@ -33,33 +28,6 @@ sealed partial class DocumentOutlineControl : UserControl private bool _navigating; // reentrancy guard private bool _sortByName; // false = sort by document order (default) - // ----------------------------------------------------------------------- - // Image source cache: maps glyph index -> ImageSource - // ----------------------------------------------------------------------- - private static readonly Dictionary _glyphCache = new Dictionary(); - private static System.Windows.Forms.ImageList _imageList; - - static DocumentOutlineControl() - { - _imageList = new System.Windows.Forms.ImageList - { - ImageSize = new System.Drawing.Size(16, 16), - TransparentColor = System.Drawing.Color.FromArgb(255, 0, 255) - }; - try - { - Stream stream = typeof(Microsoft.VisualStudio.Package.LanguageService) - .Assembly - .GetManifestResourceStream("Resources.completionset.bmp"); - if (stream != null) - _imageList.Images.AddStrip(new System.Drawing.Bitmap(stream)); - } - catch (Exception) - { - // If images cannot be loaded the tree will still work without icons. - } - } - // ----------------------------------------------------------------------- // Construction // ----------------------------------------------------------------------- @@ -155,7 +123,7 @@ private OutlineTreeNode CreateNode(XSourceEntity entity) string label = entity.ComboPrototype; if (string.IsNullOrEmpty(label)) label = entity.Name; - return new OutlineTreeNode(entity, label, GetGlyphImage(entity.Glyph)); + return new OutlineTreeNode(entity, label, entity.Kind.GetImageMoniker(entity.Visibility)); } private void AddMemberNodes(OutlineTreeNode parentNode, XSourceTypeSymbol type) @@ -209,48 +177,6 @@ private static void FindBestNode(OutlineTreeNode node, int line, ref OutlineTree FindBestNode(child, line, ref best, ref bestLength); } - // ----------------------------------------------------------------------- - // Glyph -> ImageSource conversion - // ----------------------------------------------------------------------- - private static ImageSource GetGlyphImage(int glyphIndex) - { - if (_imageList == null || glyphIndex < 0 || glyphIndex >= _imageList.Images.Count) - return null; - - if (_glyphCache.TryGetValue(glyphIndex, out var cached)) - return cached; - - var bmp = _imageList.Images[glyphIndex] as System.Drawing.Bitmap; - if (bmp == null) - return null; - - ImageSource source; - try - { - var handle = bmp.GetHbitmap(); - try - { - source = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap( - handle, - IntPtr.Zero, - Int32Rect.Empty, - BitmapSizeOptions.FromEmptyOptions()); - source.Freeze(); - } - finally - { - NativeMethods.DeleteObject(handle); - } - } - catch (Exception) - { - return null; - } - - _glyphCache[glyphIndex] = source; - return source; - } - // ----------------------------------------------------------------------- // Event handlers // ----------------------------------------------------------------------- @@ -376,22 +302,19 @@ internal sealed class OutlineTreeNode : TreeViewItem { public XSourceEntity Entity { get; } - public OutlineTreeNode(XSourceEntity entity, string label, ImageSource icon) + public OutlineTreeNode(XSourceEntity entity, string label, ImageMoniker moniker) { Entity = entity; var panel = new StackPanel { Orientation = Orientation.Horizontal }; - if (icon != null) + panel.Children.Add(new CrispImage { - panel.Children.Add(new System.Windows.Controls.Image - { - Source = icon, - Width = 16, - Height = 16, - Margin = new Thickness(0, 0, 4, 0), - VerticalAlignment = VerticalAlignment.Center - }); - } + Moniker = moniker, + Width = 16, + Height = 16, + Margin = new Thickness(0, 0, 4, 0), + VerticalAlignment = VerticalAlignment.Center + }); panel.Children.Add(new TextBlock { Text = label, @@ -401,15 +324,5 @@ public OutlineTreeNode(XSourceEntity entity, string label, ImageSource icon) Header = panel; } } - - // --------------------------------------------------------------------------- - // P/Invoke helper for bitmap conversion - // --------------------------------------------------------------------------- - internal static class NativeMethods - { - [System.Runtime.InteropServices.DllImport("gdi32.dll")] - [return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)] - internal static extern bool DeleteObject(IntPtr hObject); - } } diff --git a/src/VisualStudio/LanguageService/DocumentOutline/DocumentOutlineControl.xaml b/src/VisualStudio/LanguageService/Controls/DocumentOutlineControl.xaml similarity index 100% rename from src/VisualStudio/LanguageService/DocumentOutline/DocumentOutlineControl.xaml rename to src/VisualStudio/LanguageService/Controls/DocumentOutlineControl.xaml diff --git a/src/VisualStudio/LanguageService/Controls/GotoDefinitionResultsWindow.xaml b/src/VisualStudio/LanguageService/Controls/GotoDefinitionResultsWindow.xaml new file mode 100644 index 0000000000..36b253f5d2 --- /dev/null +++ b/src/VisualStudio/LanguageService/Controls/GotoDefinitionResultsWindow.xaml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/VisualStudio/LanguageService/Controls/GotoDefinitionResultsWindow.xaml.cs b/src/VisualStudio/LanguageService/Controls/GotoDefinitionResultsWindow.xaml.cs new file mode 100644 index 0000000000..3ab01f6156 --- /dev/null +++ b/src/VisualStudio/LanguageService/Controls/GotoDefinitionResultsWindow.xaml.cs @@ -0,0 +1,120 @@ +// Copyright (c) XSharp B.V. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. +// See License.txt in the project root for license information. +// +using Community.VisualStudio.Toolkit; + +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Text.Editor; +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Input; +using System.Windows.Interop; +using XSharpModel; + +namespace XSharp.LanguageService +{ + /// + /// Floating tool window shown when Goto Definition finds multiple locations. + /// Double-clicking an item (or pressing Enter) navigates to that location and closes the window. + /// + partial class GotoDefinitionResultsWindow : Window + { + private readonly ITextView _textView; + private readonly CompletionState _state; + + internal GotoDefinitionResultsWindow(IList results, ITextView textView, CompletionState state) + { + InitializeComponent(); + _textView = textView; + _state = state; + + var items = new List(); + foreach (var symbol in results) + { + items.Add(new GotoDefinitionResultItem(symbol)); + } + _listView.ItemsSource = items; + if (items.Count > 0) + _listView.SelectedIndex = 0; + + // Set the VS main window as the owner so the popup stays on top of the IDE + SetVsOwner(); + } + + private void SetVsOwner() + { + try + { + ThreadHelper.JoinableTaskFactory.Run(async () => + { + await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); + var vsUIShell = await VS.Services.GetUIShellAsync(); + if (vsUIShell != null) + { + vsUIShell.GetDialogOwnerHwnd(out IntPtr ownerHwnd); + if (ownerHwnd != IntPtr.Zero) + { + new WindowInteropHelper(this).Owner = ownerHwnd; + } + } + }); + } + catch (Exception) + { + // Fallback: no owner; window will still work + } + } + + private void NavigateToSelected() + { + if (_listView.SelectedItem is GotoDefinitionResultItem item) + { + Close(); + XSharpGotoDefinition.Goto(item.Symbol, _textView, _state); + } + } + + private void OnItemDoubleClick(object sender, MouseButtonEventArgs e) + { + if (_listView.SelectedItem != null) + NavigateToSelected(); + } + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + if (e.Key == Key.Enter) + { + NavigateToSelected(); + e.Handled = true; + } + else if (e.Key == Key.Escape) + { + Close(); + e.Handled = true; + } + base.OnPreviewKeyDown(e); + } + } + + /// + /// View-model item for a single Goto Definition result. + /// + internal sealed class GotoDefinitionResultItem + { + internal IXSymbol Symbol { get; } + internal string DisplayName { get; } + internal string Location { get; } + + internal GotoDefinitionResultItem(IXSymbol symbol) + { + Symbol = symbol; + DisplayName = symbol.Description; + if (string.IsNullOrEmpty(DisplayName)) + DisplayName = symbol.FullName; + Location = symbol.Location; + } + public override string ToString() => DisplayName + " (" + Location + ")"; + } +} diff --git a/src/VisualStudio/LanguageService/Controls/KindExtensions.cs b/src/VisualStudio/LanguageService/Controls/KindExtensions.cs new file mode 100644 index 0000000000..ec714ccd71 --- /dev/null +++ b/src/VisualStudio/LanguageService/Controls/KindExtensions.cs @@ -0,0 +1,193 @@ +// Copyright (c) XSharp B.V. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. +// See License.txt in the project root for license information. +// +using Microsoft.VisualStudio.Imaging; +using Microsoft.VisualStudio.Imaging.Interop; +using Microsoft.VisualStudio.Shell; +using Microsoft.VisualStudio.Shell.Interop; +using System.Runtime.InteropServices; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using XSharpModel; + +namespace XSharp.LanguageService +{ + /// + /// Extension methods on that map an entity kind and visibility + /// to the appropriate from the VS catalog. + /// + internal static class KindExtensions + { + /// + /// Returns the from that best + /// represents the given and . + /// + internal static ImageMoniker GetImageMoniker(this Kind kind, Modifiers visibility) + { + switch (kind) + { + case Kind.Class: + return VisibilityMoniker(visibility, + KnownMonikers.ClassPublic, KnownMonikers.ClassProtected, + KnownMonikers.ClassPrivate, KnownMonikers.ClassInternal); + + case Kind.Structure: + case Kind.VOStruct: + return VisibilityMoniker(visibility, + KnownMonikers.ValueTypePublic, KnownMonikers.ValueTypeProtected, + KnownMonikers.ValueTypePrivate, KnownMonikers.ValueTypeInternal); + + case Kind.Interface: + return VisibilityMoniker(visibility, + KnownMonikers.InterfacePublic, KnownMonikers.InterfaceProtected, + KnownMonikers.InterfacePrivate, KnownMonikers.InterfaceInternal); + + case Kind.Delegate: + return VisibilityMoniker(visibility, + KnownMonikers.DelegatePublic, KnownMonikers.DelegateProtected, + KnownMonikers.DelegatePrivate, KnownMonikers.DelegateInternal); + + case Kind.Enum: + return VisibilityMoniker(visibility, + KnownMonikers.EnumerationPublic, KnownMonikers.EnumerationProtected, + KnownMonikers.EnumerationPrivate, KnownMonikers.EnumerationInternal); + + case Kind.EnumMember: + return KnownMonikers.EnumerationItemPublic; + + case Kind.Constructor: + case Kind.Destructor: + case Kind.Method: + return VisibilityMoniker(visibility, + KnownMonikers.MethodPublic, KnownMonikers.MethodProtected, + KnownMonikers.MethodPrivate, KnownMonikers.MethodInternal); + + case Kind.Function: + case Kind.Procedure: + case Kind.LocalFunc: + case Kind.LocalProc: + // Global/module-level routines have no class visibility + return KnownMonikers.MethodPublic; + + case Kind.Access: + case Kind.Assign: + case Kind.Property: + return VisibilityMoniker(visibility, + KnownMonikers.PropertyPublic, KnownMonikers.PropertyProtected, + KnownMonikers.PropertyPrivate, KnownMonikers.PropertyInternal); + + case Kind.Event: + return VisibilityMoniker(visibility, + KnownMonikers.EventPublic, KnownMonikers.EventProtected, + KnownMonikers.EventPrivate, KnownMonikers.EventInternal); + + case Kind.Field: + case Kind.VOGlobal: + return VisibilityMoniker(visibility, + KnownMonikers.FieldPublic, KnownMonikers.FieldProtected, + KnownMonikers.FieldPrivate, KnownMonikers.FieldInternal); + + case Kind.Operator: + return KnownMonikers.Operator; + + case Kind.Namespace: + case Kind.Using: + return KnownMonikers.Namespace; + + case Kind.Union: + return KnownMonikers.Union; + + case Kind.VODefine: + case Kind.Define: + case Kind.Undefine: + return VisibilityMoniker(visibility, + KnownMonikers.ConstantPublic, KnownMonikers.ConstantProtected, + KnownMonikers.ConstantPrivate, KnownMonikers.ConstantInternal); + + case Kind.Command: + case Kind.XCommand: + case Kind.YCommand: + case Kind.Translate: + case Kind.XTranslate: + case Kind.YTranslate: + return KnownMonikers.MacroPublic; + + case Kind.Include: + return KnownMonikers.Library; + + case Kind.Keyword: + return KnownMonikers.IntellisenseKeyword; + + case Kind.Attribute: + return KnownMonikers.Attribute; + + case Kind.TypeParameter: + return KnownMonikers.Type; + + case Kind.Local: + case Kind.Parameter: + case Kind.MemVar: + case Kind.DbField: + case Kind.Undeclared: + return KnownMonikers.LocalVariable; + + default: + return KnownMonikers.Item; + } + } + + /// + /// Picks one of four visibility-specific monikers based on . + /// maps to the + /// because that is the closest visual equivalent available in the catalog. + /// Any other value (including and ) + /// returns . + /// + private static ImageMoniker VisibilityMoniker(Modifiers visibility, + ImageMoniker publicMoniker, ImageMoniker protectedMoniker, + ImageMoniker privateMoniker, ImageMoniker internalMoniker) + { + switch (visibility) + { + case Modifiers.Protected: + case Modifiers.ProtectedInternal: + return protectedMoniker; + case Modifiers.Private: + return privateMoniker; + case Modifiers.Internal: + return internalMoniker; + default: + return publicMoniker; + } + } + + /// + /// Converts an to a WPF at 16×16 logical pixels + /// using the VS image service. Returns null when the image service is unavailable. + /// + internal static ImageSource GetImageSource(this ImageMoniker moniker) + { + var imageService = Package.GetGlobalService(typeof(SVsImageService)) as IVsImageService2; + if (imageService == null) + return null; + + var attributes = new ImageAttributes + { + StructSize = Marshal.SizeOf(typeof(ImageAttributes)), + ImageType = (uint)_UIImageType.IT_Bitmap, + Format = (uint)_UIDataFormat.DF_WPF, + LogicalWidth = 16, + LogicalHeight = 16, + Flags = (uint)_ImageAttributesFlags.IAF_RequiredFlags, + }; + + IVsUIObject uiObject = imageService.GetImage(moniker, attributes); + if (uiObject == null) + return null; + + uiObject.get_Data(out object data); + return data as BitmapSource; + } + } +} diff --git a/src/VisualStudio/LanguageService/Generic/DropDownClient.cs b/src/VisualStudio/LanguageService/Generic/DropDownClient.cs index bdd856e6fc..5eba739fa8 100644 --- a/src/VisualStudio/LanguageService/Generic/DropDownClient.cs +++ b/src/VisualStudio/LanguageService/Generic/DropDownClient.cs @@ -1,18 +1,18 @@ using Microsoft.VisualStudio; +using Microsoft.VisualStudio.Imaging; +using Microsoft.VisualStudio.Imaging.Interop; using Microsoft.VisualStudio.Shell; using Microsoft.VisualStudio.Text.Editor; using Microsoft.VisualStudio.TextManager.Interop; using System; using System.Collections.Generic; using System.Diagnostics; -using System.Drawing; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Forms; using XSharpModel; using File = System.IO.File; -using MVP = Microsoft.VisualStudio.Package; using Task = System.Threading.Tasks.Task; using XSharp.Settings; using XSharp.Support; @@ -46,13 +46,12 @@ internal bool Changed } - public class XSharpDropDownClient : IVsDropdownBarClient + public class XSharpDropDownClient : IVsDropdownBarClient, IVsDropdownBarClient4 { const int PROJECTINDEX = 0; const int TYPEINDEX = 1; const int MEMBERINDEX = 2; - static readonly ImageList _imageList = new ImageList(); private IVsDropdownBar _dropDownBar; readonly Dictionary _textViews; ITextView _activeView = null; @@ -74,7 +73,6 @@ public class XSharpDropDownClient : IVsDropdownBarClient private DropdownSettings _settings; private List _relatedFiles; private DateTime _lastFileChanged = DateTime.MinValue; - private static readonly int projectIcon = -1; private XDocument _document; XProject ActiveProject { @@ -88,20 +86,6 @@ XProject ActiveProject } } - static XSharpDropDownClient() - { - // Load images from Microsoft and Our project system (linked resource file) - Stream stream = typeof(MVP.LanguageService).Assembly.GetManifestResourceStream("Resources.completionset.bmp"); - _imageList.ImageSize = new Size(16, 16); - _imageList.TransparentColor = Color.FromArgb(255, 0, 255); - _imageList.Images.AddStrip(new Bitmap(stream)); - // the project Icon is the first in the ImageList from the project package - projectIcon = _imageList.Images.Count; - stream = typeof(XSharpDropDownClient).Assembly.GetManifestResourceStream("XSharp.LanguageService.Resources.XSharpProjectImageList.bmp"); - _imageList.Images.AddStrip(new Bitmap(stream)); - } - - public XSharpDropDownClient(IVsDropdownBarManager manager, XFile file) { _manager = manager; @@ -525,7 +509,7 @@ private void loadTypeCombos(int nLine) { name = "?"; } - elt = new XDropDownMember(name, sp, eltType.Glyph, ft, eltType); + elt = new XDropDownMember(name, sp, eltType.Kind.GetImageMoniker(eltType.Visibility), ft, eltType); nSelect = _types.Count; _types.Add(elt); if (eltType.Range.StartLine <= nLine && eltType.Range.EndLine >= nLine) @@ -602,21 +586,21 @@ private void loadMemberCombos(int selectedType) { if (currentType.Kind != Kind.Delegate) { - elt = new XDropDownMember("(" + currentType.Name + ")", spM, currentType.Glyph, ft, currentType); + elt = new XDropDownMember("(" + currentType.Name + ")", spM, currentType.Kind.GetImageMoniker(currentType.Visibility), ft, currentType); _members.Add(elt); _addToDict(currentType); } } else { - elt = new XDropDownMember(currentType.Name, spM, currentType.Glyph, ft, currentType); + elt = new XDropDownMember(currentType.Name, spM, currentType.Kind.GetImageMoniker(currentType.Visibility), ft, currentType); _members.Add(elt); _addToDict(currentType); } } else if (!_settings.IncludeFields) { - elt = new XDropDownMember(globalType.Name, spM, globalType.Glyph, ft, globalType); + elt = new XDropDownMember(globalType.Name, spM, globalType.Kind.GetImageMoniker(globalType.Visibility), ft, globalType); _members.Add(elt); _addToDict(globalType); } @@ -677,7 +661,7 @@ private void loadMemberCombos(int selectedType) ft = DROPDOWNFONTATTR.FONTATTR_GRAY; prototype += " (" + System.IO.Path.GetFileName(member.File.SourcePath) + ")"; } - elt = new XDropDownMember(prototype, spM, member.Glyph, ft, member); + elt = new XDropDownMember(prototype, spM, member.Kind.GetImageMoniker(member.Visibility), ft, member); var nSelect = _members.Count; _members.Add(elt); _addToDict(member); @@ -774,7 +758,7 @@ public async System.Threading.Tasks.Task RefreshDropDownAsync(bool needsUI) public int GetComboAttributes(int combo, out uint entries, out uint entryType, out IntPtr imageList) { entries = 0; - imageList = _imageList.Handle; + imageList = IntPtr.Zero; // no HIMAGELIST needed; IVsDropdownBarClient4.GetEntryImage returns monikers entryType = (uint)(DROPDOWNENTRYTYPE.ENTRY_ATTR | DROPDOWNENTRYTYPE.ENTRY_IMAGE | DROPDOWNENTRYTYPE.ENTRY_TEXT); switch (combo) { @@ -827,30 +811,27 @@ public int GetEntryAttributes(int combo, int index, out uint attr) public int GetEntryImage(int combo, int index, out int imageIndex) { + // IVsDropdownBarClient4.GetEntryImage is called instead when VS supports it + imageIndex = -1; + return VSConstants.E_NOTIMPL; + } - imageIndex = 0; - if (index < 0) - { - return VSConstants.E_FAIL; - } + ImageMoniker IVsDropdownBarClient4.GetEntryImage(int combo, int index) + { switch (combo) { - case TYPEINDEX: // types - if (index < _types.Count) - imageIndex = _types[index].Glyph; - break; - case MEMBERINDEX: // members - if (index < _members.Count) - imageIndex = _members[index].Glyph; + case TYPEINDEX: + if (index >= 0 && index < _types.Count) + return _types[index].Moniker; break; - case PROJECTINDEX: // projects - imageIndex = projectIcon; + case MEMBERINDEX: + if (index >= 0 && index < _members.Count) + return _members[index].Moniker; break; - default: - throw new ArgumentOutOfRangeException(); - + case PROJECTINDEX: + return KnownMonikers.Application; } - return 0; + return default; } public int GetEntryText(int combo, int index, out string text) @@ -984,14 +965,14 @@ internal class XDropDownMember { public TextSpan Span { get; set; } public string Label { get; set; } - public int Glyph { get; set; } + public ImageMoniker Moniker { get; set; } public DROPDOWNFONTATTR FontAttr { get; set; } public XSourceEntity Entity { get; set; } - internal XDropDownMember(string label, TextSpan span, int glyph, DROPDOWNFONTATTR fontAttribute, XSourceEntity element) + internal XDropDownMember(string label, TextSpan span, ImageMoniker moniker, DROPDOWNFONTATTR fontAttribute, XSourceEntity element) { Label = label; Span = span; - Glyph = glyph; + Moniker = moniker; FontAttr = fontAttribute; Entity = element; } diff --git a/src/VisualStudio/LanguageService/LanguageService.csproj b/src/VisualStudio/LanguageService/LanguageService.csproj index b79a58ae01..410dc2e170 100644 --- a/src/VisualStudio/LanguageService/LanguageService.csproj +++ b/src/VisualStudio/LanguageService/LanguageService.csproj @@ -61,6 +61,10 @@ + + GotoDefinitionResultsWindow.xaml + Code + @@ -103,10 +107,7 @@ - Form - - - CtorParamsDlg.cs + CtorParamsDlg.xaml @@ -131,34 +132,22 @@ - UserControl - - - CompletionOptionsControl.cs + CompletionOptionsControl.xaml Component - UserControl - - - IndentingOptionsControl.cs + IndentingOptionsControl.xaml - UserControl - - - FormattingOptionsControl.cs + FormattingOptionsControl.xaml Component - UserControl - - - GeneratorOptionsControl.cs + GeneratorOptionsControl.xaml @@ -168,16 +157,10 @@ - UserControl - - - OtherOptionsControl.cs + OtherOptionsControl.xaml - UserControl - - - IntellisenseOptionsControl.cs + IntellisenseOptionsControl.xaml Component @@ -191,18 +174,11 @@ Component - - Component - + - Form - - - XSharpSpecialOptions.cs - - - UserControl + XSharpSpecialOptions.xaml + @@ -220,6 +196,7 @@ + DocumentOutlineControl.xaml Code @@ -277,30 +254,6 @@ - - CtorParamsDlg.cs - - - CompletionOptionsControl.cs - - - IndentingOptionsControl.cs - - - FormattingOptionsControl.cs - - - GeneratorOptionsControl.cs - - - OtherOptionsControl.cs - - - IntellisenseOptionsControl.cs - - - XSharpSpecialOptions.cs - Designer @@ -320,9 +273,6 @@ - - Resources\XSharpProjectImageList.bmp - @@ -339,10 +289,46 @@ + + MSBuild:Compile + Designer + MSBuild:Compile Designer + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + diff --git a/src/VisualStudio/LanguageService/LanguageService2022.csproj b/src/VisualStudio/LanguageService/LanguageService2022.csproj index 1e1c1767e3..f04ae1ebb0 100644 --- a/src/VisualStudio/LanguageService/LanguageService2022.csproj +++ b/src/VisualStudio/LanguageService/LanguageService2022.csproj @@ -63,6 +63,10 @@ + + GotoDefinitionResultsWindow.xaml + Code + @@ -105,10 +109,7 @@ - Form - - - CtorParamsDlg.cs + CtorParamsDlg.xaml @@ -132,34 +133,22 @@ - UserControl - - - CompletionOptionsControl.cs + CompletionOptionsControl.xaml Component - UserControl - - - IndentingOptionsControl.cs + IndentingOptionsControl.xaml - UserControl - - - FormattingOptionsControl.cs + FormattingOptionsControl.xaml Component - UserControl - - - GeneratorOptionsControl.cs + GeneratorOptionsControl.xaml @@ -169,16 +158,10 @@ - UserControl - - - OtherOptionsControl.cs + OtherOptionsControl.xaml - UserControl - - - IntellisenseOptionsControl.cs + IntellisenseOptionsControl.xaml Component @@ -192,18 +175,11 @@ Component - - Component - + - Form - - - XSharpSpecialOptions.cs - - - UserControl + XSharpSpecialOptions.xaml + @@ -221,7 +197,8 @@ - + + DocumentOutlineControl.xaml Code @@ -294,30 +271,6 @@ - - CtorParamsDlg.cs - - - CompletionOptionsControl.cs - - - IndentingOptionsControl.cs - - - FormattingOptionsControl.cs - - - GeneratorOptionsControl.cs - - - OtherOptionsControl.cs - - - IntellisenseOptionsControl.cs - - - XSharpSpecialOptions.cs - Designer @@ -337,9 +290,6 @@ - - Resources\XSharpProjectImageList.bmp - @@ -351,11 +301,47 @@ - DocumentOutline\VsThemeDictionary.xaml + Controls\VsThemeDictionary.xaml + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + MSBuild:Compile Designer - + MSBuild:Compile Designer diff --git a/src/VisualStudio/LanguageService/LightBulb/ConstructorAction.cs b/src/VisualStudio/LanguageService/LightBulb/ConstructorAction.cs index 73b32e9f12..bed88da6ec 100644 --- a/src/VisualStudio/LanguageService/LightBulb/ConstructorAction.cs +++ b/src/VisualStudio/LanguageService/LightBulb/ConstructorAction.cs @@ -169,7 +169,7 @@ private List CreateCtor(string prefix, int indentSize) { CtorParamsDlg dlg = new CtorParamsDlg(); dlg.FillMembers(_fieldsNProps); - if ( dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK ) + if ( dlg.ShowDialog() == true ) { insertText.Append(prefix); insertText.Append("PUBLIC "); diff --git a/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.Designer.cs b/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.Designer.cs deleted file mode 100644 index 4b4b831edf..0000000000 --- a/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.Designer.cs +++ /dev/null @@ -1,172 +0,0 @@ - -namespace XSharp.LanguageService.Editors.LightBulb -{ - partial class CtorParamsDlg - { - /// - /// Required designer variable. - /// - private System.ComponentModel.IContainer components = null; - - /// - /// Clean up any resources being used. - /// - /// true if managed resources should be disposed; otherwise, false. - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - #region Windows Form Designer generated code - - /// - /// Required method for Designer support - do not modify - /// the contents of this method with the code editor. - /// - private void InitializeComponent() - { - this.btnCancel = new System.Windows.Forms.Button(); - this.btnOk = new System.Windows.Forms.Button(); - this.groupBox1 = new System.Windows.Forms.GroupBox(); - this.btnDeselect = new System.Windows.Forms.Button(); - this.btnSelect = new System.Windows.Forms.Button(); - this.btnDown = new System.Windows.Forms.Button(); - this.btnUp = new System.Windows.Forms.Button(); - this.listMembers = new System.Windows.Forms.ListView(); - this.colMembers = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); - this.groupBox1.SuspendLayout(); - this.SuspendLayout(); - // - // btnCancel - // - this.btnCancel.Location = new System.Drawing.Point(452, 373); - this.btnCancel.Name = "btnCancel"; - this.btnCancel.Size = new System.Drawing.Size(75, 30); - this.btnCancel.TabIndex = 0; - this.btnCancel.Text = "Cancel"; - this.btnCancel.UseVisualStyleBackColor = true; - this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); - // - // btnOk - // - this.btnOk.Location = new System.Drawing.Point(371, 373); - this.btnOk.Name = "btnOk"; - this.btnOk.Size = new System.Drawing.Size(75, 30); - this.btnOk.TabIndex = 1; - this.btnOk.Text = "OK"; - this.btnOk.UseVisualStyleBackColor = true; - this.btnOk.Click += new System.EventHandler(this.btnOk_Click); - // - // groupBox1 - // - this.groupBox1.Controls.Add(this.btnDeselect); - this.groupBox1.Controls.Add(this.btnSelect); - this.groupBox1.Controls.Add(this.btnDown); - this.groupBox1.Controls.Add(this.btnUp); - this.groupBox1.Controls.Add(this.listMembers); - this.groupBox1.Location = new System.Drawing.Point(12, 36); - this.groupBox1.Name = "groupBox1"; - this.groupBox1.Size = new System.Drawing.Size(515, 314); - this.groupBox1.TabIndex = 2; - this.groupBox1.TabStop = false; - this.groupBox1.Text = "Pick members to be used as constructor parameters"; - // - // btnDeselect - // - this.btnDeselect.Location = new System.Drawing.Point(404, 161); - this.btnDeselect.Name = "btnDeselect"; - this.btnDeselect.Size = new System.Drawing.Size(105, 30); - this.btnDeselect.TabIndex = 6; - this.btnDeselect.Text = "Deselect All"; - this.btnDeselect.UseVisualStyleBackColor = true; - this.btnDeselect.Click += new System.EventHandler(this.btnDeselect_Click); - // - // btnSelect - // - this.btnSelect.Location = new System.Drawing.Point(404, 125); - this.btnSelect.Name = "btnSelect"; - this.btnSelect.Size = new System.Drawing.Size(105, 30); - this.btnSelect.TabIndex = 5; - this.btnSelect.Text = "Select All"; - this.btnSelect.UseVisualStyleBackColor = true; - this.btnSelect.Click += new System.EventHandler(this.btnSelect_Click); - // - // btnDown - // - this.btnDown.Location = new System.Drawing.Point(404, 67); - this.btnDown.Name = "btnDown"; - this.btnDown.Size = new System.Drawing.Size(105, 30); - this.btnDown.TabIndex = 4; - this.btnDown.Text = "Down"; - this.btnDown.UseVisualStyleBackColor = true; - this.btnDown.Click += new System.EventHandler(this.btnDown_Click); - // - // btnUp - // - this.btnUp.Location = new System.Drawing.Point(404, 31); - this.btnUp.Name = "btnUp"; - this.btnUp.Size = new System.Drawing.Size(105, 30); - this.btnUp.TabIndex = 3; - this.btnUp.Text = "Up"; - this.btnUp.UseVisualStyleBackColor = true; - this.btnUp.Click += new System.EventHandler(this.btnUp_Click); - // - // listMembers - // - this.listMembers.Activation = System.Windows.Forms.ItemActivation.OneClick; - this.listMembers.CheckBoxes = true; - this.listMembers.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { - this.colMembers}); - this.listMembers.FullRowSelect = true; - this.listMembers.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; - this.listMembers.HideSelection = false; - this.listMembers.HotTracking = true; - this.listMembers.HoverSelection = true; - this.listMembers.Location = new System.Drawing.Point(19, 31); - this.listMembers.Name = "listMembers"; - this.listMembers.Size = new System.Drawing.Size(368, 265); - this.listMembers.TabIndex = 0; - this.listMembers.UseCompatibleStateImageBehavior = false; - this.listMembers.View = System.Windows.Forms.View.Details; - // - // colMembers - // - this.colMembers.Text = "Members"; - this.colMembers.Width = 329; - // - // CtorParamsDlg - // - this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 16F); - this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(539, 415); - this.Controls.Add(this.groupBox1); - this.Controls.Add(this.btnOk); - this.Controls.Add(this.btnCancel); - this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; - this.MaximizeBox = false; - this.MinimizeBox = false; - this.Name = "CtorParamsDlg"; - this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; - this.Text = "Pick members"; - this.groupBox1.ResumeLayout(false); - this.ResumeLayout(false); - - } - - #endregion - - private System.Windows.Forms.Button btnCancel; - private System.Windows.Forms.Button btnOk; - private System.Windows.Forms.GroupBox groupBox1; - private System.Windows.Forms.ListView listMembers; - private System.Windows.Forms.Button btnDeselect; - private System.Windows.Forms.Button btnSelect; - private System.Windows.Forms.Button btnDown; - private System.Windows.Forms.Button btnUp; - private System.Windows.Forms.ColumnHeader colMembers; - } -} diff --git a/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.cs b/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.cs index e4daf6a07e..9e1cbc2239 100644 --- a/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.cs +++ b/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.cs @@ -1,156 +1,130 @@ -using System; +// Copyright (c) XSharp B.V. All Rights Reserved. +// Licensed under the Apache License, Version 2.0. +// See License.txt in the project root for license information. +using Microsoft.VisualStudio.Imaging.Interop; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.ComponentModel; -using System.Data; -using System.Drawing; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Windows.Forms; +using System.Runtime.CompilerServices; +using System.Windows; +using XSharp.LanguageService; using XSharpModel; -using MVP = Microsoft.VisualStudio.Package; namespace XSharp.LanguageService.Editors.LightBulb { - public partial class CtorParamsDlg : Form + public partial class CtorParamsDlg : Window { - ImageList _imageList = new ImageList(); - List selectedFieldsNProps = new List(); - - public List FieldsNProps { get { return selectedFieldsNProps; } } + private readonly ObservableCollection _items = new ObservableCollection(); public CtorParamsDlg() { InitializeComponent(); - this.InitImageList(); - // - this.listMembers.ListViewItemSorter = new MemberTagValueComparer(); + _listView.ItemsSource = _items; } - private void InitImageList() + public List FieldsNProps { - Stream stream = typeof(MVP.LanguageService).Assembly.GetManifestResourceStream("Resources.completionset.bmp"); - _imageList.ImageSize = new Size(16, 16); - _imageList.TransparentColor = Color.FromArgb(255, 0, 255); - _imageList.Images.AddStrip(new Bitmap(stream)); - // - this.listMembers.SmallImageList = _imageList; + get + { + var result = new List(); + foreach (var item in _items) + { + if (item.IsChecked) + result.Add(item.Member); + } + return result; + } } - public void FillMembers(List fieldsNProps) + public void FillMembers(List fieldsNProps) { + _items.Clear(); int i = 0; foreach (var mbr in fieldsNProps) { - ListViewItem lvi = new ListViewItem(mbr.Name); - lvi.Checked = true; - lvi.Tag = ( i++, mbr ); - if (mbr is XSymbol xmbr) + _items.Add(new MemberItem { - lvi.ImageIndex = xmbr.Glyph; - } - this.listMembers.Items.Add(lvi); + Name = mbr.Name, + Member = mbr, + IsChecked = true, + Order = i++, + Moniker = mbr.Kind.GetImageMoniker(mbr.Visibility) + }); } } - private void btnSelect_Click(object sender, EventArgs e) + private void OnUp(object sender, RoutedEventArgs e) { - foreach (ListViewItem lvi in listMembers.Items) + int idx = _listView.SelectedIndex; + if (idx > 0) { - lvi.Checked = true; + _items.Move(idx, idx - 1); + _listView.SelectedIndex = idx - 1; } } - private void btnDeselect_Click(object sender, EventArgs e) + private void OnDown(object sender, RoutedEventArgs e) { - foreach (ListViewItem lvi in listMembers.Items) + int idx = _listView.SelectedIndex; + if (idx >= 0 && idx < _items.Count - 1) { - lvi.Checked = false; + _items.Move(idx, idx + 1); + _listView.SelectedIndex = idx + 1; } } - private void btnUp_Click(object sender, EventArgs e) + private void OnSelectAll(object sender, RoutedEventArgs e) { - if (listMembers.SelectedItems.Count > 0) - { - ListViewItem lvi = listMembers.SelectedItems[0]; - (int, IXMemberSymbol) t1 = ((int, IXMemberSymbol))lvi.Tag; - int tagValue = t1.Item1; - if ( tagValue > 0) - { - ListViewItem otherLvi = listMembers.Items[tagValue-1]; - (int, IXMemberSymbol) t2 = ((int, IXMemberSymbol))otherLvi.Tag; - t1.Item1 = t2.Item1; - t2.Item1 = tagValue; - // - lvi.Tag = t1; - otherLvi.Tag = t2; - // - listMembers.Sort(); - } - } + foreach (var item in _items) + item.IsChecked = true; } - private void btnDown_Click(object sender, EventArgs e) + private void OnDeselectAll(object sender, RoutedEventArgs e) { - if (listMembers.SelectedItems.Count > 0) + foreach (var item in _items) + item.IsChecked = false; + } + + private void OnOk(object sender, RoutedEventArgs e) + { + bool any = false; + foreach (var item in _items) { - ListViewItem lvi = listMembers.SelectedItems[0]; - (int, IXMemberSymbol) t1 = ((int, IXMemberSymbol))lvi.Tag; - int tagValue = t1.Item1; - if (tagValue < listMembers.Items.Count-1) - { - ListViewItem otherLvi = listMembers.Items[tagValue + 1]; - (int, IXMemberSymbol) t2 = ((int, IXMemberSymbol))otherLvi.Tag; - t1.Item1 = t2.Item1; - t2.Item1 = tagValue; - // - lvi.Tag = t1; - otherLvi.Tag = t2; - // - listMembers.Sort(); - } + if (item.IsChecked) { any = true; break; } } + DialogResult = any; } - private void btnCancel_Click(object sender, EventArgs e) + private void OnCancel(object sender, RoutedEventArgs e) { - this.DialogResult = DialogResult.Cancel; + DialogResult = false; } + } + + internal sealed class MemberItem : INotifyPropertyChanged + { + private bool _isChecked; - private void btnOk_Click(object sender, EventArgs e) + public bool IsChecked { - foreach( ListViewItem lvi in listMembers.Items ) + get => _isChecked; + set { - if ( lvi.Checked ) + if (_isChecked != value) { - (int, IXMemberSymbol) t1 = ((int, IXMemberSymbol))lvi.Tag; - this.selectedFieldsNProps.Add(t1.Item2); + _isChecked = value; + OnPropertyChanged(); } } - if ( this.selectedFieldsNProps.Count > 0 ) - { - this.DialogResult = DialogResult.OK; - } - else - { - this.DialogResult = DialogResult.Cancel; - } } - } - class MemberTagValueComparer : System.Collections.IComparer - { - public int Compare(object o1, object o2) - { - ListViewItem i1 = (ListViewItem)o1; - ListViewItem i2 = (ListViewItem)o2; - // - (int, IXMemberSymbol) t1 = ((int, IXMemberSymbol))i1.Tag; - (int, IXMemberSymbol) t2 = ((int, IXMemberSymbol))i2.Tag; - // - return t1.Item1.CompareTo(t2.Item1); - } + public string Name { get; set; } + public int Order { get; set; } + public IXMemberSymbol Member { get; set; } + public ImageMoniker Moniker { get; set; } + + public event PropertyChangedEventHandler PropertyChanged; + private void OnPropertyChanged([CallerMemberName] string name = null) + => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); } } diff --git a/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.xaml b/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.xaml new file mode 100644 index 0000000000..7e4e2c3ba8 --- /dev/null +++ b/src/VisualStudio/LanguageService/LightBulb/CtorParamsDlg.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +