aboutsummaryrefslogtreecommitdiff
path: root/atom/packages/vim-mode/lib/vim-state.coffee
diff options
context:
space:
mode:
Diffstat (limited to 'atom/packages/vim-mode/lib/vim-state.coffee')
-rw-r--r--atom/packages/vim-mode/lib/vim-state.coffee680
1 files changed, 0 insertions, 680 deletions
diff --git a/atom/packages/vim-mode/lib/vim-state.coffee b/atom/packages/vim-mode/lib/vim-state.coffee
deleted file mode 100644
index db59ee5..0000000
--- a/atom/packages/vim-mode/lib/vim-state.coffee
+++ /dev/null
@@ -1,680 +0,0 @@
-Grim = require 'grim'
-_ = require 'underscore-plus'
-{Point, Range} = require 'atom'
-{Emitter, Disposable, CompositeDisposable} = require 'event-kit'
-settings = require './settings'
-
-Operators = require './operators/index'
-Prefixes = require './prefixes'
-Motions = require './motions/index'
-InsertMode = require './insert-mode'
-
-TextObjects = require './text-objects'
-Utils = require './utils'
-Scroll = require './scroll'
-
-module.exports =
-class VimState
- editor: null
- opStack: null
- mode: null
- submode: null
- destroyed: false
- replaceModeListener: null
-
- constructor: (@editorElement, @statusBarManager, @globalVimState) ->
- @emitter = new Emitter
- @subscriptions = new CompositeDisposable
- @editor = @editorElement.getModel()
- @opStack = []
- @history = []
- @marks = {}
- @subscriptions.add @editor.onDidDestroy => @destroy()
-
- @editorElement.addEventListener 'mouseup', @checkSelections
- if atom.commands.onDidDispatch?
- @subscriptions.add atom.commands.onDidDispatch (e) =>
- if e.target is @editorElement
- @checkSelections()
-
- @editorElement.classList.add("vim-mode")
- @setupNormalMode()
- if settings.startInInsertMode()
- @activateInsertMode()
- else
- @activateNormalMode()
-
- destroy: ->
- unless @destroyed
- @destroyed = true
- @subscriptions.dispose()
- if @editor.isAlive()
- @deactivateInsertMode()
- @editorElement.component?.setInputEnabled(true)
- @editorElement.classList.remove("vim-mode")
- @editorElement.classList.remove("normal-mode")
- @editorElement.removeEventListener 'mouseup', @checkSelections
- @editor = null
- @editorElement = null
- @emitter.emit 'did-destroy'
-
- # Private: Creates the plugin's bindings
- #
- # Returns nothing.
- setupNormalMode: ->
- @registerCommands
- 'activate-normal-mode': => @activateNormalMode()
- 'activate-linewise-visual-mode': => @activateVisualMode('linewise')
- 'activate-characterwise-visual-mode': => @activateVisualMode('characterwise')
- 'activate-blockwise-visual-mode': => @activateVisualMode('blockwise')
- 'reset-normal-mode': => @resetNormalMode()
- 'repeat-prefix': (e) => @repeatPrefix(e)
- 'reverse-selections': (e) => @reverseSelections(e)
- 'undo': (e) => @undo(e)
- 'replace-mode-backspace': => @replaceModeUndo()
- 'insert-mode-put': (e) => @insertRegister(@registerName(e))
- 'copy-from-line-above': => InsertMode.copyCharacterFromAbove(@editor, this)
- 'copy-from-line-below': => InsertMode.copyCharacterFromBelow(@editor, this)
-
- @registerOperationCommands
- 'activate-insert-mode': => new Operators.Insert(@editor, this)
- 'activate-replace-mode': => new Operators.ReplaceMode(@editor, this)
- 'substitute': => [new Operators.Change(@editor, this), new Motions.MoveRight(@editor, this)]
- 'substitute-line': => [new Operators.Change(@editor, this), new Motions.MoveToRelativeLine(@editor, this)]
- 'insert-after': => new Operators.InsertAfter(@editor, this)
- 'insert-after-end-of-line': => new Operators.InsertAfterEndOfLine(@editor, this)
- 'insert-at-beginning-of-line': => new Operators.InsertAtBeginningOfLine(@editor, this)
- 'insert-above-with-newline': => new Operators.InsertAboveWithNewline(@editor, this)
- 'insert-below-with-newline': => new Operators.InsertBelowWithNewline(@editor, this)
- 'delete': => @linewiseAliasedOperator(Operators.Delete)
- 'change': => @linewiseAliasedOperator(Operators.Change)
- 'change-to-last-character-of-line': => [new Operators.Change(@editor, this), new Motions.MoveToLastCharacterOfLine(@editor, this)]
- 'delete-right': => [new Operators.Delete(@editor, this), new Motions.MoveRight(@editor, this)]
- 'delete-left': => [new Operators.Delete(@editor, this), new Motions.MoveLeft(@editor, this)]
- 'delete-to-last-character-of-line': => [new Operators.Delete(@editor, this), new Motions.MoveToLastCharacterOfLine(@editor, this)]
- 'toggle-case': => new Operators.ToggleCase(@editor, this)
- 'upper-case': => new Operators.UpperCase(@editor, this)
- 'lower-case': => new Operators.LowerCase(@editor, this)
- 'toggle-case-now': => new Operators.ToggleCase(@editor, this, complete: true)
- 'yank': => @linewiseAliasedOperator(Operators.Yank)
- 'yank-line': => [new Operators.Yank(@editor, this), new Motions.MoveToRelativeLine(@editor, this)]
- 'put-before': => new Operators.Put(@editor, this, location: 'before')
- 'put-after': => new Operators.Put(@editor, this, location: 'after')
- 'join': => new Operators.Join(@editor, this)
- 'indent': => @linewiseAliasedOperator(Operators.Indent)
- 'outdent': => @linewiseAliasedOperator(Operators.Outdent)
- 'auto-indent': => @linewiseAliasedOperator(Operators.Autoindent)
- 'increase': => new Operators.Increase(@editor, this)
- 'decrease': => new Operators.Decrease(@editor, this)
- 'move-left': => new Motions.MoveLeft(@editor, this)
- 'move-up': => new Motions.MoveUp(@editor, this)
- 'move-down': => new Motions.MoveDown(@editor, this)
- 'move-right': => new Motions.MoveRight(@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)
- 'move-to-end-of-whole-word': => new Motions.MoveToEndOfWholeWord(@editor, this)
- 'move-to-previous-word': => new Motions.MoveToPreviousWord(@editor, this)
- 'move-to-previous-whole-word': => new Motions.MoveToPreviousWholeWord(@editor, this)
- 'move-to-next-paragraph': => new Motions.MoveToNextParagraph(@editor, this)
- 'move-to-previous-paragraph': => new Motions.MoveToPreviousParagraph(@editor, this)
- 'move-to-first-character-of-line': => new Motions.MoveToFirstCharacterOfLine(@editor, this)
- 'move-to-first-character-of-line-and-down': => new Motions.MoveToFirstCharacterOfLineAndDown(@editor, this)
- 'move-to-last-character-of-line': => new Motions.MoveToLastCharacterOfLine(@editor, this)
- 'move-to-last-nonblank-character-of-line-and-down': => new Motions.MoveToLastNonblankCharacterOfLineAndDown(@editor, this)
- 'move-to-beginning-of-line': (e) => @moveOrRepeat(e)
- 'move-to-first-character-of-line-up': => new Motions.MoveToFirstCharacterOfLineUp(@editor, this)
- 'move-to-first-character-of-line-down': => new Motions.MoveToFirstCharacterOfLineDown(@editor, this)
- 'move-to-start-of-file': => new Motions.MoveToStartOfFile(@editor, this)
- 'move-to-line': => new Motions.MoveToAbsoluteLine(@editor, this)
- 'move-to-top-of-screen': => new Motions.MoveToTopOfScreen(@editorElement, this)
- 'move-to-bottom-of-screen': => new Motions.MoveToBottomOfScreen(@editorElement, this)
- 'move-to-middle-of-screen': => new Motions.MoveToMiddleOfScreen(@editorElement, this)
- 'scroll-down': => new Scroll.ScrollDown(@editorElement)
- 'scroll-up': => new Scroll.ScrollUp(@editorElement)
- 'scroll-cursor-to-top': => new Scroll.ScrollCursorToTop(@editorElement)
- 'scroll-cursor-to-top-leave': => new Scroll.ScrollCursorToTop(@editorElement, {leaveCursor: true})
- 'scroll-cursor-to-middle': => new Scroll.ScrollCursorToMiddle(@editorElement)
- 'scroll-cursor-to-middle-leave': => new Scroll.ScrollCursorToMiddle(@editorElement, {leaveCursor: true})
- 'scroll-cursor-to-bottom': => new Scroll.ScrollCursorToBottom(@editorElement)
- 'scroll-cursor-to-bottom-leave': => new Scroll.ScrollCursorToBottom(@editorElement, {leaveCursor: true})
- 'scroll-half-screen-up': => new Motions.ScrollHalfUpKeepCursor(@editorElement, this)
- 'scroll-full-screen-up': => new Motions.ScrollFullUpKeepCursor(@editorElement, this)
- 'scroll-half-screen-down': => new Motions.ScrollHalfDownKeepCursor(@editorElement, this)
- 'scroll-full-screen-down': => new Motions.ScrollFullDownKeepCursor(@editorElement, this)
- 'scroll-cursor-to-left': => new Scroll.ScrollCursorToLeft(@editorElement)
- 'scroll-cursor-to-right': => new Scroll.ScrollCursorToRight(@editorElement)
- 'select-inside-word': => new TextObjects.SelectInsideWord(@editor)
- 'select-inside-whole-word': => new TextObjects.SelectInsideWholeWord(@editor)
- 'select-inside-double-quotes': => new TextObjects.SelectInsideQuotes(@editor, '"', false)
- 'select-inside-single-quotes': => new TextObjects.SelectInsideQuotes(@editor, '\'', false)
- 'select-inside-back-ticks': => new TextObjects.SelectInsideQuotes(@editor, '`', false)
- 'select-inside-curly-brackets': => new TextObjects.SelectInsideBrackets(@editor, '{', '}', false)
- 'select-inside-angle-brackets': => new TextObjects.SelectInsideBrackets(@editor, '<', '>', false)
- 'select-inside-tags': => new TextObjects.SelectInsideBrackets(@editor, '>', '<', false)
- 'select-inside-square-brackets': => new TextObjects.SelectInsideBrackets(@editor, '[', ']', false)
- 'select-inside-parentheses': => new TextObjects.SelectInsideBrackets(@editor, '(', ')', false)
- 'select-inside-paragraph': => new TextObjects.SelectInsideParagraph(@editor, false)
- 'select-a-word': => new TextObjects.SelectAWord(@editor)
- 'select-a-whole-word': => new TextObjects.SelectAWholeWord(@editor)
- 'select-around-double-quotes': => new TextObjects.SelectInsideQuotes(@editor, '"', true)
- 'select-around-single-quotes': => new TextObjects.SelectInsideQuotes(@editor, '\'', true)
- 'select-around-back-ticks': => new TextObjects.SelectInsideQuotes(@editor, '`', true)
- 'select-around-curly-brackets': => new TextObjects.SelectInsideBrackets(@editor, '{', '}', true)
- 'select-around-angle-brackets': => new TextObjects.SelectInsideBrackets(@editor, '<', '>', true)
- 'select-around-square-brackets': => new TextObjects.SelectInsideBrackets(@editor, '[', ']', true)
- 'select-around-parentheses': => new TextObjects.SelectInsideBrackets(@editor, '(', ')', true)
- 'select-around-paragraph': => new TextObjects.SelectAParagraph(@editor, true)
- 'register-prefix': (e) => @registerPrefix(e)
- 'repeat': (e) => new Operators.Repeat(@editor, this)
- 'repeat-search': (e) => new Motions.RepeatSearch(@editor, this)
- 'repeat-search-backwards': (e) => new Motions.RepeatSearch(@editor, this).reversed()
- 'move-to-mark': (e) => new Motions.MoveToMark(@editor, this)
- 'move-to-mark-literal': (e) => new Motions.MoveToMark(@editor, this, false)
- 'mark': (e) => new Operators.Mark(@editor, this)
- 'find': (e) => new Motions.Find(@editor, this)
- 'find-backwards': (e) => new Motions.Find(@editor, this).reverse()
- 'till': (e) => new Motions.Till(@editor, this)
- 'till-backwards': (e) => new Motions.Till(@editor, this).reverse()
- 'repeat-find': (e) => new @globalVimState.currentFind.constructor(@editor, this, repeated: true) if @globalVimState.currentFind
- 'repeat-find-reverse': (e) => new @globalVimState.currentFind.constructor(@editor, this, repeated: true, reverse: true) if @globalVimState.currentFind
- 'replace': (e) => new Operators.Replace(@editor, this)
- 'search': (e) => new Motions.Search(@editor, this)
- 'reverse-search': (e) => (new Motions.Search(@editor, this)).reversed()
- 'search-current-word': (e) => new Motions.SearchCurrentWord(@editor, this)
- 'bracket-matching-motion': (e) => new Motions.BracketMatchingMotion(@editor, this)
- 'reverse-search-current-word': (e) => (new Motions.SearchCurrentWord(@editor, this)).reversed()
-
- # Private: Register multiple command handlers via an {Object} that maps
- # command names to command handler functions.
- #
- # Prefixes the given command names with 'vim-mode:' to reduce redundancy in
- # the provided object.
- registerCommands: (commands) ->
- for commandName, fn of commands
- do (fn) =>
- @subscriptions.add(atom.commands.add(@editorElement, "vim-mode:#{commandName}", fn))
-
- # Private: Register multiple Operators via an {Object} that
- # maps command names to functions that return operations to push.
- #
- # Prefixes the given command names with 'vim-mode:' to reduce redundancy in
- # the given object.
- registerOperationCommands: (operationCommands) ->
- commands = {}
- for commandName, operationFn of operationCommands
- do (operationFn) =>
- commands[commandName] = (event) => @pushOperations(operationFn(event))
- @registerCommands(commands)
-
- # Private: Push the given operations onto the operation stack, then process
- # it.
- pushOperations: (operations) ->
- return unless operations?
- operations = [operations] unless _.isArray(operations)
-
- for operation in operations
- # Motions in visual mode perform their selections.
- if @mode is 'visual' and (operation instanceof Motions.Motion or operation instanceof TextObjects.TextObject)
- operation.execute = operation.select
-
- # if we have started an operation that responds to canComposeWith check if it can compose
- # with the operation we're going to push onto the stack
- if (topOp = @topOperation())? and topOp.canComposeWith? and not topOp.canComposeWith(operation)
- @resetNormalMode()
- @emitter.emit('failed-to-compose')
- break
-
- @opStack.push(operation)
-
- # If we've received an operator in visual mode, mark the current
- # selection as the motion to operate on.
- if @mode is 'visual' and operation instanceof Operators.Operator
- @opStack.push(new Motions.CurrentSelection(@editor, this))
-
- @processOpStack()
-
- onDidFailToCompose: (fn) ->
- @emitter.on('failed-to-compose', fn)
-
- onDidDestroy: (fn) ->
- @emitter.on('did-destroy', fn)
-
- # Private: Removes all operations from the stack.
- #
- # Returns nothing.
- clearOpStack: ->
- @opStack = []
-
- undo: ->
- @editor.undo()
- @activateNormalMode()
-
- # Private: Processes the command if the last operation is complete.
- #
- # Returns nothing.
- processOpStack: ->
- unless @opStack.length > 0
- return
-
- unless @topOperation().isComplete()
- if @mode is 'normal' and @topOperation() instanceof Operators.Operator
- @activateOperatorPendingMode()
- return
-
- poppedOperation = @opStack.pop()
- if @opStack.length
- try
- @topOperation().compose(poppedOperation)
- @processOpStack()
- catch e
- if (e instanceof Operators.OperatorError) or (e instanceof Motions.MotionError)
- @resetNormalMode()
- else
- throw e
- else
- @history.unshift(poppedOperation) if poppedOperation.isRecordable()
- poppedOperation.execute()
-
- # Private: Fetches the last operation.
- #
- # Returns the last operation.
- topOperation: ->
- _.last @opStack
-
- # Private: Fetches the value of a given register.
- #
- # name - The name of the register to fetch.
- #
- # Returns the value of the given register or undefined if it hasn't
- # been set.
- getRegister: (name) ->
- if name is '"'
- name = settings.defaultRegister()
- if name in ['*', '+']
- text = atom.clipboard.read()
- type = Utils.copyType(text)
- {text, type}
- else if name is '%'
- text = @editor.getURI()
- type = Utils.copyType(text)
- {text, type}
- else if name is "_" # Blackhole always returns nothing
- text = ''
- type = Utils.copyType(text)
- {text, type}
- else
- @globalVimState.registers[name.toLowerCase()]
-
- # Private: Fetches the value of a given mark.
- #
- # name - The name of the mark to fetch.
- #
- # Returns the value of the given mark or undefined if it hasn't
- # been set.
- getMark: (name) ->
- if @marks[name]
- @marks[name].getBufferRange().start
- else
- undefined
-
- # Private: Sets the value of a given register.
- #
- # name - The name of the register to fetch.
- # value - The value to set the register to.
- #
- # Returns nothing.
- setRegister: (name, value) ->
- if name is '"'
- name = settings.defaultRegister()
- if name in ['*', '+']
- atom.clipboard.write(value.text)
- else if name is '_'
- # Blackhole register, nothing to do
- else if /^[A-Z]$/.test(name)
- @appendRegister(name.toLowerCase(), value)
- else
- @globalVimState.registers[name] = value
-
-
- # Private: append a value into a given register
- # like setRegister, but appends the value
- appendRegister: (name, value) ->
- register = @globalVimState.registers[name] ?=
- type: 'character'
- text: ""
- if register.type is 'linewise' and value.type isnt 'linewise'
- register.text += value.text + '\n'
- else if register.type isnt 'linewise' and value.type is 'linewise'
- register.text += '\n' + value.text
- register.type = 'linewise'
- else
- register.text += value.text
-
- # Private: Sets the value of a given mark.
- #
- # name - The name of the mark to fetch.
- # pos {Point} - The value to set the mark to.
- #
- # Returns nothing.
- setMark: (name, pos) ->
- # check to make sure name is in [a-z] or is `
- if (charCode = name.charCodeAt(0)) >= 96 and charCode <= 122
- marker = @editor.markBufferRange(new Range(pos, pos), {invalidate: 'never', persistent: false})
- @marks[name] = marker
-
- # Public: Append a search to the search history.
- #
- # Motions.Search - The confirmed search motion to append
- #
- # Returns nothing
- pushSearchHistory: (search) ->
- @globalVimState.searchHistory.unshift search
-
- # Public: Get the search history item at the given index.
- #
- # index - the index of the search history item
- #
- # Returns a search motion
- getSearchHistoryItem: (index = 0) ->
- @globalVimState.searchHistory[index]
-
- ##############################################################################
- # Mode Switching
- ##############################################################################
-
- # Private: Used to enable normal mode.
- #
- # Returns nothing.
- activateNormalMode: ->
- @deactivateInsertMode()
- @deactivateVisualMode()
-
- @mode = 'normal'
- @submode = null
-
- @changeModeClass('normal-mode')
-
- @clearOpStack()
- selection.clear(autoscroll: false) for selection in @editor.getSelections()
- @ensureCursorsWithinLine()
-
- @updateStatusBar()
-
- # TODO: remove this method and bump the `vim-mode` service version number.
- activateCommandMode: ->
- Grim.deprecate("Use ::activateNormalMode instead")
- @activateNormalMode()
-
- # Private: Used to enable insert mode.
- #
- # Returns nothing.
- activateInsertMode: (subtype = null) ->
- @mode = 'insert'
- @editorElement.component.setInputEnabled(true)
- @setInsertionCheckpoint()
- @submode = subtype
- @changeModeClass('insert-mode')
- @updateStatusBar()
-
- activateReplaceMode: ->
- @activateInsertMode('replace')
- @replaceModeCounter = 0
- @editorElement.classList.add('replace-mode')
- @subscriptions.add @replaceModeListener = @editor.onWillInsertText @replaceModeInsertHandler
- @subscriptions.add @replaceModeUndoListener = @editor.onDidInsertText @replaceModeUndoHandler
-
- replaceModeInsertHandler: (event) =>
- chars = event.text?.split('') or []
- selections = @editor.getSelections()
- for char in chars
- continue if char is '\n'
- for selection in selections
- selection.delete() unless selection.cursor.isAtEndOfLine()
- return
-
- replaceModeUndoHandler: (event) =>
- @replaceModeCounter++
-
- replaceModeUndo: ->
- if @replaceModeCounter > 0
- @editor.undo()
- @editor.undo()
- @editor.moveLeft()
- @replaceModeCounter--
-
- setInsertionCheckpoint: ->
- @insertionCheckpoint = @editor.createCheckpoint() unless @insertionCheckpoint?
-
- deactivateInsertMode: ->
- return unless @mode in [null, 'insert']
- @editorElement.component.setInputEnabled(false)
- @editorElement.classList.remove('replace-mode')
- @editor.groupChangesSinceCheckpoint(@insertionCheckpoint)
- changes = getChangesSinceCheckpoint(@editor.buffer, @insertionCheckpoint)
- item = @inputOperator(@history[0])
- @insertionCheckpoint = null
- if item?
- item.confirmChanges(changes)
- for cursor in @editor.getCursors()
- cursor.moveLeft() unless cursor.isAtBeginningOfLine()
- if @replaceModeListener?
- @replaceModeListener.dispose()
- @subscriptions.remove @replaceModeListener
- @replaceModeListener = null
- @replaceModeUndoListener.dispose()
- @subscriptions.remove @replaceModeUndoListener
- @replaceModeUndoListener = null
-
- deactivateVisualMode: ->
- return unless @mode is 'visual'
- for selection in @editor.getSelections()
- selection.cursor.moveLeft() unless (selection.isEmpty() or selection.isReversed())
-
- # Private: Get the input operator that needs to be told about about the
- # typed undo transaction in a recently completed operation, if there
- # is one.
- inputOperator: (item) ->
- return item unless item?
- return item if item.inputOperator?()
- return item.composedObject if item.composedObject?.inputOperator?()
-
- # Private: Used to enable visual mode.
- #
- # type - One of 'characterwise', 'linewise' or 'blockwise'
- #
- # Returns nothing.
- activateVisualMode: (type) ->
- # Already in 'visual', this means one of following command is
- # executed within `vim-mode.visual-mode`
- # * activate-blockwise-visual-mode
- # * activate-characterwise-visual-mode
- # * activate-linewise-visual-mode
- if @mode is 'visual'
- if @submode is type
- @activateNormalMode()
- return
-
- @submode = type
- if @submode is 'linewise'
- for selection in @editor.getSelections()
- # Keep original range as marker's property to get back
- # to characterwise.
- # Since selectLine lost original cursor column.
- originalRange = selection.getBufferRange()
- selection.marker.setProperties({originalRange})
- [start, end] = selection.getBufferRowRange()
- selection.selectLine(row) for row in [start..end]
-
- else if @submode in ['characterwise', 'blockwise']
- # Currently, 'blockwise' is not yet implemented.
- # So treat it as characterwise.
- # Recover original range.
- for selection in @editor.getSelections()
- {originalRange} = selection.marker.getProperties()
- if originalRange
- [startRow, endRow] = selection.getBufferRowRange()
- originalRange.start.row = startRow
- originalRange.end.row = endRow
- selection.setBufferRange(originalRange)
- else
- @deactivateInsertMode()
- @mode = 'visual'
- @submode = type
- @changeModeClass('visual-mode')
-
- if @submode is 'linewise'
- @editor.selectLinesContainingCursors()
- else if @editor.getSelectedText() is ''
- @editor.selectRight()
-
- @updateStatusBar()
-
- # Private: Used to re-enable visual mode
- resetVisualMode: ->
- @activateVisualMode(@submode)
-
- # Private: Used to enable operator-pending mode.
- activateOperatorPendingMode: ->
- @deactivateInsertMode()
- @mode = 'operator-pending'
- @submode = null
- @changeModeClass('operator-pending-mode')
-
- @updateStatusBar()
-
- changeModeClass: (targetMode) ->
- for mode in ['normal-mode', 'insert-mode', 'visual-mode', 'operator-pending-mode']
- if mode is targetMode
- @editorElement.classList.add(mode)
- else
- @editorElement.classList.remove(mode)
-
- # Private: Resets the normal mode back to it's initial state.
- #
- # Returns nothing.
- resetNormalMode: ->
- @clearOpStack()
- @editor.clearSelections()
- @activateNormalMode()
-
- # Private: A generic way to create a Register prefix based on the event.
- #
- # e - The event that triggered the Register prefix.
- #
- # Returns nothing.
- registerPrefix: (e) ->
- new Prefixes.Register(@registerName(e))
-
- # Private: Gets a register name from a keyboard event
- #
- # e - The event
- #
- # Returns the name of the register
- registerName: (e) ->
- keyboardEvent = e.originalEvent?.originalEvent ? e.originalEvent
- name = atom.keymaps.keystrokeForKeyboardEvent(keyboardEvent)
- if name.lastIndexOf('shift-', 0) is 0
- name = name.slice(6)
- name
-
- # Private: A generic way to create a Number prefix based on the event.
- #
- # e - The event that triggered the Number prefix.
- #
- # Returns nothing.
- repeatPrefix: (e) ->
- keyboardEvent = e.originalEvent?.originalEvent ? e.originalEvent
- num = parseInt(atom.keymaps.keystrokeForKeyboardEvent(keyboardEvent))
- if @topOperation() instanceof Prefixes.Repeat
- @topOperation().addDigit(num)
- else
- if num is 0
- e.abortKeyBinding()
- else
- @pushOperations(new Prefixes.Repeat(num))
-
- reverseSelections: ->
- reversed = not @editor.getLastSelection().isReversed()
- for selection in @editor.getSelections()
- selection.setBufferRange(selection.getBufferRange(), {reversed})
-
- # Private: Figure out whether or not we are in a repeat sequence or we just
- # want to move to the beginning of the line. If we are within a repeat
- # sequence, we pass control over to @repeatPrefix.
- #
- # e - The triggered event.
- #
- # Returns new motion or nothing.
- moveOrRepeat: (e) ->
- if @topOperation() instanceof Prefixes.Repeat
- @repeatPrefix(e)
- null
- else
- new Motions.MoveToBeginningOfLine(@editor, this)
-
- # Private: A generic way to handle Operators that can be repeated for
- # their linewise form.
- #
- # constructor - The constructor of the operator.
- #
- # Returns nothing.
- linewiseAliasedOperator: (constructor) ->
- if @isOperatorPending(constructor)
- new Motions.MoveToRelativeLine(@editor, this)
- else
- new constructor(@editor, this)
-
- # Private: Check if there is a pending operation of a certain type, or
- # if there is any pending operation, if no type given.
- #
- # constructor - The constructor of the object type you're looking for.
- #
- isOperatorPending: (constructor) ->
- if constructor?
- for op in @opStack
- return op if op instanceof constructor
- false
- else
- @opStack.length > 0
-
- updateStatusBar: ->
- @statusBarManager.update(@mode, @submode)
-
- # Private: insert the contents of the register in the editor
- #
- # name - the name of the register to insert
- #
- # Returns nothing.
- insertRegister: (name) ->
- text = @getRegister(name)?.text
- @editor.insertText(text) if text?
-
- # Private: ensure the mode follows the state of selections
- checkSelections: =>
- return unless @editor?
- if @editor.getSelections().every((selection) -> selection.isEmpty())
- @ensureCursorsWithinLine() if @mode is 'normal'
- @activateNormalMode() if @mode is 'visual'
- else
- @activateVisualMode('characterwise') if @mode is 'normal'
-
- # Private: ensure the cursor stays within the line as appropriate
- ensureCursorsWithinLine: =>
- for cursor in @editor.getCursors()
- {goalColumn} = cursor
- if cursor.isAtEndOfLine() and not cursor.isAtBeginningOfLine()
- cursor.moveLeft()
- cursor.goalColumn = goalColumn
-
- @editor.mergeCursors()
-
-# This uses private APIs and may break if TextBuffer is refactored.
-# Package authors - copy and paste this code at your own risk.
-getChangesSinceCheckpoint = (buffer, checkpoint) ->
- {history} = buffer
-
- if (index = history.getCheckpointIndex(checkpoint))?
- history.undoStack.slice(index)
- else
- []