39
39
using MonoDevelop.CSharp.Formatting;
40
40
using MonoDevelop.Ide;
41
using System.Threading.Tasks;
42
using MonoDevelop.Core.ProgressMonitoring;
43
using MonoDevelop.Ide.FindInFiles;
44
using MonoDevelop.Projects;
45
using ICSharpCode.NRefactory.CSharp.TypeSystem;
46
using MonoDevelop.Ide.Gui.Content;
42
48
namespace MonoDevelop.CSharp.Refactoring.CodeActions
44
50
public class MDRefactoringScript : DocumentScript
46
52
readonly MDRefactoringContext context;
47
readonly Document document;
48
53
readonly IDisposable undoGroup;
54
readonly ICSharpCode.NRefactory.Editor.ITextSourceVersion startVersion;
55
int operationsRunning = 0;
50
public MDRefactoringScript (MDRefactoringContext context, Document document, CSharpFormattingOptions formattingOptions) : base(document.Editor.Document, formattingOptions, document.Editor.CreateNRefactoryTextEditorOptions ())
57
public MDRefactoringScript (MDRefactoringContext context, CSharpFormattingOptions formattingOptions) : base(context.TextEditor.Document, formattingOptions, context.TextEditor.CreateNRefactoryTextEditorOptions ())
52
59
this.context = context;
53
this.document = document;
54
undoGroup = this.document.Editor.OpenUndoGroup ();
60
undoGroup = this.context.TextEditor.OpenUndoGroup ();
61
this.startVersion = this.context.TextEditor.Version;
67
DisposeOnClose (true);
68
foreach (var ver in this.context.TextEditor.Version.GetChangesTo (this.startVersion)) {
69
context.TextEditor.Document.Replace (ver.Offset, ver.RemovalLength, ver.InsertedText.Text);
57
73
public override void Select (AstNode node)
59
document.Editor.SelectionRange = new TextSegment (GetSegment (node));
75
context.TextEditor.SelectionRange = new TextSegment (GetSegment (node));
62
public override void InsertWithCursor (string operation, InsertPosition defaultPosition, IEnumerable<AstNode> nodes)
78
public override Task InsertWithCursor (string operation, InsertPosition defaultPosition, IEnumerable<AstNode> nodes)
64
var editor = document.Editor;
65
DocumentLocation loc = document.Editor.Caret.Location;
66
var declaringType = document.ParsedDocument.GetInnermostTypeDefinition (loc);
80
var tcs = new TaskCompletionSource<object> ();
81
var editor = context.TextEditor;
82
DocumentLocation loc = context.TextEditor.Caret.Location;
83
var declaringType = context.ParsedDocument.GetInnermostTypeDefinition (loc);
67
84
var mode = new InsertionCursorEditMode (
69
CodeGenerationService.GetInsertionPoints (document, declaringType));
86
CodeGenerationService.GetInsertionPoints (context.TextEditor, context.ParsedDocument, declaringType));
70
87
if (mode.InsertionPoints.Count == 0) {
71
88
MessageService.ShowError (
72
89
GettextCatalog.GetString ("No valid insertion point can be found in type '{0}'.", declaringType.Name)
76
93
var helpWindow = new Mono.TextEditor.PopupWindow.InsertionCursorLayoutModeHelpWindow ();
77
94
helpWindow.TransientFor = MonoDevelop.Ide.IdeApp.Workbench.RootWindow;
78
95
helpWindow.TitleText = operation;
96
helpWindow.Shown += (s, a) => DesktopService.RemoveWindowShadow (helpWindow);
79
97
mode.HelpWindow = helpWindow;
81
99
switch (defaultPosition) {
104
122
mode.StartMode ();
123
DesktopService.RemoveWindowShadow (helpWindow);
105
124
mode.Exited += delegate(object s, InsertionCursorEventArgs iCArgs) {
106
125
if (iCArgs.Success) {
107
foreach (var node in nodes) {
126
if (iCArgs.InsertionPoint.LineAfter == NewLineInsertion.None &&
127
iCArgs.InsertionPoint.LineBefore == NewLineInsertion.None && nodes.Count () > 1) {
128
iCArgs.InsertionPoint.LineAfter = NewLineInsertion.BlankLine;
130
foreach (var node in nodes.Reverse ()) {
108
131
var output = OutputNode (CodeGenerationService.CalculateBodyIndentLevel (declaringType), node);
109
output.RegisterTrackedSegments (this, document.Editor.LocationToOffset (iCArgs.InsertionPoint.Location));
110
iCArgs.InsertionPoint.Insert (editor, output.Text);
132
var offset = context.TextEditor.LocationToOffset (iCArgs.InsertionPoint.Location);
133
var delta = iCArgs.InsertionPoint.Insert (editor, output.Text);
134
output.RegisterTrackedSegments (this, delta + offset);
136
tcs.SetResult (null);
116
public override void InsertWithCursor (string operation, ITypeDefinition parentType, IEnumerable<AstNode> nodes)
145
public override Task InsertWithCursor (string operation, ITypeDefinition parentType, IEnumerable<AstNode> nodes)
147
var tcs = new TaskCompletionSource<object>();
148
if (parentType == null)
118
150
var part = parentType.Parts.FirstOrDefault ();
119
151
if (part == null)
122
154
var loadedDocument = Ide.IdeApp.Workbench.OpenDocument (part.Region.FileName);
124
155
loadedDocument.RunWhenLoaded (delegate {
125
156
var editor = loadedDocument.Editor;
126
157
var loc = part.Region.Begin;
169
if (declaringType.Kind == TypeKind.Enum) {
170
foreach (var node in nodes.Reverse ()) {
171
var output = OutputNode (CodeGenerationService.CalculateBodyIndentLevel (declaringType), node);
172
var point = mode.InsertionPoints.First ();
173
var offset = loadedDocument.Editor.LocationToOffset (point.Location);
174
var text = output.Text + ",";
175
var delta = point.Insert (editor, text);
176
output.RegisterTrackedSegments (this, delta + offset);
178
tcs.SetResult (null);
138
183
var helpWindow = new Mono.TextEditor.PopupWindow.InsertionCursorLayoutModeHelpWindow ();
139
184
helpWindow.TransientFor = MonoDevelop.Ide.IdeApp.Workbench.RootWindow;
140
185
helpWindow.TitleText = operation;
186
helpWindow.Shown += (s, a) => DesktopService.RemoveWindowShadow (helpWindow);
141
187
mode.HelpWindow = helpWindow;
143
189
mode.CurIndex = 0;
145
191
mode.StartMode ();
146
192
mode.Exited += delegate(object s, InsertionCursorEventArgs iCArgs) {
147
193
if (iCArgs.Success) {
148
foreach (var node in nodes) {
194
if (iCArgs.InsertionPoint.LineAfter == NewLineInsertion.None &&
195
iCArgs.InsertionPoint.LineBefore == NewLineInsertion.None && nodes.Count () > 1) {
196
iCArgs.InsertionPoint.LineAfter = NewLineInsertion.BlankLine;
198
foreach (var node in nodes.Reverse ()) {
149
199
var output = OutputNode (CodeGenerationService.CalculateBodyIndentLevel (declaringType), node);
150
output.RegisterTrackedSegments (this, loadedDocument.Editor.LocationToOffset (iCArgs.InsertionPoint.Location));
151
iCArgs.InsertionPoint.Insert (editor, output.Text);
200
var offset = loadedDocument.Editor.LocationToOffset (iCArgs.InsertionPoint.Location);
201
var text = output.Text;
202
var delta = iCArgs.InsertionPoint.Insert (editor, text);
203
output.RegisterTrackedSegments (this, delta + offset);
205
tcs.SetResult (null);
158
public override void Link (params AstNode[] nodes)
216
public override Task Link (params AstNode[] nodes)
218
var tcs = new TaskCompletionSource<object> ();
160
219
var segments = new List<TextSegment> (nodes.Select (node => new TextSegment (GetSegment (node))).OrderBy (s => s.Offset));
162
221
var link = new TextLink ("name");
163
222
segments.ForEach (s => link.AddLink (s));
164
223
var links = new List<TextLink> ();
165
224
links.Add (link);
166
var tle = new TextLinkEditMode (document.Editor.Parent, 0, links);
225
var tle = new TextLinkEditMode (context.TextEditor.Parent, 0, links);
167
226
tle.SetCaretPosition = false;
168
227
if (tle.ShouldStartTextLinkMode) {
169
document.Editor.Caret.Offset = segments [0].EndOffset;
170
tle.OldMode = document.Editor.CurrentMode;
229
context.TextEditor.Caret.Offset = segments [0].EndOffset;
230
tle.OldMode = context.TextEditor.CurrentMode;
231
tle.Cancel += (sender, e) => Rollback ();
232
tle.Exited += (sender, e) => DisposeOnClose ();
171
233
tle.StartMode ();
172
document.Editor.CurrentMode = tle;
234
context.TextEditor.CurrentMode = tle;
235
if (IdeApp.Workbench.ActiveDocument != null)
236
IdeApp.Workbench.ActiveDocument.ReparseDocument ();
241
bool isDisposed = false;
242
void DisposeOnClose (bool force = false)
247
operationsRunning = 0;
248
if (operationsRunning-- == 0) {
250
undoGroup.Dispose ();
176
255
public override void Dispose ()
178
undoGroup.Dispose ();
182
260
public override void Rename (IEntity entity, string name)
189
267
RenameRefactoring.RenameVariable (variable, name);
270
public override void Rename (INamespace ns, string name)
272
RenameRefactoring.RenameNamespace (ns, name);
192
275
public override void RenameTypeParameter (IType typeParameter, string name = null)
194
277
RenameRefactoring.RenameTypeParameter ((ITypeParameter)typeParameter, name);
280
public override void DoGlobalOperationOn (IEntity entity, Action<RefactoringContext, Script, AstNode> callback, string operationName = null)
282
using (var monitor = IdeApp.Workbench.ProgressMonitors.GetBackgroundProgressMonitor (operationName ?? GettextCatalog.GetString ("Performing refactoring task..."), null)) {
283
var col = ReferenceFinder.FindReferences (entity, true, monitor);
285
string oldFileName = null;
286
MDRefactoringContext ctx = null;
287
MDRefactoringScript script = null;
288
TextEditorData data = null;
290
System.Text.Encoding encoding = null;
293
foreach (var r in col) {
294
var memberRef = r as CSharpReferenceFinder.CSharpMemberReference;
295
if (memberRef == null)
298
if (oldFileName != memberRef.FileName) {
299
if (oldFileName != null && !isOpen) {
301
Mono.TextEditor.Utils.TextFileUtility.WriteText (oldFileName, data.Text, encoding, hadBom);
304
data = TextFileProvider.Instance.GetTextEditorData (memberRef.FileName, out hadBom, out encoding, out isOpen);
305
var project = memberRef.Project;
307
ParsedDocument parsedDocument;
308
using (var reader = new StreamReader (data.OpenStream ()))
309
parsedDocument = new MonoDevelop.CSharp.Parser.TypeSystemParser ().Parse (true, memberRef.FileName, reader, project);
310
var resolver = new CSharpAstResolver (TypeSystemService.GetCompilation (project), memberRef.SyntaxTree, parsedDocument.ParsedFile as CSharpUnresolvedFile);
312
ctx = new MDRefactoringContext (project as DotNetProject, data, parsedDocument, resolver, memberRef.AstNode.StartLocation, this.context.CancellationToken);
313
script = new MDRefactoringScript (ctx, FormattingOptions);
314
oldFileName = memberRef.FileName;
317
callback (ctx, script, memberRef.AstNode);
320
if (oldFileName != null && !isOpen) {
322
Mono.TextEditor.Utils.TextFileUtility.WriteText (oldFileName, data.Text, encoding, hadBom);
197
327
public override void CreateNewType (AstNode newType, NewTypeContext ntctx)
199
329
if (newType == null)
200
330
throw new System.ArgumentNullException ("newType");
201
331
var correctFileName = MoveTypeToFile.GetCorrectFileName (context, (EntityDeclaration)newType);
203
var content = context.Document.Editor.Text;
333
var content = context.TextEditor.Text;
205
var types = new List<TypeDeclaration> (context.Unit.GetTypes ());
335
var types = new List<EntityDeclaration> (context.Unit.GetTypes ());
206
336
types.Sort ((x, y) => y.StartLocation.CompareTo (x.StartLocation));
208
338
foreach (var removeType in types) {
214
344
var insertLocation = types.Count > 0 ? context.GetOffset (types.Last ().StartLocation) : -1;
215
var formattingPolicy = this.document.GetFormattingPolicy ();
216
345
if (insertLocation < 0 || insertLocation > content.Length)
217
346
insertLocation = content.Length;
218
content = content.Substring (0, insertLocation) + newType.GetText (formattingPolicy.CreateOptions ()) + content.Substring (insertLocation);
220
var formatter = new CSharpFormatter ();
221
content = formatter.FormatText (formattingPolicy, null, CSharpFormatter.MimeType, content, 0, content.Length);
347
content = content.Substring (0, insertLocation) + newType.ToString (FormattingOptions) + content.Substring (insertLocation);
349
var formatter = new MonoDevelop.CSharp.Formatting.CSharpFormatter ();
350
var policy = context.Project.Policies.Get<CSharpFormattingPolicy> ();
351
var textPolicy = context.Project.Policies.Get<TextStylePolicy> ();
353
content = formatter.FormatText (policy, textPolicy, MonoDevelop.CSharp.Formatting.CSharpFormatter.MimeType, content, 0, content.Length);
223
355
File.WriteAllText (correctFileName, content);
224
document.Project.AddFile (correctFileName);
225
MonoDevelop.Ide.IdeApp.ProjectOperations.Save (document.Project);
226
MonoDevelop.Ide.IdeApp.Workbench.OpenDocument (correctFileName);
356
context.Project.AddFile (correctFileName);
357
IdeApp.ProjectOperations.Save (context.Project);
358
IdeApp.Workbench.OpenDocument (correctFileName);