diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin index 4bb5ccc90c..2465327880 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin @@ -140,79 +140,54 @@ diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs index 1c8f08be47..a26fb3a993 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpLanguageBinding.cs @@ -33,8 +33,8 @@ namespace CSharpBinding ITextEditor editor; CSharpSemanticHighlighter semanticHighlighter; - InspectionManager inspectionManager; - IList contextActionProviders; + //InspectionManager inspectionManager; + IList contextActionProviders; public override void Attach(ITextEditor editor) { @@ -45,11 +45,11 @@ namespace CSharpBinding semanticHighlighter = new CSharpSemanticHighlighter(editor, highlighter); highlighter.AddAdditionalHighlighter(semanticHighlighter); } - inspectionManager = new InspectionManager(editor); + //inspectionManager = new InspectionManager(editor); //codeManipulation = new CodeManipulation(editor); if (!editor.ContextActionProviders.IsReadOnly) { - contextActionProviders = AddInTree.BuildItems("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null); + contextActionProviders = AddInTree.BuildItems("/SharpDevelop/ViewContent/TextEditor/C#/ContextActions", null); editor.ContextActionProviders.AddRange(contextActionProviders); } } @@ -63,10 +63,10 @@ namespace CSharpBinding semanticHighlighter.Dispose(); semanticHighlighter = null; } - if (inspectionManager != null) { - inspectionManager.Dispose(); - inspectionManager = null; - } +// if (inspectionManager != null) { +// inspectionManager.Dispose(); +// inspectionManager = null; +// } if (contextActionProviders != null) { editor.ContextActionProviders.RemoveWhere(contextActionProviders.Contains); } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionDoozer.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionDoozer.cs index 505708c037..de2cb57854 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionDoozer.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionDoozer.cs @@ -3,18 +3,19 @@ using System; using System.IO; +using System.Linq; using System.Threading; using System.Threading.Tasks; using CSharpBinding.Parser; using ICSharpCode.Core; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.CSharp.Refactoring; using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Refactoring; namespace CSharpBinding.Refactoring { - using NR5ContextAction = ICSharpCode.NRefactory.CSharp.Refactoring.IContextAction; - /// /// Doozer for C# context actions. /// Expects a 'class' referencing an NR5 context action and provides an SD IContextActionsProvider. @@ -27,34 +28,55 @@ namespace CSharpBinding.Refactoring public object BuildItem(BuildItemArgs args) { - return new CSharpContextActionWrapper(args.AddIn, args.Codon.Properties); + Type providerType = args.AddIn.FindType(args.Codon.Properties["class"]); + if (providerType == null) + return null; + var attributes = providerType.GetCustomAttributes(typeof(ContextActionAttribute), true); + if (attributes.Length == 0) { + LoggingService.Error("[ContextAction] attribute is missing on " + providerType.FullName); + return null; + } + if (!typeof(ICodeActionProvider).IsAssignableFrom(providerType)) { + LoggingService.Error(providerType.FullName + " does nto implement ICodeActionProvider"); + return null; + } + return new CSharpContextActionProviderWrapper((ContextActionAttribute)attributes[0], providerType); } - sealed class CSharpContextActionWrapper : ContextAction + sealed class CSharpContextActionProviderWrapper : IContextActionProvider { - readonly AddIn addIn; - readonly string className; - readonly string displayName; + readonly ContextActionAttribute attribute; + readonly Type type; - public CSharpContextActionWrapper(AddIn addIn, Properties properties) + public CSharpContextActionProviderWrapper(ContextActionAttribute attribute, Type type) { - this.addIn = addIn; - this.className = properties["class"]; - this.displayName = properties["displayName"]; + this.attribute = attribute; + this.type = type; } - bool contextActionCreated; - NR5ContextAction contextAction; + ICodeActionProvider codeActionProvider; + + bool CreateCodeActionProvider() + { + lock (this) { + if (codeActionProvider == null) { + codeActionProvider = (ICodeActionProvider)Activator.CreateInstance(type); + } + return true; + } + } - public override string ID { - get { return className; } + public string ID { + get { return type.FullName; } } - public override string DisplayName { - get { return StringParser.Parse(displayName); } + public bool AllowHiding { + get { return true; } } - public override Task IsAvailableAsync(EditorRefactoringContext context, CancellationToken cancellationToken) + public bool IsVisible { get; set; } + + public Task GetAvailableActionsAsync(EditorRefactoringContext context, CancellationToken cancellationToken) { ITextEditor editor = context.Editor; // grab SelectionStart/SelectionLength while we're still on the main thread @@ -62,32 +84,66 @@ namespace CSharpBinding.Refactoring int selectionLength = editor.SelectionLength; return Task.Run( async delegate { - CreateContextAction(); - if (contextAction == null) - return false; + if (!CreateCodeActionProvider()) + return new IContextAction[0]; CSharpAstResolver resolver = await context.GetAstResolverAsync().ConfigureAwait(false); var refactoringContext = new SDRefactoringContext(context.TextSource, resolver, context.CaretLocation, selectionStart, selectionLength, cancellationToken); - return contextAction.IsValid(refactoringContext); + return codeActionProvider.GetActions(refactoringContext) + .Select((action, index) => new CSharpContextActionWrapper(this, action, index)).ToArray(); }, cancellationToken); } - void CreateContextAction() + internal CodeAction GetCodeAction(RefactoringContext refactoringContext, int index, string description) { - lock (this) { - if (!contextActionCreated) { - contextActionCreated = true; - contextAction = (NR5ContextAction)addIn.CreateObject(className); - } + if (!CreateCodeActionProvider()) + return null; + var actions = codeActionProvider.GetActions(refactoringContext).ToList(); + if (index < actions.Count) { + var action = actions[index]; + if (action.Description == description) + return action; } + return null; } + } + + sealed class CSharpContextActionWrapper : IContextAction + { + readonly CSharpContextActionProviderWrapper provider; + readonly int index; + readonly string description; - public override void Execute(EditorRefactoringContext context) + public CSharpContextActionWrapper(CSharpContextActionProviderWrapper provider, CodeAction codeAction, int index) { - AnalyticsMonitorService.TrackFeature(className); + if (provider == null) + throw new ArgumentNullException("provider"); + if (codeAction == null) + throw new ArgumentNullException("codeAction"); + this.provider = provider; + this.description = codeAction.Description; + this.index = index; + // Don't maintain a reference to 'action', it indirectly references the compilation etc. + } + + public IContextActionProvider Provider { + get { return provider; } + } + + public string DisplayName { + get { return description; } + } + + public void Execute(EditorRefactoringContext context) + { + AnalyticsMonitorService.TrackFeature(provider.ID); var resolver = context.GetAstResolverAsync().Result; var refactoringContext = new SDRefactoringContext(context.Editor, resolver, context.CaretLocation); - CreateContextAction(); - contextAction.Run(refactoringContext); + var action = provider.GetCodeAction(refactoringContext, index, description); + if (action != null) { + using (var script = refactoringContext.StartScript()) { + action.Run(script); + } + } } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InspectionManager.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InspectionManager.cs index 3662ae153d..64f6ca082e 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InspectionManager.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/InspectionManager.cs @@ -18,6 +18,7 @@ using ICSharpCode.SharpDevelop.Parser; namespace CSharpBinding.Refactoring { + /* /// /// Performs code analysis in the background and creates text markers to show warnings. /// @@ -153,4 +154,5 @@ namespace CSharpBinding.Refactoring cancellationTokenSource = null; } } + */ } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs index 9b341c0960..7590829ae0 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorAdapter.cs @@ -86,7 +86,7 @@ namespace ICSharpCode.AvalonEdit.AddIn } } - public override IList ContextActionProviders { + public override IList ContextActionProviders { get { return ((CodeEditorView)TextEditor).ContextActionProviders; } } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs index 38e69ef807..fbc893f53e 100755 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditorView.cs @@ -84,7 +84,7 @@ namespace ICSharpCode.AvalonEdit.AddIn hiddenDefinitionRenderer.Dispose(); } - public IList ContextActionProviders { + public IList ContextActionProviders { get { return contextActionsRenderer.Providers; } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/ContextActionsRenderer.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/ContextActionsRenderer.cs index 35fd4676e4..4561af7c1c 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/ContextActionsRenderer.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/ContextActionsRenderer.cs @@ -23,7 +23,7 @@ namespace ICSharpCode.AvalonEdit.AddIn.ContextActions public sealed class ContextActionsRenderer : IDisposable { readonly CodeEditorView editorView; - ObservableCollection providers = new ObservableCollection(); + ObservableCollection providers = new ObservableCollection(); ITextEditor Editor { get { return this.editorView.Adapter; } } @@ -62,7 +62,7 @@ namespace ICSharpCode.AvalonEdit.AddIn.ContextActions ClosePopup(); } - public IList Providers { + public IList Providers { get { return providers; } } diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/EditorActionsProvider.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/EditorActionsProvider.cs index a6a1ca75fc..c3bbc9faca 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/EditorActionsProvider.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/EditorActionsProvider.cs @@ -29,20 +29,20 @@ namespace ICSharpCode.AvalonEdit.AddIn.ContextActions return PropertyService.Get(PropertyServiceKey, new List()); } - static void SaveProviderVisibilities(IEnumerable providers) + static void SaveProviderVisibilities(IEnumerable providers) { List disabledProviders = providers.Where(p => !p.IsVisible).Select(p => p.ID).ToList(); PropertyService.Set(PropertyServiceKey, disabledProviders); } - readonly IList providers; + readonly IList providers; readonly EditorRefactoringContext editorContext; public EditorRefactoringContext EditorContext { get { return editorContext; } } - public EditorActionsProvider(EditorRefactoringContext editorContext, IList providers) + public EditorActionsProvider(EditorRefactoringContext editorContext, IList providers) { if (editorContext == null) throw new ArgumentNullException("editorContext"); @@ -69,7 +69,7 @@ namespace ICSharpCode.AvalonEdit.AddIn.ContextActions public void SetVisible(IContextAction action, bool isVisible) { - IContextActionsProvider provider; + IContextActionProvider provider; if (providerForAction.TryGetValue(action, out provider)) { provider.IsVisible = isVisible; } @@ -79,12 +79,12 @@ namespace ICSharpCode.AvalonEdit.AddIn.ContextActions /// /// For every returned action remembers its provider for so that SetVisible can work. /// - Dictionary providerForAction = new Dictionary(); + Dictionary providerForAction = new Dictionary(); /// /// Gets actions available for current caret position in the editor. /// - async Task> GetActionsAsync(IEnumerable providers, CancellationToken cancellationToken) + async Task> GetActionsAsync(IEnumerable providers, CancellationToken cancellationToken) { if (ParserService.LoadSolutionProjectsThreadRunning) return EmptyList.Instance; diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/GoToEntityAction.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/GoToEntityAction.cs index ceca94092a..61a908d69c 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/GoToEntityAction.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/ContextActions/GoToEntityAction.cs @@ -43,5 +43,9 @@ namespace ICSharpCode.AvalonEdit.AddIn.ContextActions { NavigationService.NavigateTo(this.Entity); } + + IContextActionProvider IContextAction.Provider { + get { return null; } + } } } diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextActionAttribute.cs b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextActionAttribute.cs index 4d989e61fe..24c479a191 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextActionAttribute.cs +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/ContextActionAttribute.cs @@ -1,4 +1,4 @@ -// +// // ProviderDescriptionAttribute.cs // // Author: diff --git a/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs b/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs index ccd0c3a52e..0b838307ac 100755 --- a/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs +++ b/src/Main/Base/Project/Src/Editor/AvalonEdit/AvalonEditTextEditorAdapter.cs @@ -239,8 +239,8 @@ namespace ICSharpCode.SharpDevelop.Editor.AvalonEdit return Enumerable.Empty(); } - public virtual IList ContextActionProviders { - get { return EmptyList.Instance; } + public virtual IList ContextActionProviders { + get { return EmptyList.Instance; } } public virtual ITextEditor PrimaryView { diff --git a/src/Main/Base/Project/Src/Editor/ITextEditor.cs b/src/Main/Base/Project/Src/Editor/ITextEditor.cs index 5106852c67..46b50ca2f6 100644 --- a/src/Main/Base/Project/Src/Editor/ITextEditor.cs +++ b/src/Main/Base/Project/Src/Editor/ITextEditor.cs @@ -123,7 +123,7 @@ namespace ICSharpCode.SharpDevelop.Editor /// /// Gets the list of context action providers. /// - IList ContextActionProviders { get; } + IList ContextActionProviders { get; } } public interface ITextEditorOptions : INotifyPropertyChanged diff --git a/src/Main/Base/Project/Src/Refactoring/ContextAction.cs b/src/Main/Base/Project/Src/Refactoring/ContextAction.cs index 0736c5b155..0a8ab495f6 100644 --- a/src/Main/Base/Project/Src/Refactoring/ContextAction.cs +++ b/src/Main/Base/Project/Src/Refactoring/ContextAction.cs @@ -14,7 +14,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// Base class for implementing one context action. /// Useful for implementing that provides just one action - common scenario. /// - public abstract class ContextAction : IContextActionsProvider, IContextAction + public abstract class ContextAction : IContextActionProvider, IContextAction { public virtual string ID { get { return GetType().FullName; } @@ -36,7 +36,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring public abstract void Execute(EditorRefactoringContext context); - async Task IContextActionsProvider.GetAvailableActionsAsync(EditorRefactoringContext context, CancellationToken cancellationToken) + async Task IContextActionProvider.GetAvailableActionsAsync(EditorRefactoringContext context, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); if (await IsAvailableAsync(context, cancellationToken).ConfigureAwait(false)) @@ -44,5 +44,9 @@ namespace ICSharpCode.SharpDevelop.Refactoring else return new IContextAction[0]; } + + IContextActionProvider IContextAction.Provider { + get { return this; } + } } } diff --git a/src/Main/Base/Project/Src/Refactoring/IContextAction.cs b/src/Main/Base/Project/Src/Refactoring/IContextAction.cs index a0ecb5f3c2..0cdc85852a 100644 --- a/src/Main/Base/Project/Src/Refactoring/IContextAction.cs +++ b/src/Main/Base/Project/Src/Refactoring/IContextAction.cs @@ -12,6 +12,11 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// public interface IContextAction { + /// + /// Gets the provider that was used to create this action. + /// + IContextActionProvider Provider { get; } + /// /// Name displayed in the context actions popup. /// diff --git a/src/Main/Base/Project/Src/Refactoring/IContextActionsProvider.cs b/src/Main/Base/Project/Src/Refactoring/IContextActionsProvider.cs index 0560f87ade..acda86f708 100644 --- a/src/Main/Base/Project/Src/Refactoring/IContextActionsProvider.cs +++ b/src/Main/Base/Project/Src/Refactoring/IContextActionsProvider.cs @@ -11,7 +11,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// /// Provides a set of refactoring s. /// - public interface IContextActionsProvider + public interface IContextActionProvider { /// /// Unique identifier for the context actions provider; used to hide context actions