Browse Source

fix #282: Pressing Ctrl+Z in InsertWithCursor mode causes InvalidOperationException

pull/297/head
Siegfried Pammer 12 years ago
parent
commit
096c88c954
  1. 87
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Refactoring/EditorScript.cs
  2. 2
      src/Libraries/AvalonEdit/ICSharpCode.AvalonEdit/Document/UndoStack.cs
  3. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Refactoring/DocumentScript.cs

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

@ -114,35 +114,44 @@ namespace CSharpBinding.Refactoring
} }
break; break;
} }
operationsRunning++;
InsertWithCursorOnLayer(this, layer, tcs, nodes, editor.Document); InsertWithCursorOnLayer(this, layer, tcs, nodes, editor.Document);
return tcs.Task; return tcs.Task;
} }
void InsertWithCursorOnLayer(EditorScript currentScript, InsertionCursorLayer layer, TaskCompletionSource<Script> tcs, IList<AstNode> nodes, IDocument target) void InsertWithCursorOnLayer(EditorScript currentScript, InsertionCursorLayer layer, TaskCompletionSource<Script> tcs, IList<AstNode> nodes, IDocument target)
{ {
var doc = target as TextDocument;
var op = new UndoOperation(layer, tcs);
if (doc != null) {
doc.UndoStack.Push(op);
}
layer.Exited += delegate(object s, InsertionCursorEventArgs args) { layer.Exited += delegate(object s, InsertionCursorEventArgs args) {
if (args.Success) { doc.UndoStack.StartContinuedUndoGroup();
if (args.InsertionPoint.LineAfter == NewLineInsertion.None && try {
args.InsertionPoint.LineBefore == NewLineInsertion.None && nodes.Count > 1) { if (args.Success) {
args.InsertionPoint.LineAfter = NewLineInsertion.BlankLine; if (args.InsertionPoint.LineAfter == NewLineInsertion.None &&
} args.InsertionPoint.LineBefore == NewLineInsertion.None && nodes.Count > 1) {
foreach (var node in nodes.Reverse ()) { args.InsertionPoint.LineAfter = NewLineInsertion.BlankLine;
int indentLevel = currentScript.GetIndentLevelAt(target.GetOffset(args.InsertionPoint.Location)); }
var output = currentScript.OutputNode(indentLevel, node); foreach (var node in nodes.Reverse ()) {
var offset = target.GetOffset(args.InsertionPoint.Location); int indentLevel = currentScript.GetIndentLevelAt(target.GetOffset(args.InsertionPoint.Location));
var delta = args.InsertionPoint.Insert(target, output.Text); var output = currentScript.OutputNode(indentLevel, node);
output.RegisterTrackedSegments(currentScript, delta + offset); var offset = target.GetOffset(args.InsertionPoint.Location);
var delta = args.InsertionPoint.Insert(target, output.Text);
output.RegisterTrackedSegments(currentScript, delta + offset);
}
tcs.SetResult(currentScript);
} }
tcs.SetResult(currentScript); layer.Dispose();
DisposeOnClose();
} finally {
doc.UndoStack.EndUndoGroup();
} }
layer.Dispose(); op.Reset();
DisposeOnClose();
}; };
} }
readonly List<Script> startedScripts = new List<Script>(); readonly List<Script> startedScripts = new List<Script>();
int operationsRunning;
public override Task<Script> InsertWithCursor(string operation, ITypeDefinition parentType, Func<Script, RefactoringContext, IList<AstNode>> nodeCallback) public override Task<Script> InsertWithCursor(string operation, ITypeDefinition parentType, Func<Script, RefactoringContext, IList<AstNode>> nodeCallback)
{ {
@ -195,7 +204,6 @@ namespace CSharpBinding.Refactoring
tcs.SetResult(script); tcs.SetResult(script);
return tcs.Task; return tcs.Task;
} }
operationsRunning++;
InsertWithCursorOnLayer(script, layer, tcs, nodes, area.Document); InsertWithCursorOnLayer(script, layer, tcs, nodes, area.Document);
return tcs.Task; return tcs.Task;
} }
@ -205,14 +213,10 @@ namespace CSharpBinding.Refactoring
{ {
if (isDisposed) if (isDisposed)
return; return;
if (force) isDisposed = true;
operationsRunning = 0; base.Dispose();
if (operationsRunning-- == 0) { // refresh parse information so that the issue can disappear immediately
isDisposed = true; SD.ParserService.ParseAsync(editor.FileName, editor.Document).FireAndForget();
base.Dispose ();
// refresh parse information so that the issue can disappear immediately
SD.ParserService.ParseAsync(editor.FileName, editor.Document).FireAndForget();
}
foreach (var script in startedScripts) foreach (var script in startedScripts)
script.Dispose(); script.Dispose();
} }
@ -221,7 +225,38 @@ namespace CSharpBinding.Refactoring
{ {
DisposeOnClose(); DisposeOnClose();
} }
class UndoOperation : IUndoableOperation
{
InsertionCursorLayer layer;
TaskCompletionSource<Script> tcs;
public UndoOperation(InsertionCursorLayer layer, TaskCompletionSource<Script> tcs)
{
this.layer = layer;
this.tcs = tcs;
}
public void Reset()
{
layer = null;
tcs = null;
}
public void Undo()
{
if (layer != null)
layer.Dispose();
layer = null;
if (tcs != null)
tcs.SetCanceled();
tcs = null;
}
public void Redo()
{
}
}
} }
class InsertionCursorLayer : UIElement, IDisposable class InsertionCursorLayer : UIElement, IDisposable

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

@ -193,7 +193,7 @@ namespace ICSharpCode.AvalonEdit.Document
/// </summary> /// </summary>
/// <param name="groupDescriptor">An object that is stored with the undo group. /// <param name="groupDescriptor">An object that is stored with the undo group.
/// If this is not a top-level undo group, the parameter is ignored.</param> /// If this is not a top-level undo group, the parameter is ignored.</param>
public void StartContinuedUndoGroup(object groupDescriptor) public void StartContinuedUndoGroup(object groupDescriptor = null)
{ {
if (undoGroupDepth == 0) { if (undoGroupDepth == 0) {
actionCountInUndoGroup = (allowContinue && undostack.Count > 0) ? 1 : 0; actionCountInUndoGroup = (allowContinue && undostack.Count > 0) ? 1 : 0;

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

@ -58,7 +58,7 @@ namespace ICSharpCode.NRefactory.CSharp.Refactoring
undoGroup.Dispose(); undoGroup.Dispose();
} }
public override void Remove(AstNode node, bool removeEmptyLine) public override void Remove(AstNode node, bool removeEmptyLine = true)
{ {
var segment = GetSegment (node); var segment = GetSegment (node);
int startOffset = segment.Offset; int startOffset = segment.Offset;

Loading…
Cancel
Save