From 330e9cebd95ad23a2b642d7025a93e8a5876c5d0 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 17 Jul 2012 12:02:45 -0600 Subject: [PATCH] Make it possible for command compilation to be async by returning promises --- .../command-interpreter-spec.coffee | 336 +++++++++++------- .../command-panel/commands/address.coffee | 5 +- .../commands/composite-command.coffee | 29 +- .../commands/select-all-matches.coffee | 5 +- .../commands/substitution.coffee | 5 +- 5 files changed, 231 insertions(+), 149 deletions(-) diff --git a/spec/extensions/command-interpreter-spec.coffee b/spec/extensions/command-interpreter-spec.coffee index c961838e2..adfadc261 100644 --- a/spec/extensions/command-interpreter-spec.coffee +++ b/spec/extensions/command-interpreter-spec.coffee @@ -21,45 +21,59 @@ describe "CommandInterpreter", -> describe "a line address", -> it "selects the specified line", -> - interpreter.eval('4', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [4, 0]] + waitsForPromise -> interpreter.eval('4', editSession) + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [4, 0]] describe "0", -> it "selects the zero-length string at the start of the file", -> - interpreter.eval('0', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [0,0]] + waitsForPromise -> interpreter.eval('0', editSession) + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [0,0]] - interpreter.eval('0,1', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [1,0]] + interpreter.eval('0,1', editSession) + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [1,0]] describe "$", -> it "selects EOF", -> - interpreter.eval('$', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[12,2], [12,2]] + waitsForPromise -> interpreter.eval('$', editSession) + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[12,2], [12,2]] - interpreter.eval('1,$', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [12,2]] + waitsForPromise -> interpreter.eval('1,$', editSession) + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [12,2]] describe ".", -> describe "when a single selection", -> it 'maintains the current selection', -> editSession.clearSelections() - editSession.setSelectedBufferRange([[1,1], [2,2]]) - interpreter.eval('.', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[1,1], [2,2]] - editSession.setSelectedBufferRange([[1,1], [2,2]]) - interpreter.eval('.,', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[1,1], [12,2]] + waitsForPromise -> + editSession.setSelectedBufferRange([[1,1], [2,2]]) + interpreter.eval('.', editSession) - editSession.setSelectedBufferRange([[1,1], [2,2]]) - interpreter.eval(',.', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [2,2]] + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[1,1], [2,2]] + + waitsForPromise -> + editSession.setSelectedBufferRange([[1,1], [2,2]]) + interpreter.eval('.,', editSession) + + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[1,1], [12,2]] + + waitsForPromise -> + editSession.setSelectedBufferRange([[1,1], [2,2]]) + interpreter.eval(',.', editSession) + + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[0,0], [2,2]] describe "with multiple selections", -> it "maintains the current selections", -> @@ -67,179 +81,225 @@ describe "CommandInterpreter", -> expect(preSelections.length).toBe 3 [preRange1, preRange2, preRange3] = preSelections.map (s) -> s.getScreenRange() - interpreter.eval('.', editSession) + waitsForPromise -> interpreter.eval('.', editSession) - selections = editSession.getSelections() - expect(selections.length).toBe 3 - [selection1, selection2, selection3] = selections - expect(selection1.getScreenRange()).toEqual preRange1 - expect(selection2.getScreenRange()).toEqual preRange2 - expect(selection3.getScreenRange()).toEqual preRange3 + runs -> + selections = editSession.getSelections() + expect(selections.length).toBe 3 + [selection1, selection2, selection3] = selections + expect(selection1.getScreenRange()).toEqual preRange1 + expect(selection2.getScreenRange()).toEqual preRange2 + expect(selection3.getScreenRange()).toEqual preRange3 describe "/regex/", -> beforeEach -> editSession.clearSelections() it 'selects text matching regex after current selection', -> - editSession.setSelectedBufferRange([[4,16], [4,20]]) - interpreter.eval('/pivot/', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[6,16], [6,21]] + waitsForPromise -> + editSession.setSelectedBufferRange([[4,16], [4,20]]) + interpreter.eval('/pivot/', editSession) + + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[6,16], [6,21]] it 'does not require the trailing slash', -> - editSession.setSelectedBufferRange([[4,16], [4,20]]) - interpreter.eval('/pivot', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[6,16], [6,21]] + waitsForPromise -> + editSession.setSelectedBufferRange([[4,16], [4,20]]) + interpreter.eval('/pivot', editSession) + + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[6,16], [6,21]] it "searches from the end of each selection in the buffer", -> - editSession.clearSelections() - editSession.setSelectedBufferRange([[4,16], [4,20]]) - editSession.addSelectionForBufferRange([[1,16], [2,20]]) - expect(editSession.getSelections().length).toBe 2 - interpreter.eval('/pivot', editSession) - selections = editSession.getSelections() - expect(selections.length).toBe 2 - expect(selections[0].getBufferRange()).toEqual [[3,8], [3,13]] - expect(selections[1].getBufferRange()).toEqual [[6,16], [6,21]] + waitsForPromise -> + editSession.clearSelections() + editSession.setSelectedBufferRange([[4,16], [4,20]]) + editSession.addSelectionForBufferRange([[1,16], [2,20]]) + expect(editSession.getSelections().length).toBe 2 + interpreter.eval('/pivot', editSession) + + runs -> + selections = editSession.getSelections() + expect(selections.length).toBe 2 + expect(selections[0].getBufferRange()).toEqual [[3,8], [3,13]] + expect(selections[1].getBufferRange()).toEqual [[6,16], [6,21]] it "wraps around to the beginning of the buffer, but doesn't infinitely loop if no matches are found", -> - editSession.setSelectedBufferRange([[10, 0], [10,3]]) - interpreter.eval('/pivot', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] + waitsForPromise -> + editSession.setSelectedBufferRange([[10, 0], [10,3]]) + interpreter.eval('/pivot', editSession) - interpreter.eval('/mike tyson', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] + + waitsForPromise -> + interpreter.eval('/mike tyson', editSession) + + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] it "searches in reverse when prefixed with a -", -> - editSession.setSelectedBufferRange([[6, 16], [6, 22]]) - interpreter.eval('-/pivot', editSession) - expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] + waitsForPromise -> + editSession.setSelectedBufferRange([[6, 16], [6, 22]]) + interpreter.eval('-/pivot', editSession) + + runs -> + expect(editSession.getSelection().getBufferRange()).toEqual [[3,8], [3,13]] describe "address range", -> describe "when two addresses are specified", -> it "selects from the begining of the left address to the end of the right address", -> - interpreter.eval('4,7', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [7, 0]] + waitsForPromise -> interpreter.eval('4,7', editSession) + + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [7, 0]] describe "when the left address is unspecified", -> it "selects from the begining of buffer to the end of the right address", -> - interpreter.eval(',7', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0, 0], [7, 0]] + waitsForPromise -> interpreter.eval(',7', editSession) + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[0, 0], [7, 0]] describe "when the right address is unspecified", -> it "selects from the begining of left address to the end file", -> - interpreter.eval('4,', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [12, 2]] + waitsForPromise -> interpreter.eval('4,', editSession) + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[3, 0], [12, 2]] describe "when the neither address is specified", -> it "selects the entire file", -> - interpreter.eval(',', editSession) - expect(editSession.getSelections().length).toBe 1 - expect(editSession.getSelection().getBufferRange()).toEqual [[0, 0], [12, 2]] + waitsForPromise -> interpreter.eval(',', editSession) + runs -> + expect(editSession.getSelections().length).toBe 1 + expect(editSession.getSelection().getBufferRange()).toEqual [[0, 0], [12, 2]] describe "x/regex/", -> it "sets the current selection to every match of the regex in the current selection", -> - interpreter.eval('6,7 x/current/', editSession) + waitsForPromise -> interpreter.eval('6,7 x/current/', editSession) - selections = editSession.getSelections() - expect(selections.length).toBe 4 + runs -> + selections = editSession.getSelections() + expect(selections.length).toBe 4 - expect(selections[0].getBufferRange()).toEqual [[5,6], [5,13]] - expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]] - expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]] - expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]] + expect(selections[0].getBufferRange()).toEqual [[5,6], [5,13]] + expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]] + expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]] + expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]] describe "when matching /$/", -> it "matches the end of each line in the selected region", -> - interpreter.eval('6,8 x/$/', editSession) + waitsForPromise -> interpreter.eval('6,8 x/$/', editSession) - cursors = editSession.getCursors() - expect(cursors.length).toBe 3 + runs -> + cursors = editSession.getCursors() + expect(cursors.length).toBe 3 - expect(cursors[0].getBufferPosition()).toEqual [5, 30] - expect(cursors[1].getBufferPosition()).toEqual [6, 65] - expect(cursors[2].getBufferPosition()).toEqual [7, 5] + expect(cursors[0].getBufferPosition()).toEqual [5, 30] + expect(cursors[1].getBufferPosition()).toEqual [6, 65] + expect(cursors[2].getBufferPosition()).toEqual [7, 5] it "loops through current selections and selects text matching the regex", -> - editSession.setSelectedBufferRange [[3,0], [3,62]] - editSession.addSelectionForBufferRange [[6,0], [6,65]] + waitsForPromise -> + editSession.setSelectedBufferRange [[3,0], [3,62]] + editSession.addSelectionForBufferRange [[6,0], [6,65]] + interpreter.eval('x/current', editSession) - interpreter.eval('x/current', editSession) + runs -> + selections = editSession.getSelections() + expect(selections.length).toBe 4 - selections = editSession.getSelections() - expect(selections.length).toBe 4 - - expect(selections[0].getBufferRange()).toEqual [[3,31], [3,38]] - expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]] - expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]] - expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]] + expect(selections[0].getBufferRange()).toEqual [[3,31], [3,38]] + expect(selections[1].getBufferRange()).toEqual [[6,6], [6,13]] + expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]] + expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]] describe "substitution", -> it "does nothing if there are no matches", -> - editSession.setSelectedBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/not-in-text/foo/', editSession) - expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);' + waitsForPromise -> + editSession.setSelectedBufferRange([[6, 0], [6, 44]]) + interpreter.eval('s/not-in-text/foo/', editSession) + + runs -> + expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);' describe "when not global", -> describe "when there is a single selection", -> it "performs a single substitution within the current selection", -> - editSession.setSelectedBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/current/foo/', editSession) - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);' + waitsForPromise -> + editSession.setSelectedBufferRange([[6, 0], [6, 44]]) + interpreter.eval('s/current/foo/', editSession) + runs -> + expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);' describe "when there are multiple selections", -> it "performs a single substitutions within each of the selections", -> - editSession.setSelectedBufferRange([[5, 0], [5, 20]]) - editSession.addSelectionForBufferRange([[6, 0], [6, 44]]) + waitsForPromise -> + editSession.setSelectedBufferRange([[5, 0], [5, 20]]) + editSession.addSelectionForBufferRange([[6, 0], [6, 44]]) + interpreter.eval('s/current/foo/', editSession) - interpreter.eval('s/current/foo/', editSession) - expect(buffer.lineForRow(5)).toBe ' foo = items.shift();' - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);' + runs -> + expect(buffer.lineForRow(5)).toBe ' foo = items.shift();' + expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(current) : right.push(current);' describe "when global", -> it "performs a multiple substitutions within the current selection", -> - editSession.setSelectedBufferRange([[6, 0], [6, 44]]) - interpreter.eval('s/current/foo/g', editSession) - expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' - - describe "when prefixed with an address", -> - it "only makes substitutions within given lines", -> - interpreter.eval('4,6s/ /!/g', editSession) - expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;' - expect(buffer.lineForRow(3)).toBe '!!!!var!pivot!=!items.shift(),!current,!left!=![],!right!=![];' - expect(buffer.lineForRow(4)).toBe '!!!!while(items.length!>!0)!{' - expect(buffer.lineForRow(5)).toBe '!!!!!!current!=!items.shift();' - expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);' - - describe "when matching $", -> - it "matches the end of each line and avoids infinitely looping on a zero-width match", -> - interpreter.eval(',s/$/!!!/g', editSession) - expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {!!!' - expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;!!!' - expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);!!!' - expect(buffer.lineForRow(12)).toBe '};!!!' - - describe "when matching ^", -> - it "matches the beginning of each line and avoids infinitely looping on a zero-width match", -> - interpreter.eval(',s/^/!!!/g', editSession) - expect(buffer.lineForRow(0)).toBe '!!!var quicksort = function () {' - expect(buffer.lineForRow(2)).toBe '!!! if (items.length <= 1) return items;' - expect(buffer.lineForRow(6)).toBe '!!! current < pivot ? left.push(current) : right.push(current);' - expect(buffer.lineForRow(12)).toBe '!!!};' - - describe "when there are multiple selections", -> - it "performs a multiple substitutions within each of the selections", -> - editSession.setSelectedBufferRange([[5, 0], [5, 20]]) - editSession.addSelectionForBufferRange([[6, 0], [6, 44]]) - + waitsForPromise -> + editSession.setSelectedBufferRange([[6, 0], [6, 44]]) interpreter.eval('s/current/foo/g', editSession) - expect(buffer.lineForRow(5)).toBe ' foo = items.shift();' + + runs -> expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' + describe "when prefixed with an address", -> + it "only makes substitutions within given lines", -> + waitsForPromise -> interpreter.eval('4,6s/ /!/g', editSession) + + runs -> + expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;' + expect(buffer.lineForRow(3)).toBe '!!!!var!pivot!=!items.shift(),!current,!left!=![],!right!=![];' + expect(buffer.lineForRow(4)).toBe '!!!!while(items.length!>!0)!{' + expect(buffer.lineForRow(5)).toBe '!!!!!!current!=!items.shift();' + expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);' + + describe "when matching $", -> + it "matches the end of each line and avoids infinitely looping on a zero-width match", -> + waitsForPromise -> interpreter.eval(',s/$/!!!/g', editSession) + runs -> + expect(buffer.lineForRow(0)).toBe 'var quicksort = function () {!!!' + expect(buffer.lineForRow(2)).toBe ' if (items.length <= 1) return items;!!!' + expect(buffer.lineForRow(6)).toBe ' current < pivot ? left.push(current) : right.push(current);!!!' + expect(buffer.lineForRow(12)).toBe '};!!!' + + describe "when matching ^", -> + it "matches the beginning of each line and avoids infinitely looping on a zero-width match", -> + waitsForPromise -> interpreter.eval(',s/^/!!!/g', editSession) + runs -> + expect(buffer.lineForRow(0)).toBe '!!!var quicksort = function () {' + expect(buffer.lineForRow(2)).toBe '!!! if (items.length <= 1) return items;' + expect(buffer.lineForRow(6)).toBe '!!! current < pivot ? left.push(current) : right.push(current);' + expect(buffer.lineForRow(12)).toBe '!!!};' + + describe "when there are multiple selections", -> + it "performs a multiple substitutions within each of the selections", -> + waitsForPromise -> + editSession.setSelectedBufferRange([[5, 0], [5, 20]]) + editSession.addSelectionForBufferRange([[6, 0], [6, 44]]) + interpreter.eval('s/current/foo/g', editSession) + + runs -> + expect(buffer.lineForRow(5)).toBe ' foo = items.shift();' + expect(buffer.lineForRow(6)).toBe ' foo < pivot ? left.push(foo) : right.push(current);' + describe "when prefixed with an address", -> it "restores the original selections upon completion if it is the last command", -> - editSession.setSelectedBufferRanges([[[5, 0], [5, 20]], [[6, 0], [6, 44]]]) - interpreter.eval(',s/current/foo/g', editSession) - expect(editSession.getSelectedBufferRanges()).toEqual [[[5, 0], [5, 16]], [[6, 0], [6, 36]]] + waitsForPromise -> + editSession.setSelectedBufferRanges([[[5, 0], [5, 20]], [[6, 0], [6, 44]]]) + interpreter.eval(',s/current/foo/g', editSession) + + runs -> + expect(editSession.getSelectedBufferRanges()).toEqual [[[5, 0], [5, 16]], [[6, 0], [6, 36]]] diff --git a/src/extensions/command-panel/commands/address.coffee b/src/extensions/command-panel/commands/address.coffee index 7949a379d..9f3a7af5f 100644 --- a/src/extensions/command-panel/commands/address.coffee +++ b/src/extensions/command-panel/commands/address.coffee @@ -1,10 +1,13 @@ Command = require 'command-panel/commands/command' Operation = require 'command-panel/operation' +$ = require 'jquery' module.exports = class Address extends Command compile: (project, buffer, ranges) -> - ranges.map (range) => + deferred = $.Deferred() + deferred.resolve ranges.map (range) => new Operation(buffer: buffer, bufferRange: @getRange(buffer, range)) + deferred.promise() isAddress: -> true diff --git a/src/extensions/command-panel/commands/composite-command.coffee b/src/extensions/command-panel/commands/composite-command.coffee index b6a10c37f..6569e2828 100644 --- a/src/extensions/command-panel/commands/composite-command.coffee +++ b/src/extensions/command-panel/commands/composite-command.coffee @@ -1,4 +1,5 @@ _ = require 'underscore' +$ = require 'jquery' module.exports = class CompositeCommand @@ -6,15 +7,27 @@ class CompositeCommand execute: (project, editSession) -> currentRanges = editSession.getSelectedBufferRanges() - for command in @subcommands - operations?.forEach (o) -> o.destroy() - operations = command.compile(project, editSession.buffer, currentRanges) - currentRanges = operations.map (o) -> o.getBufferRange() + @executeCommands(@subcommands, project, editSession, currentRanges) - editSession.clearAllSelections() unless command.preserveSelections - for operation in operations - operation.execute(editSession) - operation.destroy() + executeCommands: (commands, project, editSession, ranges) -> + deferred = $.Deferred() + [currentCommand, remainingCommands...] = commands + + currentCommand.compile(project, editSession.buffer, ranges).done (operations) => + if remainingCommands.length + nextRanges = operations.map (operation) -> + operation.destroy() + operation.getBufferRange() + @executeCommands(remainingCommands, project, editSession, nextRanges).done -> + deferred.resolve() + else + editSession.clearAllSelections() unless currentCommand.preserveSelections + for operation in operations + operation.execute(editSession) + operation.destroy() + deferred.resolve() + + deferred.promise() reverse: -> new CompositeCommand(@subcommands.map (command) -> command.reverse()) diff --git a/src/extensions/command-panel/commands/select-all-matches.coffee b/src/extensions/command-panel/commands/select-all-matches.coffee index eb828f0ac..f9d490bd7 100644 --- a/src/extensions/command-panel/commands/select-all-matches.coffee +++ b/src/extensions/command-panel/commands/select-all-matches.coffee @@ -1,5 +1,6 @@ Command = require 'command-panel/commands/command' Operation = require 'command-panel/operation' +$ = require 'jquery' module.exports = class SelectAllMatches extends Command @@ -9,8 +10,10 @@ class SelectAllMatches extends Command @regex = new RegExp(pattern, 'g') compile: (project, buffer, ranges) -> + deferred = $.Deferred() operations = [] for range in ranges buffer.scanInRange @regex, range, (match, matchRange) -> operations.push(new Operation(buffer: buffer, bufferRange: matchRange)) - operations + deferred.resolve(operations) + deferred.promise() diff --git a/src/extensions/command-panel/commands/substitution.coffee b/src/extensions/command-panel/commands/substitution.coffee index 046beda20..d96aaa762 100644 --- a/src/extensions/command-panel/commands/substitution.coffee +++ b/src/extensions/command-panel/commands/substitution.coffee @@ -1,5 +1,6 @@ Command = require 'command-panel/commands/command' Operation = require 'command-panel/operation' +$ = require 'jquery' module.exports = class Substitution extends Command @@ -12,6 +13,7 @@ class Substitution extends Command @regex = new RegExp(pattern, options.join('')) compile: (project, buffer, ranges) -> + deferred = $.Deferred() operations = [] for range in ranges buffer.scanInRange @regex, range, (match, matchRange, { replace }) => @@ -21,4 +23,5 @@ class Substitution extends Command newText: @replacementText preserveSelection: true )) - operations + deferred.resolve(operations) + deferred.promise()