1 _ = require 'underscore-plus'
2 {CompositeDisposable} = require 'atom'
12 prefix: 'vim-mode-visual-block'
15 @disposables = new CompositeDisposable
16 blockwiseCommands = {}
17 commands = 'jkoDCIA'.split('')
18 commands.push 'escape', 'ctrl-v'
19 for command in commands
21 name = "#{@prefix}:#{command}"
22 blockwiseCommands[name] = (event) => @blockOperation(event, command)
24 # blockwiseCommands["#{@prefix}:toggle-debug"] = => @toggleDebug()
25 @disposables.add atom.commands.add('atom-text-editor', blockwiseCommands)
29 @disposables.dispose()
31 consumeVimMode: (@vimModeService) ->
37 atom.workspace.getActiveTextEditor()
39 isVisualBlockMode: (vimState) ->
40 (vimState.mode is 'visual') and (vimState.submode is 'blockwise')
42 getVimEditorState: (editor) ->
43 @vimModeService.getEditorState editor
45 adjustSelections: (editor, options) ->
46 for selection in editor.getSelections()
47 range = selection.getBufferRange()
48 selection.setBufferRange range, options
50 blockOperation: (event, command) ->
52 vimState = @getVimEditorState editor
54 unless @isVisualBlockMode vimState
55 event.abortKeyBinding()
59 # May be non-continuous execution.
60 if editor.getCursors().length is 1
63 currentRow = editor.getLastCursor()?.getBufferRow()
64 @startRow ?= currentRow
68 @startRow = currentRow
70 vimState.activateNormalMode()
71 event.abortKeyBinding()
72 when 'escape', 'ctrl-v'
73 vimState.activateNormalMode()
74 editor.clearSelections()
76 cursors = editor.getCursorsOrderedByBufferPosition()
77 cursorTop = _.first cursors
78 cursorBottom = _.last cursors
80 if (command is 'j' and cursorTop.getBufferRow() >= @startRow) or
81 (command is 'k' and cursorBottom.getBufferRow() <= @startRow)
82 lastSelection = editor.getLastSelection()
85 editor.addSelectionBelow()
87 editor.addSelectionAbove()
90 # When addSelectionAbove(), addSelectionBelow() doesn't respect
91 # reversed stated, need improved.
95 # When selection is NOT empty and add selection by addSelectionAbove()
96 # and then move right, selection range got wrong, maybe this is bug..
97 @adjustSelections editor, reversed: lastSelection.isReversed()
100 # Guard to not destroying last cursor
101 # This guard is no longer needed
102 # Remove unnecessary code after re-think.
103 if (editor.getCursors().length < 2)
110 cursorBottom.destroy()
114 adjustCursor = (selection) ->
115 {start, end} = selection.getBufferRange()
116 pointEndOfLine = editor.bufferRangeForBufferRow(start.row).end
117 pointTarget = {'I': start, 'A': end}[command]
120 if pointTarget.isGreaterThanOrEqual(pointEndOfLine)
121 pointTarget = pointEndOfLine
122 cursorsAdjusted.push cursor
123 cursor.setBufferPosition(pointTarget)
125 adjustCursor(selection) for selection in editor.getSelections()
126 vimState.activateNormalMode()
127 vimState.activateInsertMode()
129 if command is 'A' and cursorsAdjusted.length
130 cursor.moveRight() for cursor in cursorsAdjusted
132 unless @isVisualBlockMode vimState
136 oldState = atom.config.get("#{@prefix}.debug")
137 atom.config.set("#{@prefix}.debug", not oldState)
138 state = atom.config.get("#{@prefix}.debug") and "enabled" or "disabled"
139 console.log "#{@prefix}: debug #{state}"
142 return unless atom.config.get("#{@prefix}.debug")
146 # @debug "@startRow = #{@startRow}"