CommandPanel commands have optional error messages

This commit is contained in:
Corey Johnson
2012-11-01 14:38:12 -07:00
parent 837005176c
commit 79a7d35798
7 changed files with 63 additions and 36 deletions

View File

@@ -172,17 +172,21 @@ describe "CommandInterpreter", ->
runs ->
expect(interpreter.lastRelativeAddress.subcommands[0].regex.toString()).toEqual "/a\\Sray/i"
it "is case-sentive when the pattern contains a non-escaped uppercase letters (behavior copied from vim)", ->
waitsForPromise ->
interpreter.eval('/arRay', editSession)
runs ->
expect(interpreter.lastRelativeAddress.subcommands[0].regex.toString()).toEqual "/arRay/"
describe "when no match is found", ->
it "it returns an error messages", ->
errorMessages = null
waitsForPromise ->
interpreter.eval('/garbage!', editSession).done (results) -> { errorMessages } = results
runs ->
expect(errorMessages.length).toBe 1
waitsForPromise ->
interpreter.eval('/Array', editSession)
runs ->
expect(interpreter.lastRelativeAddress.subcommands[0].regex.toString()).toEqual "/Array/"
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", ->
@@ -278,16 +282,6 @@ describe "CommandInterpreter", ->
expect(selections[2].getBufferRange()).toEqual [[6,34], [6,41]]
expect(selections[3].getBufferRange()).toEqual [[6,56], [6,63]]
describe "when nothing is matched", ->
it "preserves the existing selection", ->
previousSelections = null
waitsForPromise ->
previousSelections = editSession.getSelectedBufferRanges()
interpreter.eval(',x/this will match nothing', editSession)
runs ->
expect(editSession.getSelectedBufferRanges()).toEqual previousSelections
describe "substitution", ->
it "does nothing if there are no matches", ->
waitsForPromise ->
@@ -400,13 +394,13 @@ describe "CommandInterpreter", ->
project = new Project(fixturesProject.resolve('dir/'))
interpreter = new CommandInterpreter(project)
operations = null
operationsToPreview = null
waitsForPromise ->
interpreter.eval("X x/a+/").done (ops) -> operations = ops
interpreter.eval("X x/a+/").done (result) -> {operationsToPreview} = result
runs ->
expect(operations.length).toBeGreaterThan 3
for operation in operations
expect(operationsToPreview.length).toBeGreaterThan 3
for operation in operationsToPreview
editSession = project.buildEditSessionForPath(operation.getPath())
editSession.setSelectedBufferRange(operation.execute(editSession))
expect(editSession.getSelectedText()).toMatch /a+/
@@ -414,3 +408,14 @@ describe "CommandInterpreter", ->
operation.destroy()
editSession = null
describe "nested commands", ->
describe "/regex/ /regex", ->
it "returns an error message if the last regex has no matches", ->
previousSelections = null
errorMessages = null
waitsForPromise ->
previousSelections = editSession.getSelectedBufferRanges()
interpreter.eval('/sort/ /no match', editSession).done (results) -> { errorMessages } = results
runs ->
expect(errorMessages.length).toBe 1

View File

@@ -35,6 +35,7 @@ class CommandPanel extends View
@content: (rootView) ->
@div class: 'command-panel tool-panel', =>
@subview 'previewList', new PreviewList(rootView)
@ul class: 'errorMessages', outlet: 'errorMessages'
@div class: 'prompt-and-editor', =>
@div ':', class: 'prompt', outlet: 'prompt'
@subview 'miniEditor', new Editor(mini: true)
@@ -107,7 +108,7 @@ class CommandPanel extends View
execute: (command=@escapedCommand())->
try
@commandInterpreter.eval(command, @rootView.getActiveEditSession()).done (operationsToPreview) =>
@commandInterpreter.eval(command, @rootView.getActiveEditSession()).done ({operationsToPreview, errorMessages}) =>
@history.push(command)
@historyIndex = @history.length
if operationsToPreview?.length

View File

@@ -7,10 +7,13 @@ class Address extends Command
compile: (project, buffer, ranges) ->
deferred = $.Deferred()
deferred.resolve ranges.map (range) =>
newRange = @getRange(buffer, range)
new Operation
project: project
buffer: buffer
bufferRange: @getRange(buffer, range)
bufferRange: newRange
errorMessage: @errorMessage
deferred.promise()

View File

@@ -3,5 +3,7 @@ _ = require 'underscore'
module.exports =
class Command
isAddress: -> false
errorMessage: null
preserveSelections: false
previewOperations: false

View File

@@ -15,26 +15,37 @@ class CompositeCommand
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()
errorMessages = @errorMessagesForOperations(operations)
nextRanges = operations.map (operation) -> operation.getBufferRange()
operations.forEach (operation) -> operation.destroy()
@executeCommands(remainingCommands, project, editSession, nextRanges).done ({errorMessages: moreErrorMessages})->
errorMessages.push(moreErrorMessages...) if moreErrorMessages
deferred.resolve({errorMessages})
else
errorMessages = @errorMessagesForOperations(operations)
if currentCommand.previewOperations
deferred.resolve(operations)
deferred.resolve({operationsToPreview: operations, errorMessages})
else
bufferRanges = []
errorMessages = @errorMessagesForOperations(operations)
for operation in operations
bufferRange = operation.execute(editSession)
bufferRanges.push(bufferRange) if bufferRange
operation.destroy()
if bufferRanges.length and not currentCommand.preserveSelections
editSession.setSelectedBufferRanges(bufferRanges)
deferred.resolve()
if bufferRanges.length and not currentCommand.preserveSelections
editSession.setSelectedBufferRanges(bufferRanges)
deferred.resolve({errorMessages})
deferred.promise()
errorMessagesForOperations: (operations) ->
operationsWithErrorMessages = operations.filter (operation) -> operation.errorMessage?
operationsWithErrorMessages.map (operation) -> operation.errorMessage
reverse: ->
new CompositeCommand(@subcommands.map (command) -> command.reverse())

View File

@@ -6,7 +6,7 @@ class RegexAddress extends Address
regex: null
reverse: null
constructor: (pattern, isReversed, options) ->
constructor: (@pattern, isReversed, options) ->
flags = ""
pattern = pattern.source if pattern.source
@@ -27,14 +27,19 @@ class RegexAddress extends Address
buffer[scanMethodName] @regex, rangeToSearch, (match, range) ->
rangeToReturn = range
if rangeToReturn
rangeToReturn
else
if not rangeToReturn
rangeToSearch = if @isReversed then rangeAfter else rangeBefore
buffer[scanMethodName] @regex, rangeToSearch, (match, range) ->
rangeToReturn = range
rangeToReturn or range
if not rangeToReturn
flags = ""
flags += "i" if @regex.ignoreCase
flags += "g" if @regex.global
flags += "m" if @regex.multiline
@errorMessage = "Pattern not found /#{@regex.source}/#{flags}"
rangeToReturn or range
isRelative: -> true

View File

@@ -2,7 +2,7 @@
module.exports =
class Operation
constructor: ({@project, @buffer, bufferRange, @newText, @preserveSelection}) ->
constructor: ({@project, @buffer, bufferRange, @newText, @preserveSelection, @errorMessage}) ->
@buffer.retain()
@anchorRange = @buffer.addAnchorRange(bufferRange)