diff options
| author | Ben Beltran <ben@nsovocal.com> | 2019-03-14 23:19:58 +0100 |
|---|---|---|
| committer | Ben Beltran <ben@nsovocal.com> | 2019-03-14 23:19:58 +0100 |
| commit | b009b50e81b6c1d0d691505b5f5c0418f559bfc0 (patch) | |
| tree | 5fae800e76219eba28634cb236565f9b4bb7a2f7 /atom/packages/vim-mode/lib | |
| parent | 4efcafab7f0aa454f9ebe767133654bc9f44e12c (diff) | |
Remove Atom config
Diffstat (limited to 'atom/packages/vim-mode/lib')
25 files changed, 0 insertions, 2900 deletions
diff --git a/atom/packages/vim-mode/lib/global-vim-state.coffee b/atom/packages/vim-mode/lib/global-vim-state.coffee deleted file mode 100644 index acda507..0000000 --- a/atom/packages/vim-mode/lib/global-vim-state.coffee +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = -class GlobalVimState - registers: {} - searchHistory: [] - currentSearch: {} - currentFind: null diff --git a/atom/packages/vim-mode/lib/insert-mode.coffee b/atom/packages/vim-mode/lib/insert-mode.coffee deleted file mode 100644 index d600e7e..0000000 --- a/atom/packages/vim-mode/lib/insert-mode.coffee +++ /dev/null @@ -1,19 +0,0 @@ -copyCharacterFromAbove = (editor, vimState) -> - editor.transact -> - for cursor in editor.getCursors() - {row, column} = cursor.getScreenPosition() - continue if row is 0 - range = [[row-1, column], [row-1, column+1]] - cursor.selection.insertText(editor.getTextInBufferRange(editor.bufferRangeForScreenRange(range))) - -copyCharacterFromBelow = (editor, vimState) -> - editor.transact -> - for cursor in editor.getCursors() - {row, column} = cursor.getScreenPosition() - range = [[row+1, column], [row+1, column+1]] - cursor.selection.insertText(editor.getTextInBufferRange(editor.bufferRangeForScreenRange(range))) - -module.exports = { - copyCharacterFromAbove, - copyCharacterFromBelow -} diff --git a/atom/packages/vim-mode/lib/motions/find-motion.coffee b/atom/packages/vim-mode/lib/motions/find-motion.coffee deleted file mode 100644 index 2a577a8..0000000 --- a/atom/packages/vim-mode/lib/motions/find-motion.coffee +++ /dev/null @@ -1,72 +0,0 @@ -{MotionWithInput} = require './general-motions' -{ViewModel} = require '../view-models/view-model' -{Point, Range} = require 'atom' - -class Find extends MotionWithInput - operatesInclusively: true - - constructor: (@editor, @vimState, opts={}) -> - super(@editor, @vimState) - @offset = 0 - - if not opts.repeated - @viewModel = new ViewModel(this, class: 'find', singleChar: true, hidden: true) - @backwards = false - @repeated = false - @vimState.globalVimState.currentFind = this - - else - @repeated = true - - orig = @vimState.globalVimState.currentFind - @backwards = orig.backwards - @complete = orig.complete - @input = orig.input - - @reverse() if opts.reverse - - match: (cursor, count) -> - currentPosition = cursor.getBufferPosition() - line = @editor.lineTextForBufferRow(currentPosition.row) - if @backwards - index = currentPosition.column - for i in [0..count-1] - return if index <= 0 # we can't move backwards any further, quick return - index = line.lastIndexOf(@input.characters, index-1-(@offset*@repeated)) - if index >= 0 - new Point(currentPosition.row, index + @offset) - else - index = currentPosition.column - for i in [0..count-1] - index = line.indexOf(@input.characters, index+1+(@offset*@repeated)) - return if index < 0 # no match found - if index >= 0 - new Point(currentPosition.row, index - @offset) - - reverse: -> - @backwards = not @backwards - this - - moveCursor: (cursor, count=1) -> - if (match = @match(cursor, count))? - cursor.setBufferPosition(match) - -class Till extends Find - constructor: (@editor, @vimState, opts={}) -> - super(@editor, @vimState, opts) - @offset = 1 - - match: -> - @selectAtLeastOne = false - retval = super - if retval? and not @backwards - @selectAtLeastOne = true - retval - - moveSelectionInclusively: (selection, count, options) -> - super - if selection.isEmpty() and @selectAtLeastOne - selection.modifySelection -> - selection.cursor.moveRight() - -module.exports = {Find, Till} diff --git a/atom/packages/vim-mode/lib/motions/general-motions.coffee b/atom/packages/vim-mode/lib/motions/general-motions.coffee deleted file mode 100644 index b5cd627..0000000 --- a/atom/packages/vim-mode/lib/motions/general-motions.coffee +++ /dev/null @@ -1,483 +0,0 @@ -_ = require 'underscore-plus' -{Point, Range} = require 'atom' -settings = require '../settings' - -WholeWordRegex = /\S+/ -WholeWordOrEmptyLineRegex = /^\s*$|\S+/ -AllWhitespace = /^\s$/ - -class MotionError - constructor: (@message) -> - @name = 'Motion Error' - -class Motion - operatesInclusively: false - operatesLinewise: false - - constructor: (@editor, @vimState) -> - - select: (count, options) -> - value = for selection in @editor.getSelections() - if @isLinewise() - @moveSelectionLinewise(selection, count, options) - else if @vimState.mode is 'visual' - @moveSelectionVisual(selection, count, options) - else if @operatesInclusively - @moveSelectionInclusively(selection, count, options) - else - @moveSelection(selection, count, options) - not selection.isEmpty() - - @editor.mergeCursors() - @editor.mergeIntersectingSelections() - value - - execute: (count) -> - for cursor in @editor.getCursors() - @moveCursor(cursor, count) - @editor.mergeCursors() - - moveSelectionLinewise: (selection, count, options) -> - selection.modifySelection => - [oldStartRow, oldEndRow] = selection.getBufferRowRange() - - wasEmpty = selection.isEmpty() - wasReversed = selection.isReversed() - unless wasEmpty or wasReversed - selection.cursor.moveLeft() - - @moveCursor(selection.cursor, count, options) - - isEmpty = selection.isEmpty() - isReversed = selection.isReversed() - unless isEmpty or isReversed - selection.cursor.moveRight() - - [newStartRow, newEndRow] = selection.getBufferRowRange() - - if isReversed and not wasReversed - newEndRow = Math.max(newEndRow, oldStartRow) - if wasReversed and not isReversed - newStartRow = Math.min(newStartRow, oldEndRow) - - selection.setBufferRange([[newStartRow, 0], [newEndRow + 1, 0]]) - - moveSelectionInclusively: (selection, count, options) -> - return @moveSelectionVisual(selection, count, options) unless selection.isEmpty() - - selection.modifySelection => - @moveCursor(selection.cursor, count, options) - return if selection.isEmpty() - - if selection.isReversed() - # for backward motion, add the original starting character of the motion - {start, end} = selection.getBufferRange() - selection.setBufferRange([start, [end.row, end.column + 1]]) - else - # for forward motion, add the ending character of the motion - selection.cursor.moveRight() - - moveSelectionVisual: (selection, count, options) -> - selection.modifySelection => - range = selection.getBufferRange() - [oldStart, oldEnd] = [range.start, range.end] - - # in visual mode, atom cursor is after the last selected character, - # so here put cursor in the expected place for the following motion - wasEmpty = selection.isEmpty() - wasReversed = selection.isReversed() - unless wasEmpty or wasReversed - selection.cursor.moveLeft() - - @moveCursor(selection.cursor, count, options) - - # put cursor back after the last character so it is also selected - isEmpty = selection.isEmpty() - isReversed = selection.isReversed() - unless isEmpty or isReversed - selection.cursor.moveRight() - - range = selection.getBufferRange() - [newStart, newEnd] = [range.start, range.end] - - # if we reversed or emptied a normal selection - # we need to select again the last character deselected above the motion - if (isReversed or isEmpty) and not (wasReversed or wasEmpty) - selection.setBufferRange([newStart, [newEnd.row, oldStart.column + 1]]) - - # if we re-reversed a reversed non-empty selection, - # we need to keep the last character of the old selection selected - if wasReversed and not wasEmpty and not isReversed - selection.setBufferRange([[oldEnd.row, oldEnd.column - 1], newEnd]) - - # keep a single-character selection non-reversed - range = selection.getBufferRange() - [newStart, newEnd] = [range.start, range.end] - if selection.isReversed() and newStart.row is newEnd.row and newStart.column + 1 is newEnd.column - selection.setBufferRange(range, reversed: false) - - moveSelection: (selection, count, options) -> - selection.modifySelection => @moveCursor(selection.cursor, count, options) - - isComplete: -> true - - isRecordable: -> false - - isLinewise: -> - if @vimState?.mode is 'visual' - @vimState?.submode is 'linewise' - else - @operatesLinewise - -class CurrentSelection extends Motion - constructor: (@editor, @vimState) -> - super(@editor, @vimState) - @lastSelectionRange = @editor.getSelectedBufferRange() - @wasLinewise = @isLinewise() - - execute: (count=1) -> - _.times(count, -> true) - - select: (count=1) -> - # in visual mode, the current selections are already there - # if we're not in visual mode, we are repeating some operation and need to re-do the selections - unless @vimState.mode is 'visual' - if @wasLinewise - @selectLines() - else - @selectCharacters() - - _.times(count, -> true) - - selectLines: -> - lastSelectionExtent = @lastSelectionRange.getExtent() - for selection in @editor.getSelections() - cursor = selection.cursor.getBufferPosition() - selection.setBufferRange [[cursor.row, 0], [cursor.row + lastSelectionExtent.row, 0]] - return - - selectCharacters: -> - lastSelectionExtent = @lastSelectionRange.getExtent() - for selection in @editor.getSelections() - {start} = selection.getBufferRange() - newEnd = start.traverse(lastSelectionExtent) - selection.setBufferRange([start, newEnd]) - return - -# Public: Generic class for motions that require extra input -class MotionWithInput extends Motion - constructor: (@editor, @vimState) -> - super(@editor, @vimState) - @complete = false - - isComplete: -> @complete - - canComposeWith: (operation) -> return operation.characters? - - compose: (input) -> - if not input.characters - throw new MotionError('Must compose with an Input') - @input = input - @complete = true - -class MoveLeft extends Motion - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveLeft() if not cursor.isAtBeginningOfLine() or settings.wrapLeftRightMotion() - -class MoveRight extends Motion - moveCursor: (cursor, count=1) -> - _.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() - - cursor.moveRight() unless cursor.isAtEndOfLine() - cursor.moveRight() if wrapToNextLine and cursor.isAtEndOfLine() - -class MoveUp extends Motion - operatesLinewise: true - - moveCursor: (cursor, count=1) -> - _.times count, -> - unless cursor.getScreenRow() is 0 - cursor.moveUp() - -class MoveDown extends Motion - operatesLinewise: true - - moveCursor: (cursor, count=1) -> - _.times count, => - unless cursor.getScreenRow() is @editor.getLastScreenRow() - cursor.moveDown() - -class MoveToPreviousWord extends Motion - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveToBeginningOfWord() - -class MoveToPreviousWholeWord extends Motion - moveCursor: (cursor, count=1) -> - _.times count, => - cursor.moveToBeginningOfWord() - while not @isWholeWord(cursor) and not @isBeginningOfFile(cursor) - cursor.moveToBeginningOfWord() - - isWholeWord: (cursor) -> - char = cursor.getCurrentWordPrefix().slice(-1) - AllWhitespace.test(char) - - isBeginningOfFile: (cursor) -> - cur = cursor.getBufferPosition() - not cur.row and not cur.column - -class MoveToNextWord extends Motion - wordRegex: null - - moveCursor: (cursor, count=1, options) -> - _.times count, => - current = cursor.getBufferPosition() - - next = if options?.excludeWhitespace - cursor.getEndOfCurrentWordBufferPosition(wordRegex: @wordRegex) - else - cursor.getBeginningOfNextWordBufferPosition(wordRegex: @wordRegex) - - return if @isEndOfFile(cursor) - - if cursor.isAtEndOfLine() - cursor.moveDown() - cursor.moveToBeginningOfLine() - cursor.skipLeadingWhitespace() - else if current.row is next.row and current.column is next.column - cursor.moveToEndOfWord() - else - cursor.setBufferPosition(next) - - isEndOfFile: (cursor) -> - cur = cursor.getBufferPosition() - eof = @editor.getEofBufferPosition() - cur.row is eof.row and cur.column is eof.column - -class MoveToNextWholeWord extends MoveToNextWord - wordRegex: WholeWordOrEmptyLineRegex - -class MoveToEndOfWord extends Motion - operatesInclusively: true - wordRegex: null - - moveCursor: (cursor, count=1) -> - _.times count, => - current = cursor.getBufferPosition() - - next = cursor.getEndOfCurrentWordBufferPosition(wordRegex: @wordRegex) - next.column-- if next.column > 0 - - if next.isEqual(current) - cursor.moveRight() - if cursor.isAtEndOfLine() - cursor.moveDown() - cursor.moveToBeginningOfLine() - - next = cursor.getEndOfCurrentWordBufferPosition(wordRegex: @wordRegex) - next.column-- if next.column > 0 - - cursor.setBufferPosition(next) - -class MoveToEndOfWholeWord extends MoveToEndOfWord - wordRegex: WholeWordRegex - -class MoveToNextParagraph extends Motion - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveToBeginningOfNextParagraph() - -class MoveToPreviousParagraph extends Motion - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveToBeginningOfPreviousParagraph() - -class MoveToLine extends Motion - operatesLinewise: true - - getDestinationRow: (count) -> - if count? then count - 1 else (@editor.getLineCount() - 1) - -class MoveToAbsoluteLine extends MoveToLine - moveCursor: (cursor, count) -> - cursor.setBufferPosition([@getDestinationRow(count), Infinity]) - cursor.moveToFirstCharacterOfLine() - cursor.moveToEndOfLine() if cursor.getBufferColumn() is 0 - -class MoveToRelativeLine extends MoveToLine - moveCursor: (cursor, count=1) -> - {row, column} = cursor.getBufferPosition() - cursor.setBufferPosition([row + (count - 1), 0]) - -class MoveToScreenLine extends MoveToLine - constructor: (@editorElement, @vimState, @scrolloff) -> - @scrolloff = 2 # atom default - super(@editorElement.getModel(), @vimState) - - moveCursor: (cursor, count=1) -> - {row, column} = cursor.getBufferPosition() - cursor.setScreenPosition([@getDestinationRow(count), 0]) - -class MoveToBeginningOfLine extends Motion - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveToBeginningOfLine() - -class MoveToFirstCharacterOfLine extends Motion - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveToBeginningOfLine() - cursor.moveToFirstCharacterOfLine() - -class MoveToFirstCharacterOfLineAndDown extends Motion - operatesLinewise: true - - moveCursor: (cursor, count=1) -> - _.times count-1, -> - cursor.moveDown() - cursor.moveToBeginningOfLine() - cursor.moveToFirstCharacterOfLine() - -class MoveToLastCharacterOfLine extends Motion - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveToEndOfLine() - cursor.goalColumn = Infinity - -class MoveToLastNonblankCharacterOfLineAndDown extends Motion - operatesInclusively: true - - # moves cursor to the last non-whitespace character on the line - # similar to skipLeadingWhitespace() in atom's cursor.coffee - skipTrailingWhitespace: (cursor) -> - position = cursor.getBufferPosition() - scanRange = cursor.getCurrentLineBufferRange() - startOfTrailingWhitespace = [scanRange.end.row, scanRange.end.column - 1] - @editor.scanInBufferRange /[ \t]+$/, scanRange, ({range}) -> - startOfTrailingWhitespace = range.start - startOfTrailingWhitespace.column -= 1 - cursor.setBufferPosition(startOfTrailingWhitespace) - - moveCursor: (cursor, count=1) -> - _.times count-1, -> - cursor.moveDown() - @skipTrailingWhitespace(cursor) - -class MoveToFirstCharacterOfLineUp extends Motion - operatesLinewise: true - - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveUp() - cursor.moveToBeginningOfLine() - cursor.moveToFirstCharacterOfLine() - -class MoveToFirstCharacterOfLineDown extends Motion - operatesLinewise: true - - moveCursor: (cursor, count=1) -> - _.times count, -> - cursor.moveDown() - cursor.moveToBeginningOfLine() - cursor.moveToFirstCharacterOfLine() - -class MoveToStartOfFile extends MoveToLine - moveCursor: (cursor, count=1) -> - {row, column} = @editor.getCursorBufferPosition() - cursor.setBufferPosition([@getDestinationRow(count), 0]) - unless @isLinewise() - cursor.moveToFirstCharacterOfLine() - -class MoveToTopOfScreen extends MoveToScreenLine - getDestinationRow: (count=0) -> - firstScreenRow = @editorElement.getFirstVisibleScreenRow() - if firstScreenRow > 0 - offset = Math.max(count - 1, @scrolloff) - else - offset = if count > 0 then count - 1 else count - firstScreenRow + offset - -class MoveToBottomOfScreen extends MoveToScreenLine - getDestinationRow: (count=0) -> - lastScreenRow = @editorElement.getLastVisibleScreenRow() - lastRow = @editor.getBuffer().getLastRow() - if lastScreenRow isnt lastRow - offset = Math.max(count - 1, @scrolloff) - else - offset = if count > 0 then count - 1 else count - lastScreenRow - offset - -class MoveToMiddleOfScreen extends MoveToScreenLine - getDestinationRow: -> - firstScreenRow = @editorElement.getFirstVisibleScreenRow() - lastScreenRow = @editorElement.getLastVisibleScreenRow() - height = lastScreenRow - firstScreenRow - Math.floor(firstScreenRow + (height / 2)) - -class ScrollKeepingCursor extends MoveToLine - previousFirstScreenRow: 0 - currentFirstScreenRow: 0 - - constructor: (@editorElement, @vimState) -> - super(@editorElement.getModel(), @vimState) - - select: (count, options) -> - finalDestination = @scrollScreen(count) - super(count, options) - @editor.setScrollTop(finalDestination) - - execute: (count) -> - finalDestination = @scrollScreen(count) - super(count) - @editor.setScrollTop(finalDestination) - - moveCursor: (cursor, count=1) -> - cursor.setScreenPosition([@getDestinationRow(count), 0]) - - getDestinationRow: (count) -> - {row, column} = @editor.getCursorScreenPosition() - @currentFirstScreenRow - @previousFirstScreenRow + row - - scrollScreen: (count=1) -> - @previousFirstScreenRow = @editorElement.getFirstVisibleScreenRow() - destination = @scrollDestination(count) - @editor.setScrollTop(destination) - @currentFirstScreenRow = @editorElement.getFirstVisibleScreenRow() - destination - -class ScrollHalfUpKeepCursor extends ScrollKeepingCursor - scrollDestination: (count) -> - half = (Math.floor(@editor.getRowsPerPage() / 2) * @editor.getLineHeightInPixels()) - @editor.getScrollTop() - count * half - -class ScrollFullUpKeepCursor extends ScrollKeepingCursor - scrollDestination: (count) -> - @editor.getScrollTop() - (count * @editor.getHeight()) - -class ScrollHalfDownKeepCursor extends ScrollKeepingCursor - scrollDestination: (count) -> - half = (Math.floor(@editor.getRowsPerPage() / 2) * @editor.getLineHeightInPixels()) - @editor.getScrollTop() + count * half - -class ScrollFullDownKeepCursor extends ScrollKeepingCursor - scrollDestination: (count) -> - @editor.getScrollTop() + (count * @editor.getHeight()) - -module.exports = { - Motion, MotionWithInput, CurrentSelection, MoveLeft, MoveRight, MoveUp, MoveDown, - MoveToPreviousWord, MoveToPreviousWholeWord, MoveToNextWord, MoveToNextWholeWord, - MoveToEndOfWord, MoveToNextParagraph, MoveToPreviousParagraph, MoveToAbsoluteLine, MoveToRelativeLine, MoveToBeginningOfLine, - MoveToFirstCharacterOfLineUp, MoveToFirstCharacterOfLineDown, - MoveToFirstCharacterOfLine, MoveToFirstCharacterOfLineAndDown, MoveToLastCharacterOfLine, - MoveToLastNonblankCharacterOfLineAndDown, MoveToStartOfFile, - MoveToTopOfScreen, MoveToBottomOfScreen, MoveToMiddleOfScreen, MoveToEndOfWholeWord, MotionError, - ScrollHalfUpKeepCursor, ScrollFullUpKeepCursor, - ScrollHalfDownKeepCursor, ScrollFullDownKeepCursor -} diff --git a/atom/packages/vim-mode/lib/motions/index.coffee b/atom/packages/vim-mode/lib/motions/index.coffee deleted file mode 100644 index 0fd420f..0000000 --- a/atom/packages/vim-mode/lib/motions/index.coffee +++ /dev/null @@ -1,14 +0,0 @@ -Motions = require './general-motions' -{Search, SearchCurrentWord, BracketMatchingMotion, RepeatSearch} = require './search-motion' -MoveToMark = require './move-to-mark-motion' -{Find, Till} = require './find-motion' - -Motions.Search = Search -Motions.SearchCurrentWord = SearchCurrentWord -Motions.BracketMatchingMotion = BracketMatchingMotion -Motions.RepeatSearch = RepeatSearch -Motions.MoveToMark = MoveToMark -Motions.Find = Find -Motions.Till = Till - -module.exports = Motions diff --git a/atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee b/atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee deleted file mode 100644 index 3603e1e..0000000 --- a/atom/packages/vim-mode/lib/motions/move-to-mark-motion.coffee +++ /dev/null @@ -1,23 +0,0 @@ -{MotionWithInput, MoveToFirstCharacterOfLine} = require './general-motions' -{ViewModel} = require '../view-models/view-model' -{Point, Range} = require 'atom' - -module.exports = -class MoveToMark extends MotionWithInput - constructor: (@editor, @vimState, @linewise=true) -> - super(@editor, @vimState) - @operatesLinewise = @linewise - @viewModel = new ViewModel(this, class: 'move-to-mark', singleChar: true, hidden: true) - - isLinewise: -> @linewise - - moveCursor: (cursor, count=1) -> - markPosition = @vimState.getMark(@input.characters) - - if @input.characters is '`' # double '`' pressed - markPosition ?= [0, 0] # if markPosition not set, go to the beginning of the file - @vimState.setMark('`', cursor.getBufferPosition()) - - cursor.setBufferPosition(markPosition) if markPosition? - if @linewise - cursor.moveToFirstCharacterOfLine() diff --git a/atom/packages/vim-mode/lib/motions/search-motion.coffee b/atom/packages/vim-mode/lib/motions/search-motion.coffee deleted file mode 100644 index fa65e19..0000000 --- a/atom/packages/vim-mode/lib/motions/search-motion.coffee +++ /dev/null @@ -1,220 +0,0 @@ -_ = require 'underscore-plus' -{MotionWithInput} = require './general-motions' -SearchViewModel = require '../view-models/search-view-model' -{Input} = require '../view-models/view-model' -{Point, Range} = require 'atom' -settings = require '../settings' - -class SearchBase extends MotionWithInput - constructor: (@editor, @vimState, options = {}) -> - super(@editor, @vimState) - @reverse = @initiallyReversed = false - @updateCurrentSearch() unless options.dontUpdateCurrentSearch - - reversed: => - @initiallyReversed = @reverse = true - @updateCurrentSearch() - this - - moveCursor: (cursor, count=1) -> - ranges = @scan(cursor) - if ranges.length > 0 - range = ranges[(count - 1) % ranges.length] - cursor.setBufferPosition(range.start) - else - atom.beep() - - scan: (cursor) -> - return [] if @input.characters is "" - - currentPosition = cursor.getBufferPosition() - - [rangesBefore, rangesAfter] = [[], []] - @editor.scan @getSearchTerm(@input.characters), ({range}) => - isBefore = if @reverse - range.start.compare(currentPosition) < 0 - else - range.start.compare(currentPosition) <= 0 - - if isBefore - rangesBefore.push(range) - else - rangesAfter.push(range) - - if @reverse - rangesAfter.concat(rangesBefore).reverse() - else - rangesAfter.concat(rangesBefore) - - getSearchTerm: (term) -> - modifiers = {'g': true} - - if not term.match('[A-Z]') and settings.useSmartcaseForSearch() - modifiers['i'] = true - - if term.indexOf('\\c') >= 0 - term = term.replace('\\c', '') - modifiers['i'] = true - - modFlags = Object.keys(modifiers).join('') - - try - new RegExp(term, modFlags) - catch - new RegExp(_.escapeRegExp(term), modFlags) - - updateCurrentSearch: -> - @vimState.globalVimState.currentSearch.reverse = @reverse - @vimState.globalVimState.currentSearch.initiallyReversed = @initiallyReversed - - replicateCurrentSearch: -> - @reverse = @vimState.globalVimState.currentSearch.reverse - @initiallyReversed = @vimState.globalVimState.currentSearch.initiallyReversed - -class Search extends SearchBase - constructor: (@editor, @vimState) -> - super(@editor, @vimState) - @viewModel = new SearchViewModel(this) - @updateViewModel() - - reversed: => - @initiallyReversed = @reverse = true - @updateCurrentSearch() - @updateViewModel() - this - - updateViewModel: -> - @viewModel.update(@initiallyReversed) - -class SearchCurrentWord extends SearchBase - @keywordRegex: null - - constructor: (@editor, @vimState) -> - super(@editor, @vimState) - - # FIXME: This must depend on the current language - defaultIsKeyword = "[@a-zA-Z0-9_\-]+" - userIsKeyword = atom.config.get('vim-mode.iskeyword') - @keywordRegex = new RegExp(userIsKeyword or defaultIsKeyword) - - searchString = @getCurrentWordMatch() - @input = new Input(searchString) - @vimState.pushSearchHistory(searchString) unless searchString is @vimState.getSearchHistoryItem() - - getCurrentWord: -> - cursor = @editor.getLastCursor() - wordStart = cursor.getBeginningOfCurrentWordBufferPosition(wordRegex: @keywordRegex, allowPrevious: false) - wordEnd = cursor.getEndOfCurrentWordBufferPosition (wordRegex: @keywordRegex, allowNext: false) - cursorPosition = cursor.getBufferPosition() - - if wordEnd.column is cursorPosition.column - # either we don't have a current word, or it ends on cursor, i.e. precedes it, so look for the next one - wordEnd = cursor.getEndOfCurrentWordBufferPosition (wordRegex: @keywordRegex, allowNext: true) - return "" if wordEnd.row isnt cursorPosition.row # don't look beyond the current line - - cursor.setBufferPosition wordEnd - wordStart = cursor.getBeginningOfCurrentWordBufferPosition(wordRegex: @keywordRegex, allowPrevious: false) - - cursor.setBufferPosition wordStart - - @editor.getTextInBufferRange([wordStart, wordEnd]) - - cursorIsOnEOF: (cursor) -> - pos = cursor.getNextWordBoundaryBufferPosition(wordRegex: @keywordRegex) - eofPos = @editor.getEofBufferPosition() - pos.row is eofPos.row and pos.column is eofPos.column - - getCurrentWordMatch: -> - characters = @getCurrentWord() - if characters.length > 0 - if /\W/.test(characters) then "#{characters}\\b" else "\\b#{characters}\\b" - else - characters - - isComplete: -> true - - execute: (count=1) -> - super(count) if @input.characters.length > 0 - -OpenBrackets = ['(', '{', '['] -CloseBrackets = [')', '}', ']'] -AnyBracket = new RegExp(OpenBrackets.concat(CloseBrackets).map(_.escapeRegExp).join("|")) - -class BracketMatchingMotion extends SearchBase - operatesInclusively: true - - isComplete: -> true - - searchForMatch: (startPosition, reverse, inCharacter, outCharacter) -> - depth = 0 - point = startPosition.copy() - lineLength = @editor.lineTextForBufferRow(point.row).length - eofPosition = @editor.getEofBufferPosition().translate([0, 1]) - increment = if reverse then -1 else 1 - - loop - character = @characterAt(point) - depth++ if character is inCharacter - depth-- if character is outCharacter - - return point if depth is 0 - - point.column += increment - - return null if depth < 0 - return null if point.isEqual([0, -1]) - return null if point.isEqual(eofPosition) - - if point.column < 0 - point.row-- - lineLength = @editor.lineTextForBufferRow(point.row).length - point.column = lineLength - 1 - else if point.column >= lineLength - point.row++ - lineLength = @editor.lineTextForBufferRow(point.row).length - point.column = 0 - - characterAt: (position) -> - @editor.getTextInBufferRange([position, position.translate([0, 1])]) - - getSearchData: (position) -> - character = @characterAt(position) - if (index = OpenBrackets.indexOf(character)) >= 0 - [character, CloseBrackets[index], false] - else if (index = CloseBrackets.indexOf(character)) >= 0 - [character, OpenBrackets[index], true] - else - [] - - moveCursor: (cursor) -> - startPosition = cursor.getBufferPosition() - - [inCharacter, outCharacter, reverse] = @getSearchData(startPosition) - - unless inCharacter? - restOfLine = [startPosition, [startPosition.row, Infinity]] - @editor.scanInBufferRange AnyBracket, restOfLine, ({range, stop}) -> - startPosition = range.start - stop() - - [inCharacter, outCharacter, reverse] = @getSearchData(startPosition) - - return unless inCharacter? - - if matchPosition = @searchForMatch(startPosition, reverse, inCharacter, outCharacter) - cursor.setBufferPosition(matchPosition) - -class RepeatSearch extends SearchBase - constructor: (@editor, @vimState) -> - super(@editor, @vimState, dontUpdateCurrentSearch: true) - @input = new Input(@vimState.getSearchHistoryItem(0) ? "") - @replicateCurrentSearch() - - isComplete: -> true - - reversed: -> - @reverse = not @initiallyReversed - this - - -module.exports = {Search, SearchCurrentWord, BracketMatchingMotion, RepeatSearch} diff --git a/atom/packages/vim-mode/lib/operators/general-operators.coffee b/atom/packages/vim-mode/lib/operators/general-operators.coffee deleted file mode 100644 index 9547941..0000000 --- a/atom/packages/vim-mode/lib/operators/general-operators.coffee +++ /dev/null @@ -1,260 +0,0 @@ -_ = require 'underscore-plus' -{Point, Range} = require 'atom' -{ViewModel} = require '../view-models/view-model' -Utils = require '../utils' -settings = require '../settings' - -class OperatorError - constructor: (@message) -> - @name = 'Operator Error' - -class Operator - vimState: null - motion: null - complete: null - - constructor: (@editor, @vimState) -> - @complete = false - - # Public: Determines when the command can be executed. - # - # Returns true if ready to execute and false otherwise. - isComplete: -> @complete - - # Public: Determines if this command should be recorded in the command - # history for repeats. - # - # Returns true if this command should be recorded. - isRecordable: -> true - - # Public: Marks this as ready to execute and saves the motion. - # - # motion - The motion used to select what to operate on. - # - # Returns nothing. - compose: (motion) -> - if not motion.select - throw new OperatorError('Must compose with a motion') - - @motion = motion - @complete = true - - canComposeWith: (operation) -> operation.select? - - # Public: Preps text and sets the text register - # - # Returns nothing - setTextRegister: (register, text) -> - if @motion?.isLinewise?() - type = 'linewise' - if text[-1..] isnt '\n' - text += '\n' - else - type = Utils.copyType(text) - @vimState.setRegister(register, {text, type}) unless text is '' - -# Public: Generic class for an operator that requires extra input -class OperatorWithInput extends Operator - constructor: (@editor, @vimState) -> - @editor = @editor - @complete = false - - canComposeWith: (operation) -> operation.characters? or operation.select? - - compose: (operation) -> - if operation.select? - @motion = operation - if operation.characters? - @input = operation - @complete = true - -# -# It deletes everything selected by the following motion. -# -class Delete extends Operator - register: null - - constructor: (@editor, @vimState) -> - @complete = false - @register = settings.defaultRegister() - - # Public: Deletes the text selected by the given motion. - # - # count - The number of times to execute. - # - # Returns nothing. - execute: (count) -> - if _.contains(@motion.select(count), true) - @setTextRegister(@register, @editor.getSelectedText()) - @editor.transact => - for selection in @editor.getSelections() - selection.deleteSelectedText() - for cursor in @editor.getCursors() - if @motion.isLinewise?() - cursor.skipLeadingWhitespace() - else - cursor.moveLeft() if cursor.isAtEndOfLine() and not cursor.isAtBeginningOfLine() - - @vimState.activateNormalMode() - -# -# It toggles the case of everything selected by the following motion -# -class ToggleCase extends Operator - constructor: (@editor, @vimState, {@complete}={}) -> - - execute: (count) -> - if @motion? - if _.contains(@motion.select(count), true) - @editor.replaceSelectedText {}, (text) -> - text.split('').map((char) -> - lower = char.toLowerCase() - if char is lower - char.toUpperCase() - else - lower - ).join('') - else - @editor.transact => - for cursor in @editor.getCursors() - point = cursor.getBufferPosition() - lineLength = @editor.lineTextForBufferRow(point.row).length - cursorCount = Math.min(count ? 1, lineLength - point.column) - - _.times cursorCount, => - point = cursor.getBufferPosition() - range = Range.fromPointWithDelta(point, 0, 1) - char = @editor.getTextInBufferRange(range) - - if char is char.toLowerCase() - @editor.setTextInBufferRange(range, char.toUpperCase()) - else - @editor.setTextInBufferRange(range, char.toLowerCase()) - - cursor.moveRight() unless point.column >= lineLength - 1 - - @vimState.activateNormalMode() - -# -# In visual mode or after `g` with a motion, it makes the selection uppercase -# -class UpperCase extends Operator - constructor: (@editor, @vimState) -> - @complete = false - - execute: (count) -> - if _.contains(@motion.select(count), true) - @editor.replaceSelectedText {}, (text) -> - text.toUpperCase() - - @vimState.activateNormalMode() - -# -# In visual mode or after `g` with a motion, it makes the selection lowercase -# -class LowerCase extends Operator - constructor: (@editor, @vimState) -> - @complete = false - - execute: (count) -> - if _.contains(@motion.select(count), true) - @editor.replaceSelectedText {}, (text) -> - text.toLowerCase() - - @vimState.activateNormalMode() - -# -# It copies everything selected by the following motion. -# -class Yank extends Operator - register: null - - constructor: (@editor, @vimState) -> - @register = settings.defaultRegister() - - # Public: Copies the text selected by the given motion. - # - # count - The number of times to execute. - # - # Returns nothing. - execute: (count) -> - oldTop = @editor.getScrollTop() - oldLeft = @editor.getScrollLeft() - oldLastCursorPosition = @editor.getCursorBufferPosition() - - originalPositions = @editor.getCursorBufferPositions() - if _.contains(@motion.select(count), true) - text = @editor.getSelectedText() - startPositions = _.pluck(@editor.getSelectedBufferRanges(), "start") - newPositions = for originalPosition, i in originalPositions - if startPositions[i] - position = Point.min(startPositions[i], originalPositions[i]) - if @vimState.mode isnt 'visual' and @motion.isLinewise?() - position = new Point(position.row, originalPositions[i].column) - position - else - originalPosition - else - text = '' - newPositions = originalPositions - - @setTextRegister(@register, text) - - @editor.setSelectedBufferRanges(newPositions.map (p) -> new Range(p, p)) - - if oldLastCursorPosition.isEqual(@editor.getCursorBufferPosition()) - @editor.setScrollLeft(oldLeft) - @editor.setScrollTop(oldTop) - - @vimState.activateNormalMode() - -# -# It combines the current line with the following line. -# -class Join extends Operator - constructor: (@editor, @vimState) -> @complete = true - - # Public: Combines the current with the following lines - # - # count - The number of times to execute. - # - # Returns nothing. - execute: (count=1) -> - @editor.transact => - _.times count, => - @editor.joinLines() - @vimState.activateNormalMode() - -# -# Repeat the last operation -# -class Repeat extends Operator - constructor: (@editor, @vimState) -> @complete = true - - isRecordable: -> false - - execute: (count=1) -> - @editor.transact => - _.times count, => - cmd = @vimState.history[0] - cmd?.execute() -# -# It creates a mark at the current cursor position -# -class Mark extends OperatorWithInput - constructor: (@editor, @vimState) -> - super(@editor, @vimState) - @viewModel = new ViewModel(this, class: 'mark', singleChar: true, hidden: true) - - # Public: Creates the mark in the specified mark register (from user input) - # at the current position - # - # Returns nothing. - execute: -> - @vimState.setMark(@input.characters, @editor.getCursorBufferPosition()) - @vimState.activateNormalMode() - -module.exports = { - Operator, OperatorWithInput, OperatorError, Delete, ToggleCase, - UpperCase, LowerCase, Yank, Join, Repeat, Mark -} diff --git a/atom/packages/vim-mode/lib/operators/increase-operators.coffee b/atom/packages/vim-mode/lib/operators/increase-operators.coffee deleted file mode 100644 index e62f781..0000000 --- a/atom/packages/vim-mode/lib/operators/increase-operators.coffee +++ /dev/null @@ -1,57 +0,0 @@ -{Operator} = require './general-operators' -{Range} = require 'atom' -settings = require '../settings' - -# -# It increases or decreases the next number on the line -# -class Increase extends Operator - step: 1 - - constructor: -> - super - @complete = true - @numberRegex = new RegExp(settings.numberRegex()) - - execute: (count=1) -> - @editor.transact => - increased = false - for cursor in @editor.getCursors() - if @increaseNumber(count, cursor) then increased = true - atom.beep() unless increased - - increaseNumber: (count, cursor) -> - # find position of current number, adapted from from SearchCurrentWord - cursorPosition = cursor.getBufferPosition() - numEnd = cursor.getEndOfCurrentWordBufferPosition(wordRegex: @numberRegex, allowNext: false) - - if numEnd.column is cursorPosition.column - # either we don't have a current number, or it ends on cursor, i.e. precedes it, so look for the next one - numEnd = cursor.getEndOfCurrentWordBufferPosition(wordRegex: @numberRegex, allowNext: true) - return if numEnd.row isnt cursorPosition.row # don't look beyond the current line - return if numEnd.column is cursorPosition.column # no number after cursor - - cursor.setBufferPosition numEnd - numStart = cursor.getBeginningOfCurrentWordBufferPosition(wordRegex: @numberRegex, allowPrevious: false) - - range = new Range(numStart, numEnd) - - # parse number, increase/decrease - number = parseInt(@editor.getTextInBufferRange(range), 10) - if isNaN(number) - cursor.setBufferPosition(cursorPosition) - return - - number += @step*count - - # replace current number with new - newValue = String(number) - @editor.setTextInBufferRange(range, newValue, normalizeLineEndings: false) - - cursor.setBufferPosition(row: numStart.row, column: numStart.column-1+newValue.length) - return true - -class Decrease extends Increase - step: -1 - -module.exports = {Increase, Decrease} diff --git a/atom/packages/vim-mode/lib/operators/indent-operators.coffee b/atom/packages/vim-mode/lib/operators/indent-operators.coffee deleted file mode 100644 index ba3c155..0000000 --- a/atom/packages/vim-mode/lib/operators/indent-operators.coffee +++ /dev/null @@ -1,35 +0,0 @@ -_ = require 'underscore-plus' -{Operator} = require './general-operators' - -class AdjustIndentation extends Operator - execute: (count) -> - mode = @vimState.mode - @motion.select(count) - originalRanges = @editor.getSelectedBufferRanges() - - if mode is 'visual' - @editor.transact => - _.times(count ? 1, => @indent()) - else - @indent() - - @editor.clearSelections() - @editor.getLastCursor().setBufferPosition([originalRanges.shift().start.row, 0]) - for range in originalRanges - @editor.addCursorAtBufferPosition([range.start.row, 0]) - @editor.moveToFirstCharacterOfLine() - @vimState.activateNormalMode() - -class Indent extends AdjustIndentation - indent: -> - @editor.indentSelectedRows() - -class Outdent extends AdjustIndentation - indent: -> - @editor.outdentSelectedRows() - -class Autoindent extends AdjustIndentation - indent: -> - @editor.autoIndentSelectedRows() - -module.exports = {Indent, Outdent, Autoindent} diff --git a/atom/packages/vim-mode/lib/operators/index.coffee b/atom/packages/vim-mode/lib/operators/index.coffee deleted file mode 100644 index 575def3..0000000 --- a/atom/packages/vim-mode/lib/operators/index.coffee +++ /dev/null @@ -1,14 +0,0 @@ -_ = require 'underscore-plus' -IndentOperators = require './indent-operators' -IncreaseOperators = require './increase-operators' -Put = require './put-operator' -InputOperators = require './input' -Replace = require './replace-operator' -Operators = require './general-operators' - -Operators.Put = Put -Operators.Replace = Replace -_.extend(Operators, IndentOperators) -_.extend(Operators, IncreaseOperators) -_.extend(Operators, InputOperators) -module.exports = Operators diff --git a/atom/packages/vim-mode/lib/operators/input.coffee b/atom/packages/vim-mode/lib/operators/input.coffee deleted file mode 100644 index 0fee121..0000000 --- a/atom/packages/vim-mode/lib/operators/input.coffee +++ /dev/null @@ -1,213 +0,0 @@ -Motions = require '../motions/index' -{Operator, Delete} = require './general-operators' -_ = require 'underscore-plus' -settings = require '../settings' - -# The operation for text entered in input mode. Broadly speaking, input -# operators manage an undo transaction and set a @typingCompleted variable when -# it's done. When the input operation is completed, the typingCompleted variable -# tells the operation to repeat itself instead of enter insert mode. -class Insert extends Operator - standalone: true - - isComplete: -> @standalone or super - - confirmChanges: (changes) -> - bundler = new TransactionBundler(changes, @editor) - @typedText = bundler.buildInsertText() - - execute: -> - if @typingCompleted - return unless @typedText? and @typedText.length > 0 - @editor.insertText(@typedText, normalizeLineEndings: true, autoIndent: true) - for cursor in @editor.getCursors() - cursor.moveLeft() unless cursor.isAtBeginningOfLine() - else - @vimState.activateInsertMode() - @typingCompleted = true - return - - inputOperator: -> true - -class ReplaceMode extends Insert - - execute: -> - if @typingCompleted - return unless @typedText? and @typedText.length > 0 - @editor.transact => - @editor.insertText(@typedText, normalizeLineEndings: true) - toDelete = @typedText.length - @countChars('\n', @typedText) - for selection in @editor.getSelections() - count = toDelete - selection.delete() while count-- and not selection.cursor.isAtEndOfLine() - for cursor in @editor.getCursors() - cursor.moveLeft() unless cursor.isAtBeginningOfLine() - else - @vimState.activateReplaceMode() - @typingCompleted = true - - countChars: (char, string) -> - string.split(char).length - 1 - -class InsertAfter extends Insert - execute: -> - @editor.moveRight() unless @editor.getLastCursor().isAtEndOfLine() - super - -class InsertAfterEndOfLine extends Insert - execute: -> - @editor.moveToEndOfLine() - super - -class InsertAtBeginningOfLine extends Insert - execute: -> - @editor.moveToBeginningOfLine() - @editor.moveToFirstCharacterOfLine() - super - -class InsertAboveWithNewline extends Insert - execute: -> - @vimState.setInsertionCheckpoint() unless @typingCompleted - @editor.insertNewlineAbove() - @editor.getLastCursor().skipLeadingWhitespace() - - if @typingCompleted - # We'll have captured the inserted newline, but we want to do that - # over again by hand, or differing indentations will be wrong. - @typedText = @typedText.trimLeft() - return super - - @vimState.activateInsertMode() - @typingCompleted = true - -class InsertBelowWithNewline extends Insert - execute: -> - @vimState.setInsertionCheckpoint() unless @typingCompleted - @editor.insertNewlineBelow() - @editor.getLastCursor().skipLeadingWhitespace() - - if @typingCompleted - # We'll have captured the inserted newline, but we want to do that - # over again by hand, or differing indentations will be wrong. - @typedText = @typedText.trimLeft() - return super - - @vimState.activateInsertMode() - @typingCompleted = true - -# -# Delete the following motion and enter insert mode to replace it. -# -class Change extends Insert - standalone: false - register: null - - constructor: (@editor, @vimState) -> - @register = settings.defaultRegister() - - # Public: Changes the text selected by the given motion. - # - # count - The number of times to execute. - # - # Returns nothing. - execute: (count) -> - if _.contains(@motion.select(count, excludeWhitespace: true), true) - # If we've typed, we're being repeated. If we're being repeated, - # undo transactions are already handled. - @vimState.setInsertionCheckpoint() unless @typingCompleted - - @setTextRegister(@register, @editor.getSelectedText()) - if @motion.isLinewise?() and not @typingCompleted - for selection in @editor.getSelections() - if selection.getBufferRange().end.row is 0 - selection.deleteSelectedText() - else - selection.insertText("\n", autoIndent: true) - selection.cursor.moveLeft() - else - for selection in @editor.getSelections() - selection.deleteSelectedText() - - return super if @typingCompleted - - @vimState.activateInsertMode() - @typingCompleted = true - else - @vimState.activateNormalMode() - -# Takes a transaction and turns it into a string of what was typed. -# This class is an implementation detail of Insert -class TransactionBundler - constructor: (@changes, @editor) -> - @start = null - @end = null - - buildInsertText: -> - @addChange(change) for change in @changes - if @start? - @editor.getTextInBufferRange [@start, @end] - else - "" - - addChange: (change) -> - return unless change.newRange? - if @isRemovingFromPrevious(change) - @subtractRange change.oldRange - if @isAddingWithinPrevious(change) - @addRange change.newRange - - isAddingWithinPrevious: (change) -> - return false unless @isAdding(change) - - return true if @start is null - - @start.isLessThanOrEqual(change.newRange.start) and - @end.isGreaterThanOrEqual(change.newRange.start) - - isRemovingFromPrevious: (change) -> - return false unless @isRemoving(change) and @start? - - @start.isLessThanOrEqual(change.oldRange.start) and - @end.isGreaterThanOrEqual(change.oldRange.end) - - isAdding: (change) -> - change.newText.length > 0 - - isRemoving: (change) -> - change.oldText.length > 0 - - addRange: (range) -> - if @start is null - {@start, @end} = range - return - - rows = range.end.row - range.start.row - - if (range.start.row is @end.row) - cols = range.end.column - range.start.column - else - cols = 0 - - @end = @end.translate [rows, cols] - - subtractRange: (range) -> - rows = range.end.row - range.start.row - - if (range.end.row is @end.row) - cols = range.end.column - range.start.column - else - cols = 0 - - @end = @end.translate [-rows, -cols] - - -module.exports = { - Insert, - InsertAfter, - InsertAfterEndOfLine, - InsertAtBeginningOfLine, - InsertAboveWithNewline, - InsertBelowWithNewline, - ReplaceMode, - Change -} diff --git a/atom/packages/vim-mode/lib/operators/put-operator.coffee b/atom/packages/vim-mode/lib/operators/put-operator.coffee deleted file mode 100644 index 611d6fa..0000000 --- a/atom/packages/vim-mode/lib/operators/put-operator.coffee +++ /dev/null @@ -1,73 +0,0 @@ -_ = require 'underscore-plus' -{Operator} = require './general-operators' -settings = require '../settings' - -module.exports = -# -# It pastes everything contained within the specifed register -# -class Put extends Operator - register: null - - constructor: (@editor, @vimState, {@location}={}) -> - @location ?= 'after' - @complete = true - @register = settings.defaultRegister() - - # Public: Pastes the text in the given register. - # - # count - The number of times to execute. - # - # Returns nothing. - execute: (count=1) -> - {text, type} = @vimState.getRegister(@register) or {} - return unless text - - textToInsert = _.times(count, -> text).join('') - - selection = @editor.getSelectedBufferRange() - if selection.isEmpty() - # Clean up some corner cases on the last line of the file - if type is 'linewise' - textToInsert = textToInsert.replace(/\n$/, '') - if @location is 'after' and @onLastRow() - textToInsert = "\n#{textToInsert}" - else - textToInsert = "#{textToInsert}\n" - - if @location is 'after' - if type is 'linewise' - if @onLastRow() - @editor.moveToEndOfLine() - - originalPosition = @editor.getCursorScreenPosition() - originalPosition.row += 1 - else - @editor.moveDown() - else - unless @onLastColumn() - @editor.moveRight() - - if type is 'linewise' and not originalPosition? - @editor.moveToBeginningOfLine() - originalPosition = @editor.getCursorScreenPosition() - - @editor.insertText(textToInsert) - - if originalPosition? - @editor.setCursorScreenPosition(originalPosition) - @editor.moveToFirstCharacterOfLine() - - if type isnt 'linewise' - @editor.moveLeft() - @vimState.activateNormalMode() - - # Private: Helper to determine if the editor is currently on the last row. - # - # Returns true on the last row and false otherwise. - onLastRow: -> - {row, column} = @editor.getCursorBufferPosition() - row is @editor.getBuffer().getLastRow() - - onLastColumn: -> - @editor.getLastCursor().isAtEndOfLine() diff --git a/atom/packages/vim-mode/lib/operators/replace-operator.coffee b/atom/packages/vim-mode/lib/operators/replace-operator.coffee deleted file mode 100644 index 9cf44b3..0000000 --- a/atom/packages/vim-mode/lib/operators/replace-operator.coffee +++ /dev/null @@ -1,50 +0,0 @@ -_ = require 'underscore-plus' -{OperatorWithInput} = require './general-operators' -{ViewModel} = require '../view-models/view-model' -{Range} = require 'atom' - -module.exports = -class Replace extends OperatorWithInput - constructor: (@editor, @vimState) -> - super(@editor, @vimState) - @viewModel = new ViewModel(this, class: 'replace', hidden: true, singleChar: true, defaultText: '\n') - - execute: (count=1) -> - if @input.characters is "" - # replace canceled - - if @vimState.mode is "visual" - @vimState.resetVisualMode() - else - @vimState.activateNormalMode() - - return - - @editor.transact => - if @motion? - if _.contains(@motion.select(), true) - @editor.replaceSelectedText null, (text) => - text.replace(/./g, @input.characters) - for selection in @editor.getSelections() - point = selection.getBufferRange().start - selection.setBufferRange(Range.fromPointWithDelta(point, 0, 0)) - else - for cursor in @editor.getCursors() - pos = cursor.getBufferPosition() - currentRowLength = @editor.lineTextForBufferRow(pos.row).length - continue unless currentRowLength - pos.column >= count - - _.times count, => - point = cursor.getBufferPosition() - @editor.setTextInBufferRange(Range.fromPointWithDelta(point, 0, 1), @input.characters) - cursor.moveRight() - cursor.setBufferPosition(pos) - - # Special case: when replaced with a newline move to the start of the - # next row. - if @input.characters is "\n" - _.times count, => - @editor.moveDown() - @editor.moveToFirstCharacterOfLine() - - @vimState.activateNormalMode() diff --git a/atom/packages/vim-mode/lib/prefixes.coffee b/atom/packages/vim-mode/lib/prefixes.coffee deleted file mode 100644 index c910963..0000000 --- a/atom/packages/vim-mode/lib/prefixes.coffee +++ /dev/null @@ -1,68 +0,0 @@ -class Prefix - complete: null - composedObject: null - - isComplete: -> @complete - - isRecordable: -> @composedObject.isRecordable() - - # Public: Marks this as complete upon receiving an object to compose with. - # - # composedObject - The next motion or operator. - # - # Returns nothing. - compose: (@composedObject) -> - @complete = true - - # Public: Executes the composed operator or motion. - # - # Returns nothing. - execute: -> - @composedObject.execute?(@count) - - # Public: Selects using the composed motion. - # - # Returns an array of booleans representing whether each selections' success. - select: -> - @composedObject.select?(@count) - - isLinewise: -> - @composedObject.isLinewise?() - -# -# Used to track the number of times either a motion or operator should -# be repeated. -# -class Repeat extends Prefix - count: null - - # count - The initial digit of the repeat sequence. - constructor: (@count) -> @complete = false - - # Public: Adds an additional digit to this repeat sequence. - # - # digit - A single digit, 0-9. - # - # Returns nothing. - addDigit: (digit) -> - @count = @count * 10 + digit - -# -# Used to track which register the following operator should operate on. -# -class Register extends Prefix - name: null - - # name - The single character name of the desired register - constructor: (@name) -> @complete = false - - # Public: Marks as complete and sets the operator's register if it accepts it. - # - # composedOperator - The operator this register pertains to. - # - # Returns nothing. - compose: (composedObject) -> - super(composedObject) - composedObject.register = @name if composedObject.register? - -module.exports = {Repeat, Register} diff --git a/atom/packages/vim-mode/lib/scroll.coffee b/atom/packages/vim-mode/lib/scroll.coffee deleted file mode 100644 index 275f0f9..0000000 --- a/atom/packages/vim-mode/lib/scroll.coffee +++ /dev/null @@ -1,110 +0,0 @@ -class Scroll - isComplete: -> true - isRecordable: -> false - constructor: (@editorElement) -> - @scrolloff = 2 # atom default - @editor = @editorElement.getModel() - @rows = - first: @editorElement.getFirstVisibleScreenRow() - last: @editorElement.getLastVisibleScreenRow() - final: @editor.getLastScreenRow() - -class ScrollDown extends Scroll - execute: (count=1) -> - @keepCursorOnScreen(count) - @scrollUp(count) - - keepCursorOnScreen: (count) -> - {row, column} = @editor.getCursorScreenPosition() - firstScreenRow = @rows.first + @scrolloff + 1 - if row - count <= firstScreenRow - @editor.setCursorScreenPosition([firstScreenRow + count, column]) - - scrollUp: (count) -> - lastScreenRow = @rows.last - @scrolloff - @editor.scrollToScreenPosition([lastScreenRow + count, 0]) - -class ScrollUp extends Scroll - execute: (count=1) -> - @keepCursorOnScreen(count) - @scrollDown(count) - - keepCursorOnScreen: (count) -> - {row, column} = @editor.getCursorScreenPosition() - lastScreenRow = @rows.last - @scrolloff - 1 - if row + count >= lastScreenRow - @editor.setCursorScreenPosition([lastScreenRow - count, column]) - - scrollDown: (count) -> - firstScreenRow = @rows.first + @scrolloff - @editor.scrollToScreenPosition([firstScreenRow - count, 0]) - -class ScrollCursor extends Scroll - constructor: (@editorElement, @opts={}) -> - super - cursor = @editor.getCursorScreenPosition() - @pixel = @editorElement.pixelPositionForScreenPosition(cursor).top - -class ScrollCursorToTop extends ScrollCursor - execute: -> - @moveToFirstNonBlank() unless @opts.leaveCursor - @scrollUp() - - scrollUp: -> - return if @rows.last is @rows.final - @pixel -= (@editor.getLineHeightInPixels() * @scrolloff) - @editor.setScrollTop(@pixel) - - moveToFirstNonBlank: -> - @editor.moveToFirstCharacterOfLine() - -class ScrollCursorToMiddle extends ScrollCursor - execute: -> - @moveToFirstNonBlank() unless @opts.leaveCursor - @scrollMiddle() - - scrollMiddle: -> - @pixel -= (@editor.getHeight() / 2) - @editor.setScrollTop(@pixel) - - moveToFirstNonBlank: -> - @editor.moveToFirstCharacterOfLine() - -class ScrollCursorToBottom extends ScrollCursor - execute: -> - @moveToFirstNonBlank() unless @opts.leaveCursor - @scrollDown() - - scrollDown: -> - return if @rows.first is 0 - offset = (@editor.getLineHeightInPixels() * (@scrolloff + 1)) - @pixel -= (@editor.getHeight() - offset) - @editor.setScrollTop(@pixel) - - moveToFirstNonBlank: -> - @editor.moveToFirstCharacterOfLine() - -class ScrollHorizontal - isComplete: -> true - isRecordable: -> false - constructor: (@editorElement) -> - @editor = @editorElement.getModel() - cursorPos = @editor.getCursorScreenPosition() - @pixel = @editorElement.pixelPositionForScreenPosition(cursorPos).left - @cursor = @editor.getLastCursor() - - putCursorOnScreen: -> - @editor.scrollToCursorPosition({center: false}) - -class ScrollCursorToLeft extends ScrollHorizontal - execute: -> - @editor.setScrollLeft(@pixel) - @putCursorOnScreen() - -class ScrollCursorToRight extends ScrollHorizontal - execute: -> - @editor.setScrollRight(@pixel) - @putCursorOnScreen() - -module.exports = {ScrollDown, ScrollUp, ScrollCursorToTop, ScrollCursorToMiddle, - ScrollCursorToBottom, ScrollCursorToLeft, ScrollCursorToRight} diff --git a/atom/packages/vim-mode/lib/settings.coffee b/atom/packages/vim-mode/lib/settings.coffee deleted file mode 100644 index 30ff35b..0000000 --- a/atom/packages/vim-mode/lib/settings.coffee +++ /dev/null @@ -1,28 +0,0 @@ - -settings = - config: - startInInsertMode: - type: 'boolean' - default: false - useSmartcaseForSearch: - type: 'boolean' - default: false - wrapLeftRightMotion: - type: 'boolean' - default: false - useClipboardAsDefaultRegister: - type: 'boolean' - default: false - numberRegex: - type: 'string' - default: '-?[0-9]+' - description: 'Use this to control how Ctrl-A/Ctrl-X finds numbers; use "(?:\\B-)?[0-9]+" to treat numbers as positive if the minus is preceded by a character, e.g. in "identifier-1".' - -Object.keys(settings.config).forEach (k) -> - settings[k] = -> - atom.config.get('vim-mode.'+k) - -settings.defaultRegister = -> - if settings.useClipboardAsDefaultRegister() then '*' else '"' - -module.exports = settings diff --git a/atom/packages/vim-mode/lib/status-bar-manager.coffee b/atom/packages/vim-mode/lib/status-bar-manager.coffee deleted file mode 100644 index 080e4bf..0000000 --- a/atom/packages/vim-mode/lib/status-bar-manager.coffee +++ /dev/null @@ -1,40 +0,0 @@ -ContentsByMode = - 'insert': ["status-bar-vim-mode-insert", "Insert"] - 'insert.replace': ["status-bar-vim-mode-insert", "Replace"] - 'normal': ["status-bar-vim-mode-normal", "Normal"] - 'visual': ["status-bar-vim-mode-visual", "Visual"] - 'visual.characterwise': ["status-bar-vim-mode-visual", "Visual"] - 'visual.linewise': ["status-bar-vim-mode-visual", "Visual Line"] - 'visual.blockwise': ["status-bar-vim-mode-visual", "Visual Block"] - -module.exports = -class StatusBarManager - constructor: -> - @element = document.createElement("div") - @element.id = "status-bar-vim-mode" - - @container = document.createElement("div") - @container.className = "inline-block" - @container.appendChild(@element) - - initialize: (@statusBar) -> - - update: (currentMode, currentSubmode) -> - currentMode = currentMode + "." + currentSubmode if currentSubmode? - if newContents = ContentsByMode[currentMode] - [klass, text] = newContents - @element.className = klass - @element.textContent = text - else - @hide() - - hide: -> - @element.className = 'hidden' - - # Private - - attach: -> - @tile = @statusBar.addRightTile(item: @container, priority: 20) - - detach: -> - @tile.destroy() diff --git a/atom/packages/vim-mode/lib/text-objects.coffee b/atom/packages/vim-mode/lib/text-objects.coffee deleted file mode 100644 index bf38605..0000000 --- a/atom/packages/vim-mode/lib/text-objects.coffee +++ /dev/null @@ -1,207 +0,0 @@ -{Range} = require 'atom' -AllWhitespace = /^\s$/ -WholeWordRegex = /\S+/ -{mergeRanges} = require './utils' - -class TextObject - constructor: (@editor, @state) -> - - isComplete: -> true - isRecordable: -> false - - execute: -> @select.apply(this, arguments) - -class SelectInsideWord extends TextObject - select: -> - for selection in @editor.getSelections() - selection.expandOverWord() - [true] - -class SelectInsideWholeWord extends TextObject - select: -> - for selection in @editor.getSelections() - range = selection.cursor.getCurrentWordBufferRange({wordRegex: WholeWordRegex}) - selection.setBufferRange(mergeRanges(selection.getBufferRange(), range)) - true - -# SelectInsideQuotes and the next class defined (SelectInsideBrackets) are -# almost-but-not-quite-repeated code. They are different because of the depth -# checks in the bracket matcher. - -class SelectInsideQuotes extends TextObject - constructor: (@editor, @char, @includeQuotes) -> - - findOpeningQuote: (pos) -> - start = pos.copy() - pos = pos.copy() - while pos.row >= 0 - line = @editor.lineTextForBufferRow(pos.row) - pos.column = line.length - 1 if pos.column is -1 - while pos.column >= 0 - if line[pos.column] is @char - if pos.column is 0 or line[pos.column - 1] isnt '\\' - if @isStartQuote(pos) - return pos - else - return @lookForwardOnLine(start) - -- pos.column - pos.column = -1 - -- pos.row - @lookForwardOnLine(start) - - isStartQuote: (end) -> - line = @editor.lineTextForBufferRow(end.row) - numQuotes = line.substring(0, end.column + 1).replace( "'#{@char}", '').split(@char).length - 1 - numQuotes % 2 - - lookForwardOnLine: (pos) -> - line = @editor.lineTextForBufferRow(pos.row) - - index = line.substring(pos.column).indexOf(@char) - if index >= 0 - pos.column += index - return pos - null - - findClosingQuote: (start) -> - end = start.copy() - escaping = false - - while end.row < @editor.getLineCount() - endLine = @editor.lineTextForBufferRow(end.row) - while end.column < endLine.length - if endLine[end.column] is '\\' - ++ end.column - else if endLine[end.column] is @char - -- start.column if @includeQuotes - ++ end.column if @includeQuotes - return end - ++ end.column - end.column = 0 - ++ end.row - return - - select: -> - for selection in @editor.getSelections() - start = @findOpeningQuote(selection.cursor.getBufferPosition()) - if start? - ++ start.column # skip the opening quote - end = @findClosingQuote(start) - if end? - selection.setBufferRange(mergeRanges(selection.getBufferRange(), [start, end])) - not selection.isEmpty() - -# SelectInsideBrackets and the previous class defined (SelectInsideQuotes) are -# almost-but-not-quite-repeated code. They are different because of the depth -# checks in the bracket matcher. - -class SelectInsideBrackets extends TextObject - constructor: (@editor, @beginChar, @endChar, @includeBrackets) -> - - findOpeningBracket: (pos) -> - pos = pos.copy() - depth = 0 - while pos.row >= 0 - line = @editor.lineTextForBufferRow(pos.row) - pos.column = line.length - 1 if pos.column is -1 - while pos.column >= 0 - switch line[pos.column] - when @endChar then ++ depth - when @beginChar - return pos if -- depth < 0 - -- pos.column - pos.column = -1 - -- pos.row - - findClosingBracket: (start) -> - end = start.copy() - depth = 0 - while end.row < @editor.getLineCount() - endLine = @editor.lineTextForBufferRow(end.row) - while end.column < endLine.length - switch endLine[end.column] - when @beginChar then ++ depth - when @endChar - if -- depth < 0 - -- start.column if @includeBrackets - ++ end.column if @includeBrackets - return end - ++ end.column - end.column = 0 - ++ end.row - return - - select: -> - for selection in @editor.getSelections() - start = @findOpeningBracket(selection.cursor.getBufferPosition()) - if start? - ++ start.column # skip the opening quote - end = @findClosingBracket(start) - if end? - selection.setBufferRange(mergeRanges(selection.getBufferRange(), [start, end])) - not selection.isEmpty() - -class SelectAWord extends TextObject - select: -> - for selection in @editor.getSelections() - selection.expandOverWord() - loop - endPoint = selection.getBufferRange().end - char = @editor.getTextInRange(Range.fromPointWithDelta(endPoint, 0, 1)) - break unless AllWhitespace.test(char) - selection.selectRight() - true - -class SelectAWholeWord extends TextObject - select: -> - for selection in @editor.getSelections() - range = selection.cursor.getCurrentWordBufferRange({wordRegex: WholeWordRegex}) - selection.setBufferRange(mergeRanges(selection.getBufferRange(), range)) - loop - endPoint = selection.getBufferRange().end - char = @editor.getTextInRange(Range.fromPointWithDelta(endPoint, 0, 1)) - break unless AllWhitespace.test(char) - selection.selectRight() - true - -class Paragraph extends TextObject - - select: -> - for selection in @editor.getSelections() - @selectParagraph(selection) - - # Return a range delimted by the start or the end of a paragraph - paragraphDelimitedRange: (startPoint) -> - inParagraph = @isParagraphLine(@editor.lineTextForBufferRow(startPoint.row)) - upperRow = @searchLines(startPoint.row, -1, inParagraph) - lowerRow = @searchLines(startPoint.row, @editor.getLineCount(), inParagraph) - new Range([upperRow + 1, 0], [lowerRow, 0]) - - searchLines: (startRow, rowLimit, startedInParagraph) -> - for currentRow in [startRow..rowLimit] - line = @editor.lineTextForBufferRow(currentRow) - if startedInParagraph isnt @isParagraphLine(line) - return currentRow - rowLimit - - isParagraphLine: (line) -> (/\S/.test(line)) - -class SelectInsideParagraph extends Paragraph - selectParagraph: (selection) -> - oldRange = selection.getBufferRange() - startPoint = selection.cursor.getBufferPosition() - newRange = @paragraphDelimitedRange(startPoint) - selection.setBufferRange(mergeRanges(oldRange, newRange)) - true - -class SelectAParagraph extends Paragraph - selectParagraph: (selection) -> - oldRange = selection.getBufferRange() - startPoint = selection.cursor.getBufferPosition() - newRange = @paragraphDelimitedRange(startPoint) - nextRange = @paragraphDelimitedRange(newRange.end) - selection.setBufferRange(mergeRanges(oldRange, [newRange.start, nextRange.end])) - true - -module.exports = {TextObject, SelectInsideWord, SelectInsideWholeWord, SelectInsideQuotes, - SelectInsideBrackets, SelectAWord, SelectAWholeWord, SelectInsideParagraph, SelectAParagraph} diff --git a/atom/packages/vim-mode/lib/utils.coffee b/atom/packages/vim-mode/lib/utils.coffee deleted file mode 100644 index 5a26310..0000000 --- a/atom/packages/vim-mode/lib/utils.coffee +++ /dev/null @@ -1,27 +0,0 @@ -{Range} = require 'atom' - -module.exports = - # Public: Determines if a string should be considered linewise or character - # - # text - The string to consider - # - # Returns 'linewise' if the string ends with a line return and 'character' - # otherwise. - copyType: (text) -> - if text.lastIndexOf("\n") is text.length - 1 - 'linewise' - else if text.lastIndexOf("\r") is text.length - 1 - 'linewise' - else - 'character' - - # Public: return a union of two ranges, or simply the newRange if the oldRange is empty. - # - # Returns a Range - mergeRanges: (oldRange, newRange) -> - oldRange = Range.fromObject oldRange - newRange = Range.fromObject newRange - if oldRange.isEmpty() - newRange - else - oldRange.union(newRange) diff --git a/atom/packages/vim-mode/lib/view-models/search-view-model.coffee b/atom/packages/vim-mode/lib/view-models/search-view-model.coffee deleted file mode 100644 index 8e63fd2..0000000 --- a/atom/packages/vim-mode/lib/view-models/search-view-model.coffee +++ /dev/null @@ -1,50 +0,0 @@ -{ViewModel} = require './view-model' - -module.exports = -class SearchViewModel extends ViewModel - constructor: (@searchMotion) -> - super(@searchMotion, class: 'search') - @historyIndex = -1 - - atom.commands.add(@view.editorElement, 'core:move-up', @increaseHistorySearch) - atom.commands.add(@view.editorElement, 'core:move-down', @decreaseHistorySearch) - - restoreHistory: (index) -> - @view.editorElement.getModel().setText(@history(index)) - - history: (index) -> - @vimState.getSearchHistoryItem(index) - - increaseHistorySearch: => - if @history(@historyIndex + 1)? - @historyIndex += 1 - @restoreHistory(@historyIndex) - - decreaseHistorySearch: => - if @historyIndex <= 0 - # get us back to a clean slate - @historyIndex = -1 - @view.editorElement.getModel().setText('') - else - @historyIndex -= 1 - @restoreHistory(@historyIndex) - - confirm: (view) => - repeatChar = if @searchMotion.initiallyReversed then '?' else '/' - if @view.value is '' or @view.value is repeatChar - lastSearch = @history(0) - if lastSearch? - @view.value = lastSearch - else - @view.value = '' - atom.beep() - super(view) - @vimState.pushSearchHistory(@view.value) - - update: (reverse) -> - if reverse - @view.classList.add('reverse-search-input') - @view.classList.remove('search-input') - else - @view.classList.add('search-input') - @view.classList.remove('reverse-search-input') diff --git a/atom/packages/vim-mode/lib/view-models/view-model.coffee b/atom/packages/vim-mode/lib/view-models/view-model.coffee deleted file mode 100644 index b9da169..0000000 --- a/atom/packages/vim-mode/lib/view-models/view-model.coffee +++ /dev/null @@ -1,25 +0,0 @@ -VimNormalModeInputElement = require './vim-normal-mode-input-element' - -class ViewModel - constructor: (@operation, opts={}) -> - {@editor, @vimState} = @operation - @view = new VimNormalModeInputElement().initialize(this, atom.views.getView(@editor), opts) - @editor.normalModeInputView = @view - @vimState.onDidFailToCompose => @view.remove() - - confirm: (view) -> - @vimState.pushOperations(new Input(@view.value)) - - cancel: (view) -> - if @vimState.isOperatorPending() - @vimState.pushOperations(new Input('')) - delete @editor.normalModeInputView - -class Input - constructor: (@characters) -> - isComplete: -> true - isRecordable: -> true - -module.exports = { - ViewModel, Input -} diff --git a/atom/packages/vim-mode/lib/view-models/vim-normal-mode-input-element.coffee b/atom/packages/vim-mode/lib/view-models/vim-normal-mode-input-element.coffee deleted file mode 100644 index 2371753..0000000 --- a/atom/packages/vim-mode/lib/view-models/vim-normal-mode-input-element.coffee +++ /dev/null @@ -1,66 +0,0 @@ -class VimNormalModeInputElement extends HTMLDivElement - createdCallback: -> - @className = "normal-mode-input" - - initialize: (@viewModel, @mainEditorElement, opts = {}) -> - if opts.class? - @classList.add(opts.class) - - @editorElement = document.createElement "atom-text-editor" - @editorElement.classList.add('editor') - @editorElement.getModel().setMini(true) - @editorElement.setAttribute('mini', '') - @appendChild(@editorElement) - - @singleChar = opts.singleChar - @defaultText = opts.defaultText ? '' - - if opts.hidden - @classList.add('vim-hidden-normal-mode-input') - @mainEditorElement.parentNode.appendChild(this) - else - @panel = atom.workspace.addBottomPanel(item: this, priority: 100) - - @focus() - @handleEvents() - - this - - handleEvents: -> - if @singleChar? - compositing = false - @editorElement.getModel().getBuffer().onDidChange (e) => - @confirm() if e.newText and not compositing - @editorElement.addEventListener 'compositionstart', -> compositing = true - @editorElement.addEventListener 'compositionend', -> compositing = false - else - atom.commands.add(@editorElement, 'editor:newline', @confirm.bind(this)) - - atom.commands.add(@editorElement, 'core:confirm', @confirm.bind(this)) - atom.commands.add(@editorElement, 'core:cancel', @cancel.bind(this)) - atom.commands.add(@editorElement, 'blur', @cancel.bind(this)) - - confirm: -> - @value = @editorElement.getModel().getText() or @defaultText - @viewModel.confirm(this) - @removePanel() - - focus: -> - @editorElement.focus() - - cancel: (e) -> - @viewModel.cancel(this) - @removePanel() - - removePanel: -> - atom.workspace.getActivePane().activate() - if @panel? - @panel.destroy() - else - this.remove() - -module.exports = -document.registerElement("vim-normal-mode-input" - extends: "div", - prototype: VimNormalModeInputElement.prototype -) diff --git a/atom/packages/vim-mode/lib/vim-mode.coffee b/atom/packages/vim-mode/lib/vim-mode.coffee deleted file mode 100644 index b8ef936..0000000 --- a/atom/packages/vim-mode/lib/vim-mode.coffee +++ /dev/null @@ -1,60 +0,0 @@ -{Disposable, CompositeDisposable} = require 'event-kit' -StatusBarManager = require './status-bar-manager' -GlobalVimState = require './global-vim-state' -VimState = require './vim-state' -settings = require './settings' - -module.exports = - config: settings.config - - activate: (state) -> - @disposables = new CompositeDisposable - @globalVimState = new GlobalVimState - @statusBarManager = new StatusBarManager - - @vimStates = new Set - @vimStatesByEditor = new WeakMap - - @disposables.add atom.workspace.observeTextEditors (editor) => - return if editor.isMini() or @getEditorState(editor) - - vimState = new VimState( - atom.views.getView(editor), - @statusBarManager, - @globalVimState - ) - - @vimStates.add(vimState) - @vimStatesByEditor.set(editor, vimState) - vimState.onDidDestroy => @vimStates.delete(vimState) - - @disposables.add atom.workspace.onDidChangeActivePaneItem @updateToPaneItem.bind(this) - - @disposables.add new Disposable => - @vimStates.forEach (vimState) -> vimState.destroy() - - deactivate: -> - @disposables.dispose() - - getGlobalState: -> - @globalVimState - - getEditorState: (editor) -> - @vimStatesByEditor.get(editor) - - consumeStatusBar: (statusBar) -> - @statusBarManager.initialize(statusBar) - @statusBarManager.attach() - @disposables.add new Disposable => - @statusBarManager.detach() - - updateToPaneItem: (item) -> - vimState = @getEditorState(item) if item? - if vimState? - vimState.updateStatusBar() - else - @statusBarManager.hide() - - provideVimMode: -> - getGlobalState: @getGlobalState.bind(this) - getEditorState: @getEditorState.bind(this) 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 - [] |