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

Insert with count, repeating . with prefix #609

Closed
wants to merge 11 commits into from
6 changes: 6 additions & 0 deletions keymaps/vim-mode.cson
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@
'atom-text-editor.vim-mode.insert-mode':
'ctrl-w': 'editor:delete-to-beginning-of-word'
'ctrl-u': 'editor:delete-to-beginning-of-line'
'left': 'vim-mode:move-left-insert'
'right': 'vim-mode:move-right-insert'

'atom-text-editor.vim-mode.insert-mode:not(.autocomplete-active)':
'up': 'vim-mode:move-up-insert'
'down': 'vim-mode:move-down-insert'

'atom-text-editor.vim-mode:not(.insert-mode)':
'h': 'vim-mode:move-left'
Expand Down
9 changes: 5 additions & 4 deletions lib/motions/general-motions.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class Motion
selection.modifySelection => @moveCursor(selection.cursor, count, options)

ensureCursorIsWithinLine: (cursor) ->
return if @vimState.mode is 'visual' or not cursor.selection.isEmpty()
return if @vimState.mode is 'visual' or @vimState.mode is 'insert' or not cursor.selection.isEmpty()
{goalColumn} = cursor
{row, column} = cursor.getBufferPosition()
lastColumn = cursor.getCurrentLineBufferRange().end.column
Expand Down Expand Up @@ -153,9 +153,10 @@ class MoveRight extends Motion
_.times count, =>
wrapToNextLine = settings.wrapLeftRightMotion()

# when the motion is combined with an operator, we will only wrap to the next line
# if we are already at the end of the line (after the last character)
wrapToNextLine = false if @vimState.mode is 'operator-pending' and not cursor.isAtEndOfLine()
# when the motion is in insert mode or is combined with an operator,
# we will only wrap to the next line if we are already
# at the end of the line (after the last character)
wrapToNextLine = false if (@vimState.mode is 'insert' or @vimState.mode is 'operator-pending') and not cursor.isAtEndOfLine()

cursor.moveRight() unless cursor.isAtEndOfLine()
cursor.moveRight() if wrapToNextLine and cursor.isAtEndOfLine()
Expand Down
22 changes: 18 additions & 4 deletions lib/operators/general-operators.coffee
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
_ = require 'underscore-plus'
{Point, Range} = require 'atom'
{ViewModel} = require '../view-models/view-model'
Prefixes = require '../prefixes'
Utils = require '../utils'
settings = require '../settings'

Expand Down Expand Up @@ -228,11 +229,24 @@ class Repeat extends Operator

isRecordable: -> false

execute: (count=1) ->
execute: (count) ->
return unless (cmd = @vimState.history[0])?

@editor.transact =>
_.times count, =>
cmd = @vimState.history[0]
cmd?.execute()

if count?
# try to propagate prefix to inner operation
if cmd instanceof Prefixes.Repeat
cmd.count = count
else if cmd.motion instanceof Prefixes.Repeat
cmd.motion.count = count
else
repeat = new Prefixes.Repeat(count)
repeat.compose(cmd)
cmd = @vimState.history[0] = repeat

cmd.execute()

#
# It creates a mark at the current cursor position
#
Expand Down
28 changes: 22 additions & 6 deletions lib/operators/input.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,23 @@ settings = require '../settings'
# tells the operation to repeat itself instead of enter insert mode.
class Insert extends Operator
standalone: true
count: 1

isComplete: -> @standalone or super

confirmChanges: (changes) ->
confirmChanges: (changes, insertionCheckpoint, options) ->
interrupted = options?.interrupted
bundler = new TransactionBundler(changes)
@typedText = bundler.buildInsertText()
if @count > 1 and not interrupted
@editor.insertText(@typedText) for i in [2..@count]

