Skip to content
This repository was archived by the owner on Oct 16, 2020. It is now read-only.

Commit 096c88c

Browse files
fix #282: Pressing Ctrl+Z in InsertWithCursor mode causes InvalidOperationException
1 parent a1aebe8 commit 096c88c

3 files changed

Lines changed: 63 additions & 28 deletions

File tree

src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/EditorScript.cs

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -114,35 +114,44 @@ public override Task<Script> InsertWithCursor(string operation, InsertPosition d
114114
}
115115
break;
116116
}
117-
operationsRunning++;
118117
InsertWithCursorOnLayer(this, layer, tcs, nodes, editor.Document);
119118
return tcs.Task;
120119
}
121120

122121
void InsertWithCursorOnLayer(EditorScript currentScript, InsertionCursorLayer layer, TaskCompletionSource<Script> tcs, IList<AstNode> nodes, IDocument target)
123122
{
123+
var doc = target as TextDocument;
124+
var op = new UndoOperation(layer, tcs);
125+
if (doc != null) {
126+
doc.UndoStack.Push(op);
127+
}
124128
layer.Exited += delegate(object s, InsertionCursorEventArgs args) {
125-
if (args.Success) {
126-
if (args.InsertionPoint.LineAfter == NewLineInsertion.None &&
127-
args.InsertionPoint.LineBefore == NewLineInsertion.None && nodes.Count > 1) {
128-
args.InsertionPoint.LineAfter = NewLineInsertion.BlankLine;
129-
}
130-
foreach (var node in nodes.Reverse ()) {
131-
int indentLevel = currentScript.GetIndentLevelAt(target.GetOffset(args.InsertionPoint.Location));
132-
var output = currentScript.OutputNode(indentLevel, node);
133-
var offset = target.GetOffset(args.InsertionPoint.Location);
134-
var delta = args.InsertionPoint.Insert(target, output.Text);
135-
output.RegisterTrackedSegments(currentScript, delta + offset);
129+
doc.UndoStack.StartContinuedUndoGroup();
130+
try {
131+
if (args.Success) {
132+
if (args.InsertionPoint.LineAfter == NewLineInsertion.None &&
133+
args.InsertionPoint.LineBefore == NewLineInsertion.None && nodes.Count > 1) {
134+
args.InsertionPoint.LineAfter = NewLineInsertion.BlankLine;
135+
}
136+
foreach (var node in nodes.Reverse ()) {
137+
int indentLevel = currentScript.GetIndentLevelAt(target.GetOffset(args.InsertionPoint.Location));
138+
var output = currentScript.OutputNode(indentLevel, node);
139+
var offset = target.GetOffset(args.InsertionPoint.Location);
140+
var delta = args.InsertionPoint.Insert(target, output.Text);
141+
output.RegisterTrackedSegments(currentScript, delta + offset);
142+
}
143+
tcs.SetResult(currentScript);
136144
}
137-
tcs.SetResult(currentScript);
145+
layer.Dispose();
146+
DisposeOnClose();
147+
} finally {
148+
doc.UndoStack.EndUndoGroup();
138149
}
139-
layer.Dispose();
140-
DisposeOnClose();
150+
op.Reset();
141151
};
142152
}
143153

144154
readonly List<Script> startedScripts = new List<Script>();
145-
int operationsRunning;
146155

147156
public override Task<Script> InsertWithCursor(string operation, ITypeDefinition parentType, Func<Script, RefactoringContext, IList<AstNode>> nodeCallback)
148157
{
@@ -195,7 +204,6 @@ public override Task<Script> InsertWithCursor(string operation, ITypeDefinition
195204
tcs.SetResult(script);
196205
return tcs.Task;
197206
}
198-
operationsRunning++;
199207
InsertWithCursorOnLayer(script, layer, tcs, nodes, area.Document);
200208
return tcs.Task;
201209
}
@@ -205,14 +213,10 @@ void DisposeOnClose(bool force = false)
205213
{
206214
if (isDisposed)
207215
return;
208-
if (force)
209-
operationsRunning = 0;
210-
if (operationsRunning-- == 0) {
211-
isDisposed = true;
212-
base.Dispose ();
213-
// refresh parse information so that the issue can disappear immediately
214-
SD.ParserService.ParseAsync(editor.FileName, editor.Document).FireAndForget();
215-
}
216+
isDisposed = true;
217+
base.Dispose();
218+
// refresh parse information so that the issue can disappear immediately
219+
SD.ParserService.ParseAsync(editor.FileName, editor.Document).FireAndForget();
216220
foreach (var script in startedScripts)
217221
script.Dispose();
218222
}
@@ -221,7 +225,38 @@ public override void Dispose()
221225
{
222226
DisposeOnClose();
223227
}
224-
228+
229+
class UndoOperation : IUndoableOperation
230+
{
231+
InsertionCursorLayer layer;
232+
TaskCompletionSource<Script> tcs;
233+
234+
public UndoOperation(InsertionCursorLayer layer, TaskCompletionSource<Script> tcs)
235+
{
236+
this.layer = layer;
237+
this.tcs = tcs;
238+
}
239+
240+
public void Reset()
241+
{
242+
layer = null;
243+
tcs = null;
244+
}
245+
246+
public void Undo()
247+
{
248+
if (layer != null)
249+
layer.Dispose();
250+
layer = null;
251+
if (tcs != null)
252+
tcs.SetCanceled();
253+
tcs = null;
254+
}
255+
256+
public void Redo()
257+
{
258+
}
259+
}
225260
}
226261

227262
class InsertionCursorLayer : UIElement, IDisposable

src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoStack.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ public void StartUndoGroup(object groupDescriptor)
193193
/// </summary>
194194
/// <param name="groupDescriptor">An object that is stored with the undo group.
195195
/// If this is not a top-level undo group, the parameter is ignored.</param>
196-
public void StartContinuedUndoGroup(object groupDescriptor)
196+
public void StartContinuedUndoGroup(object groupDescriptor = null)
197197
{
198198
if (undoGroupDepth == 0) {
199199
actionCountInUndoGroup = (allowContinue && undostack.Count > 0) ? 1 : 0;

src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public override void Dispose()
5858
undoGroup.Dispose();
5959
}
6060

61-
public override void Remove(AstNode node, bool removeEmptyLine)
61+
public override void Remove(AstNode node, bool removeEmptyLine = true)
6262
{
6363
var segment = GetSegment (node);
6464
int startOffset = segment.Offset;

0 commit comments

Comments
 (0)