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

Commit c384079

Browse files
author
Max Brunsfeld
committed
Merge pull request #770 from jacekkopecky/ensure-cursor-on-line
use onDidChangeCursorPosition for keeping cursor in line
2 parents ffec3b8 + 13a1233 commit c384079

File tree

5 files changed

+50
-61
lines changed

5 files changed

+50
-61
lines changed

lib/motions/general-motions.coffee

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,6 @@ class Motion
8888
moveSelection: (selection, count, options) ->
8989
selection.modifySelection => @moveCursor(selection.cursor, count, options)
9090

91-
ensureCursorIsWithinLine: (cursor) ->
92-
return if @vimState.mode is 'visual' or not cursor.selection.isEmpty()
93-
{goalColumn} = cursor
94-
{row, column} = cursor.getBufferPosition()
95-
lastColumn = cursor.getCurrentLineBufferRange().end.column
96-
if column >= lastColumn - 1
97-
cursor.setBufferPosition([row, Math.max(lastColumn - 1, 0)])
98-
cursor.goalColumn ?= goalColumn
99-
10091
isComplete: -> true
10192

10293
isRecordable: -> false
@@ -142,9 +133,8 @@ class MoveLeft extends Motion
142133
operatesInclusively: false
143134

144135
moveCursor: (cursor, count=1) ->
145-
_.times count, =>
136+
_.times count, ->
146137
cursor.moveLeft() if not cursor.isAtBeginningOfLine() or settings.wrapLeftRightMotion()
147-
@ensureCursorIsWithinLine(cursor)
148138

149139
class MoveRight extends Motion
150140
operatesInclusively: false
@@ -159,16 +149,14 @@ class MoveRight extends Motion
159149

160150
cursor.moveRight() unless cursor.isAtEndOfLine()
161151
cursor.moveRight() if wrapToNextLine and cursor.isAtEndOfLine()
162-
@ensureCursorIsWithinLine(cursor)
163152

164153
class MoveUp extends Motion
165154
operatesLinewise: true
166155

167156
moveCursor: (cursor, count=1) ->
168-
_.times count, =>
157+
_.times count, ->
169158
unless cursor.getScreenRow() is 0
170159
cursor.moveUp()
171-
@ensureCursorIsWithinLine(cursor)
172160

173161
class MoveDown extends Motion
174162
operatesLinewise: true
@@ -177,7 +165,6 @@ class MoveDown extends Motion
177165
_.times count, =>
178166
unless cursor.getScreenRow() is @editor.getLastScreenRow()
179167
cursor.moveDown()
180-
@ensureCursorIsWithinLine(cursor)
181168

182169
class MoveToPreviousWord extends Motion
183170
operatesInclusively: false
@@ -328,10 +315,9 @@ class MoveToLastCharacterOfLine extends Motion
328315
operatesInclusively: false
329316

330317
moveCursor: (cursor, count=1) ->
331-
_.times count, =>
318+
_.times count, ->
332319
cursor.moveToEndOfLine()
333320
cursor.goalColumn = Infinity
334-
@ensureCursorIsWithinLine(cursor)
335321

336322
class MoveToLastNonblankCharacterOfLineAndDown extends Motion
337323
operatesInclusively: true

lib/vim-state.coffee

Lines changed: 37 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class VimState
3939
@activateVisualMode('characterwise') if @mode is 'normal'
4040
, 100)
4141

42+
@subscriptions.add @editor.onDidChangeCursorPosition ({cursor}) => @ensureCursorIsWithinLine(cursor)
43+
@subscriptions.add @editor.onDidAddCursor @ensureCursorIsWithinLine
44+
4245
@editorElement.classList.add("vim-mode")
4346
@setupNormalMode()
4447
if settings.startInInsertMode()
@@ -212,28 +215,33 @@ class VimState
212215
# it.
213216
pushOperations: (operations) ->
214217
return unless operations?
215-
operations = [operations] unless _.isArray(operations)
216-
217-
for operation in operations
218-
# Motions in visual mode perform their selections.
219-
if @mode is 'visual' and (operation instanceof Motions.Motion or operation instanceof TextObjects.TextObject)
220-
operation.execute = operation.select
221-
222-
# if we have started an operation that responds to canComposeWith check if it can compose
223-
# with the operation we're going to push onto the stack
224-
if (topOp = @topOperation())? and topOp.canComposeWith? and not topOp.canComposeWith(operation)
225-
@resetNormalMode()
226-
@emitter.emit('failed-to-compose')
227-
break
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
228233

229-
@opStack.push(operation)
234+
@opStack.push(operation)
230235

231-
# If we've received an operator in visual mode, mark the current
232-
# selection as the motion to operate on.
233-
if @mode is 'visual' and operation instanceof Operators.Operator
234-
@opStack.push(new Motions.CurrentSelection(@editor, this))
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))
235240

236-
@processOpStack()
241+
@processOpStack()
242+
finally
243+
@processing = false
244+
@ensureCursorIsWithinLine(cursor) for cursor in @editor.getCursors()
237245

238246
onDidFailToCompose: (fn) ->
239247
@emitter.on('failed-to-compose', fn)
@@ -654,6 +662,16 @@ class VimState
654662
text = @getRegister(name)?.text
655663
@editor.insertText(text) if text?
656664

