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:
parent
3a104fe061
commit
1b8f6238c2
5 changed files with 84 additions and 27 deletions
|
|
@ -5,7 +5,8 @@ CommandError = require './command-error'
|
|||
|
||||
class Command
|
||||
constructor: (@editor, @exState) ->
|
||||
@viewModel = new ExViewModel(@)
|
||||
@selections = @exState.getSelections()
|
||||
@viewModel = new ExViewModel(@, Object.keys(@selections).length > 0)
|
||||
|
||||
parseAddr: (str, curPos) ->
|
||||
if str is '.'
|
||||
|
|
@ -97,6 +98,13 @@ class Command
|
|||
|
||||
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?
|
||||
address1 = @parseAddr(addr1, curPos)
|
||||
else
|
||||
|
|
@ -149,9 +157,7 @@ class Command
|
|||
[m, command, args] = cl.match(/^(\w+)(.*)/)
|
||||
|
||||
# If the command matches an existing one exactly, execute that one
|
||||
if (func = Ex.singleton()[command])?
|
||||
func({ range, args, @vimState, @exState, @editor })
|
||||
else
|
||||
unless (func = Ex.singleton()[command])?
|
||||
# Step 8: Match command against existing commands
|
||||
matching = (name for name, val of Ex.singleton() when \
|
||||
name.indexOf(command) is 0)
|
||||
|
|
@ -161,7 +167,14 @@ class Command
|
|||
command = matching[0]
|
||||
|
||||
func = Ex.singleton()[command]
|
||||
|
||||
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 })
|
||||
else
|
||||
throw new CommandError("Not an editor command: #{input.characters}")
|
||||
|
|
|
|||
|
|
@ -60,4 +60,13 @@ class ExState
|
|||
@clearOpStack()
|
||||
@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
|
||||
|
|
|
|||
|
|
@ -4,10 +4,13 @@ Ex = require './ex'
|
|||
|
||||
module.exports =
|
||||
class ExViewModel extends ViewModel
|
||||
constructor: (@exCommand) ->
|
||||
constructor: (@exCommand, withSelection) ->
|
||||
super(@exCommand, class: 'command')
|
||||
@historyIndex = -1
|
||||
|
||||
if withSelection
|
||||
@view.editorElement.getModel().setText("'<,'>")
|
||||
|
||||
@view.editorElement.addEventListener('keydown', @tabAutocomplete)
|
||||
atom.commands.add(@view.editorElement, 'core:move-up', @increaseHistoryEx)
|
||||
atom.commands.add(@view.editorElement, 'core:move-down', @decreaseHistoryEx)
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ describe "the commands", ->
|
|||
|
||||
helpers.getEditorElement (element) ->
|
||||
atom.commands.dispatch(element, "ex-mode:open")
|
||||
keydown('escape')
|
||||
atom.commands.dispatch(element.getModel().normalModeInputView.editorElement,
|
||||
"core:cancel")
|
||||
editorElement = element
|
||||
editor = editorElement.getModel()
|
||||
vimState = vimMode.mainModule.getEditorState(editor)
|
||||
|
|
@ -848,3 +849,25 @@ describe "the commands", ->
|
|||
WArgs = Ex.W.calls[0].args[0]
|
||||
writeArgs = Ex.write.calls[0].args[0]
|
||||
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]
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ describe "the input element", ->
|
|||
expect(getVisibility()).toBe true
|
||||
commandEditor = getCommandEditor()
|
||||
model = commandEditor.getModel()
|
||||
expect(model.getText()).toBe ''
|
||||
model.setText('abc')
|
||||
atom.commands.dispatch(commandEditor, "core:backspace")
|
||||
expect(getVisibility()).toBe true
|
||||
|
|
@ -82,3 +83,11 @@ describe "the input element", ->
|
|||
expect(model.getText()).toBe ''
|
||||
atom.commands.dispatch(commandEditor, "core:backspace")
|
||||
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 "'<,'>"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue