Skip to content
This repository was archived by the owner on Apr 6, 2018. It is now read-only.

Commit 3647d73

Browse files
author
Max Brunsfeld
committed
Merge pull request #827 from jacekkopecky/fix-806-b
Fix 806 regression
2 parents 2ab86b2 + d4efc7d commit 3647d73

File tree

3 files changed

+76
-69
lines changed

3 files changed

+76
-69
lines changed

lib/vim-state.coffee

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,11 @@ class VimState
3131
@marks = {}
3232
@subscriptions.add @editor.onDidDestroy => @destroy()
3333

34-
@subscriptions.add @editor.onDidChangeSelectionRange _.debounce(=>
35-
return unless @editor?
36-
if @editor.getSelections().every((selection) -> selection.isEmpty())
37-
@activateNormalMode() if @mode is 'visual'
38-
else
39-
@activateVisualMode('characterwise') if @mode is 'normal'
40-
, 100)
41-
42-
@subscriptions.add @editor.onDidChangeCursorPosition ({cursor}) => @ensureCursorIsWithinLine(cursor)
43-
@subscriptions.add @editor.onDidAddCursor @ensureCursorIsWithinLine
34+
@editorElement.addEventListener 'mouseup', @checkSelections
35+
if atom.commands.onDidDispatch?
36+
@subscriptions.add atom.commands.onDidDispatch (e) =>
37+
if e.target is @editorElement
38+
@checkSelections()
4439

4540
@editorElement.classList.add("vim-mode")
4641
@setupNormalMode()
@@ -52,15 +47,16 @@ class VimState
5247
destroy: ->
5348
unless @destroyed
5449
@destroyed = true
55-
@emitter.emit 'did-destroy'
5650
@subscriptions.dispose()
5751
if @editor.isAlive()
5852
@deactivateInsertMode()
5953
@editorElement.component?.setInputEnabled(true)
6054
@editorElement.classList.remove("vim-mode")
6155
@editorElement.classList.remove("normal-mode")
56+
@editorElement.removeEventListener 'mouseup', @checkSelections
6257
@editor = null
6358
@editorElement = null
59+
@emitter.emit 'did-destroy'
6460

6561
# Private: Creates the plugin's bindings
6662
#
@@ -215,33 +211,28 @@ class VimState
215211
# it.
216212
pushOperations: (operations) ->
217213
return unless operations?
218-
try
219-
@processing = true
220-
operations = [operations] unless _.isArray(operations)
221-
222-
for operation in operations
223-
# Motions in visual mode perform their selections.
224-
if @mode is 'visual' and (operation instanceof Motions.Motion or operation instanceof TextObjects.TextObject)
225-
operation.execute = operation.select
226-
227-
# if we have started an operation that responds to canComposeWith check if it can compose
228-
# with the operation we're going to push onto the stack
229-
if (topOp = @topOperation())? and topOp.canComposeWith? and not topOp.canComposeWith(operation)
230-
@resetNormalMode()
231-
@emitter.emit('failed-to-compose')
232-
break
214+
operations = [operations] unless _.isArray(operations)
233215

234-
@opStack.push(operation)
216+
for operation in operations
217+
# Motions in visual mode perform their selections.
218+
if @mode is 'visual' and (operation instanceof Motions.Motion or operation instanceof TextObjects.TextObject)
219+
operation.execute = operation.select
235220

236-
# If we've received an operator in visual mode, mark the current
237-
# selection as the motion to operate on.
238-
if @mode is 'visual' and operation instanceof Operators.Operator
239-
@opStack.push(new Motions.CurrentSelection(@editor, this))
221+
# if we have started an operation that responds to canComposeWith check if it can compose
222+
# with the operation we're going to push onto the stack
223+
if (topOp = @topOperation())? and topOp.canComposeWith? and not topOp.canComposeWith(operation)
224+
@resetNormalMode()
225+
@emitter.emit('failed-to-compose')
226+
break
240227

241-
@processOpStack()
242-
finally
243-
@processing = false
244-
@ensureCursorIsWithinLine(cursor) for cursor in @editor.getCursors()
228+
@opStack.push(operation)
229+
230+
# If we've received an operator in visual mode, mark the current
231+
# selection as the motion to operate on.
232+
if @mode is 'visual' and operation instanceof Operators.Operator
233+
@opStack.push(new Motions.CurrentSelection(@editor, this))
234+
235+
@processOpStack()
245236

246237
onDidFailToCompose: (fn) ->
247238
@emitter.on('failed-to-compose', fn)
@@ -406,9 +397,7 @@ class VimState
406397

407398
@clearOpStack()
408399
selection.clear(autoscroll: false) for selection in @editor.getSelections()
409-
for cursor in @editor.getCursors()
410-
if cursor.isAtEndOfLine() and not cursor.isAtBeginningOfLine()
411-
cursor.moveLeft()
400+
@ensureCursorsWithinLine()
412401

413402
@updateStatusBar()
414403

@@ -661,15 +650,24 @@ class VimState
661650
text = @getRegister(name)?.text
662651
@editor.insertText(text) if text?
663652

664-
ensureCursorIsWithinLine: (cursor) =>
665-
return if @processing or @mode isnt 'normal'
653+
# Private: ensure the mode follows the state of selections
654+
checkSelections: =>
655+
return unless @editor?
656+
if @editor.getSelections().every((selection) -> selection.isEmpty())
657+
@ensureCursorsWithinLine() if @mode is 'normal'
658+
@activateNormalMode() if @mode is 'visual'
659+
else
660+
@activateVisualMode('characterwise') if @mode is 'normal'
661+
662+
# Private: ensure the cursor stays within the line as appropriate
663+
ensureCursorsWithinLine: =>
664+
for cursor in @editor.getCursors()
665+
{goalColumn} = cursor
666+
if cursor.isAtEndOfLine() and not cursor.isAtBeginningOfLine()
667+
cursor.moveLeft()
668+
cursor.goalColumn = goalColumn
666669

667-
{goalColumn} = cursor
668-
if cursor.isAtEndOfLine() and not cursor.isAtBeginningOfLine()
669-
@processing = true # to ignore the cursor change (and recursion) caused by the next line
670-
cursor.moveLeft()
671-
@processing = false
672-
cursor.goalColumn = goalColumn
670+
@editor.mergeCursors()
673671

674672
# This uses private APIs and may break if TextBuffer is refactored.
675673
# Package authors - copy and paste this code at your own risk.

spec/motions-spec.coffee

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,10 +452,10 @@ describe "Motions", ->
452452

453453
describe "as a selection", ->
454454
it "selects to the beginning of the whole word", ->
455-
editor.setCursorScreenPosition([1, 10])
455+
editor.setCursorScreenPosition([1, 9])
456456
keydown('y')
457457
keydown('B', shift: true)
458-
expect(vimState.getRegister('"').text).toBe 'xyz-12' # because cursor is on the `3`
458+
expect(vimState.getRegister('"').text).toBe 'xyz-12'
459459

460460
it "doesn't go past the beginning of the file", ->
461461
editor.setCursorScreenPosition([0, 0])

spec/vim-state-spec.coffee

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -114,34 +114,39 @@ describe "VimState", ->
114114
expect(editor.getLastSelection().getText()).toEqual '012345\n'
115115

116116
describe "the ctrl-v keybinding", ->
117-
beforeEach -> keydown('v', ctrl: true)
117+
beforeEach ->
118+
editor.setText("012345\nabcdef")
119+
editor.setCursorScreenPosition([0, 0])
120+
keydown('v', ctrl: true)
118121

119-
it "puts the editor into visual characterwise mode", ->
122+
it "puts the editor into visual blockwise mode", ->
120123
expect(editorElement.classList.contains('visual-mode')).toBe(true)
121124
expect(vimState.submode).toEqual 'blockwise'
122125
expect(editorElement.classList.contains('normal-mode')).toBe(false)
123126

124127
describe "selecting text", ->
125128
beforeEach ->
126-
spyOn(_._, "now").andCallFake -> window.now
127129
editor.setText("abc def")
130+
editor.setCursorScreenPosition([0, 0])
128131

129132
it "puts the editor into visual mode", ->
130133
expect(vimState.mode).toEqual 'normal'
131-
editor.setSelectedBufferRanges([[[0, 0], [0, 3]]])
132-
133-
advanceClock(100)
134+
atom.commands.dispatch(editorElement, "core:select-right")
134135

135136
expect(vimState.mode).toEqual 'visual'
136137
expect(vimState.submode).toEqual 'characterwise'
137-
expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 3]]])
138+
expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 1]]])
138139

139140
it "handles the editor being destroyed shortly after selecting text", ->
140141
editor.setSelectedBufferRanges([[[0, 0], [0, 3]]])
141142
editor.destroy()
142143
vimState.destroy()
143144
advanceClock(100)
144145

146+
it "handles native selection such as core:select-all", ->
147+
atom.commands.dispatch(editorElement, "core:select-all")
148+
expect(editor.getSelectedBufferRanges()).toEqual([[[0, 0], [0, 7]]])
149+
145150
describe "the i keybinding", ->
146151
beforeEach -> keydown('i')
147152

@@ -158,18 +163,21 @@ describe "VimState", ->
158163
expect(editorElement.classList.contains('normal-mode')).toBe(false)
159164

160165
describe "with content", ->
161-
beforeEach -> editor.setText("012345\n\nabcdef")
166+
beforeEach ->
167+
editor.setText("012345\n\nabcdef")
168+
editor.setCursorScreenPosition([0, 0])
162169

163170
describe "on a line with content", ->
164-
beforeEach -> editor.setCursorScreenPosition([0, 6])
165-
166-
it "does not allow the cursor to be placed on the \n character", ->
171+
it "does not allow atom commands to place the cursor on the \\n character", ->
172+
atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
167173
expect(editor.getCursorScreenPosition()).toEqual [0, 5]
168174

169175
describe "on an empty line", ->
170-
beforeEach -> editor.setCursorScreenPosition([1, 0])
176+
beforeEach ->
177+
editor.setCursorScreenPosition([1, 0])
178+
atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
171179

172-
it "allows the cursor to be placed on the \n character", ->
180+
it "allows the cursor to be placed on the \\n character", ->
173181
expect(editor.getCursorScreenPosition()).toEqual [1, 0]
174182

175183
describe 'with character-input operations', ->
@@ -206,9 +214,11 @@ describe "VimState", ->
206214
expect(editor.getCursorScreenPosition()).toEqual [1, 0]
207215

208216
describe "on a line with content", ->
209-
beforeEach -> editor.setCursorScreenPosition([0, 6])
217+
beforeEach ->
218+
editor.setCursorScreenPosition([0, 0])
219+
atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
210220

211-
it "allows the cursor to be placed on the \n character", ->
221+
it "allows the cursor to be placed on the \\n character", ->
212222
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
213223

214224
it "puts the editor into normal mode when <escape> is pressed", ->
@@ -252,9 +262,10 @@ describe "VimState", ->
252262
describe "on a line with content", ->
253263
beforeEach ->
254264
keydown('R', shift: true)
255-
editor.setCursorScreenPosition([0, 6])
265+
editor.setCursorScreenPosition([0, 0])
266+
atom.commands.dispatch(editorElement, "editor:move-to-end-of-line")
256267

257-
it "allows the cursor to be placed on the \n character", ->
268+
it "allows the cursor to be placed on the \\n character", ->
258269
expect(editor.getCursorScreenPosition()).toEqual [0, 6]
259270

260271
it "puts the editor into normal mode when <escape> is pressed", ->
@@ -365,15 +376,13 @@ describe "VimState", ->
365376
])
366377

367378
it "harmonizes selection directions", ->
368-
editor.setCursorBufferPosition([0, 0])
369-
keydown("e")
370379
keydown("e")
371380
editor.addCursorAtBufferPosition([0, Infinity])
372381
keydown("h")
373382
keydown("h")
374383

375384
expect(editor.getSelectedBufferRanges()).toEqual([
376-
[[0, 0], [0, 5]],
385+
[[0, 4], [0, 5]],
377386
[[0, 11], [0, 13]]
378387
])
379388
expect(editor.getCursorBufferPositions()).toEqual([
@@ -384,7 +393,7 @@ describe "VimState", ->
384393
keydown("o")
385394

386395
expect(editor.getSelectedBufferRanges()).toEqual([
387-
[[0, 0], [0, 5]],
396+
[[0, 4], [0, 5]],
388397
[[0, 11], [0, 13]]
389398
])
390399
expect(editor.getCursorBufferPositions()).toEqual([

0 commit comments

Comments
 (0)