private void InvokedApplyPatches(DiffMessage diffMessage) { string old = Context.Data; // Apply diff to shadow var diffs = DiffMatchPatch.diff_fromDelta(Shadow.Data, diffMessage.Delta); var patches = DiffMatchPatch.patch_make(Shadow.Data, diffs); Shadow.Data = (string)DiffMatchPatch.patch_apply(patches, Shadow.Data)[0]; /* For the real context, we have to perform each operation by hand, so the context can do things like moving around the selection area */ foreach (Patch p in patches) { System.Console.WriteLine(p); } //Console.WriteLine("--"); //Console.WriteLine("Selection was: {0} {1} = '{2}'", Context.SelectionStart, Context.SelectionEnd, Context.SelectedText); //Console.WriteLine("Caret was: {0}", Context.CaretPosition); bool hadSelection = Context.HasSelection; int start = Context.SelectionStart; int end = Context.SelectionEnd; int caret = Context.CaretPosition; // TODO: check whether patches we're applied at all // We restore the offset locations using absolute referencing // See: http://neil.fraser.name/writing/cursor/ foreach (Patch patch in patches) { //Console.WriteLine("Patch = {0} ({1}, {2}, {3}, {4})", patch, patch.start1, patch.start2, patch.length1, patch.length2); int index = patch.start1; //Console.WriteLine("index {0}, start {1}, end {2}, caret {3}", index, start, end, caret); foreach (Diff diff in patch.diffs) { //Console.WriteLine("Diff {0}", diff.ToString()); switch(diff.operation) { case Operation.DELETE: if (start > index) { start -= diff.text.Length; } if (end > index) { end -= diff.text.Length; } if (caret >= index) { caret -= diff.text.Length; } break; case Operation.EQUAL: index += diff.text.Length; break; case Operation.INSERT: if (start >= index) { start += diff.text.Length; } if (end > index) { end += diff.text.Length; } if (caret >= index) { caret += diff.text.Length; } index += diff.text.Length; break; } //Console.WriteLine("index {0}, start {1}, end {2}, caret {3}", index, start, end, caret); } } start = Math.Max(0, start); caret = Math.Max(0, caret); Context.Data = (string)DiffMatchPatch.patch_apply(patches, Context.Data)[0]; end = Math.Min(Context.Data.Length, end); start = Math.Min(Context.Data.Length, start); caret = Math.Min(Context.Data.Length, caret); if (end < start) { end = start; } if (hadSelection) { Context.SetSelection(start, end); } Context.CaretPosition = caret; //Console.WriteLine("Selection is: {0} {1}", start, end); //Console.WriteLine("Caret is: {0}", caret); //Console.WriteLine("Was {0} now {1}", old, Context.Data); // Display remote selection // TODO: when adding support for multiple users, we need to actually provide a real identifier Context.SetRemoteSelection(0, diffMessage.SelectionStart, diffMessage.SelectionEnd); Context.Refresh(); }
private void ApplyPatches(DiffMessage diffMessage) { Debug.Assert(TokenState == TokenState.WaitingForToken); lock(this) { Context.Invoke((Action)delegate { InvokedApplyPatches(diffMessage); }); } }