From b35cfaed20151623d68c477cd9146575640d0877 Mon Sep 17 00:00:00 2001 From: t9md Date: Mon, 15 Jan 2018 17:40:51 +0900 Subject: [PATCH 1/3] Pass selectionsMarkerLayer on transact, undo and redo To restore selections of change initiated editor on undo/redo. --- src/text-editor.js | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/text-editor.js b/src/text-editor.js index 9bfa8ff3e..51470a6b2 100644 --- a/src/text-editor.js +++ b/src/text-editor.js @@ -224,7 +224,7 @@ class TextEditor { this.defaultMarkerLayer = this.displayLayer.addMarkerLayer() if (!this.selectionsMarkerLayer) { - this.selectionsMarkerLayer = this.addMarkerLayer({maintainHistory: true, persistent: true}) + this.selectionsMarkerLayer = this.addMarkerLayer({maintainHistory: true, persistent: true, role: 'selections'}) } this.decorationManager = new DecorationManager(this) @@ -1808,13 +1808,13 @@ class TextEditor { // Essential: Undo the last change. undo () { - this.avoidMergingSelections(() => this.buffer.undo()) + this.avoidMergingSelections(() => this.buffer.undo({selectionsMarkerLayer: this.selectionsMarkerLayer})) this.getLastSelection().autoscroll() } // Essential: Redo the last change. redo () { - this.avoidMergingSelections(() => this.buffer.redo()) + this.avoidMergingSelections(() => this.buffer.redo({selectionsMarkerLayer: this.selectionsMarkerLayer})) this.getLastSelection().autoscroll() } @@ -1831,7 +1831,13 @@ class TextEditor { // still 'groupable', the two transactions are merged with respect to undo and redo. // * `fn` A {Function} to call inside the transaction. transact (groupingInterval, fn) { - return this.buffer.transact(groupingInterval, fn) + const options = {selectionsMarkerLayer: this.selectionsMarkerLayer} + if (typeof groupingInterval === 'function') { + fn = groupingInterval + } else { + options.groupingInterval = groupingInterval + } + return this.buffer.transact(options, fn) } // Extended: Abort an open transaction, undoing any operations performed so far @@ -1842,7 +1848,9 @@ class TextEditor { // with {::revertToCheckpoint} and {::groupChangesSinceCheckpoint}. // // Returns a checkpoint value. - createCheckpoint () { return this.buffer.createCheckpoint() } + createCheckpoint () { + return this.buffer.createCheckpoint({selectionsMarkerLayer: this.selectionsMarkerLayer}) + } // Extended: Revert the buffer to the state it was in when the given // checkpoint was created. @@ -1866,7 +1874,9 @@ class TextEditor { // * `checkpoint` The checkpoint from which to group changes. // // Returns a {Boolean} indicating whether the operation succeeded. - groupChangesSinceCheckpoint (checkpoint) { return this.buffer.groupChangesSinceCheckpoint(checkpoint) } + groupChangesSinceCheckpoint (checkpoint) { + return this.buffer.groupChangesSinceCheckpoint(checkpoint, {selectionsMarkerLayer: this.selectionsMarkerLayer}) + } /* Section: TextEditor Coordinates From f303d5906e3da7f20387947f1154468cdf1455c6 Mon Sep 17 00:00:00 2001 From: t9md Date: Wed, 21 Mar 2018 14:16:14 +0900 Subject: [PATCH 2/3] :white_check_mark: undo/redo restore selection of change-initiated-editor --- spec/text-editor-spec.js | 105 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 69be6be32..491c20dfa 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -5193,6 +5193,111 @@ describe('TextEditor', () => { }) }) + describe('undo/redo restore selections of editor which initiated original change', () => { + let editor1, editor2 + + beforeEach(async () => { + editor1 = editor + editor2 = new TextEditor({buffer: editor1.buffer}) + + editor1.setText(dedent ` + aaaaaa + bbbbbb + cccccc + dddddd + eeeeee + `) + }) + + it('[editor.transact] restore selection of change-initiated-editor', async () => { + editor1.setCursorBufferPosition([0, 0]); editor1.transact(() => editor1.insertText('1')) + editor2.setCursorBufferPosition([1, 0]); editor2.transact(() => editor2.insertText('2')) + editor1.setCursorBufferPosition([2, 0]); editor1.transact(() => editor1.insertText('3')) + editor2.setCursorBufferPosition([3, 0]); editor2.transact(() => editor2.insertText('4')) + + expect(editor1.getText()).toBe(dedent ` + 1aaaaaa + 2bbbbbb + 3cccccc + 4dddddd + eeeeee + `) + + editor2.setCursorBufferPosition([4, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) + expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) + expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + + editor1.setCursorBufferPosition([4, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) + expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) + expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + }) + + it('[manually group checkpoint] restore selection of change-initiated-editor', async () => { + const transact = (editor, fn) => { + const checkpoint = editor.createCheckpoint() + fn() + editor.groupChangesSinceCheckpoint(checkpoint) + } + + editor1.setCursorBufferPosition([0, 0]); transact(editor1, () => editor1.insertText('1')) + editor2.setCursorBufferPosition([1, 0]); transact(editor2, () => editor2.insertText('2')) + editor1.setCursorBufferPosition([2, 0]); transact(editor1, () => editor1.insertText('3')) + editor2.setCursorBufferPosition([3, 0]); transact(editor2, () => editor2.insertText('4')) + + expect(editor1.getText()).toBe(dedent ` + 1aaaaaa + 2bbbbbb + 3cccccc + 4dddddd + eeeeee + `) + + editor2.setCursorBufferPosition([4, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 0]) + editor1.undo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 0]) + expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([0, 1]) + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([1, 1]) + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([2, 1]) + editor1.redo(); expect(editor1.getCursorBufferPosition()).toEqual([3, 1]) + expect(editor2.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + + editor1.setCursorBufferPosition([4, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 0]) + editor2.undo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 0]) + expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([0, 1]) + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([1, 1]) + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([2, 1]) + editor2.redo(); expect(editor2.getCursorBufferPosition()).toEqual([3, 1]) + expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged + }) + }) + describe('when the buffer is changed (via its direct api, rather than via than edit session)', () => { it('moves the cursor so it is in the same relative position of the buffer', () => { expect(editor.getCursorScreenPosition()).toEqual([0, 0]) From 38f080ef07f6f05c652e8e0e58956bbf55f3046e Mon Sep 17 00:00:00 2001 From: t9md Date: Wed, 21 Mar 2018 14:28:38 +0900 Subject: [PATCH 3/3] :fire: unnecessary async --- spec/text-editor-spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/text-editor-spec.js b/spec/text-editor-spec.js index 491c20dfa..815a0e8d4 100644 --- a/spec/text-editor-spec.js +++ b/spec/text-editor-spec.js @@ -5209,7 +5209,7 @@ describe('TextEditor', () => { `) }) - it('[editor.transact] restore selection of change-initiated-editor', async () => { + it('[editor.transact] restore selection of change-initiated-editor', () => { editor1.setCursorBufferPosition([0, 0]); editor1.transact(() => editor1.insertText('1')) editor2.setCursorBufferPosition([1, 0]); editor2.transact(() => editor2.insertText('2')) editor1.setCursorBufferPosition([2, 0]); editor1.transact(() => editor1.insertText('3')) @@ -5250,7 +5250,7 @@ describe('TextEditor', () => { expect(editor1.getCursorBufferPosition()).toEqual([4, 0]) // remain unchanged }) - it('[manually group checkpoint] restore selection of change-initiated-editor', async () => { + it('[manually group checkpoint] restore selection of change-initiated-editor', () => { const transact = (editor, fn) => { const checkpoint = editor.createCheckpoint() fn()