From 27cc953c07252266e25309f28408a3a23c52031f Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 01:08:28 -0800 Subject: [PATCH 01/14] Destroy pending item when new item is activated --- src/pane.coffee | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 412fc5251bd..3b698c44437 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -337,14 +337,18 @@ class Pane extends Model # # * `index` {Number} activateItemAtIndex: (index) -> - @activateItem(@itemAtIndex(index)) + @setActiveItem(@itemAtIndex(index)) # Public: Make the given item *active*, causing it to be displayed by # the pane's view. activateItem: (item) -> if item? - @addItem(item, @getActiveItemIndex() + 1, false) - @setActiveItem(item) + if @activeItem?.isPending() + index = @getActiveItemIndex() + @destroyActiveItem() + else + index = @getActiveItemIndex() + 1 + @addItem(item, index, false) # Public: Add the given item to the pane. # @@ -358,14 +362,16 @@ class Pane extends Model throw new Error("Pane items must be objects. Attempted to add item #{item}.") unless item? and typeof item is 'object' throw new Error("Adding a pane item with URI '#{item.getURI?()}' that has already been destroyed") if item.isDestroyed?() - return if item in @items + if item in @items + @setActiveItem(item) + return if typeof item.onDidDestroy is 'function' @itemSubscriptions.set item, item.onDidDestroy => @removeItem(item, false) @items.splice(index, 0, item) @emitter.emit 'did-add-item', {item, index, moved} - @setActiveItem(item) unless @getActiveItem()? + @setActiveItem(item) item # Public: Add the given items to the pane. From b24250289e81ee2464217d2655597a69fc796b26 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 01:10:42 -0800 Subject: [PATCH 02/14] Add pending status to text editors Add event methods for 'did-confirm-pending-state'. --- src/text-editor.coffee | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 1435aef199b..f769646dc64 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -92,9 +92,10 @@ class TextEditor extends Model softWrapped, @displayBuffer, @selectionsMarkerLayer, buffer, suppressCursorCreation, @mini, @placeholderText, lineNumberGutterVisible, largeFileMode, @config, @notificationManager, @packageManager, @clipboard, @viewRegistry, @grammarRegistry, - @project, @assert, @applicationDelegate + @project, @assert, @applicationDelegate, @pending } = params + throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? throw new Error("Must pass a notificationManager parameter when constructing TextEditors") unless @notificationManager? throw new Error("Must pass a packageManager parameter when constructing TextEditors") unless @packageManager? @@ -161,6 +162,9 @@ class TextEditor extends Model @disposables.add @buffer.onDidChangeEncoding => @emitter.emit 'did-change-encoding', @getEncoding() @disposables.add @buffer.onDidDestroy => @destroy() + if @pending + @disposables.add @buffer.onDidChangeModified => + @confirmPendingState() if @buffer.isModified() @preserveCursorPositionOnBufferReload() @@ -569,6 +573,13 @@ class TextEditor extends Model getEditorWidthInChars: -> @displayBuffer.getEditorWidthInChars() + onDidConfirmPendingState: (callback) -> + @emitter.on 'did-confirm-pending-state', callback + + confirmPendingState: -> + @pending = false + @emitter.emit 'did-confirm-pending-state', this + ### Section: File Details ### @@ -652,6 +663,9 @@ class TextEditor extends Model # Essential: Returns {Boolean} `true` if this editor has no content. isEmpty: -> @buffer.isEmpty() + # Returns {Boolean} `true` if this editor is pending and `false` if it is permanent. + isPending: -> Boolean(@pending) + # Copies the current file path to the native clipboard. copyPathToClipboard: -> if filePath = @getPath() From 219ebea98b08a5f8b7463f3ef5ad81249863a7cb Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 01:31:19 -0800 Subject: [PATCH 03/14] Fix bug in ::activate Item Check if isPending function exists on item before invoking. --- src/pane.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pane.coffee b/src/pane.coffee index 3b698c44437..4e97e8bdc5a 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -343,7 +343,7 @@ class Pane extends Model # the pane's view. activateItem: (item) -> if item? - if @activeItem?.isPending() + if @activeItem?.isPending?() index = @getActiveItemIndex() @destroyActiveItem() else From 4c4e16ac3bd2b1cc7ec2416ead90ae33f769d077 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 12:29:22 -0800 Subject: [PATCH 04/14] Fix bug in ::activateItem Only destroy active item if it is not the same as the new item. --- src/pane.coffee | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 4e97e8bdc5a..b0758f4c433 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -345,7 +345,7 @@ class Pane extends Model if item? if @activeItem?.isPending?() index = @getActiveItemIndex() - @destroyActiveItem() + @destroyActiveItem() unless item is @activeItem else index = @getActiveItemIndex() + 1 @addItem(item, index, false) @@ -580,7 +580,6 @@ class Pane extends Model # Public: Makes this pane the *active* pane, causing it to gain focus. activate: -> throw new Error("Pane has been destroyed") if @isDestroyed() - @container?.setActivePane(this) @emitter.emit 'did-activate' From e26ae05597c5c45726b1b5340a5a3ece418f6234 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 13:34:58 -0800 Subject: [PATCH 05/14] Fix bug in ::activateItemAtIndex Revert to original code to conform to specs. --- src/pane.coffee | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index b0758f4c433..21d74b3d7e9 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -337,7 +337,7 @@ class Pane extends Model # # * `index` {Number} activateItemAtIndex: (index) -> - @setActiveItem(@itemAtIndex(index)) + @activateItem(@itemAtIndex(index)) # Public: Make the given item *active*, causing it to be displayed by # the pane's view. @@ -349,6 +349,7 @@ class Pane extends Model else index = @getActiveItemIndex() + 1 @addItem(item, index, false) + @setActiveItem(item) # Public: Add the given item to the pane. # @@ -362,16 +363,14 @@ class Pane extends Model throw new Error("Pane items must be objects. Attempted to add item #{item}.") unless item? and typeof item is 'object' throw new Error("Adding a pane item with URI '#{item.getURI?()}' that has already been destroyed") if item.isDestroyed?() - if item in @items - @setActiveItem(item) - return + return if item in @items if typeof item.onDidDestroy is 'function' @itemSubscriptions.set item, item.onDidDestroy => @removeItem(item, false) @items.splice(index, 0, item) @emitter.emit 'did-add-item', {item, index, moved} - @setActiveItem(item) + @setActiveItem(item) unless @getActiveItem() item # Public: Add the given items to the pane. From 63b5ddbd9952c7ef10c769de5f7d23fe27d626f1 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 13:58:59 -0800 Subject: [PATCH 06/14] Handle out-of-bound indices for ::activateItemAtIndex --- src/pane.coffee | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pane.coffee b/src/pane.coffee index 21d74b3d7e9..70687227a56 100644 --- a/src/pane.coffee +++ b/src/pane.coffee @@ -337,7 +337,8 @@ class Pane extends Model # # * `index` {Number} activateItemAtIndex: (index) -> - @activateItem(@itemAtIndex(index)) + item = @itemAtIndex(index) or @getActiveItem() + @setActiveItem(item) # Public: Make the given item *active*, causing it to be displayed by # the pane's view. @@ -370,7 +371,7 @@ class Pane extends Model @items.splice(index, 0, item) @emitter.emit 'did-add-item', {item, index, moved} - @setActiveItem(item) unless @getActiveItem() + @setActiveItem(item) unless @getActiveItem()? item # Public: Add the given items to the pane. From cca9ea4b608c9e40cc673372fa438b2de5c6a4f5 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 17:56:18 -0800 Subject: [PATCH 07/14] Rename onDidConfirmPendingState for clarity Now it is called onDidTerminatePendingState. --- src/text-editor.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index f769646dc64..e547342575b 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -164,7 +164,7 @@ class TextEditor extends Model @disposables.add @buffer.onDidDestroy => @destroy() if @pending @disposables.add @buffer.onDidChangeModified => - @confirmPendingState() if @buffer.isModified() + @terminatePendingState() if @buffer.isModified() @preserveCursorPositionOnBufferReload() @@ -573,10 +573,10 @@ class TextEditor extends Model getEditorWidthInChars: -> @displayBuffer.getEditorWidthInChars() - onDidConfirmPendingState: (callback) -> + onDidTerminatePendingState: (callback) -> @emitter.on 'did-confirm-pending-state', callback - confirmPendingState: -> + terminatePendingState: -> @pending = false @emitter.emit 'did-confirm-pending-state', this From fa86d2d1568c326900953b247aae3679e170a07b Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 17:57:08 -0800 Subject: [PATCH 08/14] Add tests for pending status --- spec/text-editor-spec.coffee | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 02d2e4a9666..c51ec41d70f 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5804,3 +5804,20 @@ describe "TextEditor", -> screenRange: marker1.getRange(), rangeIsReversed: false } + + describe "pending state", -> + editor1 = null + beforeEach -> + waitsForPromise -> + atom.workspace.open('sample.txt', pending: true).then (o) -> editor1 = o + + it "should open file in pending state if 'pending' option is true", -> + expect(editor1.isPending()).toBe true + expect(editor.isPending()).toBe false # By default pending status is false + + it "invokes ::onDidTerminatePendingState observers if pending status is removed", -> + events = [] + editor1.onDidTerminatePendingState (event) -> events.push(event) + editor1.terminatePendingState() + expect(editor1.isPending()).toBe false + expect(events).toEqual [editor1] From 7f57b0ada488845675d9bda5d31137ded3866979 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 18:02:07 -0800 Subject: [PATCH 09/14] Change event to 'did-terminate-pending-state' --- src/text-editor.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index e547342575b..55a7b026f5e 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -574,11 +574,11 @@ class TextEditor extends Model @displayBuffer.getEditorWidthInChars() onDidTerminatePendingState: (callback) -> - @emitter.on 'did-confirm-pending-state', callback + @emitter.on 'did-terminate-pending-state', callback terminatePendingState: -> @pending = false - @emitter.emit 'did-confirm-pending-state', this + @emitter.emit 'did-terminate-pending-state', this ### Section: File Details From 217e07530feead0d3295d1577d589e814cc437a0 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 18:43:57 -0800 Subject: [PATCH 10/14] Add test: modified buffer terminates pending state Test not yet passing. ::insertText is not triggering terminatePendingState. Not sure why... --- spec/text-editor-spec.coffee | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index c51ec41d70f..225a1485aae 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5821,3 +5821,11 @@ describe "TextEditor", -> editor1.terminatePendingState() expect(editor1.isPending()).toBe false expect(events).toEqual [editor1] + + it "should terminate pending state when buffer is changed", -> + events = [] + editor1.onDidTerminatePendingState (event) -> events.push(event) + expect(editor1.isPending()).toBe true + editor1.insertText('I\'ll be back!') + expect(editor1.isPending()).toBe false + expect(events).toEqual [editor1] From def62fc6c7849b3b2c705939cee02848d7332432 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Thu, 24 Dec 2015 21:42:00 -0800 Subject: [PATCH 11/14] Fix test: modified buffer terminates pending state --- spec/text-editor-spec.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 225a1485aae..686bb6868ae 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5827,5 +5827,6 @@ describe "TextEditor", -> editor1.onDidTerminatePendingState (event) -> events.push(event) expect(editor1.isPending()).toBe true editor1.insertText('I\'ll be back!') + advanceClock(500) expect(editor1.isPending()).toBe false expect(events).toEqual [editor1] From 67d49955f136a48cb215a698ab1f06ab3e60d176 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 5 Jan 2016 10:38:13 -0800 Subject: [PATCH 12/14] Add tests for pending pane items --- spec/pane-spec.coffee | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/spec/pane-spec.coffee b/spec/pane-spec.coffee index 36803bde6d0..5c5cd9e9537 100644 --- a/spec/pane-spec.coffee +++ b/spec/pane-spec.coffee @@ -18,6 +18,8 @@ describe "Pane", -> onDidDestroy: (fn) -> @emitter.on('did-destroy', fn) destroy: -> @destroyed = true; @emitter.emit('did-destroy') isDestroyed: -> @destroyed + isPending: -> @pending + pending: false beforeEach -> confirm = spyOn(atom.applicationDelegate, 'confirm') @@ -153,6 +155,26 @@ describe "Pane", -> pane.activateItem(pane.itemAtIndex(1)) expect(observed).toEqual [pane.itemAtIndex(1)] + it "replaces pending items", -> + itemC = new Item("C") + itemD = new Item("D") + itemC.pending = true + itemD.pending = true + + expect(itemC.isPending()).toBe true + pane.activateItem(itemC) + expect(pane.getItems().length).toBe 3 + expect(pane.getActiveItem()).toBe pane.itemAtIndex(1) + + expect(itemD.isPending()).toBe true + pane.activateItem(itemD) + expect(pane.getItems().length).toBe 3 + expect(pane.getActiveItem()).toBe pane.itemAtIndex(1) + + pane.activateItem(pane.itemAtIndex(2)) + expect(pane.getItems().length).toBe 2 + expect(pane.getActiveItem()).toBe pane.itemAtIndex(1) + describe "::activateNextItem() and ::activatePreviousItem()", -> it "sets the active item to the next/previous item, looping around at either end", -> pane = new Pane(paneParams(items: [new Item("A"), new Item("B"), new Item("C")])) From cee41a2fb0c513c92fc6f056d6ad87f28d951a73 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Tue, 5 Jan 2016 10:42:07 -0800 Subject: [PATCH 13/14] Remove new line --- src/text-editor.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/text-editor.coffee b/src/text-editor.coffee index 55a7b026f5e..7410f8209ed 100644 --- a/src/text-editor.coffee +++ b/src/text-editor.coffee @@ -95,7 +95,6 @@ class TextEditor extends Model @project, @assert, @applicationDelegate, @pending } = params - throw new Error("Must pass a config parameter when constructing TextEditors") unless @config? throw new Error("Must pass a notificationManager parameter when constructing TextEditors") unless @notificationManager? throw new Error("Must pass a packageManager parameter when constructing TextEditors") unless @packageManager? From 5738b14eda476e90c85aaf67128df5baf7cbff23 Mon Sep 17 00:00:00 2001 From: Katrina Uychaco Date: Fri, 8 Jan 2016 13:39:46 -0800 Subject: [PATCH 14/14] :art: --- spec/text-editor-spec.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/text-editor-spec.coffee b/spec/text-editor-spec.coffee index 686bb6868ae..ce84d2c50d7 100644 --- a/spec/text-editor-spec.coffee +++ b/spec/text-editor-spec.coffee @@ -5815,7 +5815,7 @@ describe "TextEditor", -> expect(editor1.isPending()).toBe true expect(editor.isPending()).toBe false # By default pending status is false - it "invokes ::onDidTerminatePendingState observers if pending status is removed", -> + it "invokes ::onDidTerminatePendingState observers if pending status is terminated", -> events = [] editor1.onDidTerminatePendingState (event) -> events.push(event) editor1.terminatePendingState()