diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin index d9ea3c9b84..6cbab75ecc 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.addin @@ -10,7 +10,7 @@ - + @@ -156,7 +156,7 @@ class = "ICSharpCode.NRefactory.CSharp.Refactoring.GenerateGetter" /> @@ -175,9 +175,9 @@ - + class = "ICSharpCode.NRefactory.CSharp.Refactoring.RemoveRegion" />--> @@ -192,6 +192,6 @@ class = "ICSharpCode.NRefactory.CSharp.Refactoring.UseExplicitType" /> --> + class = "ICSharpCode.NRefactory.CSharp.Refactoring.UseVarKeyword" /> diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj index a938ab8c8e..829ce472b2 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/CSharpBinding.csproj @@ -66,6 +66,7 @@ + @@ -74,10 +75,10 @@ - - + + @@ -134,6 +135,7 @@ + \ No newline at end of file diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpContextActionDoozer.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionDoozer.cs similarity index 65% rename from src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpContextActionDoozer.cs rename to src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionDoozer.cs index d6f3b8361e..952fef9ed6 100644 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpContextActionDoozer.cs +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/CSharpContextActionDoozer.cs @@ -8,9 +8,10 @@ using System.Threading.Tasks; using CSharpBinding.Parser; using ICSharpCode.Core; using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Refactoring; -namespace CSharpBinding +namespace CSharpBinding.Refactoring { using NR5ContextAction = ICSharpCode.NRefactory.CSharp.Refactoring.IContextAction; @@ -57,28 +58,37 @@ namespace CSharpBinding { if (!string.Equals(Path.GetExtension(context.FileName), ".cs", StringComparison.OrdinalIgnoreCase)) return Task.FromResult(false); + ITextEditor editor = context.Editor; + // grab SelectionStart/SelectionLength while we're still on the main thread + int selectionStart = editor.SelectionStart; + int selectionLength = editor.SelectionLength; return Task.Run( async delegate { -// var parseInfo = (await context.GetParseInformationAsync().ConfigureAwait(false)) as CSharpFullParseInformation; -// if (parseInfo == null) -// return false; - lock (this) { - if (!contextActionCreated) { - contextActionCreated = true; - contextAction = (NR5ContextAction)addIn.CreateObject(className); - } - } + CreateContextAction(); if (contextAction == null) return false; CSharpAstResolver resolver = await context.GetAstResolverAsync().ConfigureAwait(false); - //var refactoringContext = new SDRefactoringContext(context, resolver, cancellationToken); - return true; + var refactoringContext = new SDRefactoringContext(context.TextSource, resolver, context.CaretLocation, selectionStart, selectionLength, cancellationToken); + return contextAction.IsValid(refactoringContext); }, cancellationToken); } - public override void Execute(EditorContext context) + void CreateContextAction() { - throw new NotImplementedException(); + lock (this) { + if (!contextActionCreated) { + contextActionCreated = true; + contextAction = (NR5ContextAction)addIn.CreateObject(className); + } + } + } + + public override async Task ExecuteAsync(EditorContext context) + { + var resolver = await context.GetAstResolverAsync(); + var refactoringContext = new SDRefactoringContext(context.Editor, resolver, context.CaretLocation); + CreateContextAction(); + contextAction.Run(refactoringContext); } } } diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs new file mode 100644 index 0000000000..a2b8e26800 --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDRefactoringContext.cs @@ -0,0 +1,158 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Threading; +using CSharpBinding.Parser; +using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.CSharp.Refactoring; +using ICSharpCode.NRefactory.CSharp.Resolver; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.NRefactory.Semantics; +using ICSharpCode.NRefactory.TypeSystem; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Editor; +using ICSharpCode.SharpDevelop.Parser; +using ICSharpCode.SharpDevelop.Refactoring; + +namespace CSharpBinding.Refactoring +{ + public class SDRefactoringContext : RefactoringContext + { + readonly ITextEditor editor; + readonly ITextSource textSource; + volatile IDocument document; + readonly CSharpAstResolver resolver; + int selectionStart, selectionLength; + CancellationToken cancellationToken; + + public SDRefactoringContext(ITextSource textSource, CSharpAstResolver resolver, TextLocation location, int selectionStart, int selectionLength, CancellationToken cancellationToken) + { + this.textSource = textSource; + this.document = textSource as IDocument; + this.resolver = resolver; + this.selectionStart = selectionStart; + this.selectionLength = selectionLength; + this.cancellationToken = cancellationToken; + + this.Unit = resolver.RootNode as CompilationUnit; + this.Compilation = resolver.Compilation; + this.Location = location; + } + + public SDRefactoringContext(ITextEditor editor, CSharpAstResolver resolver, TextLocation location) + { + this.editor = editor; + this.textSource = editor.Document; + this.document = editor.Document; + this.resolver = resolver; + this.selectionStart = editor.SelectionStart; + this.selectionLength = editor.SelectionLength; + + this.Unit = resolver.RootNode as CompilationUnit; + this.Compilation = resolver.Compilation; + this.Location = location; + } + + public override bool Supports(Version version) + { + CSharpProject project = resolver.TypeResolveContext.Compilation.GetProject() as CSharpProject; + if (project == null) + return false; + return project.LanguageVersion >= version; + } + + public override NodeOutputAction CreateNodeOutputAction(int offset, int removedChars, NodeOutput output) + { + return new SDScript.SDNodeOutputAction(document, offset, removedChars, output); + } + + public override Script StartScript() + { + if (editor == null) + throw new InvalidOperationException("Cannot start a script in IsAvailable()."); + return new SDScript(editor, this); + } + + public override int SelectionStart { + get { return selectionStart; } + } + + public override int SelectionLength { + get { return selectionLength; } + } + + public override int SelectionEnd { + get { + return selectionStart + selectionLength; + } + } + + public override string SelectedText { + get { + return textSource.GetText(selectionStart, selectionLength); + } + } + + public override ResolveResult Resolve(AstNode expression) + { + lock (resolver) + return resolver.Resolve(expression, cancellationToken); + } + + public override void ReplaceReferences(IMember member, MemberDeclaration replaceWidth) + { + throw new NotImplementedException(); + } + + public override bool IsSomethingSelected { + get { + return selectionLength > 0; + } + } + + public override string GetText(int offset, int length) + { + return textSource.GetText(offset, length); + } + + public override int GetOffset(TextLocation location) + { + if (document == null) + document = new ReadOnlyDocument(textSource); + return document.GetOffset(location); + } + + public override TextLocation GetLocation(int offset) + { + if (document == null) + document = new ReadOnlyDocument(textSource); + return document.GetLocation(offset); + } + + public override CSharpFormattingOptions FormattingOptions { + get { + return new CSharpFormattingOptions(); + } + } + + public override string EolMarker { + get { + if (document == null) + document = new ReadOnlyDocument(textSource); + return DocumentUtilitites.GetLineTerminator(document, 1); + } + } + + public override AstType CreateShortType(IType fullType) + { + CSharpResolver csResolver; + lock (resolver) { + csResolver = resolver.GetResolverStateBefore(GetNode()); + } + var builder = new TypeSystemAstBuilder(csResolver); + return builder.ConvertType(fullType); + } + } +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs new file mode 100644 index 0000000000..31df894785 --- /dev/null +++ b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/SDScript.cs @@ -0,0 +1,83 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) + +using System; +using System.Collections.Generic; +using ICSharpCode.NRefactory.CSharp; +using ICSharpCode.NRefactory.CSharp.Refactoring; +using ICSharpCode.NRefactory.Editor; +using ICSharpCode.SharpDevelop.Editor; + +namespace CSharpBinding.Refactoring +{ + /// + /// Refactoring change script. + /// + sealed class SDScript : Script + { + readonly ITextEditor editor; + + public SDScript(ITextEditor editor, SDRefactoringContext context) : base(context) + { + this.editor = editor; + } + + public static void RunActions (IList actions, Script script) + { + for (int i = 0; i < actions.Count; i++) { + actions [i].Perform (script); + var replaceChange = actions [i] as TextReplaceAction; + if (replaceChange == null) + continue; + for (int j = 0; j < actions.Count; j++) { + if (i == j) + continue; + var change = actions [j] as TextReplaceAction; + if (change == null) + continue; + if (replaceChange.Offset >= 0 && change.Offset >= 0) { + if (replaceChange.Offset < change.Offset) { + change.Offset -= replaceChange.RemovedChars; + if (!string.IsNullOrEmpty (replaceChange.InsertedText)) + change.Offset += replaceChange.InsertedText.Length; + } else if (replaceChange.Offset < change.Offset + change.RemovedChars) { + change.RemovedChars = Math.Max (0, change.RemovedChars - replaceChange.RemovedChars); + change.Offset = replaceChange.Offset + (!string.IsNullOrEmpty (replaceChange.InsertedText) ? replaceChange.InsertedText.Length : 0); + } + } + } + } + } + + public override void Dispose () + { + using (editor.Document.OpenUndoGroup ()) { + RunActions (changes, this); + } + } + + public override void InsertWithCursor(string operation, AstNode node, InsertPosition defaultPosition) + { + throw new NotImplementedException(); + } + + internal class SDNodeOutputAction : NodeOutputAction + { + IDocument doc; + + public SDNodeOutputAction(IDocument doc, int offset, int removedChars, NodeOutput output) : base (offset, removedChars, output) + { + if (doc == null) + throw new ArgumentNullException ("doc"); + if (output == null) + throw new ArgumentNullException ("output"); + this.doc = doc; + } + + public override void Perform (Script script) + { + doc.Replace (Offset, RemovedChars, NodeOutput.Text); + } + } + } +} diff --git a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/SDRefactoringContext.cs b/src/AddIns/BackendBindings/CSharpBinding/Project/Src/SDRefactoringContext.cs deleted file mode 100644 index 3c8a5c6b0e..0000000000 --- a/src/AddIns/BackendBindings/CSharpBinding/Project/Src/SDRefactoringContext.cs +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using System.Threading; -using CSharpBinding.Parser; -using ICSharpCode.NRefactory; -using ICSharpCode.NRefactory.CSharp; -using ICSharpCode.NRefactory.CSharp.Refactoring; -using ICSharpCode.NRefactory.CSharp.Resolver; -using ICSharpCode.NRefactory.Semantics; -using ICSharpCode.NRefactory.TypeSystem; -using ICSharpCode.SharpDevelop; -using ICSharpCode.SharpDevelop.Editor; -using ICSharpCode.SharpDevelop.Parser; - -namespace CSharpBinding -{ - public class SDRefactoringContext : RefactoringContext - { - ITextEditor editor; - ICompilation compilation; - CancellationToken cancellationToken; - - public SDRefactoringContext(ITextEditor editor, CancellationToken cancellationToken) - { - this.editor = editor; - this.cancellationToken = cancellationToken; - this.compilation = ParserService.GetCompilationForFile(editor.FileName); - } - - public override bool Supports(Version version) - { - CSharpProject project = compilation.GetProject() as CSharpProject; - if (project == null) - return false; - return project.LanguageVersion >= version; - } - - public override Script StartScript() - { - throw new NotImplementedException(); - } - - public override int SelectionStart { - get { - return editor.SelectionStart; - } - } - - public override int SelectionLength { - get { - return editor.SelectionLength; - } - } - - public override int SelectionEnd { - get { - return editor.SelectionStart + editor.SelectionLength; - } - } - - public override string SelectedText { - get { - return editor.SelectedText; - } - } - - public override ResolveResult Resolve(AstNode expression) - { - var parseInfo = ParserService.Parse(editor.FileName, editor.Document) as CSharpFullParseInformation; - var resolver = new CSharpAstResolver(compilation, parseInfo.CompilationUnit, parseInfo.ParsedFile); - return resolver.Resolve(expression, cancellationToken); - } - - public override void ReplaceReferences(IMember member, MemberDeclaration replaceWidth) - { - throw new NotImplementedException(); - } - - public override bool IsSomethingSelected { - get { - return editor.SelectionLength > 0; - } - } - - public override string GetText(int offset, int length) - { - return editor.Document.GetText(offset, length); - } - - public override int GetOffset(TextLocation location) - { - return editor.Document.GetOffset(location); - } - - public override TextLocation GetLocation(int offset) - { - return editor.Document.GetLocation(offset); - } - - public override CSharpFormattingOptions FormattingOptions { - get { - return new CSharpFormattingOptions(); - } - } - - public override string EolMarker { - get { - return DocumentUtilitites.GetLineTerminator(editor.Document, 1); - } - } - - public override AstType CreateShortType(IType fullType) - { - var parseInfo = ParserService.Parse(editor.FileName, editor.Document) as CSharpFullParseInformation; - var parsedFile = parseInfo.ParsedFile; - var csResolver = parsedFile.GetResolver(compilation, editor.Caret.Location); - var builder = new TypeSystemAstBuilder(csResolver); - return builder.ConvertType(fullType); - } - } -} diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextAction.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextAction.cs index 276f9e8114..7cfd9f9391 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextAction.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextAction.cs @@ -30,7 +30,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// public abstract Task IsAvailableAsync(EditorContext context, CancellationToken cancellationToken); - public abstract void Execute(EditorContext context); + public abstract Task ExecuteAsync(EditorContext context); async Task IContextActionsProvider.GetAvailableActionsAsync(EditorContext context, CancellationToken cancellationToken) { diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionViewModel.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionViewModel.cs index ca46e68133..f07519c5c2 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionViewModel.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/ContextActionViewModel.cs @@ -86,7 +86,7 @@ namespace ICSharpCode.SharpDevelop.Refactoring public void Execute(object parameter) { - this.action.Execute(context); + this.action.ExecuteAsync(context).FireAndForget(); } public bool CanExecute(object parameter) diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs index 8470661a7b..efe497ae45 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs @@ -59,6 +59,13 @@ namespace ICSharpCode.SharpDevelop.Refactoring get { return caretOffset; } } + /// + /// Gets caret location, at the time when this editor context was created. + /// + public TextLocation CaretLocation { + get { return caretLocation; } + } + Task parseInformation; Task compilation; diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/IContextAction.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/IContextAction.cs index 3c9237faab..aa0dc6347a 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/IContextAction.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/IContextAction.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Threading.Tasks; using System.Windows; namespace ICSharpCode.SharpDevelop.Refactoring @@ -18,6 +19,6 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// /// Executes this action. Called when this action is selected from the context actions popup. /// - void Execute(EditorContext context); + Task ExecuteAsync(EditorContext context); } } diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/GoToEntityAction.cs b/src/Main/Base/Project/Src/Services/RefactoringService/GoToEntityAction.cs index f9dddd5e2e..8282507e34 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/GoToEntityAction.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/GoToEntityAction.cs @@ -2,6 +2,7 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; +using System.Threading.Tasks; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.SharpDevelop.Parser; @@ -22,9 +23,10 @@ namespace ICSharpCode.SharpDevelop.Refactoring this.DisplayName = ambience.ConvertEntity(entity); } - public void Execute(EditorContext context) + public Task ExecuteAsync(EditorContext context) { NavigationService.NavigateTo(this.Entity); + return Task.FromResult(null); } } }