665+
ensureCursorIsWithinLine: (cursor) =>
666+
return if @processing or @mode isnt 'normal'
667+
668+
{goalColumn} = cursor
669+
if cursor.isAtEndOfLine() and not cursor.isAtBeginningOfLine()
670+
@processing = true # to ignore the cursor change (and recursion) caused by the next line
671+
cursor.moveLeft()
672+
@processing = false
673+
cursor.goalColumn = goalColumn
674+
657675
# This uses private APIs and may break if TextBuffer is refactored.
658676
# Package authors - copy and paste this code at your own risk.
659677
getChangesSinceCheckpoint = (buffer, checkpoint) ->

spec/motions-spec.coffee

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -145,30 +145,21 @@ describe "Motions", ->
145145
keydown('w')
146146
expect(editor.getCursorScreenPosition()).toEqual [2, 0]
147147

148-
# FIXME: The definition of Cursor#getEndOfCurrentWordBufferPosition,
149-
# means that the end of the word can't be the current cursor
150-
# position (even though it is when your cursor is on a new line).
151-
#
152-
# Therefore it picks the end of the next word here (which is [3,3])
153-
# to start looking for the next word, which is also the end of the
154-
# buffer so the cursor never advances.
155-
#
156-
# See atom/vim-mode#3
157148
keydown('w')
158149
expect(editor.getCursorScreenPosition()).toEqual [3, 0]
159150

160151
keydown('w')
161-
expect(editor.getCursorScreenPosition()).toEqual [3, 3]
152+
expect(editor.getCursorScreenPosition()).toEqual [3, 2]
162153

163-
# After cursor gets to the EOF, it should stay there.
154+
# When the cursor gets to the EOF, it should stay there.
164155
keydown('w')
165-
expect(editor.getCursorScreenPosition()).toEqual [3, 3]
156+
expect(editor.getCursorScreenPosition()).toEqual [3, 2]
166157

167158
it "moves the cursor to the end of the word if last word in file", ->
168159
editor.setText("abc")
169160
editor.setCursorScreenPosition([0, 0])
170161
keydown('w')
171-
expect(editor.getCursorScreenPosition()).toEqual([0, 3])
162+
expect(editor.getCursorScreenPosition()).toEqual([0, 2])
172163

173164
describe "as a selection", ->
174165
describe "within a word", ->
@@ -464,7 +455,7 @@ describe "Motions", ->
464455
editor.setCursorScreenPosition([1, 10])
465456
keydown('y')
466457
keydown('B', shift: true)
467-
expect(vimState.getRegister('"').text).toBe 'xyz-123'
458+
expect(vimState.getRegister('"').text).toBe 'xyz-12' # because cursor is on the `3`
468459

469460
it "doesn't go past the beginning of the file", ->
470461
editor.setCursorScreenPosition([0, 0])
@@ -966,7 +957,7 @@ describe "Motions", ->
966957
beforeEach -> keydown('G', shift: true)
967958

968959
it "moves the cursor to the last line after whitespace", ->
969-
expect(editor.getCursorScreenPosition()).toEqual [3, 1]
960+
expect(editor.getCursorScreenPosition()).toEqual [3, 0]
970961

971962
describe "as a repeated motion", ->
972963
beforeEach ->
@@ -1263,14 +1254,9 @@ describe "Motions", ->
12631254

12641255
it "doesn't move cursor unless next match has exact word ending", ->
12651256
editor.setText("abc\n@def\nabc\n@def1\n")
1266-
# FIXME: I suspect there is a bug laying around
1267-
# Cursor#getEndOfCurrentWordBufferPosition, this function
1268-
# is returning '@' as a word, instead of returning the whole
1269-
# word '@def', this behavior is avoided in this test, when we
1270-
# execute the '*' command when cursor is on character after '@'
1271-
# (in this particular example, the 'd' char)
12721257
editor.setCursorBufferPosition([1, 1])
12731258
keydown("*")
1259+
# this is because of the default isKeyword value of vim-mode that includes @
12741260
expect(editor.getCursorBufferPosition()).toEqual [1, 0]
12751261

12761262
# FIXME: This behavior is different from the one found in

spec/scroll-spec.coffee

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ describe "Scrolling", ->
176176
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
177177
pos10 = zsPos(10)
178178
expect(pos10).toEqual(startPosition)
179-
expect(editor.getCursorBufferPosition()).toEqual [0, 5]
179+
expect(editor.getCursorBufferPosition()).toEqual [0, 4]
180180

181181

182182
describe "the ze keybinding", ->
@@ -227,4 +227,4 @@ describe "Scrolling", ->
227227
expect(editor.getCursorBufferPosition()).toEqual [0, 1]
228228
pos10 = zePos(10)
229229
expect(pos10).toEqual(startPosition)
230-
expect(editor.getCursorBufferPosition()).toEqual [0, 5]
230+
expect(editor.getCursorBufferPosition()).toEqual [0, 4]

spec/vim-state-spec.coffee

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ describe "VimState", ->
154154
describe "with content", ->
155155
beforeEach -> editor.setText("012345\n\nabcdef")
156156

157-
# FIXME: See atom/vim-mode#2
158-
xdescribe "on a line with content", ->
157+
describe "on a line with content", ->
159158
beforeEach -> editor.setCursorScreenPosition([0, 6])
160159

161160
it "does not allow the cursor to be placed on the \n character", ->

0 commit comments

Comments
 (0)