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