execute: ->
execute: (count) ->
@count = count if count?
if @typingCompleted
return unless @typedText? and @typedText.length > 0
@editor.insertText(@typedText, normalizeLineEndings: true)
@editor.transact =>
@editor.insertText(@typedText, normalizeLineEndings: true) for i in [1..@count]
for cursor in @editor.getCursors()
cursor.moveLeft() unless cursor.isAtBeginningOfLine()
else
Expand All @@ -28,6 +34,15 @@ class Insert extends Operator

inputOperator: -> true

# an insert operation following cursor motion in insert mode can be cancelled
# and forgotten like it never happened
class InsertCancellable extends Insert

confirmTransaction: (transaction) ->
super
if @typedText?.length is 0
@vimState.history.shift() if @vimState.history[0] is this

class InsertAfter extends Insert
execute: ->
@editor.moveRight() unless @editor.getLastCursor().isAtEndOfLine()
Expand Down Expand Up @@ -103,7 +118,7 @@ class Change extends Insert
for selection in @editor.getSelections()
selection.deleteSelectedText()

return super if @typingCompleted
return super(1) if @typingCompleted

@vimState.activateInsertMode()
@typingCompleted = true
Expand All @@ -123,7 +138,7 @@ class Substitute extends Insert

if @typingCompleted
@typedText = @typedText.trimLeft()
return super
return super(1)

@vimState.activateInsertMode()
@typingCompleted = true
Expand All @@ -147,7 +162,7 @@ class SubstituteLine extends Insert

if @typingCompleted
@typedText = @typedText.trimLeft()
return super
return super(1)

@vimState.activateInsertMode()
@typingCompleted = true
Expand Down Expand Up @@ -189,6 +204,7 @@ module.exports = {
InsertAtBeginningOfLine,
InsertAboveWithNewline,
InsertBelowWithNewline,
InsertCancellable,
Change,
Substitute,
SubstituteLine
Expand Down
21 changes: 18 additions & 3 deletions lib/vim-state.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class VimState
'move-up': => new Motions.MoveUp(@editor, this)
'move-down': => new Motions.MoveDown(@editor, this)
'move-right': => new Motions.MoveRight(@editor, this)
'move-left-insert': => @interruptInsertMode(); [new Motions.MoveLeft(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-up-insert': => @interruptInsertMode(); [new Motions.MoveUp(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-down-insert': => @interruptInsertMode(); [new Motions.MoveDown(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-right-insert': => @interruptInsertMode(); [new Motions.MoveRight(@editor, this), new Operators.InsertCancellable(@editor, this)]
'move-to-next-word': => new Motions.MoveToNextWord(@editor, this)
'move-to-next-whole-word': => new Motions.MoveToNextWholeWord(@editor, this)
'move-to-end-of-word': => new Motions.MoveToEndOfWord(@editor, this)
Expand Down Expand Up @@ -405,15 +409,26 @@ class VimState
deactivateInsertMode: ->
return unless @mode in [null, 'insert']
@editorElement.component.setInputEnabled(false)
@editor.groupChangesSinceCheckpoint(@insertionCheckpoint)
changes = getChangesSinceCheckpoint(@editor.buffer, @insertionCheckpoint)
item = @inputOperator(@history[0])
@insertionCheckpoint = null
if item?
item.confirmChanges(changes)
item.confirmChanges(changes, @insertionCheckpoint)
@editor.groupChangesSinceCheckpoint(@insertionCheckpoint)
@insertionCheckpoint = null
for cursor in @editor.getCursors()
cursor.moveLeft() unless cursor.isAtBeginningOfLine()

interruptInsertMode: ->
return unless @mode is 'insert'
changes = getChangesSinceCheckpoint(@editor.buffer, @insertionCheckpoint)
item = @inputOperator(@history[0])
if item?
item.confirmChanges(changes, @insertionCheckpoint, interrupted: true)
@editor.groupChangesSinceCheckpoint(@insertionCheckpoint)
@insertionCheckpoint = null
@setInsertionCheckpoint()


deactivateVisualMode: ->
return unless @mode is 'visual'
for selection in @editor.getSelections()
Expand Down
Loading