Add basic support for visual marks < and >

Only works with range '<,'>. If there are multiple selections, run the
command for each one.

Closes #31.
This commit is contained in:
jazzpi 2016-08-15 21:13:32 +02:00
parent 3a104fe061
commit 1b8f6238c2
5 changed files with 84 additions and 27 deletions

View file

@ -5,7 +5,8 @@ CommandError = require './command-error'
class Command class Command
constructor: (@editor, @exState) -> constructor: (@editor, @exState) ->
@viewModel = new ExViewModel(@) @selections = @exState.getSelections()
@viewModel = new ExViewModel(@, Object.keys(@selections).length > 0)
parseAddr: (str, curPos) -> parseAddr: (str, curPos) ->
if str is '.' if str is '.'
@ -97,6 +98,13 @@ class Command
curPos = @editor.getCursorBufferPosition() curPos = @editor.getCursorBufferPosition()
# Special case: run command on selection. This can't be handled by simply
# parsing the mark since vim-mode doesn't set it (and it would be fairly
# useless with multiple selections)
if addr1 is "'<" and addr2 is "'>"
runOverSelections = true
else
runOverSelections = false
if addr1? if addr1?
address1 = @parseAddr(addr1, curPos) address1 = @parseAddr(addr1, curPos)
else else
@ -149,9 +157,7 @@ class Command
[m, command, args] = cl.match(/^(\w+)(.*)/) [m, command, args] = cl.match(/^(\w+)(.*)/)
# If the command matches an existing one exactly, execute that one # If the command matches an existing one exactly, execute that one
if (func = Ex.singleton()[command])? unless (func = Ex.singleton()[command])?
func({ range, args, @vimState, @exState, @editor })
else
# Step 8: Match command against existing commands # Step 8: Match command against existing commands
matching = (name for name, val of Ex.singleton() when \ matching = (name for name, val of Ex.singleton() when \
name.indexOf(command) is 0) name.indexOf(command) is 0)
@ -161,7 +167,14 @@ class Command
command = matching[0] command = matching[0]
func = Ex.singleton()[command] func = Ex.singleton()[command]
if func? if func?
if runOverSelections
for id, selection of @selections
bufferRange = selection.getBufferRange()
range = [bufferRange.start.row, bufferRange.end.row]
func({ range, args, @vimState, @exState, @editor })
else
func({ range, args, @vimState, @exState, @editor }) func({ range, args, @vimState, @exState, @editor })
else else
throw new CommandError("Not an editor command: #{input.characters}") throw new CommandError("Not an editor command: #{input.characters}")

View file

@ -60,4 +60,13 @@ class ExState
@clearOpStack() @clearOpStack()
@emitter.emit('processed-op-stack') @emitter.emit('processed-op-stack')
# Returns all non-empty selections
getSelections: ->
filtered = {}
for id, selection of @editor.getSelections()
unless selection.isEmpty()
filtered[id] = selection
return filtered
module.exports = ExState module.exports = ExState

View file

@ -4,10 +4,13 @@ Ex = require './ex'
module.exports = module.exports =
class ExViewModel extends ViewModel class ExViewModel extends ViewModel
constructor: (@exCommand) -> constructor: (@exCommand, withSelection) ->
super(@exCommand, class: 'command') super(@exCommand, class: 'command')
@historyIndex = -1 @historyIndex = -1
if withSelection
@view.editorElement.getModel().setText("'<,'>")
@view.editorElement.addEventListener('keydown', @tabAutocomplete) @view.editorElement.addEventListener('keydown', @tabAutocomplete)
atom.commands.add(@view.editorElement, 'core:move-up', @increaseHistoryEx) atom.commands.add(@view.editorElement, 'core:move-up', @increaseHistoryEx)
atom.commands.add(@view.editorElement, 'core:move-down', @decreaseHistoryEx) atom.commands.add(@view.editorElement, 'core:move-down', @decreaseHistoryEx)

View file

@ -36,7 +36,8 @@ describe "the commands", ->
helpers.getEditorElement (element) -> helpers.getEditorElement (element) ->
atom.commands.dispatch(element, "ex-mode:open") atom.commands.dispatch(element, "ex-mode:open")
keydown('escape') atom.commands.dispatch(element.getModel().normalModeInputView.editorElement,
"core:cancel")
editorElement = element editorElement = element
editor = editorElement.getModel() editor = editorElement.getModel()
vimState = vimMode.mainModule.getEditorState(editor) vimState = vimMode.mainModule.getEditorState(editor)
@ -848,3 +849,25 @@ describe "the commands", ->
WArgs = Ex.W.calls[0].args[0] WArgs = Ex.W.calls[0].args[0]
writeArgs = Ex.write.calls[0].args[0] writeArgs = Ex.write.calls[0].args[0]
expect(WArgs).toBe writeArgs expect(WArgs).toBe writeArgs
describe "with selections", ->
it "executes on the selected range", ->
spyOn(Ex, 's')
editor.setCursorBufferPosition([0, 0])
editor.selectToBufferPosition([2, 1])
atom.commands.dispatch(editorElement, 'ex-mode:open')
submitNormalModeInputText("'<,'>s/abc/def")
expect(Ex.s.calls[0].args[0].range).toEqual [0, 2]
it "calls the functions multiple times if there are multiple selections", ->
spyOn(Ex, 's')
editor.setCursorBufferPosition([0, 0])
editor.selectToBufferPosition([2, 1])
editor.addCursorAtBufferPosition([3, 0])
editor.selectToBufferPosition([3, 2])
atom.commands.dispatch(editorElement, 'ex-mode:open')
submitNormalModeInputText("'<,'>s/abc/def")
calls = Ex.s.calls
expect(calls.length).toEqual 2
expect(calls[0].args[0].range).toEqual [0, 2]
expect(calls[1].args[0].range).toEqual [3, 3]

View file

@ -70,6 +70,7 @@ describe "the input element", ->
expect(getVisibility()).toBe true expect(getVisibility()).toBe true
commandEditor = getCommandEditor() commandEditor = getCommandEditor()
model = commandEditor.getModel() model = commandEditor.getModel()
expect(model.getText()).toBe ''
model.setText('abc') model.setText('abc')
atom.commands.dispatch(commandEditor, "core:backspace") atom.commands.dispatch(commandEditor, "core:backspace")
expect(getVisibility()).toBe true expect(getVisibility()).toBe true
@ -82,3 +83,11 @@ describe "the input element", ->
expect(model.getText()).toBe '' expect(model.getText()).toBe ''
atom.commands.dispatch(commandEditor, "core:backspace") atom.commands.dispatch(commandEditor, "core:backspace")
expect(getVisibility()).toBe false expect(getVisibility()).toBe false
it "contains '<,'> when opened while there are selections", ->
editor.setCursorBufferPosition([0, 0])
editor.selectToBufferPosition([0, 1])
editor.addCursorAtBufferPosition([2, 0])
editor.selectToBufferPosition([2, 1])
atom.commands.dispatch(editorElement, "ex-mode:open")
expect(getCommandEditor().getModel().getText()).toBe "'<,'>"