1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
_ = require 'underscore-plus'
{CompositeDisposable} = require 'atom'
Config =
debug:
type: 'boolean'
default: false
module.exports =
disposables: null
active: false
prefix: 'vim-mode-visual-block'
activate: (state) ->
@disposables = new CompositeDisposable
blockwiseCommands = {}
commands = 'jkoDCIA'.split('')
commands.push 'escape', 'ctrl-v'
for command in commands
do (command) =>
name = "#{@prefix}:#{command}"
blockwiseCommands[name] = (event) => @blockOperation(event, command)
# blockwiseCommands["#{@prefix}:toggle-debug"] = => @toggleDebug()
@disposables.add atom.commands.add('atom-text-editor', blockwiseCommands)
@reset()
deactivate: ->
@disposables.dispose()
consumeVimMode: (@vimModeService) ->
reset: ->
@startRow = null
getEditor: ->
atom.workspace.getActiveTextEditor()
isVisualBlockMode: (vimState) ->
(vimState.mode is 'visual') and (vimState.submode is 'blockwise')
getVimEditorState: (editor) ->
@vimModeService.getEditorState editor
adjustSelections: (editor, options) ->
for selection in editor.getSelections()
range = selection.getBufferRange()
selection.setBufferRange range, options
blockOperation: (event, command) ->
editor = @getEditor()
vimState = @getVimEditorState editor
unless @isVisualBlockMode vimState
event.abortKeyBinding()
@reset()
return
# May be non-continuous execution.
if editor.getCursors().length is 1
@reset()
currentRow = editor.getLastCursor()?.getBufferRow()
@startRow ?= currentRow
switch command
when 'o'
@startRow = currentRow
when 'D', 'C'
vimState.activateNormalMode()
event.abortKeyBinding()
when 'escape', 'ctrl-v'
vimState.activateNormalMode()
editor.clearSelections()
when 'j', 'k'
cursors = editor.getCursorsOrderedByBufferPosition()
cursorTop = _.first cursors
cursorBottom = _.last cursors
if (command is 'j' and cursorTop.getBufferRow() >= @startRow) or
(command is 'k' and cursorBottom.getBufferRow() <= @startRow)
lastSelection = editor.getLastSelection()
if command is 'j'
editor.addSelectionBelow()
else
editor.addSelectionAbove()
# [FIXME]
# When addSelectionAbove(), addSelectionBelow() doesn't respect
# reversed stated, need improved.
#
# and one more..
#
# When selection is NOT empty and add selection by addSelectionAbove()
# and then move right, selection range got wrong, maybe this is bug..
@adjustSelections editor, reversed: lastSelection.isReversed()
else
# [FIXME]
# Guard to not destroying last cursor
# This guard is no longer needed
# Remove unnecessary code after re-think.
if (editor.getCursors().length < 2)
@reset()
return
if command is 'j'
cursorTop.destroy()
else
cursorBottom.destroy()
when 'I', 'A'
cursorsAdjusted = []
adjustCursor = (selection) ->
{start, end} = selection.getBufferRange()
pointEndOfLine = editor.bufferRangeForBufferRow(start.row).end
pointTarget = {'I': start, 'A': end}[command]
{cursor} = selection
if pointTarget.isGreaterThanOrEqual(pointEndOfLine)
pointTarget = pointEndOfLine
cursorsAdjusted.push cursor
cursor.setBufferPosition(pointTarget)
adjustCursor(selection) for selection in editor.getSelections()
vimState.activateNormalMode()
vimState.activateInsertMode()
if command is 'A' and cursorsAdjusted.length
cursor.moveRight() for cursor in cursorsAdjusted
unless @isVisualBlockMode vimState
@reset()
toggleDebug: ->
oldState = atom.config.get("#{@prefix}.debug")
atom.config.set("#{@prefix}.debug", not oldState)
state = atom.config.get("#{@prefix}.debug") and "enabled" or "disabled"
console.log "#{@prefix}: debug #{state}"
debug: (msg) ->
return unless atom.config.get("#{@prefix}.debug")
console.log msg
# dump: ->
# @debug "@startRow = #{@startRow}"
|