1{"version":3,"sources":["../../node_modules/codemirror/keymap/vim.js"],"names":["mod","exports","module","require","define","amd","CodeMirror","defaultKeymap","keys","type","toKeys","context","action","motion","motionArgs","linewise","toJumplist","forward","wordEnd","bigWord","inclusive","explicitRepeat","toFirstChar","repeatOffset","isEdit","actionArgs","after","matchIndent","sameLine","operator","operatorArgs","indentRight","toLower","operatorMotionArgs","visualLine","shouldMoveCursor","insertAt","interlaceInsertRepeat","blockwise","keepSpaces","replace","fullLine","exitVisualBlock","position","increase","backtrack","textObjectInner","searchArgs","querySrc","wholeWordOnly","defaultKeymapLength","length","defaultExCommandMap","name","shortName","possiblyAsync","excludeFromCommandHistory","Pos","Vim","enterVimMode","cm","setOption","signal","mode","on","onCursorActivity","maybeInitVimState","getInputField","getOnPasteFn","leaveVimMode","off","state","vim","detachVimMap","next","this","keyMap","rmClass","getWrapperElement","getOption","document","body","style","caretColor","disableFatCursorMark","attach","attachVimMap","prev","addClass","enableFatCursorMark","updateFatCursorMark","fatCursorMarks","clearFatCursorMark","ranges","listSelections","result","i","range","empty","lineLength","getLine","anchor","line","ch","push","markText","className","marks","clear","defineOption","val","Init","test","cmKey","key","undefined","vimKey","cmKeyToVimKey","cmd","findKey","modifiers","Shift","Ctrl","Alt","Cmd","Mod","specialKeys","Enter","Backspace","Delete","Insert","charAt","pieces","split","lastPiece","hasCharacter","piece","isUpperCase","toLowerCase","join","onPasteFn","insertMode","setCursor","offsetCursor","getCursor","actions","enterInsertMode","numberRegex","wordCharTest","isWordChar","bigWordCharTest","makeKeyRange","start","size","String","fromCharCode","upperCaseAlphabet","lowerCaseAlphabet","numbers","validMarks","concat","validRegisters","isLine","firstLine","lastLine","isLowerCase","k","isMatchableSymbol","indexOf","isNumber","isWhiteSpaceString","isEndOfSentenceSymbol","inArray","arr","options","defaultValue","aliases","callback","Error","value","cfg","option","scope","local","createCircularJumpList","pointer","head","tail","buffer","Array","add","oldCur","newCur","current","curMark","useNextSlot","cursor","trashMark","setBookmark","markPos","find","cursorEqual","move","offset","mark","inc","oldPointer","cachedCursor","createInsertModeChanges","c","changes","expectCursorActivityForChange","MacroModeState","latestRegister","isPlaying","isRecording","replaySearchQueries","onRecordingDone","lastInsertModeChanges","prototype","exitMacroRecordMode","macroModeState","vimGlobalState","enterMacroRecordMode","registerName","register","registerController","getRegister","openDialog","bottom","inputState","InputState","lastEditInputState","lastEditActionCommand","lastHPos","lastHSPos","lastMotion","fakeCursor","insertModeRepeat","visualMode","visualBlock","lastSelection","lastPastedText","sel","resetVimGlobalState","searchQuery","searchIsReversed","lastSubstituteReplacePart","jumpList","lastCharacterSearch","increment","selectedCharacter","RegisterController","searchHistoryController","HistoryController","exCommandHistoryController","optionName","lastInsertModeKeyTimer","vimApi","buildKeyMap","getRegisterController","resetVimGlobalState_","getVimGlobalState_","maybeInitVimState_","suppressErrorLogging","InsertModeKey","map","lhs","rhs","ctx","exCommandDispatcher","unmap","noremap","toCtxArray","ctxsToMap","actualLength","origLength","mapping","substr","newMapping","_mapCommand","mappedCtxs","filter","el","mapclear","userKeymap","slice","contexts","j","defineEx","prefix","func","exCommands","commandMap_","handleKey","origin","command","handleMacroRecording","clearInputState","logKey","handleEsc","exitVisualMode","exitInsertMode","doKeyToKey","match","exec","substring","index","handleKeyInsertMode","keyBuffer","keysAreChars","commandDispatcher","matchCommand","thisMatch","window","clearTimeout","setTimeout","selections","here","replaceRange","pop","handleKeyNonInsertMode","keysMatcher","pushRepeatDigit","operation","curOp","isVimOp","processCommand","e","console","handleEx","input","defineMotion","defineAction","defineOperator","mapCommand","defineRegister","prefixRepeat","motionRepeat","n","getRepeat","repeat","parseInt","reason","Register","text","insertModeChanges","searchQueries","setText","pushText","pushInsertModeChanges","pushSearchQuery","query","toString","registers","unnamedRegister","isValidRegister","shiftNumericRegisters_","append","historyBuffer","iterator","initialPrefix","nextMatch","up","dir","element","pushInput","splice","reset","matches","commandMatches","full","partial","bestMatch","character","lastChar","repeatOverride","processMotion","processOperator","processOperatorMotion","processAction","processSearch","processEx","copyArgs","evalInput","updateCmSelection","repeatIsExplicit","recordLastEdit","getSearchCursor","getSearchState","setReversed","promptPrefix","originalQuery","getQuery","originalScrollPos","getScrollInfo","handleQuery","ignoreCase","smartCase","updateSearchQuery","showConfirm","onPromptClose","scrollTo","left","top","logSearchQuery","onPromptKeyUp","close","keyName","target","selectionEnd","selectionStart","Math","min","parsedQuery","scrollIntoView","findNext","clearSearchHighlight","onPromptKeyDown","e_stop","focus","shift","showPrompt","onClose","desc","searchPromptDesc","onKeyUp","onKeyDown","word","expandWordUnderCursor","isKeyword","end","escapeRegex","exArgs","selectValueOnOpen","origHead","copyCursor","clipCursorToContent","origAnchor","oldHead","oldAnchor","newHead","newAnchor","noRepeat","motionResult","motions","recordJumpPosition","Infinity","updateMark","cursorIsBefore","lastSel","lineOffset","abs","chOffset","curStart","curEnd","cmSel","cursorMin","cursorMax","makeCmSelection","tmp","expandSelectionToLine","clipToLine","exclusive","setSelections","primary","operatorMoveTo","operators","actionCommand","moveToTopLine","_head","getUserVisibleLines","findFirstNonWhiteSpaceCharacter","moveToMiddleLine","floor","moveToBottomLine","expandToLine","_cm","cur","isReversed","highlightSearchMatches","goToMark","pos","getMarkPos","moveToOtherHighlightedEnd","jumpToMark","best","isWrongDirection","equal","between","cursorIsBetween","moveByCharacters","moveByLines","endCh","moveByDisplayLines","moveByScroll","moveToColumn","moveToEol","first","last","posV","findPosV","hasMarkedText","moveToStartOfLine","charCoords","res","hitSide","lastCharCoords","goalCoords","coordsChar","resCoords","moveByPage","moveByParagraph","findParagraph","moveBySentence","findSentence","scrollbox","clientHeight","defaultTextHeight","orig","dest","moveByWords","moveToWord","moveTillCharacter","moveToCharacter","recordLastCharacterSearch","moveToSymbol","findSymbol","keepHPos","retval","clipPos","moveToFirstNonWhiteSpaceCharacter","moveToMatchedSymbol","lineText","symbol","getTokenTypeAt","re","matched","findMatchingBracket","bracketRegex","to","moveToLineOrEdgeOfDocument","lineNum","textObjectManipulation","mirroredPairs","(",")","{","}","[","]","<",">","selfPaired","'","\"","`","selectCompanionObject","findBeginningAndEnd","expandTagUnderCursor","expandSelection","repeatLastCharacterSearch","lastSearch","moveH","fn","fillArray","times","change","args","finalHead","getRange","lastState","prevLineEnd","Number","MAX_VALUE","wasLastLine","commands","newlineAndIndent","setSelection","getSelection","replaceSelection","replacement","replaceSelections","delete","indent","startLine","endLine","indentLine","indentAuto","_args","execCommand","changeCase","getSelections","swapped","toSwap","toUpperCase","yank","endPos","jumpListWalk","scroll","lineHeight","delta","newPos","cursorCoords","ceil","newBottom","scrollToCursor","height","y","replayMacro","executeMacroRegister","toggleOverwrite","overwrite","max","getLastEditPos","onChange","onKeyEventTargetKeyDown","selectForInsert","toggleVisualMode","subMode","reselectLastSelection","_actionArgs","updateLastSelection","anchorMark","headMark","joinLines","finalCh","curFinalPos","newLineAndEnterInsertMode","newlineFn","newlineAndIndentContinueComment","paste","tabSize","whitespaceLength","str","tabs","spaces","currentLine","chompedText","wasChomped","firstIndent","wspace","newIndent","quotient","curPosFinal","idx","lastSelectionCurEnd","selectedArea","getSelectedAreaRange","selectedText","emptyStrings","selectBlock","posFromIndex","indexFromPos","lastCh","extendLineToColumn","undo","repeatFn","redo","setRegister","setMark","markName","replaceWith","replaceTo","replaceWithStr","incrementNumberToken","lineStr","numberStr","baseStr","digits","base","0b","0","","0x","number","zeroPadding","from","repeatLastEdit","includeLineBreak","maxCh","ret","prop","hasOwnProperty","offsetLine","offsetCh","commandMatch","pressed","mapped","prefixLen","pressedPrefix","mappedPrefix","cur1","cur2","arguments","apply","call","cur3","cur1before2","cur2before3","trim","s","column","isClipped","curHead","primIndex","getIndex","wasClipped","baseCh","headCh","newDir","lineHead","atAnchor","atHead","getCurrentSelectedAreaRange","getLastSelectedAreaRange","block","width","updateFakeCursor","headOffset","anchorOffset","right","getHead","moveHead","clearFakeCursor","selection","lines","firstNonWS","search","_forward","noSymbol","wordStart","findMatchingTag","findEnclosingTag","tags","open","symbolToMode","*","/","m","M","#","findSymbolModes","bracket","isComplete","nextCh","symb","depth","reverseSymb","section","init","curMoveThrough","comment","found","method","preprocess","token","lineCount","curCh","lineLen","findWord","emptyLineIsWord","charTests","stop","foundWord","words","eodCh","shortCircuit","firstWord","lastWord","charIdxInLine","includeChar","lastIndexOf","isEmpty","isBoundary","any","startState","nextChar","ln","curr","last_valid","skip_empty_lines","reverse","curr_index","bracketRegexp","openSym","curChar","scanForBracket","chars","len","firstIndex","SearchState","setQuery","getOverlay","searchOverlay","setOverlay","overlay","reversed","getScrollbarAnnotate","annotate","setScrollbarAnnotate","searchState_","dialog","template","shortText","prompt","splitBySlash","argString","splitBySeparator","findUnescapedSlashes","findUnescapedSeparators","separator","slashes","tokens","escapeNextChar","translateRegex","specials","unescape","out","specialComesNext","charUnescapes","\\n","\\r","\\t","translateRegexReplace","unescapes","\\/","\\\\","\\&","unescapeRegexReplace","stream","StringStream","output","eol","peek","matcher","parseQuery","lastSearchRegister","RegExp","regexPart","forceIgnoreCase","flagsPart","regexp","openNotification","duration","alert","makePrompt","raw","regexEqual","r1","r2","props","rawQuery","source","matchSol","sol","skipToEnd","backUp","highlightTimeout","searchState","removeOverlay","addOverlay","showMatchesOnScrollbar","isInRange","scrollInfo","occludeToleranceTop","occludeToleranceBottom","bottomY","done","doc","history","ExCommandDispatcher","buildCommandMap_","opt_params","that","_processCommand","commandHistoryRegister","previousCommand","inputStream","params","parseInput_","commandName","matchCommand_","parseCommandArgs_","toInput","eatWhile","eat","lineEnd","parseLineSpec_","numberMatch","parseLineSpecOffset_","offsetMatch","delim","argDelimiter","user","unshift","colorscheme","mapArgs","imap","nmap","vmap","set","setArgs","setCfg","expr","forceGet","optionIsBoolean","oldValue","message","setOptionReturn","setlocal","setglobal","regArgs","regInfo","sort","unique","pattern","parseArgs","eatSpace","opts","decimal","hex","octal","err","lineStart","radix","numPart","textPart","matchPart","compareFn","a","b","anum","bnum","comparePatternFn","textOld","global","matchedLines","content","nextCommand","substitute","replacePart","trailing","count","confirm","startPos","doReplace","write","save","nohlsearch","delmarks","sym","startMark","finishMark","charCodeAt","finish","searchCursor","exMode","lastPos","replaceAll","newText","_value","savedCallback","detach","insertModeChangeRegister","lastChange","logInsertModeChange","extra","fallthrough","imc","repeatInsertModeChanges","changeObj","ignoreCount","selectionCount","maybeReset","handleExternalSelection","widget","createElement","textContent","fakeCursorBookmark","somethingSelected","onKeyFound","lookupKey","repeatForInsert","isAction","cachedInputState","repeatCommand","repeatInsert","changeObject","keyHandler","binding"],"mappings":"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","file":"vim.min.js","sourcesContent":["// CodeMirror, copyright (c) by Marijn Haverbeke and others\n// Distributed under an MIT license: https://codemirror.net/LICENSE\n\n/**\n * Supported keybindings:\n *   Too many to list. Refer to defaultKeymap below.\n *\n * Supported Ex commands:\n *   Refer to defaultExCommandMap below.\n *\n * Registers: unnamed, -, a-z, A-Z, 0-9\n *   (Does not respect the special case for number registers when delete\n *    operator is made with these commands: %, (, ),  , /, ?, n, N, {, } )\n *   TODO: Implement the remaining registers.\n *\n * Marks: a-z, A-Z, and 0-9\n *   TODO: Implement the remaining special marks. They have more complex\n *       behavior.\n *\n * Events:\n *  'vim-mode-change' - raised on the editor anytime the current mode changes,\n *                      Event object: {mode: \"visual\", subMode: \"linewise\"}\n *\n * Code structure:\n *  1. Default keymap\n *  2. Variable declarations and short basic helpers\n *  3. Instance (External API) implementation\n *  4. Internal state tracking objects (input state, counter) implementation\n *     and instantiation\n *  5. Key handler (the main command dispatcher) implementation\n *  6. Motion, operator, and action implementations\n *  7. Helper functions for the key handler, motions, operators, and actions\n *  8. Set up Vim to work as a keymap for CodeMirror.\n *  9. Ex command implementations.\n */\n\n(function(mod) {\n  if (typeof exports == \"object\" && typeof module == \"object\") // CommonJS\n    mod(require(\"../lib/codemirror\"), require(\"../addon/search/searchcursor\"), require(\"../addon/dialog/dialog\"), require(\"../addon/edit/matchbrackets.js\"));\n  else if (typeof define == \"function\" && define.amd) // AMD\n    define([\"../lib/codemirror\", \"../addon/search/searchcursor\", \"../addon/dialog/dialog\", \"../addon/edit/matchbrackets\"], mod);\n  else // Plain browser env\n    mod(CodeMirror);\n})(function(CodeMirror) {\n  'use strict';\n\n  var defaultKeymap = [\n    // Key to key mapping. This goes first to make it possible to override\n    // existing mappings.\n    { keys: '<Left>', type: 'keyToKey', toKeys: 'h' },\n    { keys: '<Right>', type: 'keyToKey', toKeys: 'l' },\n    { keys: '<Up>', type: 'keyToKey', toKeys: 'k' },\n    { keys: '<Down>', type: 'keyToKey', toKeys: 'j' },\n    { keys: '<Space>', type: 'keyToKey', toKeys: 'l' },\n    { keys: '<BS>', type: 'keyToKey', toKeys: 'h', context: 'normal'},\n    { keys: '<Del>', type: 'keyToKey', toKeys: 'x', context: 'normal'},\n    { keys: '<C-Space>', type: 'keyToKey', toKeys: 'W' },\n    { keys: '<C-BS>', type: 'keyToKey', toKeys: 'B', context: 'normal' },\n    { keys: '<S-Space>', type: 'keyToKey', toKeys: 'w' },\n    { keys: '<S-BS>', type: 'keyToKey', toKeys: 'b', context: 'normal' },\n    { keys: '<C-n>', type: 'keyToKey', toKeys: 'j' },\n    { keys: '<C-p>', type: 'keyToKey', toKeys: 'k' },\n    { keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' },\n    { keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>' },\n    { keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },\n    { keys: '<C-c>', type: 'keyToKey', toKeys: '<Esc>', context: 'insert' },\n    { keys: 's', type: 'keyToKey', toKeys: 'cl', context: 'normal' },\n    { keys: 's', type: 'keyToKey', toKeys: 'c', context: 'visual'},\n    { keys: 'S', type: 'keyToKey', toKeys: 'cc', context: 'normal' },\n    { keys: 'S', type: 'keyToKey', toKeys: 'VdO', context: 'visual' },\n    { keys: '<Home>', type: 'keyToKey', toKeys: '0' },\n    { keys: '<End>', type: 'keyToKey', toKeys: '$' },\n    { keys: '<PageUp>', type: 'keyToKey', toKeys: '<C-b>' },\n    { keys: '<PageDown>', type: 'keyToKey', toKeys: '<C-f>' },\n    { keys: '<CR>', type: 'keyToKey', toKeys: 'j^', context: 'normal' },\n    { keys: '<Ins>', type: 'action', action: 'toggleOverwrite', context: 'insert' },\n    // Motions\n    { keys: 'H', type: 'motion', motion: 'moveToTopLine', motionArgs: { linewise: true, toJumplist: true }},\n    { keys: 'M', type: 'motion', motion: 'moveToMiddleLine', motionArgs: { linewise: true, toJumplist: true }},\n    { keys: 'L', type: 'motion', motion: 'moveToBottomLine', motionArgs: { linewise: true, toJumplist: true }},\n    { keys: 'h', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: false }},\n    { keys: 'l', type: 'motion', motion: 'moveByCharacters', motionArgs: { forward: true }},\n    { keys: 'j', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, linewise: true }},\n    { keys: 'k', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, linewise: true }},\n    { keys: 'gj', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: true }},\n    { keys: 'gk', type: 'motion', motion: 'moveByDisplayLines', motionArgs: { forward: false }},\n    { keys: 'w', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false }},\n    { keys: 'W', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: false, bigWord: true }},\n    { keys: 'e', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, inclusive: true }},\n    { keys: 'E', type: 'motion', motion: 'moveByWords', motionArgs: { forward: true, wordEnd: true, bigWord: true, inclusive: true }},\n    { keys: 'b', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }},\n    { keys: 'B', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false, bigWord: true }},\n    { keys: 'ge', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, inclusive: true }},\n    { keys: 'gE', type: 'motion', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: true, bigWord: true, inclusive: true }},\n    { keys: '{', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: false, toJumplist: true }},\n    { keys: '}', type: 'motion', motion: 'moveByParagraph', motionArgs: { forward: true, toJumplist: true }},\n    { keys: '(', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: false }},\n    { keys: ')', type: 'motion', motion: 'moveBySentence', motionArgs: { forward: true }},\n    { keys: '<C-f>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: true }},\n    { keys: '<C-b>', type: 'motion', motion: 'moveByPage', motionArgs: { forward: false }},\n    { keys: '<C-d>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: true, explicitRepeat: true }},\n    { keys: '<C-u>', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }},\n    { keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }},\n    { keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }},\n    { keys: '0', type: 'motion', motion: 'moveToStartOfLine' },\n    { keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' },\n    { keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }},\n    { keys: '-', type: 'motion', motion: 'moveByLines', motionArgs: { forward: false, toFirstChar:true }},\n    { keys: '_', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true, repeatOffset:-1 }},\n    { keys: '$', type: 'motion', motion: 'moveToEol', motionArgs: { inclusive: true }},\n    { keys: '%', type: 'motion', motion: 'moveToMatchedSymbol', motionArgs: { inclusive: true, toJumplist: true }},\n    { keys: 'f<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: true , inclusive: true }},\n    { keys: 'F<character>', type: 'motion', motion: 'moveToCharacter', motionArgs: { forward: false }},\n    { keys: 't<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: true, inclusive: true }},\n    { keys: 'T<character>', type: 'motion', motion: 'moveTillCharacter', motionArgs: { forward: false }},\n    { keys: ';', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: true }},\n    { keys: ',', type: 'motion', motion: 'repeatLastCharacterSearch', motionArgs: { forward: false }},\n    { keys: '\\'<character>', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true, linewise: true}},\n    { keys: '`<character>', type: 'motion', motion: 'goToMark', motionArgs: {toJumplist: true}},\n    { keys: ']`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true } },\n    { keys: '[`', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false } },\n    { keys: ']\\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: true, linewise: true } },\n    { keys: '[\\'', type: 'motion', motion: 'jumpToMark', motionArgs: { forward: false, linewise: true } },\n    // the next two aren't motions but must come before more general motion declarations\n    { keys: ']p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true, matchIndent: true}},\n    { keys: '[p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true, matchIndent: true}},\n    { keys: ']<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: true, toJumplist: true}},\n    { keys: '[<character>', type: 'motion', motion: 'moveToSymbol', motionArgs: { forward: false, toJumplist: true}},\n    { keys: '|', type: 'motion', motion: 'moveToColumn'},\n    { keys: 'o', type: 'motion', motion: 'moveToOtherHighlightedEnd', context:'visual'},\n    { keys: 'O', type: 'motion', motion: 'moveToOtherHighlightedEnd', motionArgs: {sameLine: true}, context:'visual'},\n    // Operators\n    { keys: 'd', type: 'operator', operator: 'delete' },\n    { keys: 'y', type: 'operator', operator: 'yank' },\n    { keys: 'c', type: 'operator', operator: 'change' },\n    { keys: '=', type: 'operator', operator: 'indentAuto' },\n    { keys: '>', type: 'operator', operator: 'indent', operatorArgs: { indentRight: true }},\n    { keys: '<', type: 'operator', operator: 'indent', operatorArgs: { indentRight: false }},\n    { keys: 'g~', type: 'operator', operator: 'changeCase' },\n    { keys: 'gu', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, isEdit: true },\n    { keys: 'gU', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, isEdit: true },\n    { keys: 'n', type: 'motion', motion: 'findNext', motionArgs: { forward: true, toJumplist: true }},\n    { keys: 'N', type: 'motion', motion: 'findNext', motionArgs: { forward: false, toJumplist: true }},\n    // Operator-Motion dual commands\n    { keys: 'x', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorMotionArgs: { visualLine: false }},\n    { keys: 'X', type: 'operatorMotion', operator: 'delete', motion: 'moveByCharacters', motionArgs: { forward: false }, operatorMotionArgs: { visualLine: true }},\n    { keys: 'D', type: 'operatorMotion', operator: 'delete', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'},\n    { keys: 'D', type: 'operator', operator: 'delete', operatorArgs: { linewise: true }, context: 'visual'},\n    { keys: 'Y', type: 'operatorMotion', operator: 'yank', motion: 'expandToLine', motionArgs: { linewise: true }, context: 'normal'},\n    { keys: 'Y', type: 'operator', operator: 'yank', operatorArgs: { linewise: true }, context: 'visual'},\n    { keys: 'C', type: 'operatorMotion', operator: 'change', motion: 'moveToEol', motionArgs: { inclusive: true }, context: 'normal'},\n    { keys: 'C', type: 'operator', operator: 'change', operatorArgs: { linewise: true }, context: 'visual'},\n    { keys: '~', type: 'operatorMotion', operator: 'changeCase', motion: 'moveByCharacters', motionArgs: { forward: true }, operatorArgs: { shouldMoveCursor: true }, context: 'normal'},\n    { keys: '~', type: 'operator', operator: 'changeCase', context: 'visual'},\n    { keys: '<C-w>', type: 'operatorMotion', operator: 'delete', motion: 'moveByWords', motionArgs: { forward: false, wordEnd: false }, context: 'insert' },\n    //ignore C-w in normal mode\n    { keys: '<C-w>', type: 'idle', context: 'normal' },\n    // Actions\n    { keys: '<C-i>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: true }},\n    { keys: '<C-o>', type: 'action', action: 'jumpListWalk', actionArgs: { forward: false }},\n    { keys: '<C-e>', type: 'action', action: 'scroll', actionArgs: { forward: true, linewise: true }},\n    { keys: '<C-y>', type: 'action', action: 'scroll', actionArgs: { forward: false, linewise: true }},\n    { keys: 'a', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'charAfter' }, context: 'normal' },\n    { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'eol' }, context: 'normal' },\n    { keys: 'A', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'endOfSelectedArea' }, context: 'visual' },\n    { keys: 'i', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'inplace' }, context: 'normal' },\n    { keys: 'gi', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'lastEdit' }, context: 'normal' },\n    { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'firstNonBlank'}, context: 'normal' },\n    { keys: 'gI', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'bol'}, context: 'normal' },\n    { keys: 'I', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { insertAt: 'startOfSelectedArea' }, context: 'visual' },\n    { keys: 'o', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: true }, context: 'normal' },\n    { keys: 'O', type: 'action', action: 'newLineAndEnterInsertMode', isEdit: true, interlaceInsertRepeat: true, actionArgs: { after: false }, context: 'normal' },\n    { keys: 'v', type: 'action', action: 'toggleVisualMode' },\n    { keys: 'V', type: 'action', action: 'toggleVisualMode', actionArgs: { linewise: true }},\n    { keys: '<C-v>', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }},\n    { keys: '<C-q>', type: 'action', action: 'toggleVisualMode', actionArgs: { blockwise: true }},\n    { keys: 'gv', type: 'action', action: 'reselectLastSelection' },\n    { keys: 'J', type: 'action', action: 'joinLines', isEdit: true },\n    { keys: 'gJ', type: 'action', action: 'joinLines', actionArgs: { keepSpaces: true }, isEdit: true },\n    { keys: 'p', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: true, isEdit: true }},\n    { keys: 'P', type: 'action', action: 'paste', isEdit: true, actionArgs: { after: false, isEdit: true }},\n    { keys: 'r<character>', type: 'action', action: 'replace', isEdit: true },\n    { keys: '@<character>', type: 'action', action: 'replayMacro' },\n    { keys: 'q<character>', type: 'action', action: 'enterMacroRecordMode' },\n    // Handle Replace-mode as a special case of insert mode.\n    { keys: 'R', type: 'action', action: 'enterInsertMode', isEdit: true, actionArgs: { replace: true }, context: 'normal'},\n    { keys: 'R', type: 'operator', operator: 'change', operatorArgs: { linewise: true, fullLine: true }, context: 'visual', exitVisualBlock: true},\n    { keys: 'u', type: 'action', action: 'undo', context: 'normal' },\n    { keys: 'u', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: true}, context: 'visual', isEdit: true },\n    { keys: 'U', type: 'operator', operator: 'changeCase', operatorArgs: {toLower: false}, context: 'visual', isEdit: true },\n    { keys: '<C-r>', type: 'action', action: 'redo' },\n    { keys: 'm<character>', type: 'action', action: 'setMark' },\n    { keys: '\"<character>', type: 'action', action: 'setRegister' },\n    { keys: 'zz', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }},\n    { keys: 'z.', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'center' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },\n    { keys: 'zt', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }},\n    { keys: 'z<CR>', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'top' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },\n    { keys: 'z-', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }},\n    { keys: 'zb', type: 'action', action: 'scrollToCursor', actionArgs: { position: 'bottom' }, motion: 'moveToFirstNonWhiteSpaceCharacter' },\n    { keys: '.', type: 'action', action: 'repeatLastEdit' },\n    { keys: '<C-a>', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: true, backtrack: false}},\n    { keys: '<C-x>', type: 'action', action: 'incrementNumberToken', isEdit: true, actionArgs: {increase: false, backtrack: false}},\n    { keys: '<C-t>', type: 'action', action: 'indent', actionArgs: { indentRight: true }, context: 'insert' },\n    { keys: '<C-d>', type: 'action', action: 'indent', actionArgs: { indentRight: false }, context: 'insert' },\n    // Text object motions\n    { keys: 'a<character>', type: 'motion', motion: 'textObjectManipulation' },\n    { keys: 'i<character>', type: 'motion', motion: 'textObjectManipulation', motionArgs: { textObjectInner: true }},\n    // Search\n    { keys: '/', type: 'search', searchArgs: { forward: true, querySrc: 'prompt', toJumplist: true }},\n    { keys: '?', type: 'search', searchArgs: { forward: false, querySrc: 'prompt', toJumplist: true }},\n    { keys: '*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }},\n    { keys: '#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', wholeWordOnly: true, toJumplist: true }},\n    { keys: 'g*', type: 'search', searchArgs: { forward: true, querySrc: 'wordUnderCursor', toJumplist: true }},\n    { keys: 'g#', type: 'search', searchArgs: { forward: false, querySrc: 'wordUnderCursor', toJumplist: true }},\n    // Ex command\n    { keys: ':', type: 'ex' }\n  ];\n  var defaultKeymapLength = defaultKeymap.length;\n\n  /**\n   * Ex commands\n   * Care must be taken when adding to the default Ex command map. For any\n   * pair of commands that have a shared prefix, at least one of their\n   * shortNames must not match the prefix of the other command.\n   */\n  var defaultExCommandMap = [\n    { name: 'colorscheme', shortName: 'colo' },\n    { name: 'map' },\n    { name: 'imap', shortName: 'im' },\n    { name: 'nmap', shortName: 'nm' },\n    { name: 'vmap', shortName: 'vm' },\n    { name: 'unmap' },\n    { name: 'write', shortName: 'w' },\n    { name: 'undo', shortName: 'u' },\n    { name: 'redo', shortName: 'red' },\n    { name: 'set', shortName: 'se' },\n    { name: 'setlocal', shortName: 'setl' },\n    { name: 'setglobal', shortName: 'setg' },\n    { name: 'sort', shortName: 'sor' },\n    { name: 'substitute', shortName: 's', possiblyAsync: true },\n    { name: 'nohlsearch', shortName: 'noh' },\n    { name: 'yank', shortName: 'y' },\n    { name: 'delmarks', shortName: 'delm' },\n    { name: 'registers', shortName: 'reg', excludeFromCommandHistory: true },\n    { name: 'global', shortName: 'g' }\n  ];\n\n  var Pos = CodeMirror.Pos;\n\n  var Vim = function() {\n    function enterVimMode(cm) {\n      cm.setOption('disableInput', true);\n      cm.setOption('showCursorWhenSelecting', false);\n      CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"normal\"});\n      cm.on('cursorActivity', onCursorActivity);\n      maybeInitVimState(cm);\n      CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));\n    }\n\n    function leaveVimMode(cm) {\n      cm.setOption('disableInput', false);\n      cm.off('cursorActivity', onCursorActivity);\n      CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));\n      cm.state.vim = null;\n    }\n\n    function detachVimMap(cm, next) {\n      if (this == CodeMirror.keyMap.vim) {\n        CodeMirror.rmClass(cm.getWrapperElement(), \"cm-fat-cursor\");\n        if (cm.getOption(\"inputStyle\") == \"contenteditable\" && document.body.style.caretColor != null) {\n          disableFatCursorMark(cm);\n          cm.getInputField().style.caretColor = \"\";\n        }\n      }\n\n      if (!next || next.attach != attachVimMap)\n        leaveVimMode(cm);\n    }\n    function attachVimMap(cm, prev) {\n      if (this == CodeMirror.keyMap.vim) {\n        CodeMirror.addClass(cm.getWrapperElement(), \"cm-fat-cursor\");\n        if (cm.getOption(\"inputStyle\") == \"contenteditable\" && document.body.style.caretColor != null) {\n          enableFatCursorMark(cm);\n          cm.getInputField().style.caretColor = \"transparent\";\n        }\n      }\n\n      if (!prev || prev.attach != attachVimMap)\n        enterVimMode(cm);\n    }\n\n    function updateFatCursorMark(cm) {\n      if (!cm.state.fatCursorMarks) return;\n      clearFatCursorMark(cm);\n      var ranges = cm.listSelections(), result = []\n      for (var i = 0; i < ranges.length; i++) {\n        var range = ranges[i];\n        if (range.empty()) {\n          var lineLength = cm.getLine(range.anchor.line).length;\n          if (range.anchor.ch < lineLength) {\n            result.push(cm.markText(range.anchor, Pos(range.anchor.line, range.anchor.ch + 1),\n                                    {className: \"cm-fat-cursor-mark\"}));\n          } else {\n            result.push(cm.markText(Pos(range.anchor.line, lineLength - 1),\n                                    Pos(range.anchor.line, lineLength),\n                                    {className: \"cm-fat-cursor-mark\"}));\n          }\n        }\n      }\n      cm.state.fatCursorMarks = result;\n    }\n\n    function clearFatCursorMark(cm) {\n      var marks = cm.state.fatCursorMarks;\n      if (marks) for (var i = 0; i < marks.length; i++) marks[i].clear();\n    }\n\n    function enableFatCursorMark(cm) {\n      cm.state.fatCursorMarks = [];\n      updateFatCursorMark(cm)\n      cm.on(\"cursorActivity\", updateFatCursorMark)\n    }\n\n    function disableFatCursorMark(cm) {\n      clearFatCursorMark(cm);\n      cm.off(\"cursorActivity\", updateFatCursorMark);\n      // explicitly set fatCursorMarks to null because event listener above\n      // can be invoke after removing it, if off is called from operation\n      cm.state.fatCursorMarks = null;\n    }\n\n    // Deprecated, simply setting the keymap works again.\n    CodeMirror.defineOption('vimMode', false, function(cm, val, prev) {\n      if (val && cm.getOption(\"keyMap\") != \"vim\")\n        cm.setOption(\"keyMap\", \"vim\");\n      else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption(\"keyMap\")))\n        cm.setOption(\"keyMap\", \"default\");\n    });\n\n    function cmKey(key, cm) {\n      if (!cm) { return undefined; }\n      if (this[key]) { return this[key]; }\n      var vimKey = cmKeyToVimKey(key);\n      if (!vimKey) {\n        return false;\n      }\n      var cmd = CodeMirror.Vim.findKey(cm, vimKey);\n      if (typeof cmd == 'function') {\n        CodeMirror.signal(cm, 'vim-keypress', vimKey);\n      }\n      return cmd;\n    }\n\n    var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'};\n    var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del',Insert:'Ins'};\n    function cmKeyToVimKey(key) {\n      if (key.charAt(0) == '\\'') {\n        // Keypress character binding of format \"'a'\"\n        return key.charAt(1);\n      }\n      var pieces = key.split(/-(?!$)/);\n      var lastPiece = pieces[pieces.length - 1];\n      if (pieces.length == 1 && pieces[0].length == 1) {\n        // No-modifier bindings use literal character bindings above. Skip.\n        return false;\n      } else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) {\n        // Ignore Shift+char bindings as they should be handled by literal character.\n        return false;\n      }\n      var hasCharacter = false;\n      for (var i = 0; i < pieces.length; i++) {\n        var piece = pieces[i];\n        if (piece in modifiers) { pieces[i] = modifiers[piece]; }\n        else { hasCharacter = true; }\n        if (piece in specialKeys) { pieces[i] = specialKeys[piece]; }\n      }\n      if (!hasCharacter) {\n        // Vim does not support modifier only keys.\n        return false;\n      }\n      // TODO: Current bindings expect the character to be lower case, but\n      // it looks like vim key notation uses upper case.\n      if (isUpperCase(lastPiece)) {\n        pieces[pieces.length - 1] = lastPiece.toLowerCase();\n      }\n      return '<' + pieces.join('-') + '>';\n    }\n\n    function getOnPasteFn(cm) {\n      var vim = cm.state.vim;\n      if (!vim.onPasteFn) {\n        vim.onPasteFn = function() {\n          if (!vim.insertMode) {\n            cm.setCursor(offsetCursor(cm.getCursor(), 0, 1));\n            actions.enterInsertMode(cm, {}, vim);\n          }\n        };\n      }\n      return vim.onPasteFn;\n    }\n\n    var numberRegex = /[\\d]/;\n    var wordCharTest = [CodeMirror.isWordChar, function(ch) {\n      return ch && !CodeMirror.isWordChar(ch) && !/\\s/.test(ch);\n    }], bigWordCharTest = [function(ch) {\n      return /\\S/.test(ch);\n    }];\n    function makeKeyRange(start, size) {\n      var keys = [];\n      for (var i = start; i < start + size; i++) {\n        keys.push(String.fromCharCode(i));\n      }\n      return keys;\n    }\n    var upperCaseAlphabet = makeKeyRange(65, 26);\n    var lowerCaseAlphabet = makeKeyRange(97, 26);\n    var numbers = makeKeyRange(48, 10);\n    var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']);\n    var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '\"', '.', ':', '/']);\n\n    function isLine(cm, line) {\n      return line >= cm.firstLine() && line <= cm.lastLine();\n    }\n    function isLowerCase(k) {\n      return (/^[a-z]$/).test(k);\n    }\n    function isMatchableSymbol(k) {\n      return '()[]{}'.indexOf(k) != -1;\n    }\n    function isNumber(k) {\n      return numberRegex.test(k);\n    }\n    function isUpperCase(k) {\n      return (/^[A-Z]$/).test(k);\n    }\n    function isWhiteSpaceString(k) {\n      return (/^\\s*$/).test(k);\n    }\n    function isEndOfSentenceSymbol(k) {\n      return '.?!'.indexOf(k) != -1;\n    }\n    function inArray(val, arr) {\n      for (var i = 0; i < arr.length; i++) {\n        if (arr[i] == val) {\n          return true;\n        }\n      }\n      return false;\n    }\n\n    var options = {};\n    function defineOption(name, defaultValue, type, aliases, callback) {\n      if (defaultValue === undefined && !callback) {\n        throw Error('defaultValue is required unless callback is provided');\n      }\n      if (!type) { type = 'string'; }\n      options[name] = {\n        type: type,\n        defaultValue: defaultValue,\n        callback: callback\n      };\n      if (aliases) {\n        for (var i = 0; i < aliases.length; i++) {\n          options[aliases[i]] = options[name];\n        }\n      }\n      if (defaultValue) {\n        setOption(name, defaultValue);\n      }\n    }\n\n    function setOption(name, value, cm, cfg) {\n      var option = options[name];\n      cfg = cfg || {};\n      var scope = cfg.scope;\n      if (!option) {\n        return new Error('Unknown option: ' + name);\n      }\n      if (option.type == 'boolean') {\n        if (value && value !== true) {\n          return new Error('Invalid argument: ' + name + '=' + value);\n        } else if (value !== false) {\n          // Boolean options are set to true if value is not defined.\n          value = true;\n        }\n      }\n      if (option.callback) {\n        if (scope !== 'local') {\n          option.callback(value, undefined);\n        }\n        if (scope !== 'global' && cm) {\n          option.callback(value, cm);\n        }\n      } else {\n        if (scope !== 'local') {\n          option.value = option.type == 'boolean' ? !!value : value;\n        }\n        if (scope !== 'global' && cm) {\n          cm.state.vim.options[name] = {value: value};\n        }\n      }\n    }\n\n    function getOption(name, cm, cfg) {\n      var option = options[name];\n      cfg = cfg || {};\n      var scope = cfg.scope;\n      if (!option) {\n        return new Error('Unknown option: ' + name);\n      }\n      if (option.callback) {\n        var local = cm && option.callback(undefined, cm);\n        if (scope !== 'global' && local !== undefined) {\n          return local;\n        }\n        if (scope !== 'local') {\n          return option.callback();\n        }\n        return;\n      } else {\n        var local = (scope !== 'global') && (cm && cm.state.vim.options[name]);\n        return (local || (scope !== 'local') && option || {}).value;\n      }\n    }\n\n    defineOption('filetype', undefined, 'string', ['ft'], function(name, cm) {\n      // Option is local. Do nothing for global.\n      if (cm === undefined) {\n        return;\n      }\n      // The 'filetype' option proxies to the CodeMirror 'mode' option.\n      if (name === undefined) {\n        var mode = cm.getOption('mode');\n        return mode == 'null' ? '' : mode;\n      } else {\n        var mode = name == '' ? 'null' : name;\n        cm.setOption('mode', mode);\n      }\n    });\n\n    var createCircularJumpList = function() {\n      var size = 100;\n      var pointer = -1;\n      var head = 0;\n      var tail = 0;\n      var buffer = new Array(size);\n      function add(cm, oldCur, newCur) {\n        var current = pointer % size;\n        var curMark = buffer[current];\n        function useNextSlot(cursor) {\n          var next = ++pointer % size;\n          var trashMark = buffer[next];\n          if (trashMark) {\n            trashMark.clear();\n          }\n          buffer[next] = cm.setBookmark(cursor);\n        }\n        if (curMark) {\n          var markPos = curMark.find();\n          // avoid recording redundant cursor position\n          if (markPos && !cursorEqual(markPos, oldCur)) {\n            useNextSlot(oldCur);\n          }\n        } else {\n          useNextSlot(oldCur);\n        }\n        useNextSlot(newCur);\n        head = pointer;\n        tail = pointer - size + 1;\n        if (tail < 0) {\n          tail = 0;\n        }\n      }\n      function move(cm, offset) {\n        pointer += offset;\n        if (pointer > head) {\n          pointer = head;\n        } else if (pointer < tail) {\n          pointer = tail;\n        }\n        var mark = buffer[(size + pointer) % size];\n        // skip marks that are temporarily removed from text buffer\n        if (mark && !mark.find()) {\n          var inc = offset > 0 ? 1 : -1;\n          var newCur;\n          var oldCur = cm.getCursor();\n          do {\n            pointer += inc;\n            mark = buffer[(size + pointer) % size];\n            // skip marks that are the same as current position\n            if (mark &&\n                (newCur = mark.find()) &&\n                !cursorEqual(oldCur, newCur)) {\n              break;\n            }\n          } while (pointer < head && pointer > tail);\n        }\n        return mark;\n      }\n      function find(cm, offset) {\n        var oldPointer = pointer;\n        var mark = move(cm, offset);\n        pointer = oldPointer;\n        return mark && mark.find();\n      }\n      return {\n        cachedCursor: undefined, //used for # and * jumps\n        add: add,\n        find: find,\n        move: move\n      };\n    };\n\n    // Returns an object to track the changes associated insert mode.  It\n    // clones the object that is passed in, or creates an empty object one if\n    // none is provided.\n    var createInsertModeChanges = function(c) {\n      if (c) {\n        // Copy construction\n        return {\n          changes: c.changes,\n          expectCursorActivityForChange: c.expectCursorActivityForChange\n        };\n      }\n      return {\n        // Change list\n        changes: [],\n        // Set to true on change, false on cursorActivity.\n        expectCursorActivityForChange: false\n      };\n    };\n\n    function MacroModeState() {\n      this.latestRegister = undefined;\n      this.isPlaying = false;\n      this.isRecording = false;\n      this.replaySearchQueries = [];\n      this.onRecordingDone = undefined;\n      this.lastInsertModeChanges = createInsertModeChanges();\n    }\n    MacroModeState.prototype = {\n      exitMacroRecordMode: function() {\n        var macroModeState = vimGlobalState.macroModeState;\n        if (macroModeState.onRecordingDone) {\n          macroModeState.onRecordingDone(); // close dialog\n        }\n        macroModeState.onRecordingDone = undefined;\n        macroModeState.isRecording = false;\n      },\n      enterMacroRecordMode: function(cm, registerName) {\n        var register =\n            vimGlobalState.registerController.getRegister(registerName);\n        if (register) {\n          register.clear();\n          this.latestRegister = registerName;\n          if (cm.openDialog) {\n            this.onRecordingDone = cm.openDialog(\n                '(recording)['+registerName+']', null, {bottom:true});\n          }\n          this.isRecording = true;\n        }\n      }\n    };\n\n    function maybeInitVimState(cm) {\n      if (!cm.state.vim) {\n        // Store instance state in the CodeMirror object.\n        cm.state.vim = {\n          inputState: new InputState(),\n          // Vim's input state that triggered the last edit, used to repeat\n          // motions and operators with '.'.\n          lastEditInputState: undefined,\n          // Vim's action command before the last edit, used to repeat actions\n          // with '.' and insert mode repeat.\n          lastEditActionCommand: undefined,\n          // When using jk for navigation, if you move from a longer line to a\n          // shorter line, the cursor may clip to the end of the shorter line.\n          // If j is pressed again and cursor goes to the next line, the\n          // cursor should go back to its horizontal position on the longer\n          // line if it can. This is to keep track of the horizontal position.\n          lastHPos: -1,\n          // Doing the same with screen-position for gj/gk\n          lastHSPos: -1,\n          // The last motion command run. Cleared if a non-motion command gets\n          // executed in between.\n          lastMotion: null,\n          marks: {},\n          // Mark for rendering fake cursor for visual mode.\n          fakeCursor: null,\n          insertMode: false,\n          // Repeat count for changes made in insert mode, triggered by key\n          // sequences like 3,i. Only exists when insertMode is true.\n          insertModeRepeat: undefined,\n          visualMode: false,\n          // If we are in visual line mode. No effect if visualMode is false.\n          visualLine: false,\n          visualBlock: false,\n          lastSelection: null,\n          lastPastedText: null,\n          sel: {},\n          // Buffer-local/window-local values of vim options.\n          options: {}\n        };\n      }\n      return cm.state.vim;\n    }\n    var vimGlobalState;\n    function resetVimGlobalState() {\n      vimGlobalState = {\n        // The current search query.\n        searchQuery: null,\n        // Whether we are searching backwards.\n        searchIsReversed: false,\n        // Replace part of the last substituted pattern\n        lastSubstituteReplacePart: undefined,\n        jumpList: createCircularJumpList(),\n        macroModeState: new MacroModeState,\n        // Recording latest f, t, F or T motion command.\n        lastCharacterSearch: {increment:0, forward:true, selectedCharacter:''},\n        registerController: new RegisterController({}),\n        // search history buffer\n        searchHistoryController: new HistoryController(),\n        // ex Command history buffer\n        exCommandHistoryController : new HistoryController()\n      };\n      for (var optionName in options) {\n        var option = options[optionName];\n        option.value = option.defaultValue;\n      }\n    }\n\n    var lastInsertModeKeyTimer;\n    var vimApi= {\n      buildKeyMap: function() {\n        // TODO: Convert keymap into dictionary format for fast lookup.\n      },\n      // Testing hook, though it might be useful to expose the register\n      // controller anyways.\n      getRegisterController: function() {\n        return vimGlobalState.registerController;\n      },\n      // Testing hook.\n      resetVimGlobalState_: resetVimGlobalState,\n\n      // Testing hook.\n      getVimGlobalState_: function() {\n        return vimGlobalState;\n      },\n\n      // Testing hook.\n      maybeInitVimState_: maybeInitVimState,\n\n      suppressErrorLogging: false,\n\n      InsertModeKey: InsertModeKey,\n      map: function(lhs, rhs, ctx) {\n        // Add user defined key bindings.\n        exCommandDispatcher.map(lhs, rhs, ctx);\n      },\n      unmap: function(lhs, ctx) {\n        exCommandDispatcher.unmap(lhs, ctx);\n      },\n      // Non-recursive map function.\n      // NOTE: This will not create mappings to key maps that aren't present\n      // in the default key map. See TODO at bottom of function.\n      noremap: function(lhs, rhs, ctx) {\n        function toCtxArray(ctx) {\n          return ctx ? [ctx] : ['normal', 'insert', 'visual'];\n        }\n        var ctxsToMap = toCtxArray(ctx);\n        // Look through all actual defaults to find a map candidate.\n        var actualLength = defaultKeymap.length, origLength = defaultKeymapLength;\n        for (var i = actualLength - origLength;\n             i < actualLength && ctxsToMap.length;\n             i++) {\n          var mapping = defaultKeymap[i];\n          // Omit mappings that operate in the wrong context(s) and those of invalid type.\n          if (mapping.keys == rhs &&\n              (!ctx || !mapping.context || mapping.context === ctx) &&\n              mapping.type.substr(0, 2) !== 'ex' &&\n              mapping.type.substr(0, 3) !== 'key') {\n            // Make a shallow copy of the original keymap entry.\n            var newMapping = {};\n            for (var key in mapping) {\n              newMapping[key] = mapping[key];\n            }\n            // Modify it point to the new mapping with the proper context.\n            newMapping.keys = lhs;\n            if (ctx && !newMapping.context) {\n              newMapping.context = ctx;\n            }\n            // Add it to the keymap with a higher priority than the original.\n            this._mapCommand(newMapping);\n            // Record the mapped contexts as complete.\n            var mappedCtxs = toCtxArray(mapping.context);\n            ctxsToMap = ctxsToMap.filter(function(el) { return mappedCtxs.indexOf(el) === -1; });\n          }\n        }\n        // TODO: Create non-recursive keyToKey mappings for the unmapped contexts once those exist.\n      },\n      // Remove all user-defined mappings for the provided context.\n      mapclear: function(ctx) {\n        // Partition the existing keymap into user-defined and true defaults.\n        var actualLength = defaultKeymap.length,\n            origLength = defaultKeymapLength;\n        var userKeymap = defaultKeymap.slice(0, actualLength - origLength);\n        defaultKeymap = defaultKeymap.slice(actualLength - origLength);\n        if (ctx) {\n          // If a specific context is being cleared, we need to keep mappings\n          // from all other contexts.\n          for (var i = userKeymap.length - 1; i >= 0; i--) {\n            var mapping = userKeymap[i];\n            if (ctx !== mapping.context) {\n              if (mapping.context) {\n                this._mapCommand(mapping);\n              } else {\n                // `mapping` applies to all contexts so create keymap copies\n                // for each context except the one being cleared.\n                var contexts = ['normal', 'insert', 'visual'];\n                for (var j in contexts) {\n                  if (contexts[j] !== ctx) {\n                    var newMapping = {};\n                    for (var key in mapping) {\n                      newMapping[key] = mapping[key];\n                    }\n                    newMapping.context = contexts[j];\n                    this._mapCommand(newMapping);\n                  }\n                }\n              }\n            }\n          }\n        }\n      },\n      // TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace\n      // them, or somehow make them work with the existing CodeMirror setOption/getOption API.\n      setOption: setOption,\n      getOption: getOption,\n      defineOption: defineOption,\n      defineEx: function(name, prefix, func){\n        if (!prefix) {\n          prefix = name;\n        } else if (name.indexOf(prefix) !== 0) {\n          throw new Error('(Vim.defineEx) \"'+prefix+'\" is not a prefix of \"'+name+'\", command not registered');\n        }\n        exCommands[name]=func;\n        exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};\n      },\n      handleKey: function (cm, key, origin) {\n        var command = this.findKey(cm, key, origin);\n        if (typeof command === 'function') {\n          return command();\n        }\n      },\n      /**\n       * This is the outermost function called by CodeMirror, after keys have\n       * been mapped to their Vim equivalents.\n       *\n       * Finds a command based on the key (and cached keys if there is a\n       * multi-key sequence). Returns `undefined` if no key is matched, a noop\n       * function if a partial match is found (multi-key), and a function to\n       * execute the bound command if a a key is matched. The function always\n       * returns true.\n       */\n      findKey: function(cm, key, origin) {\n        var vim = maybeInitVimState(cm);\n        function handleMacroRecording() {\n          var macroModeState = vimGlobalState.macroModeState;\n          if (macroModeState.isRecording) {\n            if (key == 'q') {\n              macroModeState.exitMacroRecordMode();\n              clearInputState(cm);\n              return true;\n            }\n            if (origin != 'mapping') {\n              logKey(macroModeState, key);\n            }\n          }\n        }\n        function handleEsc() {\n          if (key == '<Esc>') {\n            // Clear input state and get back to normal mode.\n            clearInputState(cm);\n            if (vim.visualMode) {\n              exitVisualMode(cm);\n            } else if (vim.insertMode) {\n              exitInsertMode(cm);\n            }\n            return true;\n          }\n        }\n        function doKeyToKey(keys) {\n          // TODO: prevent infinite recursion.\n          var match;\n          while (keys) {\n            // Pull off one command key, which is either a single character\n            // or a special sequence wrapped in '<' and '>', e.g. '<Space>'.\n            match = (/<\\w+-.+?>|<\\w+>|./).exec(keys);\n            key = match[0];\n            keys = keys.substring(match.index + key.length);\n            CodeMirror.Vim.handleKey(cm, key, 'mapping');\n          }\n        }\n\n        function handleKeyInsertMode() {\n          if (handleEsc()) { return true; }\n          var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;\n          var keysAreChars = key.length == 1;\n          var match = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert');\n          // Need to check all key substrings in insert mode.\n          while (keys.length > 1 && match.type != 'full') {\n            var keys = vim.inputState.keyBuffer = keys.slice(1);\n            var thisMatch = commandDispatcher.matchCommand(keys, defaultKeymap, vim.inputState, 'insert');\n            if (thisMatch.type != 'none') { match = thisMatch; }\n          }\n          if (match.type == 'none') { clearInputState(cm); return false; }\n          else if (match.type == 'partial') {\n            if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); }\n            lastInsertModeKeyTimer = window.setTimeout(\n              function() { if (vim.insertMode && vim.inputState.keyBuffer) { clearInputState(cm); } },\n              getOption('insertModeEscKeysTimeout'));\n            return !keysAreChars;\n          }\n\n          if (lastInsertModeKeyTimer) { window.clearTimeout(lastInsertModeKeyTimer); }\n          if (keysAreChars) {\n            var selections = cm.listSelections();\n            for (var i = 0; i < selections.length; i++) {\n              var here = selections[i].head;\n              cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input');\n            }\n            vimGlobalState.macroModeState.lastInsertModeChanges.changes.pop();\n          }\n          clearInputState(cm);\n          return match.command;\n        }\n\n        function handleKeyNonInsertMode() {\n          if (handleMacroRecording() || handleEsc()) { return true; }\n\n          var keys = vim.inputState.keyBuffer = vim.inputState.keyBuffer + key;\n          if (/^[1-9]\\d*$/.test(keys)) { return true; }\n\n          var keysMatcher = /^(\\d*)(.*)$/.exec(keys);\n          if (!keysMatcher) { clearInputState(cm); return false; }\n          var context = vim.visualMode ? 'visual' :\n                                         'normal';\n          var match = commandDispatcher.matchCommand(keysMatcher[2] || keysMatcher[1], defaultKeymap, vim.inputState, context);\n          if (match.type == 'none') { clearInputState(cm); return false; }\n          else if (match.type == 'partial') { return true; }\n\n          vim.inputState.keyBuffer = '';\n          var keysMatcher = /^(\\d*)(.*)$/.exec(keys);\n          if (keysMatcher[1] && keysMatcher[1] != '0') {\n            vim.inputState.pushRepeatDigit(keysMatcher[1]);\n          }\n          return match.command;\n        }\n\n        var command;\n        if (vim.insertMode) { command = handleKeyInsertMode(); }\n        else { command = handleKeyNonInsertMode(); }\n        if (command === false) {\n          return !vim.insertMode && key.length === 1 ? function() { return true; } : undefined;\n        } else if (command === true) {\n          // TODO: Look into using CodeMirror's multi-key handling.\n          // Return no-op since we are caching the key. Counts as handled, but\n          // don't want act on it just yet.\n          return function() { return true; };\n        } else {\n          return function() {\n            return cm.operation(function() {\n              cm.curOp.isVimOp = true;\n              try {\n                if (command.type == 'keyToKey') {\n                  doKeyToKey(command.toKeys);\n                } else {\n                  commandDispatcher.processCommand(cm, vim, command);\n                }\n              } catch (e) {\n                // clear VIM state in case it's in a bad state.\n                cm.state.vim = undefined;\n                maybeInitVimState(cm);\n                if (!CodeMirror.Vim.suppressErrorLogging) {\n                  console['log'](e);\n                }\n                throw e;\n              }\n              return true;\n            });\n          };\n        }\n      },\n      handleEx: function(cm, input) {\n        exCommandDispatcher.processCommand(cm, input);\n      },\n\n      defineMotion: defineMotion,\n      defineAction: defineAction,\n      defineOperator: defineOperator,\n      mapCommand: mapCommand,\n      _mapCommand: _mapCommand,\n\n      defineRegister: defineRegister,\n\n      exitVisualMode: exitVisualMode,\n      exitInsertMode: exitInsertMode\n    };\n\n    // Represents the current input state.\n    function InputState() {\n      this.prefixRepeat = [];\n      this.motionRepeat = [];\n\n      this.operator = null;\n      this.operatorArgs = null;\n      this.motion = null;\n      this.motionArgs = null;\n      this.keyBuffer = []; // For matching multi-key commands.\n      this.registerName = null; // Defaults to the unnamed register.\n    }\n    InputState.prototype.pushRepeatDigit = function(n) {\n      if (!this.operator) {\n        this.prefixRepeat = this.prefixRepeat.concat(n);\n      } else {\n        this.motionRepeat = this.motionRepeat.concat(n);\n      }\n    };\n    InputState.prototype.getRepeat = function() {\n      var repeat = 0;\n      if (this.prefixRepeat.length > 0 || this.motionRepeat.length > 0) {\n        repeat = 1;\n        if (this.prefixRepeat.length > 0) {\n          repeat *= parseInt(this.prefixRepeat.join(''), 10);\n        }\n        if (this.motionRepeat.length > 0) {\n          repeat *= parseInt(this.motionRepeat.join(''), 10);\n        }\n      }\n      return repeat;\n    };\n\n    function clearInputState(cm, reason) {\n      cm.state.vim.inputState = new InputState();\n      CodeMirror.signal(cm, 'vim-command-done', reason);\n    }\n\n    /*\n     * Register stores information about copy and paste registers.  Besides\n     * text, a register must store whether it is linewise (i.e., when it is\n     * pasted, should it insert itself into a new line, or should the text be\n     * inserted at the cursor position.)\n     */\n    function Register(text, linewise, blockwise) {\n      this.clear();\n      this.keyBuffer = [text || ''];\n      this.insertModeChanges = [];\n      this.searchQueries = [];\n      this.linewise = !!linewise;\n      this.blockwise = !!blockwise;\n    }\n    Register.prototype = {\n      setText: function(text, linewise, blockwise) {\n        this.keyBuffer = [text || ''];\n        this.linewise = !!linewise;\n        this.blockwise = !!blockwise;\n      },\n      pushText: function(text, linewise) {\n        // if this register has ever been set to linewise, use linewise.\n        if (linewise) {\n          if (!this.linewise) {\n            this.keyBuffer.push('\\n');\n          }\n          this.linewise = true;\n        }\n        this.keyBuffer.push(text);\n      },\n      pushInsertModeChanges: function(changes) {\n        this.insertModeChanges.push(createInsertModeChanges(changes));\n      },\n      pushSearchQuery: function(query) {\n        this.searchQueries.push(query);\n      },\n      clear: function() {\n        this.keyBuffer = [];\n        this.insertModeChanges = [];\n        this.searchQueries = [];\n        this.linewise = false;\n      },\n      toString: function() {\n        return this.keyBuffer.join('');\n      }\n    };\n\n    /**\n     * Defines an external register.\n     *\n     * The name should be a single character that will be used to reference the register.\n     * The register should support setText, pushText, clear, and toString(). See Register\n     * for a reference implementation.\n     */\n    function defineRegister(name, register) {\n      var registers = vimGlobalState.registerController.registers;\n      if (!name || name.length != 1) {\n        throw Error('Register name must be 1 character');\n      }\n      if (registers[name]) {\n        throw Error('Register already defined ' + name);\n      }\n      registers[name] = register;\n      validRegisters.push(name);\n    }\n\n    /*\n     * vim registers allow you to keep many independent copy and paste buffers.\n     * See http://usevim.com/2012/04/13/registers/ for an introduction.\n     *\n     * RegisterController keeps the state of all the registers.  An initial\n     * state may be passed in.  The unnamed register '\"' will always be\n     * overridden.\n     */\n    function RegisterController(registers) {\n      this.registers = registers;\n      this.unnamedRegister = registers['\"'] = new Register();\n      registers['.'] = new Register();\n      registers[':'] = new Register();\n      registers['/'] = new Register();\n    }\n    RegisterController.prototype = {\n      pushText: function(registerName, operator, text, linewise, blockwise) {\n        if (linewise && text.charAt(text.length - 1) !== '\\n'){\n          text += '\\n';\n        }\n        // Lowercase and uppercase registers refer to the same register.\n        // Uppercase just means append.\n        var register = this.isValidRegister(registerName) ?\n            this.getRegister(registerName) : null;\n        // if no register/an invalid register was specified, things go to the\n        // default registers\n        if (!register) {\n          switch (operator) {\n            case 'yank':\n              // The 0 register contains the text from the most recent yank.\n              this.registers['0'] = new Register(text, linewise, blockwise);\n              break;\n            case 'delete':\n            case 'change':\n              if (text.indexOf('\\n') == -1) {\n                // Delete less than 1 line. Update the small delete register.\n                this.registers['-'] = new Register(text, linewise);\n              } else {\n                // Shift down the contents of the numbered registers and put the\n                // deleted text into register 1.\n                this.shiftNumericRegisters_();\n                this.registers['1'] = new Register(text, linewise);\n              }\n              break;\n          }\n          // Make sure the unnamed register is set to what just happened\n          this.unnamedRegister.setText(text, linewise, blockwise);\n          return;\n        }\n\n        // If we've gotten to this point, we've actually specified a register\n        var append = isUpperCase(registerName);\n        if (append) {\n          register.pushText(text, linewise);\n        } else {\n          register.setText(text, linewise, blockwise);\n        }\n        // The unnamed register always has the same value as the last used\n        // register.\n        this.unnamedRegister.setText(register.toString(), linewise);\n      },\n      // Gets the register named @name.  If one of @name doesn't already exist,\n      // create it.  If @name is invalid, return the unnamedRegister.\n      getRegister: function(name) {\n        if (!this.isValidRegister(name)) {\n          return this.unnamedRegister;\n        }\n        name = name.toLowerCase();\n        if (!this.registers[name]) {\n          this.registers[name] = new Register();\n        }\n        return this.registers[name];\n      },\n      isValidRegister: function(name) {\n        return name && inArray(name, validRegisters);\n      },\n      shiftNumericRegisters_: function() {\n        for (var i = 9; i >= 2; i--) {\n          this.registers[i] = this.getRegister('' + (i - 1));\n        }\n      }\n    };\n    function HistoryController() {\n        this.historyBuffer = [];\n        this.iterator = 0;\n        this.initialPrefix = null;\n    }\n    HistoryController.prototype = {\n      // the input argument here acts a user entered prefix for a small time\n      // until we start autocompletion in which case it is the autocompleted.\n      nextMatch: function (input, up) {\n        var historyBuffer = this.historyBuffer;\n        var dir = up ? -1 : 1;\n        if (this.initialPrefix === null) this.initialPrefix = input;\n        for (var i = this.iterator + dir; up ? i >= 0 : i < historyBuffer.length; i+= dir) {\n          var element = historyBuffer[i];\n          for (var j = 0; j <= element.length; j++) {\n            if (this.initialPrefix == element.substring(0, j)) {\n              this.iterator = i;\n              return element;\n            }\n          }\n        }\n        // should return the user input in case we reach the end of buffer.\n        if (i >= historyBuffer.length) {\n          this.iterator = historyBuffer.length;\n          return this.initialPrefix;\n        }\n        // return the last autocompleted query or exCommand as it is.\n        if (i < 0 ) return input;\n      },\n      pushInput: function(input) {\n        var index = this.historyBuffer.indexOf(input);\n        if (index > -1) this.historyBuffer.splice(index, 1);\n        if (input.length) this.historyBuffer.push(input);\n      },\n      reset: function() {\n        this.initialPrefix = null;\n        this.iterator = this.historyBuffer.length;\n      }\n    };\n    var commandDispatcher = {\n      matchCommand: function(keys, keyMap, inputState, context) {\n        var matches = commandMatches(keys, keyMap, context, inputState);\n        if (!matches.full && !matches.partial) {\n          return {type: 'none'};\n        } else if (!matches.full && matches.partial) {\n          return {type: 'partial'};\n        }\n\n        var bestMatch;\n        for (var i = 0; i < matches.full.length; i++) {\n          var match = matches.full[i];\n          if (!bestMatch) {\n            bestMatch = match;\n          }\n        }\n        if (bestMatch.keys.slice(-11) == '<character>') {\n          var character = lastChar(keys);\n          if (!character) return {type: 'none'};\n          inputState.selectedCharacter = character;\n        }\n        return {type: 'full', command: bestMatch};\n      },\n      processCommand: function(cm, vim, command) {\n        vim.inputState.repeatOverride = command.repeatOverride;\n        switch (command.type) {\n          case 'motion':\n            this.processMotion(cm, vim, command);\n            break;\n          case 'operator':\n            this.processOperator(cm, vim, command);\n            break;\n          case 'operatorMotion':\n            this.processOperatorMotion(cm, vim, command);\n            break;\n          case 'action':\n            this.processAction(cm, vim, command);\n            break;\n          case 'search':\n            this.processSearch(cm, vim, command);\n            break;\n          case 'ex':\n          case 'keyToEx':\n            this.processEx(cm, vim, command);\n            break;\n          default:\n            break;\n        }\n      },\n      processMotion: function(cm, vim, command) {\n        vim.inputState.motion = command.motion;\n        vim.inputState.motionArgs = copyArgs(command.motionArgs);\n        this.evalInput(cm, vim);\n      },\n      processOperator: function(cm, vim, command) {\n        var inputState = vim.inputState;\n        if (inputState.operator) {\n          if (inputState.operator == command.operator) {\n            // Typing an operator twice like 'dd' makes the operator operate\n            // linewise\n            inputState.motion = 'expandToLine';\n            inputState.motionArgs = { linewise: true };\n            this.evalInput(cm, vim);\n            return;\n          } else {\n            // 2 different operators in a row doesn't make sense.\n            clearInputState(cm);\n          }\n        }\n        inputState.operator = command.operator;\n        inputState.operatorArgs = copyArgs(command.operatorArgs);\n        if (command.exitVisualBlock) {\n            vim.visualBlock = false;\n            updateCmSelection(cm);\n        }\n        if (vim.visualMode) {\n          // Operating on a selection in visual mode. We don't need a motion.\n          this.evalInput(cm, vim);\n        }\n      },\n      processOperatorMotion: function(cm, vim, command) {\n        var visualMode = vim.visualMode;\n        var operatorMotionArgs = copyArgs(command.operatorMotionArgs);\n        if (operatorMotionArgs) {\n          // Operator motions may have special behavior in visual mode.\n          if (visualMode && operatorMotionArgs.visualLine) {\n            vim.visualLine = true;\n          }\n        }\n        this.processOperator(cm, vim, command);\n        if (!visualMode) {\n          this.processMotion(cm, vim, command);\n        }\n      },\n      processAction: function(cm, vim, command) {\n        var inputState = vim.inputState;\n        var repeat = inputState.getRepeat();\n        var repeatIsExplicit = !!repeat;\n        var actionArgs = copyArgs(command.actionArgs) || {};\n        if (inputState.selectedCharacter) {\n          actionArgs.selectedCharacter = inputState.selectedCharacter;\n        }\n        // Actions may or may not have motions and operators. Do these first.\n        if (command.operator) {\n          this.processOperator(cm, vim, command);\n        }\n        if (command.motion) {\n          this.processMotion(cm, vim, command);\n        }\n        if (command.motion || command.operator) {\n          this.evalInput(cm, vim);\n        }\n        actionArgs.repeat = repeat || 1;\n        actionArgs.repeatIsExplicit = repeatIsExplicit;\n        actionArgs.registerName = inputState.registerName;\n        clearInputState(cm);\n        vim.lastMotion = null;\n        if (command.isEdit) {\n          this.recordLastEdit(vim, inputState, command);\n        }\n        actions[command.action](cm, actionArgs, vim);\n      },\n      processSearch: function(cm, vim, command) {\n        if (!cm.getSearchCursor) {\n          // Search depends on SearchCursor.\n          return;\n        }\n        var forward = command.searchArgs.forward;\n        var wholeWordOnly = command.searchArgs.wholeWordOnly;\n        getSearchState(cm).setReversed(!forward);\n        var promptPrefix = (forward) ? '/' : '?';\n        var originalQuery = getSearchState(cm).getQuery();\n        var originalScrollPos = cm.getScrollInfo();\n        function handleQuery(query, ignoreCase, smartCase) {\n          vimGlobalState.searchHistoryController.pushInput(query);\n          vimGlobalState.searchHistoryController.reset();\n          try {\n            updateSearchQuery(cm, query, ignoreCase, smartCase);\n          } catch (e) {\n            showConfirm(cm, 'Invalid regex: ' + query);\n            clearInputState(cm);\n            return;\n          }\n          commandDispatcher.processMotion(cm, vim, {\n            type: 'motion',\n            motion: 'findNext',\n            motionArgs: { forward: true, toJumplist: command.searchArgs.toJumplist }\n          });\n        }\n        function onPromptClose(query) {\n          cm.scrollTo(originalScrollPos.left, originalScrollPos.top);\n          handleQuery(query, true /** ignoreCase */, true /** smartCase */);\n          var macroModeState = vimGlobalState.macroModeState;\n          if (macroModeState.isRecording) {\n            logSearchQuery(macroModeState, query);\n          }\n        }\n        function onPromptKeyUp(e, query, close) {\n          var keyName = CodeMirror.keyName(e), up, offset;\n          if (keyName == 'Up' || keyName == 'Down') {\n            up = keyName == 'Up' ? true : false;\n            offset = e.target ? e.target.selectionEnd : 0;\n            query = vimGlobalState.searchHistoryController.nextMatch(query, up) || '';\n            close(query);\n            if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length);\n          } else {\n            if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift')\n              vimGlobalState.searchHistoryController.reset();\n          }\n          var parsedQuery;\n          try {\n            parsedQuery = updateSearchQuery(cm, query,\n                true /** ignoreCase */, true /** smartCase */);\n          } catch (e) {\n            // Swallow bad regexes for incremental search.\n          }\n          if (parsedQuery) {\n            cm.scrollIntoView(findNext(cm, !forward, parsedQuery), 30);\n          } else {\n            clearSearchHighlight(cm);\n            cm.scrollTo(originalScrollPos.left, originalScrollPos.top);\n          }\n        }\n        function onPromptKeyDown(e, query, close) {\n          var keyName = CodeMirror.keyName(e);\n          if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' ||\n              (keyName == 'Backspace' && query == '')) {\n            vimGlobalState.searchHistoryController.pushInput(query);\n            vimGlobalState.searchHistoryController.reset();\n            updateSearchQuery(cm, originalQuery);\n            clearSearchHighlight(cm);\n            cm.scrollTo(originalScrollPos.left, originalScrollPos.top);\n            CodeMirror.e_stop(e);\n            clearInputState(cm);\n            close();\n            cm.focus();\n          } else if (keyName == 'Up' || keyName == 'Down') {\n            CodeMirror.e_stop(e);\n          } else if (keyName == 'Ctrl-U') {\n            // Ctrl-U clears input.\n            CodeMirror.e_stop(e);\n            close('');\n          }\n        }\n        switch (command.searchArgs.querySrc) {\n          case 'prompt':\n            var macroModeState = vimGlobalState.macroModeState;\n            if (macroModeState.isPlaying) {\n              var query = macroModeState.replaySearchQueries.shift();\n              handleQuery(query, true /** ignoreCase */, false /** smartCase */);\n            } else {\n              showPrompt(cm, {\n                  onClose: onPromptClose,\n                  prefix: promptPrefix,\n                  desc: searchPromptDesc,\n                  onKeyUp: onPromptKeyUp,\n                  onKeyDown: onPromptKeyDown\n              });\n            }\n            break;\n          case 'wordUnderCursor':\n            var word = expandWordUnderCursor(cm, false /** inclusive */,\n                true /** forward */, false /** bigWord */,\n                true /** noSymbol */);\n            var isKeyword = true;\n            if (!word) {\n              word = expandWordUnderCursor(cm, false /** inclusive */,\n                  true /** forward */, false /** bigWord */,\n                  false /** noSymbol */);\n              isKeyword = false;\n            }\n            if (!word) {\n              return;\n            }\n            var query = cm.getLine(word.start.line).substring(word.start.ch,\n                word.end.ch);\n            if (isKeyword && wholeWordOnly) {\n                query = '\\\\b' + query + '\\\\b';\n            } else {\n              query = escapeRegex(query);\n            }\n\n            // cachedCursor is used to save the old position of the cursor\n            // when * or # causes vim to seek for the nearest word and shift\n            // the cursor before entering the motion.\n            vimGlobalState.jumpList.cachedCursor = cm.getCursor();\n            cm.setCursor(word.start);\n\n            handleQuery(query, true /** ignoreCase */, false /** smartCase */);\n            break;\n        }\n      },\n      processEx: function(cm, vim, command) {\n        function onPromptClose(input) {\n          // Give the prompt some time to close so that if processCommand shows\n          // an error, the elements don't overlap.\n          vimGlobalState.exCommandHistoryController.pushInput(input);\n          vimGlobalState.exCommandHistoryController.reset();\n          exCommandDispatcher.processCommand(cm, input);\n        }\n        function onPromptKeyDown(e, input, close) {\n          var keyName = CodeMirror.keyName(e), up, offset;\n          if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' ||\n              (keyName == 'Backspace' && input == '')) {\n            vimGlobalState.exCommandHistoryController.pushInput(input);\n            vimGlobalState.exCommandHistoryController.reset();\n            CodeMirror.e_stop(e);\n            clearInputState(cm);\n            close();\n            cm.focus();\n          }\n          if (keyName == 'Up' || keyName == 'Down') {\n            CodeMirror.e_stop(e);\n            up = keyName == 'Up' ? true : false;\n            offset = e.target ? e.target.selectionEnd : 0;\n            input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || '';\n            close(input);\n            if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length);\n          } else if (keyName == 'Ctrl-U') {\n            // Ctrl-U clears input.\n            CodeMirror.e_stop(e);\n            close('');\n          } else {\n            if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift')\n              vimGlobalState.exCommandHistoryController.reset();\n          }\n        }\n        if (command.type == 'keyToEx') {\n          // Handle user defined Ex to Ex mappings\n          exCommandDispatcher.processCommand(cm, command.exArgs.input);\n        } else {\n          if (vim.visualMode) {\n            showPrompt(cm, { onClose: onPromptClose, prefix: ':', value: '\\'<,\\'>',\n                onKeyDown: onPromptKeyDown, selectValueOnOpen: false});\n          } else {\n            showPrompt(cm, { onClose: onPromptClose, prefix: ':',\n                onKeyDown: onPromptKeyDown});\n          }\n        }\n      },\n      evalInput: function(cm, vim) {\n        // If the motion command is set, execute both the operator and motion.\n        // Otherwise return.\n        var inputState = vim.inputState;\n        var motion = inputState.motion;\n        var motionArgs = inputState.motionArgs || {};\n        var operator = inputState.operator;\n        var operatorArgs = inputState.operatorArgs || {};\n        var registerName = inputState.registerName;\n        var sel = vim.sel;\n        // TODO: Make sure cm and vim selections are identical outside visual mode.\n        var origHead = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.head): cm.getCursor('head'));\n        var origAnchor = copyCursor(vim.visualMode ? clipCursorToContent(cm, sel.anchor) : cm.getCursor('anchor'));\n        var oldHead = copyCursor(origHead);\n        var oldAnchor = copyCursor(origAnchor);\n        var newHead, newAnchor;\n        var repeat;\n        if (operator) {\n          this.recordLastEdit(vim, inputState);\n        }\n        if (inputState.repeatOverride !== undefined) {\n          // If repeatOverride is specified, that takes precedence over the\n          // input state's repeat. Used by Ex mode and can be user defined.\n          repeat = inputState.repeatOverride;\n        } else {\n          repeat = inputState.getRepeat();\n        }\n        if (repeat > 0 && motionArgs.explicitRepeat) {\n          motionArgs.repeatIsExplicit = true;\n        } else if (motionArgs.noRepeat ||\n            (!motionArgs.explicitRepeat && repeat === 0)) {\n          repeat = 1;\n          motionArgs.repeatIsExplicit = false;\n        }\n        if (inputState.selectedCharacter) {\n          // If there is a character input, stick it in all of the arg arrays.\n          motionArgs.selectedCharacter = operatorArgs.selectedCharacter =\n              inputState.selectedCharacter;\n        }\n        motionArgs.repeat = repeat;\n        clearInputState(cm);\n        if (motion) {\n          var motionResult = motions[motion](cm, origHead, motionArgs, vim);\n          vim.lastMotion = motions[motion];\n          if (!motionResult) {\n            return;\n          }\n          if (motionArgs.toJumplist) {\n            var jumpList = vimGlobalState.jumpList;\n            // if the current motion is # or *, use cachedCursor\n            var cachedCursor = jumpList.cachedCursor;\n            if (cachedCursor) {\n              recordJumpPosition(cm, cachedCursor, motionResult);\n              delete jumpList.cachedCursor;\n            } else {\n              recordJumpPosition(cm, origHead, motionResult);\n            }\n          }\n          if (motionResult instanceof Array) {\n            newAnchor = motionResult[0];\n            newHead = motionResult[1];\n          } else {\n            newHead = motionResult;\n          }\n          // TODO: Handle null returns from motion commands better.\n          if (!newHead) {\n            newHead = copyCursor(origHead);\n          }\n          if (vim.visualMode) {\n            if (!(vim.visualBlock && newHead.ch === Infinity)) {\n              newHead = clipCursorToContent(cm, newHead);\n            }\n            if (newAnchor) {\n              newAnchor = clipCursorToContent(cm, newAnchor);\n            }\n            newAnchor = newAnchor || oldAnchor;\n            sel.anchor = newAnchor;\n            sel.head = newHead;\n            updateCmSelection(cm);\n            updateMark(cm, vim, '<',\n                cursorIsBefore(newAnchor, newHead) ? newAnchor\n                    : newHead);\n            updateMark(cm, vim, '>',\n                cursorIsBefore(newAnchor, newHead) ? newHead\n                    : newAnchor);\n          } else if (!operator) {\n            newHead = clipCursorToContent(cm, newHead);\n            cm.setCursor(newHead.line, newHead.ch);\n          }\n        }\n        if (operator) {\n          if (operatorArgs.lastSel) {\n            // Replaying a visual mode operation\n            newAnchor = oldAnchor;\n            var lastSel = operatorArgs.lastSel;\n            var lineOffset = Math.abs(lastSel.head.line - lastSel.anchor.line);\n            var chOffset = Math.abs(lastSel.head.ch - lastSel.anchor.ch);\n            if (lastSel.visualLine) {\n              // Linewise Visual mode: The same number of lines.\n              newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch);\n            } else if (lastSel.visualBlock) {\n              // Blockwise Visual mode: The same number of lines and columns.\n              newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch + chOffset);\n            } else if (lastSel.head.line == lastSel.anchor.line) {\n              // Normal Visual mode within one line: The same number of characters.\n              newHead = Pos(oldAnchor.line, oldAnchor.ch + chOffset);\n            } else {\n              // Normal Visual mode with several lines: The same number of lines, in the\n              // last line the same number of characters as in the last line the last time.\n              newHead = Pos(oldAnchor.line + lineOffset, oldAnchor.ch);\n            }\n            vim.visualMode = true;\n            vim.visualLine = lastSel.visualLine;\n            vim.visualBlock = lastSel.visualBlock;\n            sel = vim.sel = {\n              anchor: newAnchor,\n              head: newHead\n            };\n            updateCmSelection(cm);\n          } else if (vim.visualMode) {\n            operatorArgs.lastSel = {\n              anchor: copyCursor(sel.anchor),\n              head: copyCursor(sel.head),\n              visualBlock: vim.visualBlock,\n              visualLine: vim.visualLine\n            };\n          }\n          var curStart, curEnd, linewise, mode;\n          var cmSel;\n          if (vim.visualMode) {\n            // Init visual op\n            curStart = cursorMin(sel.head, sel.anchor);\n            curEnd = cursorMax(sel.head, sel.anchor);\n            linewise = vim.visualLine || operatorArgs.linewise;\n            mode = vim.visualBlock ? 'block' :\n                   linewise ? 'line' :\n                   'char';\n            cmSel = makeCmSelection(cm, {\n              anchor: curStart,\n              head: curEnd\n            }, mode);\n            if (linewise) {\n              var ranges = cmSel.ranges;\n              if (mode == 'block') {\n                // Linewise operators in visual block mode extend to end of line\n                for (var i = 0; i < ranges.length; i++) {\n                  ranges[i].head.ch = lineLength(cm, ranges[i].head.line);\n                }\n              } else if (mode == 'line') {\n                ranges[0].head = Pos(ranges[0].head.line + 1, 0);\n              }\n            }\n          } else {\n            // Init motion op\n            curStart = copyCursor(newAnchor || oldAnchor);\n            curEnd = copyCursor(newHead || oldHead);\n            if (cursorIsBefore(curEnd, curStart)) {\n              var tmp = curStart;\n              curStart = curEnd;\n              curEnd = tmp;\n            }\n            linewise = motionArgs.linewise || operatorArgs.linewise;\n            if (linewise) {\n              // Expand selection to entire line.\n              expandSelectionToLine(cm, curStart, curEnd);\n            } else if (motionArgs.forward) {\n              // Clip to trailing newlines only if the motion goes forward.\n              clipToLine(cm, curStart, curEnd);\n            }\n            mode = 'char';\n            var exclusive = !motionArgs.inclusive || linewise;\n            cmSel = makeCmSelection(cm, {\n              anchor: curStart,\n              head: curEnd\n            }, mode, exclusive);\n          }\n          cm.setSelections(cmSel.ranges, cmSel.primary);\n          vim.lastMotion = null;\n          operatorArgs.repeat = repeat; // For indent in visual mode.\n          operatorArgs.registerName = registerName;\n          // Keep track of linewise as it affects how paste and change behave.\n          operatorArgs.linewise = linewise;\n          var operatorMoveTo = operators[operator](\n            cm, operatorArgs, cmSel.ranges, oldAnchor, newHead);\n          if (vim.visualMode) {\n            exitVisualMode(cm, operatorMoveTo != null);\n          }\n          if (operatorMoveTo) {\n            cm.setCursor(operatorMoveTo);\n          }\n        }\n      },\n      recordLastEdit: function(vim, inputState, actionCommand) {\n        var macroModeState = vimGlobalState.macroModeState;\n        if (macroModeState.isPlaying) { return; }\n        vim.lastEditInputState = inputState;\n        vim.lastEditActionCommand = actionCommand;\n        macroModeState.lastInsertModeChanges.changes = [];\n        macroModeState.lastInsertModeChanges.expectCursorActivityForChange = false;\n        macroModeState.lastInsertModeChanges.visualBlock = vim.visualBlock ? vim.sel.head.line - vim.sel.anchor.line : 0;\n      }\n    };\n\n    /**\n     * typedef {Object{line:number,ch:number}} Cursor An object containing the\n     *     position of the cursor.\n     */\n    // All of the functions below return Cursor objects.\n    var motions = {\n      moveToTopLine: function(cm, _head, motionArgs) {\n        var line = getUserVisibleLines(cm).top + motionArgs.repeat -1;\n        return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line)));\n      },\n      moveToMiddleLine: function(cm) {\n        var range = getUserVisibleLines(cm);\n        var line = Math.floor((range.top + range.bottom) * 0.5);\n        return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line)));\n      },\n      moveToBottomLine: function(cm, _head, motionArgs) {\n        var line = getUserVisibleLines(cm).bottom - motionArgs.repeat +1;\n        return Pos(line, findFirstNonWhiteSpaceCharacter(cm.getLine(line)));\n      },\n      expandToLine: function(_cm, head, motionArgs) {\n        // Expands forward to end of line, and then to next line if repeat is\n        // >1. Does not handle backward motion!\n        var cur = head;\n        return Pos(cur.line + motionArgs.repeat - 1, Infinity);\n      },\n      findNext: function(cm, _head, motionArgs) {\n        var state = getSearchState(cm);\n        var query = state.getQuery();\n        if (!query) {\n          return;\n        }\n        var prev = !motionArgs.forward;\n        // If search is initiated with ? instead of /, negate direction.\n        prev = (state.isReversed()) ? !prev : prev;\n        highlightSearchMatches(cm, query);\n        return findNext(cm, prev/** prev */, query, motionArgs.repeat);\n      },\n      goToMark: function(cm, _head, motionArgs, vim) {\n        var pos = getMarkPos(cm, vim, motionArgs.selectedCharacter);\n        if (pos) {\n          return motionArgs.linewise ? { line: pos.line, ch: findFirstNonWhiteSpaceCharacter(cm.getLine(pos.line)) } : pos;\n        }\n        return null;\n      },\n      moveToOtherHighlightedEnd: function(cm, _head, motionArgs, vim) {\n        if (vim.visualBlock && motionArgs.sameLine) {\n          var sel = vim.sel;\n          return [\n            clipCursorToContent(cm, Pos(sel.anchor.line, sel.head.ch)),\n            clipCursorToContent(cm, Pos(sel.head.line, sel.anchor.ch))\n          ];\n        } else {\n          return ([vim.sel.head, vim.sel.anchor]);\n        }\n      },\n      jumpToMark: function(cm, head, motionArgs, vim) {\n        var best = head;\n        for (var i = 0; i < motionArgs.repeat; i++) {\n          var cursor = best;\n          for (var key in vim.marks) {\n            if (!isLowerCase(key)) {\n              continue;\n            }\n            var mark = vim.marks[key].find();\n            var isWrongDirection = (motionArgs.forward) ?\n              cursorIsBefore(mark, cursor) : cursorIsBefore(cursor, mark);\n\n            if (isWrongDirection) {\n              continue;\n            }\n            if (motionArgs.linewise && (mark.line == cursor.line)) {\n              continue;\n            }\n\n            var equal = cursorEqual(cursor, best);\n            var between = (motionArgs.forward) ?\n              cursorIsBetween(cursor, mark, best) :\n              cursorIsBetween(best, mark, cursor);\n\n            if (equal || between) {\n              best = mark;\n            }\n          }\n        }\n\n        if (motionArgs.linewise) {\n          // Vim places the cursor on the first non-whitespace character of\n          // the line if there is one, else it places the cursor at the end\n          // of the line, regardless of whether a mark was found.\n          best = Pos(best.line, findFirstNonWhiteSpaceCharacter(cm.getLine(best.line)));\n        }\n        return best;\n      },\n      moveByCharacters: function(_cm, head, motionArgs) {\n        var cur = head;\n        var repeat = motionArgs.repeat;\n        var ch = motionArgs.forward ? cur.ch + repeat : cur.ch - repeat;\n        return Pos(cur.line, ch);\n      },\n      moveByLines: function(cm, head, motionArgs, vim) {\n        var cur = head;\n        var endCh = cur.ch;\n        // Depending what our last motion was, we may want to do different\n        // things. If our last motion was moving vertically, we want to\n        // preserve the HPos from our last horizontal move.  If our last motion\n        // was going to the end of a line, moving vertically we should go to\n        // the end of the line, etc.\n        switch (vim.lastMotion) {\n          case this.moveByLines:\n          case this.moveByDisplayLines:\n          case this.moveByScroll:\n          case this.moveToColumn:\n          case this.moveToEol:\n            endCh = vim.lastHPos;\n            break;\n          default:\n            vim.lastHPos = endCh;\n        }\n        var repeat = motionArgs.repeat+(motionArgs.repeatOffset||0);\n        var line = motionArgs.forward ? cur.line + repeat : cur.line - repeat;\n        var first = cm.firstLine();\n        var last = cm.lastLine();\n        var posV = cm.findPosV(cur, (motionArgs.forward ? repeat : -repeat), 'line', vim.lastHSPos);\n        var hasMarkedText = motionArgs.forward ? posV.line > line : posV.line < line;\n        if (hasMarkedText) {\n          line = posV.line;\n          endCh = posV.ch;\n        }\n        // Vim go to line begin or line end when cursor at first/last line and\n        // move to previous/next line is triggered.\n        if (line < first && cur.line == first){\n          return this.moveToStartOfLine(cm, head, motionArgs, vim);\n        }else if (line > last && cur.line == last){\n            return this.moveToEol(cm, head, motionArgs, vim, true);\n        }\n        if (motionArgs.toFirstChar){\n          endCh=findFirstNonWhiteSpaceCharacter(cm.getLine(line));\n          vim.lastHPos = endCh;\n        }\n        vim.lastHSPos = cm.charCoords(Pos(line, endCh),'div').left;\n        return Pos(line, endCh);\n      },\n      moveByDisplayLines: function(cm, head, motionArgs, vim) {\n        var cur = head;\n        switch (vim.lastMotion) {\n          case this.moveByDisplayLines:\n          case this.moveByScroll:\n          case this.moveByLines:\n          case this.moveToColumn:\n          case this.moveToEol:\n            break;\n          default:\n            vim.lastHSPos = cm.charCoords(cur,'div').left;\n        }\n        var repeat = motionArgs.repeat;\n        var res=cm.findPosV(cur,(motionArgs.forward ? repeat : -repeat),'line',vim.lastHSPos);\n        if (res.hitSide) {\n          if (motionArgs.forward) {\n            var lastCharCoords = cm.charCoords(res, 'div');\n            var goalCoords = { top: lastCharCoords.top + 8, left: vim.lastHSPos };\n            var res = cm.coordsChar(goalCoords, 'div');\n          } else {\n            var resCoords = cm.charCoords(Pos(cm.firstLine(), 0), 'div');\n            resCoords.left = vim.lastHSPos;\n            res = cm.coordsChar(resCoords, 'div');\n          }\n        }\n        vim.lastHPos = res.ch;\n        return res;\n      },\n      moveByPage: function(cm, head, motionArgs) {\n        // CodeMirror only exposes functions that move the cursor page down, so\n        // doing this bad hack to move the cursor and move it back. evalInput\n        // will move the cursor to where it should be in the end.\n        var curStart = head;\n        var repeat = motionArgs.repeat;\n        return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page');\n      },\n      moveByParagraph: function(cm, head, motionArgs) {\n        var dir = motionArgs.forward ? 1 : -1;\n        return findParagraph(cm, head, motionArgs.repeat, dir);\n      },\n      moveBySentence: function(cm, head, motionArgs) {\n        var dir = motionArgs.forward ? 1 : -1;\n        return findSentence(cm, head, motionArgs.repeat, dir);\n      },\n      moveByScroll: function(cm, head, motionArgs, vim) {\n        var scrollbox = cm.getScrollInfo();\n        var curEnd = null;\n        var repeat = motionArgs.repeat;\n        if (!repeat) {\n          repeat = scrollbox.clientHeight / (2 * cm.defaultTextHeight());\n        }\n        var orig = cm.charCoords(head, 'local');\n        motionArgs.repeat = repeat;\n        var curEnd = motions.moveByDisplayLines(cm, head, motionArgs, vim);\n        if (!curEnd) {\n          return null;\n        }\n        var dest = cm.charCoords(curEnd, 'local');\n        cm.scrollTo(null, scrollbox.top + dest.top - orig.top);\n        return curEnd;\n      },\n      moveByWords: function(cm, head, motionArgs) {\n        return moveToWord(cm, head, motionArgs.repeat, !!motionArgs.forward,\n            !!motionArgs.wordEnd, !!motionArgs.bigWord);\n      },\n      moveTillCharacter: function(cm, _head, motionArgs) {\n        var repeat = motionArgs.repeat;\n        var curEnd = moveToCharacter(cm, repeat, motionArgs.forward,\n            motionArgs.selectedCharacter);\n        var increment = motionArgs.forward ? -1 : 1;\n        recordLastCharacterSearch(increment, motionArgs);\n        if (!curEnd) return null;\n        curEnd.ch += increment;\n        return curEnd;\n      },\n      moveToCharacter: function(cm, head, motionArgs) {\n        var repeat = motionArgs.repeat;\n        recordLastCharacterSearch(0, motionArgs);\n        return moveToCharacter(cm, repeat, motionArgs.forward,\n            motionArgs.selectedCharacter) || head;\n      },\n      moveToSymbol: function(cm, head, motionArgs) {\n        var repeat = motionArgs.repeat;\n        return findSymbol(cm, repeat, motionArgs.forward,\n            motionArgs.selectedCharacter) || head;\n      },\n      moveToColumn: function(cm, head, motionArgs, vim) {\n        var repeat = motionArgs.repeat;\n        // repeat is equivalent to which column we want to move to!\n        vim.lastHPos = repeat - 1;\n        vim.lastHSPos = cm.charCoords(head,'div').left;\n        return moveToColumn(cm, repeat);\n      },\n      moveToEol: function(cm, head, motionArgs, vim, keepHPos) {\n        var cur = head;\n        var retval= Pos(cur.line + motionArgs.repeat - 1, Infinity);\n        var end=cm.clipPos(retval);\n        end.ch--;\n        if (!keepHPos) {\n          vim.lastHPos = Infinity;\n          vim.lastHSPos = cm.charCoords(end,'div').left;\n        }\n        return retval;\n      },\n      moveToFirstNonWhiteSpaceCharacter: function(cm, head) {\n        // Go to the start of the line where the text begins, or the end for\n        // whitespace-only lines\n        var cursor = head;\n        return Pos(cursor.line,\n                   findFirstNonWhiteSpaceCharacter(cm.getLine(cursor.line)));\n      },\n      moveToMatchedSymbol: function(cm, head) {\n        var cursor = head;\n        var line = cursor.line;\n        var ch = cursor.ch;\n        var lineText = cm.getLine(line);\n        var symbol;\n        for (; ch < lineText.length; ch++) {\n          symbol = lineText.charAt(ch);\n          if (symbol && isMatchableSymbol(symbol)) {\n            var style = cm.getTokenTypeAt(Pos(line, ch + 1));\n            if (style !== \"string\" && style !== \"comment\") {\n              break;\n            }\n          }\n        }\n        if (ch < lineText.length) {\n          // Only include angle brackets in analysis if they are being matched.\n          var re = (ch === '<' || ch === '>') ? /[(){}[\\]<>]/ : /[(){}[\\]]/;\n          var matched = cm.findMatchingBracket(Pos(line, ch), {bracketRegex: re});\n          return matched.to;\n        } else {\n          return cursor;\n        }\n      },\n      moveToStartOfLine: function(_cm, head) {\n        return Pos(head.line, 0);\n      },\n      moveToLineOrEdgeOfDocument: function(cm, _head, motionArgs) {\n        var lineNum = motionArgs.forward ? cm.lastLine() : cm.firstLine();\n        if (motionArgs.repeatIsExplicit) {\n          lineNum = motionArgs.repeat - cm.getOption('firstLineNumber');\n        }\n        return Pos(lineNum,\n                   findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)));\n      },\n      textObjectManipulation: function(cm, head, motionArgs, vim) {\n        // TODO: lots of possible exceptions that can be thrown here. Try da(\n        //     outside of a () block.\n        var mirroredPairs = {'(': ')', ')': '(',\n                             '{': '}', '}': '{',\n                             '[': ']', ']': '[',\n                             '<': '>', '>': '<'};\n        var selfPaired = {'\\'': true, '\"': true, '`': true};\n\n        var character = motionArgs.selectedCharacter;\n        // 'b' refers to  '()' block.\n        // 'B' refers to  '{}' block.\n        if (character == 'b') {\n          character = '(';\n        } else if (character == 'B') {\n          character = '{';\n        }\n\n        // Inclusive is the difference between a and i\n        // TODO: Instead of using the additional text object map to perform text\n        //     object operations, merge the map into the defaultKeyMap and use\n        //     motionArgs to define behavior. Define separate entries for 'aw',\n        //     'iw', 'a[', 'i[', etc.\n        var inclusive = !motionArgs.textObjectInner;\n\n        var tmp;\n        if (mirroredPairs[character]) {\n          tmp = selectCompanionObject(cm, head, character, inclusive);\n        } else if (selfPaired[character]) {\n          tmp = findBeginningAndEnd(cm, head, character, inclusive);\n        } else if (character === 'W') {\n          tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,\n                                                     true /** bigWord */);\n        } else if (character === 'w') {\n          tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,\n                                                     false /** bigWord */);\n        } else if (character === 'p') {\n          tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive);\n          motionArgs.linewise = true;\n          if (vim.visualMode) {\n            if (!vim.visualLine) { vim.visualLine = true; }\n          } else {\n            var operatorArgs = vim.inputState.operatorArgs;\n            if (operatorArgs) { operatorArgs.linewise = true; }\n            tmp.end.line--;\n          }\n        } else if (character === 't') {\n          tmp = expandTagUnderCursor(cm, head, inclusive);\n        } else {\n          // No text object defined for this, don't move.\n          return null;\n        }\n\n        if (!cm.state.vim.visualMode) {\n          return [tmp.start, tmp.end];\n        } else {\n          return expandSelection(cm, tmp.start, tmp.end);\n        }\n      },\n\n      repeatLastCharacterSearch: function(cm, head, motionArgs) {\n        var lastSearch = vimGlobalState.lastCharacterSearch;\n        var repeat = motionArgs.repeat;\n        var forward = motionArgs.forward === lastSearch.forward;\n        var increment = (lastSearch.increment ? 1 : 0) * (forward ? -1 : 1);\n        cm.moveH(-increment, 'char');\n        motionArgs.inclusive = forward ? true : false;\n        var curEnd = moveToCharacter(cm, repeat, forward, lastSearch.selectedCharacter);\n        if (!curEnd) {\n          cm.moveH(increment, 'char');\n          return head;\n        }\n        curEnd.ch += increment;\n        return curEnd;\n      }\n    };\n\n    function defineMotion(name, fn) {\n      motions[name] = fn;\n    }\n\n    function fillArray(val, times) {\n      var arr = [];\n      for (var i = 0; i < times; i++) {\n        arr.push(val);\n      }\n      return arr;\n    }\n    /**\n     * An operator acts on a text selection. It receives the list of selections\n     * as input. The corresponding CodeMirror selection is guaranteed to\n    * match the input selection.\n     */\n    var operators = {\n      change: function(cm, args, ranges) {\n        var finalHead, text;\n        var vim = cm.state.vim;\n        var anchor = ranges[0].anchor,\n            head = ranges[0].head;\n        if (!vim.visualMode) {\n          text = cm.getRange(anchor, head);\n          var lastState = vim.lastEditInputState || {};\n          if (lastState.motion == \"moveByWords\" && !isWhiteSpaceString(text)) {\n            // Exclude trailing whitespace if the range is not all whitespace.\n            var match = (/\\s+$/).exec(text);\n            if (match && lastState.motionArgs && lastState.motionArgs.forward) {\n              head = offsetCursor(head, 0, - match[0].length);\n              text = text.slice(0, - match[0].length);\n            }\n          }\n          var prevLineEnd = new Pos(anchor.line - 1, Number.MAX_VALUE);\n          var wasLastLine = cm.firstLine() == cm.lastLine();\n          if (head.line > cm.lastLine() && args.linewise && !wasLastLine) {\n            cm.replaceRange('', prevLineEnd, head);\n          } else {\n            cm.replaceRange('', anchor, head);\n          }\n          if (args.linewise) {\n            // Push the next line back down, if there is a next line.\n            if (!wasLastLine) {\n              cm.setCursor(prevLineEnd);\n              CodeMirror.commands.newlineAndIndent(cm);\n            }\n            // make sure cursor ends up at the end of the line.\n            anchor.ch = Number.MAX_VALUE;\n          }\n          finalHead = anchor;\n        } else if (args.fullLine) {\n            head.ch = Number.MAX_VALUE;\n            head.line--;\n            cm.setSelection(anchor, head)\n            text = cm.getSelection();\n            cm.replaceSelection(\"\");\n            finalHead = anchor;\n        } else {\n          text = cm.getSelection();\n          var replacement = fillArray('', ranges.length);\n          cm.replaceSelections(replacement);\n          finalHead = cursorMin(ranges[0].head, ranges[0].anchor);\n        }\n        vimGlobalState.registerController.pushText(\n            args.registerName, 'change', text,\n            args.linewise, ranges.length > 1);\n        actions.enterInsertMode(cm, {head: finalHead}, cm.state.vim);\n      },\n      // delete is a javascript keyword.\n      'delete': function(cm, args, ranges) {\n        var finalHead, text;\n        var vim = cm.state.vim;\n        if (!vim.visualBlock) {\n          var anchor = ranges[0].anchor,\n              head = ranges[0].head;\n          if (args.linewise &&\n              head.line != cm.firstLine() &&\n              anchor.line == cm.lastLine() &&\n              anchor.line == head.line - 1) {\n            // Special case for dd on last line (and first line).\n            if (anchor.line == cm.firstLine()) {\n              anchor.ch = 0;\n            } else {\n              anchor = Pos(anchor.line - 1, lineLength(cm, anchor.line - 1));\n            }\n          }\n          text = cm.getRange(anchor, head);\n          cm.replaceRange('', anchor, head);\n          finalHead = anchor;\n          if (args.linewise) {\n            finalHead = motions.moveToFirstNonWhiteSpaceCharacter(cm, anchor);\n          }\n        } else {\n          text = cm.getSelection();\n          var replacement = fillArray('', ranges.length);\n          cm.replaceSelections(replacement);\n          finalHead = ranges[0].anchor;\n        }\n        vimGlobalState.registerController.pushText(\n            args.registerName, 'delete', text,\n            args.linewise, vim.visualBlock);\n        return clipCursorToContent(cm, finalHead);\n      },\n      indent: function(cm, args, ranges) {\n        var vim = cm.state.vim;\n        var startLine = ranges[0].anchor.line;\n        var endLine = vim.visualBlock ?\n          ranges[ranges.length - 1].anchor.line :\n          ranges[0].head.line;\n        // In visual mode, n> shifts the selection right n times, instead of\n        // shifting n lines right once.\n        var repeat = (vim.visualMode) ? args.repeat : 1;\n        if (args.linewise) {\n          // The only way to delete a newline is to delete until the start of\n          // the next line, so in linewise mode evalInput will include the next\n          // line. We don't want this in indent, so we go back a line.\n          endLine--;\n        }\n        for (var i = startLine; i <= endLine; i++) {\n          for (var j = 0; j < repeat; j++) {\n            cm.indentLine(i, args.indentRight);\n          }\n        }\n        return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor);\n      },\n      indentAuto: function(cm, _args, ranges) {\n        cm.execCommand(\"indentAuto\");\n        return motions.moveToFirstNonWhiteSpaceCharacter(cm, ranges[0].anchor);\n      },\n      changeCase: function(cm, args, ranges, oldAnchor, newHead) {\n        var selections = cm.getSelections();\n        var swapped = [];\n        var toLower = args.toLower;\n        for (var j = 0; j < selections.length; j++) {\n          var toSwap = selections[j];\n          var text = '';\n          if (toLower === true) {\n            text = toSwap.toLowerCase();\n          } else if (toLower === false) {\n            text = toSwap.toUpperCase();\n          } else {\n            for (var i = 0; i < toSwap.length; i++) {\n              var character = toSwap.charAt(i);\n              text += isUpperCase(character) ? character.toLowerCase() :\n                  character.toUpperCase();\n            }\n          }\n          swapped.push(text);\n        }\n        cm.replaceSelections(swapped);\n        if (args.shouldMoveCursor){\n          return newHead;\n        } else if (!cm.state.vim.visualMode && args.linewise && ranges[0].anchor.line + 1 == ranges[0].head.line) {\n          return motions.moveToFirstNonWhiteSpaceCharacter(cm, oldAnchor);\n        } else if (args.linewise){\n          return oldAnchor;\n        } else {\n          return cursorMin(ranges[0].anchor, ranges[0].head);\n        }\n      },\n      yank: function(cm, args, ranges, oldAnchor) {\n        var vim = cm.state.vim;\n        var text = cm.getSelection();\n        var endPos = vim.visualMode\n          ? cursorMin(vim.sel.anchor, vim.sel.head, ranges[0].head, ranges[0].anchor)\n          : oldAnchor;\n        vimGlobalState.registerController.pushText(\n            args.registerName, 'yank',\n            text, args.linewise, vim.visualBlock);\n        return endPos;\n      }\n    };\n\n    function defineOperator(name, fn) {\n      operators[name] = fn;\n    }\n\n    var actions = {\n      jumpListWalk: function(cm, actionArgs, vim) {\n        if (vim.visualMode) {\n          return;\n        }\n        var repeat = actionArgs.repeat;\n        var forward = actionArgs.forward;\n        var jumpList = vimGlobalState.jumpList;\n\n        var mark = jumpList.move(cm, forward ? repeat : -repeat);\n        var markPos = mark ? mark.find() : undefined;\n        markPos = markPos ? markPos : cm.getCursor();\n        cm.setCursor(markPos);\n      },\n      scroll: function(cm, actionArgs, vim) {\n        if (vim.visualMode) {\n          return;\n        }\n        var repeat = actionArgs.repeat || 1;\n        var lineHeight = cm.defaultTextHeight();\n        var top = cm.getScrollInfo().top;\n        var delta = lineHeight * repeat;\n        var newPos = actionArgs.forward ? top + delta : top - delta;\n        var cursor = copyCursor(cm.getCursor());\n        var cursorCoords = cm.charCoords(cursor, 'local');\n        if (actionArgs.forward) {\n          if (newPos > cursorCoords.top) {\n             cursor.line += (newPos - cursorCoords.top) / lineHeight;\n             cursor.line = Math.ceil(cursor.line);\n             cm.setCursor(cursor);\n             cursorCoords = cm.charCoords(cursor, 'local');\n             cm.scrollTo(null, cursorCoords.top);\n          } else {\n             // Cursor stays within bounds.  Just reposition the scroll window.\n             cm.scrollTo(null, newPos);\n          }\n        } else {\n          var newBottom = newPos + cm.getScrollInfo().clientHeight;\n          if (newBottom < cursorCoords.bottom) {\n             cursor.line -= (cursorCoords.bottom - newBottom) / lineHeight;\n             cursor.line = Math.floor(cursor.line);\n             cm.setCursor(cursor);\n             cursorCoords = cm.charCoords(cursor, 'local');\n             cm.scrollTo(\n                 null, cursorCoords.bottom - cm.getScrollInfo().clientHeight);\n          } else {\n             // Cursor stays within bounds.  Just reposition the scroll window.\n             cm.scrollTo(null, newPos);\n          }\n        }\n      },\n      scrollToCursor: function(cm, actionArgs) {\n        var lineNum = cm.getCursor().line;\n        var charCoords = cm.charCoords(Pos(lineNum, 0), 'local');\n        var height = cm.getScrollInfo().clientHeight;\n        var y = charCoords.top;\n        var lineHeight = charCoords.bottom - y;\n        switch (actionArgs.position) {\n          case 'center': y = y - (height / 2) + lineHeight;\n            break;\n          case 'bottom': y = y - height + lineHeight;\n            break;\n        }\n        cm.scrollTo(null, y);\n      },\n      replayMacro: function(cm, actionArgs, vim) {\n        var registerName = actionArgs.selectedCharacter;\n        var repeat = actionArgs.repeat;\n        var macroModeState = vimGlobalState.macroModeState;\n        if (registerName == '@') {\n          registerName = macroModeState.latestRegister;\n        } else {\n          macroModeState.latestRegister = registerName;\n        }\n        while(repeat--){\n          executeMacroRegister(cm, vim, macroModeState, registerName);\n        }\n      },\n      enterMacroRecordMode: function(cm, actionArgs) {\n        var macroModeState = vimGlobalState.macroModeState;\n        var registerName = actionArgs.selectedCharacter;\n        if (vimGlobalState.registerController.isValidRegister(registerName)) {\n          macroModeState.enterMacroRecordMode(cm, registerName);\n        }\n      },\n      toggleOverwrite: function(cm) {\n        if (!cm.state.overwrite) {\n          cm.toggleOverwrite(true);\n          cm.setOption('keyMap', 'vim-replace');\n          CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"replace\"});\n        } else {\n          cm.toggleOverwrite(false);\n          cm.setOption('keyMap', 'vim-insert');\n          CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"insert\"});\n        }\n      },\n      enterInsertMode: function(cm, actionArgs, vim) {\n        if (cm.getOption('readOnly')) { return; }\n        vim.insertMode = true;\n        vim.insertModeRepeat = actionArgs && actionArgs.repeat || 1;\n        var insertAt = (actionArgs) ? actionArgs.insertAt : null;\n        var sel = vim.sel;\n        var head = actionArgs.head || cm.getCursor('head');\n        var height = cm.listSelections().length;\n        if (insertAt == 'eol') {\n          head = Pos(head.line, lineLength(cm, head.line));\n        } else if (insertAt == 'bol') {\n          head = Pos(head.line, 0);\n        } else if (insertAt == 'charAfter') {\n          head = offsetCursor(head, 0, 1);\n        } else if (insertAt == 'firstNonBlank') {\n          head = motions.moveToFirstNonWhiteSpaceCharacter(cm, head);\n        } else if (insertAt == 'startOfSelectedArea') {\n          if (!vim.visualMode)\n              return;\n          if (!vim.visualBlock) {\n            if (sel.head.line < sel.anchor.line) {\n              head = sel.head;\n            } else {\n              head = Pos(sel.anchor.line, 0);\n            }\n          } else {\n            head = Pos(\n                Math.min(sel.head.line, sel.anchor.line),\n                Math.min(sel.head.ch, sel.anchor.ch));\n            height = Math.abs(sel.head.line - sel.anchor.line) + 1;\n          }\n        } else if (insertAt == 'endOfSelectedArea') {\n            if (!vim.visualMode)\n              return;\n          if (!vim.visualBlock) {\n            if (sel.head.line >= sel.anchor.line) {\n              head = offsetCursor(sel.head, 0, 1);\n            } else {\n              head = Pos(sel.anchor.line, 0);\n            }\n          } else {\n            head = Pos(\n                Math.min(sel.head.line, sel.anchor.line),\n                Math.max(sel.head.ch + 1, sel.anchor.ch));\n            height = Math.abs(sel.head.line - sel.anchor.line) + 1;\n          }\n        } else if (insertAt == 'inplace') {\n          if (vim.visualMode){\n            return;\n          }\n        } else if (insertAt == 'lastEdit') {\n          head = getLastEditPos(cm) || head;\n        }\n        cm.setOption('disableInput', false);\n        if (actionArgs && actionArgs.replace) {\n          // Handle Replace-mode as a special case of insert mode.\n          cm.toggleOverwrite(true);\n          cm.setOption('keyMap', 'vim-replace');\n          CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"replace\"});\n        } else {\n          cm.toggleOverwrite(false);\n          cm.setOption('keyMap', 'vim-insert');\n          CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"insert\"});\n        }\n        if (!vimGlobalState.macroModeState.isPlaying) {\n          // Only record if not replaying.\n          cm.on('change', onChange);\n          CodeMirror.on(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);\n        }\n        if (vim.visualMode) {\n          exitVisualMode(cm);\n        }\n        selectForInsert(cm, head, height);\n      },\n      toggleVisualMode: function(cm, actionArgs, vim) {\n        var repeat = actionArgs.repeat;\n        var anchor = cm.getCursor();\n        var head;\n        // TODO: The repeat should actually select number of characters/lines\n        //     equal to the repeat times the size of the previous visual\n        //     operation.\n        if (!vim.visualMode) {\n          // Entering visual mode\n          vim.visualMode = true;\n          vim.visualLine = !!actionArgs.linewise;\n          vim.visualBlock = !!actionArgs.blockwise;\n          head = clipCursorToContent(\n              cm, Pos(anchor.line, anchor.ch + repeat - 1));\n          vim.sel = {\n            anchor: anchor,\n            head: head\n          };\n          CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"visual\", subMode: vim.visualLine ? \"linewise\" : vim.visualBlock ? \"blockwise\" : \"\"});\n          updateCmSelection(cm);\n          updateMark(cm, vim, '<', cursorMin(anchor, head));\n          updateMark(cm, vim, '>', cursorMax(anchor, head));\n        } else if (vim.visualLine ^ actionArgs.linewise ||\n            vim.visualBlock ^ actionArgs.blockwise) {\n          // Toggling between modes\n          vim.visualLine = !!actionArgs.linewise;\n          vim.visualBlock = !!actionArgs.blockwise;\n          CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"visual\", subMode: vim.visualLine ? \"linewise\" : vim.visualBlock ? \"blockwise\" : \"\"});\n          updateCmSelection(cm);\n        } else {\n          exitVisualMode(cm);\n        }\n      },\n      reselectLastSelection: function(cm, _actionArgs, vim) {\n        var lastSelection = vim.lastSelection;\n        if (vim.visualMode) {\n          updateLastSelection(cm, vim);\n        }\n        if (lastSelection) {\n          var anchor = lastSelection.anchorMark.find();\n          var head = lastSelection.headMark.find();\n          if (!anchor || !head) {\n            // If the marks have been destroyed due to edits, do nothing.\n            return;\n          }\n          vim.sel = {\n            anchor: anchor,\n            head: head\n          };\n          vim.visualMode = true;\n          vim.visualLine = lastSelection.visualLine;\n          vim.visualBlock = lastSelection.visualBlock;\n          updateCmSelection(cm);\n          updateMark(cm, vim, '<', cursorMin(anchor, head));\n          updateMark(cm, vim, '>', cursorMax(anchor, head));\n          CodeMirror.signal(cm, 'vim-mode-change', {\n            mode: 'visual',\n            subMode: vim.visualLine ? 'linewise' :\n                     vim.visualBlock ? 'blockwise' : ''});\n        }\n      },\n      joinLines: function(cm, actionArgs, vim) {\n        var curStart, curEnd;\n        if (vim.visualMode) {\n          curStart = cm.getCursor('anchor');\n          curEnd = cm.getCursor('head');\n          if (cursorIsBefore(curEnd, curStart)) {\n            var tmp = curEnd;\n            curEnd = curStart;\n            curStart = tmp;\n          }\n          curEnd.ch = lineLength(cm, curEnd.line) - 1;\n        } else {\n          // Repeat is the number of lines to join. Minimum 2 lines.\n          var repeat = Math.max(actionArgs.repeat, 2);\n          curStart = cm.getCursor();\n          curEnd = clipCursorToContent(cm, Pos(curStart.line + repeat - 1,\n                                               Infinity));\n        }\n        var finalCh = 0;\n        for (var i = curStart.line; i < curEnd.line; i++) {\n          finalCh = lineLength(cm, curStart.line);\n          var tmp = Pos(curStart.line + 1,\n                        lineLength(cm, curStart.line + 1));\n          var text = cm.getRange(curStart, tmp);\n          text = actionArgs.keepSpaces\n            ? text.replace(/\\n\\r?/g, '')\n            : text.replace(/\\n\\s*/g, ' ');\n          cm.replaceRange(text, curStart, tmp);\n        }\n        var curFinalPos = Pos(curStart.line, finalCh);\n        if (vim.visualMode) {\n          exitVisualMode(cm, false);\n        }\n        cm.setCursor(curFinalPos);\n      },\n      newLineAndEnterInsertMode: function(cm, actionArgs, vim) {\n        vim.insertMode = true;\n        var insertAt = copyCursor(cm.getCursor());\n        if (insertAt.line === cm.firstLine() && !actionArgs.after) {\n          // Special case for inserting newline before start of document.\n          cm.replaceRange('\\n', Pos(cm.firstLine(), 0));\n          cm.setCursor(cm.firstLine(), 0);\n        } else {\n          insertAt.line = (actionArgs.after) ? insertAt.line :\n              insertAt.line - 1;\n          insertAt.ch = lineLength(cm, insertAt.line);\n          cm.setCursor(insertAt);\n          var newlineFn = CodeMirror.commands.newlineAndIndentContinueComment ||\n              CodeMirror.commands.newlineAndIndent;\n          newlineFn(cm);\n        }\n        this.enterInsertMode(cm, { repeat: actionArgs.repeat }, vim);\n      },\n      paste: function(cm, actionArgs, vim) {\n        var cur = copyCursor(cm.getCursor());\n        var register = vimGlobalState.registerController.getRegister(\n            actionArgs.registerName);\n        var text = register.toString();\n        if (!text) {\n          return;\n        }\n        if (actionArgs.matchIndent) {\n          var tabSize = cm.getOption(\"tabSize\");\n          // length that considers tabs and tabSize\n          var whitespaceLength = function(str) {\n            var tabs = (str.split(\"\\t\").length - 1);\n            var spaces = (str.split(\" \").length - 1);\n            return tabs * tabSize + spaces * 1;\n          };\n          var currentLine = cm.getLine(cm.getCursor().line);\n          var indent = whitespaceLength(currentLine.match(/^\\s*/)[0]);\n          // chomp last newline b/c don't want it to match /^\\s*/gm\n          var chompedText = text.replace(/\\n$/, '');\n          var wasChomped = text !== chompedText;\n          var firstIndent = whitespaceLength(text.match(/^\\s*/)[0]);\n          var text = chompedText.replace(/^\\s*/gm, function(wspace) {\n            var newIndent = indent + (whitespaceLength(wspace) - firstIndent);\n            if (newIndent < 0) {\n              return \"\";\n            }\n            else if (cm.getOption(\"indentWithTabs\")) {\n              var quotient = Math.floor(newIndent / tabSize);\n              return Array(quotient + 1).join('\\t');\n            }\n            else {\n              return Array(newIndent + 1).join(' ');\n            }\n          });\n          text += wasChomped ? \"\\n\" : \"\";\n        }\n        if (actionArgs.repeat > 1) {\n          var text = Array(actionArgs.repeat + 1).join(text);\n        }\n        var linewise = register.linewise;\n        var blockwise = register.blockwise;\n        if (blockwise) {\n          text = text.split('\\n');\n          if (linewise) {\n              text.pop();\n          }\n          for (var i = 0; i < text.length; i++) {\n            text[i] = (text[i] == '') ? ' ' : text[i];\n          }\n          cur.ch += actionArgs.after ? 1 : 0;\n          cur.ch = Math.min(lineLength(cm, cur.line), cur.ch);\n        } else if (linewise) {\n          if(vim.visualMode) {\n            text = vim.visualLine ? text.slice(0, -1) : '\\n' + text.slice(0, text.length - 1) + '\\n';\n          } else if (actionArgs.after) {\n            // Move the newline at the end to the start instead, and paste just\n            // before the newline character of the line we are on right now.\n            text = '\\n' + text.slice(0, text.length - 1);\n            cur.ch = lineLength(cm, cur.line);\n          } else {\n            cur.ch = 0;\n          }\n        } else {\n          cur.ch += actionArgs.after ? 1 : 0;\n        }\n        var curPosFinal;\n        var idx;\n        if (vim.visualMode) {\n          //  save the pasted text for reselection if the need arises\n          vim.lastPastedText = text;\n          var lastSelectionCurEnd;\n          var selectedArea = getSelectedAreaRange(cm, vim);\n          var selectionStart = selectedArea[0];\n          var selectionEnd = selectedArea[1];\n          var selectedText = cm.getSelection();\n          var selections = cm.listSelections();\n          var emptyStrings = new Array(selections.length).join('1').split('1');\n          // save the curEnd marker before it get cleared due to cm.replaceRange.\n          if (vim.lastSelection) {\n            lastSelectionCurEnd = vim.lastSelection.headMark.find();\n          }\n          // push the previously selected text to unnamed register\n          vimGlobalState.registerController.unnamedRegister.setText(selectedText);\n          if (blockwise) {\n            // first delete the selected text\n            cm.replaceSelections(emptyStrings);\n            // Set new selections as per the block length of the yanked text\n            selectionEnd = Pos(selectionStart.line + text.length-1, selectionStart.ch);\n            cm.setCursor(selectionStart);\n            selectBlock(cm, selectionEnd);\n            cm.replaceSelections(text);\n            curPosFinal = selectionStart;\n          } else if (vim.visualBlock) {\n            cm.replaceSelections(emptyStrings);\n            cm.setCursor(selectionStart);\n            cm.replaceRange(text, selectionStart, selectionStart);\n            curPosFinal = selectionStart;\n          } else {\n            cm.replaceRange(text, selectionStart, selectionEnd);\n            curPosFinal = cm.posFromIndex(cm.indexFromPos(selectionStart) + text.length - 1);\n          }\n          // restore the the curEnd marker\n          if(lastSelectionCurEnd) {\n            vim.lastSelection.headMark = cm.setBookmark(lastSelectionCurEnd);\n          }\n          if (linewise) {\n            curPosFinal.ch=0;\n          }\n        } else {\n          if (blockwise) {\n            cm.setCursor(cur);\n            for (var i = 0; i < text.length; i++) {\n              var line = cur.line+i;\n              if (line > cm.lastLine()) {\n                cm.replaceRange('\\n',  Pos(line, 0));\n              }\n              var lastCh = lineLength(cm, line);\n              if (lastCh < cur.ch) {\n                extendLineToColumn(cm, line, cur.ch);\n              }\n            }\n            cm.setCursor(cur);\n            selectBlock(cm, Pos(cur.line + text.length-1, cur.ch));\n            cm.replaceSelections(text);\n            curPosFinal = cur;\n          } else {\n            cm.replaceRange(text, cur);\n            // Now fine tune the cursor to where we want it.\n            if (linewise && actionArgs.after) {\n              curPosFinal = Pos(\n              cur.line + 1,\n              findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line + 1)));\n            } else if (linewise && !actionArgs.after) {\n              curPosFinal = Pos(\n                cur.line,\n                findFirstNonWhiteSpaceCharacter(cm.getLine(cur.line)));\n            } else if (!linewise && actionArgs.after) {\n              idx = cm.indexFromPos(cur);\n              curPosFinal = cm.posFromIndex(idx + text.length - 1);\n            } else {\n              idx = cm.indexFromPos(cur);\n              curPosFinal = cm.posFromIndex(idx + text.length);\n            }\n          }\n        }\n        if (vim.visualMode) {\n          exitVisualMode(cm, false);\n        }\n        cm.setCursor(curPosFinal);\n      },\n      undo: function(cm, actionArgs) {\n        cm.operation(function() {\n          repeatFn(cm, CodeMirror.commands.undo, actionArgs.repeat)();\n          cm.setCursor(cm.getCursor('anchor'));\n        });\n      },\n      redo: function(cm, actionArgs) {\n        repeatFn(cm, CodeMirror.commands.redo, actionArgs.repeat)();\n      },\n      setRegister: function(_cm, actionArgs, vim) {\n        vim.inputState.registerName = actionArgs.selectedCharacter;\n      },\n      setMark: function(cm, actionArgs, vim) {\n        var markName = actionArgs.selectedCharacter;\n        updateMark(cm, vim, markName, cm.getCursor());\n      },\n      replace: function(cm, actionArgs, vim) {\n        var replaceWith = actionArgs.selectedCharacter;\n        var curStart = cm.getCursor();\n        var replaceTo;\n        var curEnd;\n        var selections = cm.listSelections();\n        if (vim.visualMode) {\n          curStart = cm.getCursor('start');\n          curEnd = cm.getCursor('end');\n        } else {\n          var line = cm.getLine(curStart.line);\n          replaceTo = curStart.ch + actionArgs.repeat;\n          if (replaceTo > line.length) {\n            replaceTo=line.length;\n          }\n          curEnd = Pos(curStart.line, replaceTo);\n        }\n        if (replaceWith=='\\n') {\n          if (!vim.visualMode) cm.replaceRange('', curStart, curEnd);\n          // special case, where vim help says to replace by just one line-break\n          (CodeMirror.commands.newlineAndIndentContinueComment || CodeMirror.commands.newlineAndIndent)(cm);\n        } else {\n          var replaceWithStr = cm.getRange(curStart, curEnd);\n          //replace all characters in range by selected, but keep linebreaks\n          replaceWithStr = replaceWithStr.replace(/[^\\n]/g, replaceWith);\n          if (vim.visualBlock) {\n            // Tabs are split in visua block before replacing\n            var spaces = new Array(cm.getOption(\"tabSize\")+1).join(' ');\n            replaceWithStr = cm.getSelection();\n            replaceWithStr = replaceWithStr.replace(/\\t/g, spaces).replace(/[^\\n]/g, replaceWith).split('\\n');\n            cm.replaceSelections(replaceWithStr);\n          } else {\n            cm.replaceRange(replaceWithStr, curStart, curEnd);\n          }\n          if (vim.visualMode) {\n            curStart = cursorIsBefore(selections[0].anchor, selections[0].head) ?\n                         selections[0].anchor : selections[0].head;\n            cm.setCursor(curStart);\n            exitVisualMode(cm, false);\n          } else {\n            cm.setCursor(offsetCursor(curEnd, 0, -1));\n          }\n        }\n      },\n      incrementNumberToken: function(cm, actionArgs) {\n        var cur = cm.getCursor();\n        var lineStr = cm.getLine(cur.line);\n        var re = /(-?)(?:(0x)([\\da-f]+)|(0b|0|)(\\d+))/gi;\n        var match;\n        var start;\n        var end;\n        var numberStr;\n        while ((match = re.exec(lineStr)) !== null) {\n          start = match.index;\n          end = start + match[0].length;\n          if (cur.ch < end)break;\n        }\n        if (!actionArgs.backtrack && (end <= cur.ch))return;\n        if (match) {\n          var baseStr = match[2] || match[4]\n          var digits = match[3] || match[5]\n          var increment = actionArgs.increase ? 1 : -1;\n          var base = {'0b': 2, '0': 8, '': 10, '0x': 16}[baseStr.toLowerCase()];\n          var number = parseInt(match[1] + digits, base) + (increment * actionArgs.repeat);\n          numberStr = number.toString(base);\n          var zeroPadding = baseStr ? new Array(digits.length - numberStr.length + 1 + match[1].length).join('0') : ''\n          if (numberStr.charAt(0) === '-') {\n            numberStr = '-' + baseStr + zeroPadding + numberStr.substr(1);\n          } else {\n            numberStr = baseStr + zeroPadding + numberStr;\n          }\n          var from = Pos(cur.line, start);\n          var to = Pos(cur.line, end);\n          cm.replaceRange(numberStr, from, to);\n        } else {\n          return;\n        }\n        cm.setCursor(Pos(cur.line, start + numberStr.length - 1));\n      },\n      repeatLastEdit: function(cm, actionArgs, vim) {\n        var lastEditInputState = vim.lastEditInputState;\n        if (!lastEditInputState) { return; }\n        var repeat = actionArgs.repeat;\n        if (repeat && actionArgs.repeatIsExplicit) {\n          vim.lastEditInputState.repeatOverride = repeat;\n        } else {\n          repeat = vim.lastEditInputState.repeatOverride || repeat;\n        }\n        repeatLastEdit(cm, vim, repeat, false /** repeatForInsert */);\n      },\n      indent: function(cm, actionArgs) {\n        cm.indentLine(cm.getCursor().line, actionArgs.indentRight);\n      },\n      exitInsertMode: exitInsertMode\n    };\n\n    function defineAction(name, fn) {\n      actions[name] = fn;\n    }\n\n    /*\n     * Below are miscellaneous utility functions used by vim.js\n     */\n\n    /**\n     * Clips cursor to ensure that line is within the buffer's range\n     * If includeLineBreak is true, then allow cur.ch == lineLength.\n     */\n    function clipCursorToContent(cm, cur) {\n      var vim = cm.state.vim;\n      var includeLineBreak = vim.insertMode || vim.visualMode;\n      var line = Math.min(Math.max(cm.firstLine(), cur.line), cm.lastLine() );\n      var maxCh = lineLength(cm, line) - 1 + !!includeLineBreak;\n      var ch = Math.min(Math.max(0, cur.ch), maxCh);\n      return Pos(line, ch);\n    }\n    function copyArgs(args) {\n      var ret = {};\n      for (var prop in args) {\n        if (args.hasOwnProperty(prop)) {\n          ret[prop] = args[prop];\n        }\n      }\n      return ret;\n    }\n    function offsetCursor(cur, offsetLine, offsetCh) {\n      if (typeof offsetLine === 'object') {\n        offsetCh = offsetLine.ch;\n        offsetLine = offsetLine.line;\n      }\n      return Pos(cur.line + offsetLine, cur.ch + offsetCh);\n    }\n    function commandMatches(keys, keyMap, context, inputState) {\n      // Partial matches are not applied. They inform the key handler\n      // that the current key sequence is a subsequence of a valid key\n      // sequence, so that the key buffer is not cleared.\n      var match, partial = [], full = [];\n      for (var i = 0; i < keyMap.length; i++) {\n        var command = keyMap[i];\n        if (context == 'insert' && command.context != 'insert' ||\n            command.context && command.context != context ||\n            inputState.operator && command.type == 'action' ||\n            !(match = commandMatch(keys, command.keys))) { continue; }\n        if (match == 'partial') { partial.push(command); }\n        if (match == 'full') { full.push(command); }\n      }\n      return {\n        partial: partial.length && partial,\n        full: full.length && full\n      };\n    }\n    function commandMatch(pressed, mapped) {\n      if (mapped.slice(-11) == '<character>') {\n        // Last character matches anything.\n        var prefixLen = mapped.length - 11;\n        var pressedPrefix = pressed.slice(0, prefixLen);\n        var mappedPrefix = mapped.slice(0, prefixLen);\n        return pressedPrefix == mappedPrefix && pressed.length > prefixLen ? 'full' :\n               mappedPrefix.indexOf(pressedPrefix) == 0 ? 'partial' : false;\n      } else {\n        return pressed == mapped ? 'full' :\n               mapped.indexOf(pressed) == 0 ? 'partial' : false;\n      }\n    }\n    function lastChar(keys) {\n      var match = /^.*(<[^>]+>)$/.exec(keys);\n      var selectedCharacter = match ? match[1] : keys.slice(-1);\n      if (selectedCharacter.length > 1){\n        switch(selectedCharacter){\n          case '<CR>':\n            selectedCharacter='\\n';\n            break;\n          case '<Space>':\n            selectedCharacter=' ';\n            break;\n          default:\n            selectedCharacter='';\n            break;\n        }\n      }\n      return selectedCharacter;\n    }\n    function repeatFn(cm, fn, repeat) {\n      return function() {\n        for (var i = 0; i < repeat; i++) {\n          fn(cm);\n        }\n      };\n    }\n    function copyCursor(cur) {\n      return Pos(cur.line, cur.ch);\n    }\n    function cursorEqual(cur1, cur2) {\n      return cur1.ch == cur2.ch && cur1.line == cur2.line;\n    }\n    function cursorIsBefore(cur1, cur2) {\n      if (cur1.line < cur2.line) {\n        return true;\n      }\n      if (cur1.line == cur2.line && cur1.ch < cur2.ch) {\n        return true;\n      }\n      return false;\n    }\n    function cursorMin(cur1, cur2) {\n      if (arguments.length > 2) {\n        cur2 = cursorMin.apply(undefined, Array.prototype.slice.call(arguments, 1));\n      }\n      return cursorIsBefore(cur1, cur2) ? cur1 : cur2;\n    }\n    function cursorMax(cur1, cur2) {\n      if (arguments.length > 2) {\n        cur2 = cursorMax.apply(undefined, Array.prototype.slice.call(arguments, 1));\n      }\n      return cursorIsBefore(cur1, cur2) ? cur2 : cur1;\n    }\n    function cursorIsBetween(cur1, cur2, cur3) {\n      // returns true if cur2 is between cur1 and cur3.\n      var cur1before2 = cursorIsBefore(cur1, cur2);\n      var cur2before3 = cursorIsBefore(cur2, cur3);\n      return cur1before2 && cur2before3;\n    }\n    function lineLength(cm, lineNum) {\n      return cm.getLine(lineNum).length;\n    }\n    function trim(s) {\n      if (s.trim) {\n        return s.trim();\n      }\n      return s.replace(/^\\s+|\\s+$/g, '');\n    }\n    function escapeRegex(s) {\n      return s.replace(/([.?*+$\\[\\]\\/\\\\(){}|\\-])/g, '\\\\$1');\n    }\n    function extendLineToColumn(cm, lineNum, column) {\n      var endCh = lineLength(cm, lineNum);\n      var spaces = new Array(column-endCh+1).join(' ');\n      cm.setCursor(Pos(lineNum, endCh));\n      cm.replaceRange(spaces, cm.getCursor());\n    }\n    // This functions selects a rectangular block\n    // of text with selectionEnd as any of its corner\n    // Height of block:\n    // Difference in selectionEnd.line and first/last selection.line\n    // Width of the block:\n    // Distance between selectionEnd.ch and any(first considered here) selection.ch\n    function selectBlock(cm, selectionEnd) {\n      var selections = [], ranges = cm.listSelections();\n      var head = copyCursor(cm.clipPos(selectionEnd));\n      var isClipped = !cursorEqual(selectionEnd, head);\n      var curHead = cm.getCursor('head');\n      var primIndex = getIndex(ranges, curHead);\n      var wasClipped = cursorEqual(ranges[primIndex].head, ranges[primIndex].anchor);\n      var max = ranges.length - 1;\n      var index = max - primIndex > primIndex ? max : 0;\n      var base = ranges[index].anchor;\n\n      var firstLine = Math.min(base.line, head.line);\n      var lastLine = Math.max(base.line, head.line);\n      var baseCh = base.ch, headCh = head.ch;\n\n      var dir = ranges[index].head.ch - baseCh;\n      var newDir = headCh - baseCh;\n      if (dir > 0 && newDir <= 0) {\n        baseCh++;\n        if (!isClipped) { headCh--; }\n      } else if (dir < 0 && newDir >= 0) {\n        baseCh--;\n        if (!wasClipped) { headCh++; }\n      } else if (dir < 0 && newDir == -1) {\n        baseCh--;\n        headCh++;\n      }\n      for (var line = firstLine; line <= lastLine; line++) {\n        var range = {anchor: new Pos(line, baseCh), head: new Pos(line, headCh)};\n        selections.push(range);\n      }\n      cm.setSelections(selections);\n      selectionEnd.ch = headCh;\n      base.ch = baseCh;\n      return base;\n    }\n    function selectForInsert(cm, head, height) {\n      var sel = [];\n      for (var i = 0; i < height; i++) {\n        var lineHead = offsetCursor(head, i, 0);\n        sel.push({anchor: lineHead, head: lineHead});\n      }\n      cm.setSelections(sel, 0);\n    }\n    // getIndex returns the index of the cursor in the selections.\n    function getIndex(ranges, cursor, end) {\n      for (var i = 0; i < ranges.length; i++) {\n        var atAnchor = end != 'head' && cursorEqual(ranges[i].anchor, cursor);\n        var atHead = end != 'anchor' && cursorEqual(ranges[i].head, cursor);\n        if (atAnchor || atHead) {\n          return i;\n        }\n      }\n      return -1;\n    }\n    function getSelectedAreaRange(cm, vim) {\n      var lastSelection = vim.lastSelection;\n      var getCurrentSelectedAreaRange = function() {\n        var selections = cm.listSelections();\n        var start =  selections[0];\n        var end = selections[selections.length-1];\n        var selectionStart = cursorIsBefore(start.anchor, start.head) ? start.anchor : start.head;\n        var selectionEnd = cursorIsBefore(end.anchor, end.head) ? end.head : end.anchor;\n        return [selectionStart, selectionEnd];\n      };\n      var getLastSelectedAreaRange = function() {\n        var selectionStart = cm.getCursor();\n        var selectionEnd = cm.getCursor();\n        var block = lastSelection.visualBlock;\n        if (block) {\n          var width = block.width;\n          var height = block.height;\n          selectionEnd = Pos(selectionStart.line + height, selectionStart.ch + width);\n          var selections = [];\n          // selectBlock creates a 'proper' rectangular block.\n          // We do not want that in all cases, so we manually set selections.\n          for (var i = selectionStart.line; i < selectionEnd.line; i++) {\n            var anchor = Pos(i, selectionStart.ch);\n            var head = Pos(i, selectionEnd.ch);\n            var range = {anchor: anchor, head: head};\n            selections.push(range);\n          }\n          cm.setSelections(selections);\n        } else {\n          var start = lastSelection.anchorMark.find();\n          var end = lastSelection.headMark.find();\n          var line = end.line - start.line;\n          var ch = end.ch - start.ch;\n          selectionEnd = {line: selectionEnd.line + line, ch: line ? selectionEnd.ch : ch + selectionEnd.ch};\n          if (lastSelection.visualLine) {\n            selectionStart = Pos(selectionStart.line, 0);\n            selectionEnd = Pos(selectionEnd.line, lineLength(cm, selectionEnd.line));\n          }\n          cm.setSelection(selectionStart, selectionEnd);\n        }\n        return [selectionStart, selectionEnd];\n      };\n      if (!vim.visualMode) {\n      // In case of replaying the action.\n        return getLastSelectedAreaRange();\n      } else {\n        return getCurrentSelectedAreaRange();\n      }\n    }\n    // Updates the previous selection with the current selection's values. This\n    // should only be called in visual mode.\n    function updateLastSelection(cm, vim) {\n      var anchor = vim.sel.anchor;\n      var head = vim.sel.head;\n      // To accommodate the effect of lastPastedText in the last selection\n      if (vim.lastPastedText) {\n        head = cm.posFromIndex(cm.indexFromPos(anchor) + vim.lastPastedText.length);\n        vim.lastPastedText = null;\n      }\n      vim.lastSelection = {'anchorMark': cm.setBookmark(anchor),\n                           'headMark': cm.setBookmark(head),\n                           'anchor': copyCursor(anchor),\n                           'head': copyCursor(head),\n                           'visualMode': vim.visualMode,\n                           'visualLine': vim.visualLine,\n                           'visualBlock': vim.visualBlock};\n    }\n    function expandSelection(cm, start, end) {\n      var sel = cm.state.vim.sel;\n      var head = sel.head;\n      var anchor = sel.anchor;\n      var tmp;\n      if (cursorIsBefore(end, start)) {\n        tmp = end;\n        end = start;\n        start = tmp;\n      }\n      if (cursorIsBefore(head, anchor)) {\n        head = cursorMin(start, head);\n        anchor = cursorMax(anchor, end);\n      } else {\n        anchor = cursorMin(start, anchor);\n        head = cursorMax(head, end);\n        head = offsetCursor(head, 0, -1);\n        if (head.ch == -1 && head.line != cm.firstLine()) {\n          head = Pos(head.line - 1, lineLength(cm, head.line - 1));\n        }\n      }\n      return [anchor, head];\n    }\n    /**\n     * Updates the CodeMirror selection to match the provided vim selection.\n     * If no arguments are given, it uses the current vim selection state.\n     */\n    function updateCmSelection(cm, sel, mode) {\n      var vim = cm.state.vim;\n      sel = sel || vim.sel;\n      var mode = mode ||\n        vim.visualLine ? 'line' : vim.visualBlock ? 'block' : 'char';\n      var cmSel = makeCmSelection(cm, sel, mode);\n      cm.setSelections(cmSel.ranges, cmSel.primary);\n      updateFakeCursor(cm);\n    }\n    function makeCmSelection(cm, sel, mode, exclusive) {\n      var head = copyCursor(sel.head);\n      var anchor = copyCursor(sel.anchor);\n      if (mode == 'char') {\n        var headOffset = !exclusive && !cursorIsBefore(sel.head, sel.anchor) ? 1 : 0;\n        var anchorOffset = cursorIsBefore(sel.head, sel.anchor) ? 1 : 0;\n        head = offsetCursor(sel.head, 0, headOffset);\n        anchor = offsetCursor(sel.anchor, 0, anchorOffset);\n        return {\n          ranges: [{anchor: anchor, head: head}],\n          primary: 0\n        };\n      } else if (mode == 'line') {\n        if (!cursorIsBefore(sel.head, sel.anchor)) {\n          anchor.ch = 0;\n\n          var lastLine = cm.lastLine();\n          if (head.line > lastLine) {\n            head.line = lastLine;\n          }\n          head.ch = lineLength(cm, head.line);\n        } else {\n          head.ch = 0;\n          anchor.ch = lineLength(cm, anchor.line);\n        }\n        return {\n          ranges: [{anchor: anchor, head: head}],\n          primary: 0\n        };\n      } else if (mode == 'block') {\n        var top = Math.min(anchor.line, head.line),\n            left = Math.min(anchor.ch, head.ch),\n            bottom = Math.max(anchor.line, head.line),\n            right = Math.max(anchor.ch, head.ch) + 1;\n        var height = bottom - top + 1;\n        var primary = head.line == top ? 0 : height - 1;\n        var ranges = [];\n        for (var i = 0; i < height; i++) {\n          ranges.push({\n            anchor: Pos(top + i, left),\n            head: Pos(top + i, right)\n          });\n        }\n        return {\n          ranges: ranges,\n          primary: primary\n        };\n      }\n    }\n    function getHead(cm) {\n      var cur = cm.getCursor('head');\n      if (cm.getSelection().length == 1) {\n        // Small corner case when only 1 character is selected. The \"real\"\n        // head is the left of head and anchor.\n        cur = cursorMin(cur, cm.getCursor('anchor'));\n      }\n      return cur;\n    }\n\n    /**\n     * If moveHead is set to false, the CodeMirror selection will not be\n     * touched. The caller assumes the responsibility of putting the cursor\n    * in the right place.\n     */\n    function exitVisualMode(cm, moveHead) {\n      var vim = cm.state.vim;\n      if (moveHead !== false) {\n        cm.setCursor(clipCursorToContent(cm, vim.sel.head));\n      }\n      updateLastSelection(cm, vim);\n      vim.visualMode = false;\n      vim.visualLine = false;\n      vim.visualBlock = false;\n      if (!vim.insertMode) CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"normal\"});\n      clearFakeCursor(vim);\n    }\n\n    // Remove any trailing newlines from the selection. For\n    // example, with the caret at the start of the last word on the line,\n    // 'dw' should word, but not the newline, while 'w' should advance the\n    // caret to the first character of the next line.\n    function clipToLine(cm, curStart, curEnd) {\n      var selection = cm.getRange(curStart, curEnd);\n      // Only clip if the selection ends with trailing newline + whitespace\n      if (/\\n\\s*$/.test(selection)) {\n        var lines = selection.split('\\n');\n        // We know this is all whitespace.\n        lines.pop();\n\n        // Cases:\n        // 1. Last word is an empty line - do not clip the trailing '\\n'\n        // 2. Last word is not an empty line - clip the trailing '\\n'\n        var line;\n        // Find the line containing the last word, and clip all whitespace up\n        // to it.\n        for (var line = lines.pop(); lines.length > 0 && line && isWhiteSpaceString(line); line = lines.pop()) {\n          curEnd.line--;\n          curEnd.ch = 0;\n        }\n        // If the last word is not an empty line, clip an additional newline\n        if (line) {\n          curEnd.line--;\n          curEnd.ch = lineLength(cm, curEnd.line);\n        } else {\n          curEnd.ch = 0;\n        }\n      }\n    }\n\n    // Expand the selection to line ends.\n    function expandSelectionToLine(_cm, curStart, curEnd) {\n      curStart.ch = 0;\n      curEnd.ch = 0;\n      curEnd.line++;\n    }\n\n    function findFirstNonWhiteSpaceCharacter(text) {\n      if (!text) {\n        return 0;\n      }\n      var firstNonWS = text.search(/\\S/);\n      return firstNonWS == -1 ? text.length : firstNonWS;\n    }\n\n    function expandWordUnderCursor(cm, inclusive, _forward, bigWord, noSymbol) {\n      var cur = getHead(cm);\n      var line = cm.getLine(cur.line);\n      var idx = cur.ch;\n\n      // Seek to first word or non-whitespace character, depending on if\n      // noSymbol is true.\n      var test = noSymbol ? wordCharTest[0] : bigWordCharTest [0];\n      while (!test(line.charAt(idx))) {\n        idx++;\n        if (idx >= line.length) { return null; }\n      }\n\n      if (bigWord) {\n        test = bigWordCharTest[0];\n      } else {\n        test = wordCharTest[0];\n        if (!test(line.charAt(idx))) {\n          test = wordCharTest[1];\n        }\n      }\n\n      var end = idx, start = idx;\n      while (test(line.charAt(end)) && end < line.length) { end++; }\n      while (test(line.charAt(start)) && start >= 0) { start--; }\n      start++;\n\n      if (inclusive) {\n        // If present, include all whitespace after word.\n        // Otherwise, include all whitespace before word, except indentation.\n        var wordEnd = end;\n        while (/\\s/.test(line.charAt(end)) && end < line.length) { end++; }\n        if (wordEnd == end) {\n          var wordStart = start;\n          while (/\\s/.test(line.charAt(start - 1)) && start > 0) { start--; }\n          if (!start) { start = wordStart; }\n        }\n      }\n      return { start: Pos(cur.line, start), end: Pos(cur.line, end) };\n    }\n\n    /**\n     * Depends on the following:\n     *\n     * - editor mode should be htmlmixedmode / xml\n     * - mode/xml/xml.js should be loaded\n     * - addon/fold/xml-fold.js should be loaded\n     *\n     * If any of the above requirements are not true, this function noops.\n     *\n     * This is _NOT_ a 100% accurate implementation of vim tag text objects.\n     * The following caveats apply (based off cursory testing, I'm sure there\n     * are other discrepancies):\n     *\n     * - Does not work inside comments:\n     *   ```\n     *   <!-- <div>broken</div> -->\n     *   ```\n     * - Does not work when tags have different cases:\n     *   ```\n     *   <div>broken</DIV>\n     *   ```\n     * - Does not work when cursor is inside a broken tag:\n     *   ```\n     *   <div><brok><en></div>\n     *   ```\n     */\n    function expandTagUnderCursor(cm, head, inclusive) {\n      var cur = head;\n      if (!CodeMirror.findMatchingTag || !CodeMirror.findEnclosingTag) {\n        return { start: cur, end: cur };\n      }\n\n      var tags = CodeMirror.findMatchingTag(cm, head) || CodeMirror.findEnclosingTag(cm, head);\n      if (!tags || !tags.open || !tags.close) {\n        return { start: cur, end: cur };\n      }\n\n      if (inclusive) {\n        return { start: tags.open.from, end: tags.close.to };\n      }\n      return { start: tags.open.to, end: tags.close.from };\n    }\n\n    function recordJumpPosition(cm, oldCur, newCur) {\n      if (!cursorEqual(oldCur, newCur)) {\n        vimGlobalState.jumpList.add(cm, oldCur, newCur);\n      }\n    }\n\n    function recordLastCharacterSearch(increment, args) {\n        vimGlobalState.lastCharacterSearch.increment = increment;\n        vimGlobalState.lastCharacterSearch.forward = args.forward;\n        vimGlobalState.lastCharacterSearch.selectedCharacter = args.selectedCharacter;\n    }\n\n    var symbolToMode = {\n        '(': 'bracket', ')': 'bracket', '{': 'bracket', '}': 'bracket',\n        '[': 'section', ']': 'section',\n        '*': 'comment', '/': 'comment',\n        'm': 'method', 'M': 'method',\n        '#': 'preprocess'\n    };\n    var findSymbolModes = {\n      bracket: {\n        isComplete: function(state) {\n          if (state.nextCh === state.symb) {\n            state.depth++;\n            if (state.depth >= 1)return true;\n          } else if (state.nextCh === state.reverseSymb) {\n            state.depth--;\n          }\n          return false;\n        }\n      },\n      section: {\n        init: function(state) {\n          state.curMoveThrough = true;\n          state.symb = (state.forward ? ']' : '[') === state.symb ? '{' : '}';\n        },\n        isComplete: function(state) {\n          return state.index === 0 && state.nextCh === state.symb;\n        }\n      },\n      comment: {\n        isComplete: function(state) {\n          var found = state.lastCh === '*' && state.nextCh === '/';\n          state.lastCh = state.nextCh;\n          return found;\n        }\n      },\n      // TODO: The original Vim implementation only operates on level 1 and 2.\n      // The current implementation doesn't check for code block level and\n      // therefore it operates on any levels.\n      method: {\n        init: function(state) {\n          state.symb = (state.symb === 'm' ? '{' : '}');\n          state.reverseSymb = state.symb === '{' ? '}' : '{';\n        },\n        isComplete: function(state) {\n          if (state.nextCh === state.symb)return true;\n          return false;\n        }\n      },\n      preprocess: {\n        init: function(state) {\n          state.index = 0;\n        },\n        isComplete: function(state) {\n          if (state.nextCh === '#') {\n            var token = state.lineText.match(/#(\\w+)/)[1];\n            if (token === 'endif') {\n              if (state.forward && state.depth === 0) {\n                return true;\n              }\n              state.depth++;\n            } else if (token === 'if') {\n              if (!state.forward && state.depth === 0) {\n                return true;\n              }\n              state.depth--;\n            }\n            if (token === 'else' && state.depth === 0)return true;\n          }\n          return false;\n        }\n      }\n    };\n    function findSymbol(cm, repeat, forward, symb) {\n      var cur = copyCursor(cm.getCursor());\n      var increment = forward ? 1 : -1;\n      var endLine = forward ? cm.lineCount() : -1;\n      var curCh = cur.ch;\n      var line = cur.line;\n      var lineText = cm.getLine(line);\n      var state = {\n        lineText: lineText,\n        nextCh: lineText.charAt(curCh),\n        lastCh: null,\n        index: curCh,\n        symb: symb,\n        reverseSymb: (forward ?  { ')': '(', '}': '{' } : { '(': ')', '{': '}' })[symb],\n        forward: forward,\n        depth: 0,\n        curMoveThrough: false\n      };\n      var mode = symbolToMode[symb];\n      if (!mode)return cur;\n      var init = findSymbolModes[mode].init;\n      var isComplete = findSymbolModes[mode].isComplete;\n      if (init) { init(state); }\n      while (line !== endLine && repeat) {\n        state.index += increment;\n        state.nextCh = state.lineText.charAt(state.index);\n        if (!state.nextCh) {\n          line += increment;\n          state.lineText = cm.getLine(line) || '';\n          if (increment > 0) {\n            state.index = 0;\n          } else {\n            var lineLen = state.lineText.length;\n            state.index = (lineLen > 0) ? (lineLen-1) : 0;\n          }\n          state.nextCh = state.lineText.charAt(state.index);\n        }\n        if (isComplete(state)) {\n          cur.line = line;\n          cur.ch = state.index;\n          repeat--;\n        }\n      }\n      if (state.nextCh || state.curMoveThrough) {\n        return Pos(line, state.index);\n      }\n      return cur;\n    }\n\n    /*\n     * Returns the boundaries of the next word. If the cursor in the middle of\n     * the word, then returns the boundaries of the current word, starting at\n     * the cursor. If the cursor is at the start/end of a word, and we are going\n     * forward/backward, respectively, find the boundaries of the next word.\n     *\n     * @param {CodeMirror} cm CodeMirror object.\n     * @param {Cursor} cur The cursor position.\n     * @param {boolean} forward True to search forward. False to search\n     *     backward.\n     * @param {boolean} bigWord True if punctuation count as part of the word.\n     *     False if only [a-zA-Z0-9] characters count as part of the word.\n     * @param {boolean} emptyLineIsWord True if empty lines should be treated\n     *     as words.\n     * @return {Object{from:number, to:number, line: number}} The boundaries of\n     *     the word, or null if there are no more words.\n     */\n    function findWord(cm, cur, forward, bigWord, emptyLineIsWord) {\n      var lineNum = cur.line;\n      var pos = cur.ch;\n      var line = cm.getLine(lineNum);\n      var dir = forward ? 1 : -1;\n      var charTests = bigWord ? bigWordCharTest: wordCharTest;\n\n      if (emptyLineIsWord && line == '') {\n        lineNum += dir;\n        line = cm.getLine(lineNum);\n        if (!isLine(cm, lineNum)) {\n          return null;\n        }\n        pos = (forward) ? 0 : line.length;\n      }\n\n      while (true) {\n        if (emptyLineIsWord && line == '') {\n          return { from: 0, to: 0, line: lineNum };\n        }\n        var stop = (dir > 0) ? line.length : -1;\n        var wordStart = stop, wordEnd = stop;\n        // Find bounds of next word.\n        while (pos != stop) {\n          var foundWord = false;\n          for (var i = 0; i < charTests.length && !foundWord; ++i) {\n            if (charTests[i](line.charAt(pos))) {\n              wordStart = pos;\n              // Advance to end of word.\n              while (pos != stop && charTests[i](line.charAt(pos))) {\n                pos += dir;\n              }\n              wordEnd = pos;\n              foundWord = wordStart != wordEnd;\n              if (wordStart == cur.ch && lineNum == cur.line &&\n                  wordEnd == wordStart + dir) {\n                // We started at the end of a word. Find the next one.\n                continue;\n              } else {\n                return {\n                  from: Math.min(wordStart, wordEnd + 1),\n                  to: Math.max(wordStart, wordEnd),\n                  line: lineNum };\n              }\n            }\n          }\n          if (!foundWord) {\n            pos += dir;\n          }\n        }\n        // Advance to next/prev line.\n        lineNum += dir;\n        if (!isLine(cm, lineNum)) {\n          return null;\n        }\n        line = cm.getLine(lineNum);\n        pos = (dir > 0) ? 0 : line.length;\n      }\n    }\n\n    /**\n     * @param {CodeMirror} cm CodeMirror object.\n     * @param {Pos} cur The position to start from.\n     * @param {int} repeat Number of words to move past.\n     * @param {boolean} forward True to search forward. False to search\n     *     backward.\n     * @param {boolean} wordEnd True to move to end of word. False to move to\n     *     beginning of word.\n     * @param {boolean} bigWord True if punctuation count as part of the word.\n     *     False if only alphabet characters count as part of the word.\n     * @return {Cursor} The position the cursor should move to.\n     */\n    function moveToWord(cm, cur, repeat, forward, wordEnd, bigWord) {\n      var curStart = copyCursor(cur);\n      var words = [];\n      if (forward && !wordEnd || !forward && wordEnd) {\n        repeat++;\n      }\n      // For 'e', empty lines are not considered words, go figure.\n      var emptyLineIsWord = !(forward && wordEnd);\n      for (var i = 0; i < repeat; i++) {\n        var word = findWord(cm, cur, forward, bigWord, emptyLineIsWord);\n        if (!word) {\n          var eodCh = lineLength(cm, cm.lastLine());\n          words.push(forward\n              ? {line: cm.lastLine(), from: eodCh, to: eodCh}\n              : {line: 0, from: 0, to: 0});\n          break;\n        }\n        words.push(word);\n        cur = Pos(word.line, forward ? (word.to - 1) : word.from);\n      }\n      var shortCircuit = words.length != repeat;\n      var firstWord = words[0];\n      var lastWord = words.pop();\n      if (forward && !wordEnd) {\n        // w\n        if (!shortCircuit && (firstWord.from != curStart.ch || firstWord.line != curStart.line)) {\n          // We did not start in the middle of a word. Discard the extra word at the end.\n          lastWord = words.pop();\n        }\n        return Pos(lastWord.line, lastWord.from);\n      } else if (forward && wordEnd) {\n        return Pos(lastWord.line, lastWord.to - 1);\n      } else if (!forward && wordEnd) {\n        // ge\n        if (!shortCircuit && (firstWord.to != curStart.ch || firstWord.line != curStart.line)) {\n          // We did not start in the middle of a word. Discard the extra word at the end.\n          lastWord = words.pop();\n        }\n        return Pos(lastWord.line, lastWord.to);\n      } else {\n        // b\n        return Pos(lastWord.line, lastWord.from);\n      }\n    }\n\n    function moveToCharacter(cm, repeat, forward, character) {\n      var cur = cm.getCursor();\n      var start = cur.ch;\n      var idx;\n      for (var i = 0; i < repeat; i ++) {\n        var line = cm.getLine(cur.line);\n        idx = charIdxInLine(start, line, character, forward, true);\n        if (idx == -1) {\n          return null;\n        }\n        start = idx;\n      }\n      return Pos(cm.getCursor().line, idx);\n    }\n\n    function moveToColumn(cm, repeat) {\n      // repeat is always >= 1, so repeat - 1 always corresponds\n      // to the column we want to go to.\n      var line = cm.getCursor().line;\n      return clipCursorToContent(cm, Pos(line, repeat - 1));\n    }\n\n    function updateMark(cm, vim, markName, pos) {\n      if (!inArray(markName, validMarks)) {\n        return;\n      }\n      if (vim.marks[markName]) {\n        vim.marks[markName].clear();\n      }\n      vim.marks[markName] = cm.setBookmark(pos);\n    }\n\n    function charIdxInLine(start, line, character, forward, includeChar) {\n      // Search for char in line.\n      // motion_options: {forward, includeChar}\n      // If includeChar = true, include it too.\n      // If forward = true, search forward, else search backwards.\n      // If char is not found on this line, do nothing\n      var idx;\n      if (forward) {\n        idx = line.indexOf(character, start + 1);\n        if (idx != -1 && !includeChar) {\n          idx -= 1;\n        }\n      } else {\n        idx = line.lastIndexOf(character, start - 1);\n        if (idx != -1 && !includeChar) {\n          idx += 1;\n        }\n      }\n      return idx;\n    }\n\n    function findParagraph(cm, head, repeat, dir, inclusive) {\n      var line = head.line;\n      var min = cm.firstLine();\n      var max = cm.lastLine();\n      var start, end, i = line;\n      function isEmpty(i) { return !cm.getLine(i); }\n      function isBoundary(i, dir, any) {\n        if (any) { return isEmpty(i) != isEmpty(i + dir); }\n        return !isEmpty(i) && isEmpty(i + dir);\n      }\n      if (dir) {\n        while (min <= i && i <= max && repeat > 0) {\n          if (isBoundary(i, dir)) { repeat--; }\n          i += dir;\n        }\n        return new Pos(i, 0);\n      }\n\n      var vim = cm.state.vim;\n      if (vim.visualLine && isBoundary(line, 1, true)) {\n        var anchor = vim.sel.anchor;\n        if (isBoundary(anchor.line, -1, true)) {\n          if (!inclusive || anchor.line != line) {\n            line += 1;\n          }\n        }\n      }\n      var startState = isEmpty(line);\n      for (i = line; i <= max && repeat; i++) {\n        if (isBoundary(i, 1, true)) {\n          if (!inclusive || isEmpty(i) != startState) {\n            repeat--;\n          }\n        }\n      }\n      end = new Pos(i, 0);\n      // select boundary before paragraph for the last one\n      if (i > max && !startState) { startState = true; }\n      else { inclusive = false; }\n      for (i = line; i > min; i--) {\n        if (!inclusive || isEmpty(i) == startState || i == line) {\n          if (isBoundary(i, -1, true)) { break; }\n        }\n      }\n      start = new Pos(i, 0);\n      return { start: start, end: end };\n    }\n\n    function findSentence(cm, cur, repeat, dir) {\n\n      /*\n        Takes an index object\n        {\n          line: the line string,\n          ln: line number,\n          pos: index in line,\n          dir: direction of traversal (-1 or 1)\n        }\n        and modifies the line, ln, and pos members to represent the\n        next valid position or sets them to null if there are\n        no more valid positions.\n       */\n      function nextChar(cm, idx) {\n        if (idx.pos + idx.dir < 0 || idx.pos + idx.dir >= idx.line.length) {\n          idx.ln += idx.dir;\n          if (!isLine(cm, idx.ln)) {\n            idx.line = null;\n            idx.ln = null;\n            idx.pos = null;\n            return;\n          }\n          idx.line = cm.getLine(idx.ln);\n          idx.pos = (idx.dir > 0) ? 0 : idx.line.length - 1;\n        }\n        else {\n          idx.pos += idx.dir;\n        }\n      }\n\n      /*\n        Performs one iteration of traversal in forward direction\n        Returns an index object of the new location\n       */\n      function forward(cm, ln, pos, dir) {\n        var line = cm.getLine(ln);\n        var stop = (line === \"\");\n\n        var curr = {\n          line: line,\n          ln: ln,\n          pos: pos,\n          dir: dir,\n        }\n\n        var last_valid = {\n          ln: curr.ln,\n          pos: curr.pos,\n        }\n\n        var skip_empty_lines = (curr.line === \"\");\n\n        // Move one step to skip character we start on\n        nextChar(cm, curr);\n\n        while (curr.line !== null) {\n          last_valid.ln = curr.ln;\n          last_valid.pos = curr.pos;\n\n          if (curr.line === \"\" && !skip_empty_lines) {\n            return { ln: curr.ln, pos: curr.pos, };\n          }\n          else if (stop && curr.line !== \"\" && !isWhiteSpaceString(curr.line[curr.pos])) {\n            return { ln: curr.ln, pos: curr.pos, };\n          }\n          else if (isEndOfSentenceSymbol(curr.line[curr.pos])\n            && !stop\n            && (curr.pos === curr.line.length - 1\n              || isWhiteSpaceString(curr.line[curr.pos + 1]))) {\n            stop = true;\n          }\n\n          nextChar(cm, curr);\n        }\n\n        /*\n          Set the position to the last non whitespace character on the last\n          valid line in the case that we reach the end of the document.\n        */\n        var line = cm.getLine(last_valid.ln);\n        last_valid.pos = 0;\n        for(var i = line.length - 1; i >= 0; --i) {\n          if (!isWhiteSpaceString(line[i])) {\n            last_valid.pos = i;\n            break;\n          }\n        }\n\n        return last_valid;\n\n      }\n\n      /*\n        Performs one iteration of traversal in reverse direction\n        Returns an index object of the new location\n       */\n      function reverse(cm, ln, pos, dir) {\n        var line = cm.getLine(ln);\n\n        var curr = {\n          line: line,\n          ln: ln,\n          pos: pos,\n          dir: dir,\n        }\n\n        var last_valid = {\n          ln: curr.ln,\n          pos: null,\n        };\n\n        var skip_empty_lines = (curr.line === \"\");\n\n        // Move one step to skip character we start on\n        nextChar(cm, curr);\n\n        while (curr.line !== null) {\n\n          if (curr.line === \"\" && !skip_empty_lines) {\n            if (last_valid.pos !== null) {\n              return last_valid;\n            }\n            else {\n              return { ln: curr.ln, pos: curr.pos };\n            }\n          }\n          else if (isEndOfSentenceSymbol(curr.line[curr.pos])\n              && last_valid.pos !== null\n              && !(curr.ln === last_valid.ln && curr.pos + 1 === last_valid.pos)) {\n            return last_valid;\n          }\n          else if (curr.line !== \"\" && !isWhiteSpaceString(curr.line[curr.pos])) {\n            skip_empty_lines = false;\n            last_valid = { ln: curr.ln, pos: curr.pos }\n          }\n\n          nextChar(cm, curr);\n        }\n\n        /*\n          Set the position to the first non whitespace character on the last\n          valid line in the case that we reach the beginning of the document.\n        */\n        var line = cm.getLine(last_valid.ln);\n        last_valid.pos = 0;\n        for(var i = 0; i < line.length; ++i) {\n          if (!isWhiteSpaceString(line[i])) {\n            last_valid.pos = i;\n            break;\n          }\n        }\n        return last_valid;\n      }\n\n      var curr_index = {\n        ln: cur.line,\n        pos: cur.ch,\n      };\n\n      while (repeat > 0) {\n        if (dir < 0) {\n          curr_index = reverse(cm, curr_index.ln, curr_index.pos, dir);\n        }\n        else {\n          curr_index = forward(cm, curr_index.ln, curr_index.pos, dir);\n        }\n        repeat--;\n      }\n\n      return Pos(curr_index.ln, curr_index.pos);\n    }\n\n    // TODO: perhaps this finagling of start and end positions belongs\n    // in codemirror/replaceRange?\n    function selectCompanionObject(cm, head, symb, inclusive) {\n      var cur = head, start, end;\n\n      var bracketRegexp = ({\n        '(': /[()]/, ')': /[()]/,\n        '[': /[[\\]]/, ']': /[[\\]]/,\n        '{': /[{}]/, '}': /[{}]/,\n        '<': /[<>]/, '>': /[<>]/})[symb];\n      var openSym = ({\n        '(': '(', ')': '(',\n        '[': '[', ']': '[',\n        '{': '{', '}': '{',\n        '<': '<', '>': '<'})[symb];\n      var curChar = cm.getLine(cur.line).charAt(cur.ch);\n      // Due to the behavior of scanForBracket, we need to add an offset if the\n      // cursor is on a matching open bracket.\n      var offset = curChar === openSym ? 1 : 0;\n\n      start = cm.scanForBracket(Pos(cur.line, cur.ch + offset), -1, undefined, {'bracketRegex': bracketRegexp});\n      end = cm.scanForBracket(Pos(cur.line, cur.ch + offset), 1, undefined, {'bracketRegex': bracketRegexp});\n\n      if (!start || !end) {\n        return { start: cur, end: cur };\n      }\n\n      start = start.pos;\n      end = end.pos;\n\n      if ((start.line == end.line && start.ch > end.ch)\n          || (start.line > end.line)) {\n        var tmp = start;\n        start = end;\n        end = tmp;\n      }\n\n      if (inclusive) {\n        end.ch += 1;\n      } else {\n        start.ch += 1;\n      }\n\n      return { start: start, end: end };\n    }\n\n    // Takes in a symbol and a cursor and tries to simulate text objects that\n    // have identical opening and closing symbols\n    // TODO support across multiple lines\n    function findBeginningAndEnd(cm, head, symb, inclusive) {\n      var cur = copyCursor(head);\n      var line = cm.getLine(cur.line);\n      var chars = line.split('');\n      var start, end, i, len;\n      var firstIndex = chars.indexOf(symb);\n\n      // the decision tree is to always look backwards for the beginning first,\n      // but if the cursor is in front of the first instance of the symb,\n      // then move the cursor forward\n      if (cur.ch < firstIndex) {\n        cur.ch = firstIndex;\n        // Why is this line even here???\n        // cm.setCursor(cur.line, firstIndex+1);\n      }\n      // otherwise if the cursor is currently on the closing symbol\n      else if (firstIndex < cur.ch && chars[cur.ch] == symb) {\n        end = cur.ch; // assign end to the current cursor\n        --cur.ch; // make sure to look backwards\n      }\n\n      // if we're currently on the symbol, we've got a start\n      if (chars[cur.ch] == symb && !end) {\n        start = cur.ch + 1; // assign start to ahead of the cursor\n      } else {\n        // go backwards to find the start\n        for (i = cur.ch; i > -1 && !start; i--) {\n          if (chars[i] == symb) {\n            start = i + 1;\n          }\n        }\n      }\n\n      // look forwards for the end symbol\n      if (start && !end) {\n        for (i = start, len = chars.length; i < len && !end; i++) {\n          if (chars[i] == symb) {\n            end = i;\n          }\n        }\n      }\n\n      // nothing found\n      if (!start || !end) {\n        return { start: cur, end: cur };\n      }\n\n      // include the symbols\n      if (inclusive) {\n        --start; ++end;\n      }\n\n      return {\n        start: Pos(cur.line, start),\n        end: Pos(cur.line, end)\n      };\n    }\n\n    // Search functions\n    defineOption('pcre', true, 'boolean');\n    function SearchState() {}\n    SearchState.prototype = {\n      getQuery: function() {\n        return vimGlobalState.query;\n      },\n      setQuery: function(query) {\n        vimGlobalState.query = query;\n      },\n      getOverlay: function() {\n        return this.searchOverlay;\n      },\n      setOverlay: function(overlay) {\n        this.searchOverlay = overlay;\n      },\n      isReversed: function() {\n        return vimGlobalState.isReversed;\n      },\n      setReversed: function(reversed) {\n        vimGlobalState.isReversed = reversed;\n      },\n      getScrollbarAnnotate: function() {\n        return this.annotate;\n      },\n      setScrollbarAnnotate: function(annotate) {\n        this.annotate = annotate;\n      }\n    };\n    function getSearchState(cm) {\n      var vim = cm.state.vim;\n      return vim.searchState_ || (vim.searchState_ = new SearchState());\n    }\n    function dialog(cm, template, shortText, onClose, options) {\n      if (cm.openDialog) {\n        cm.openDialog(template, onClose, { bottom: true, value: options.value,\n            onKeyDown: options.onKeyDown, onKeyUp: options.onKeyUp,\n            selectValueOnOpen: false});\n      }\n      else {\n        onClose(prompt(shortText, ''));\n      }\n    }\n    function splitBySlash(argString) {\n      return splitBySeparator(argString, '/');\n    }\n\n    function findUnescapedSlashes(argString) {\n      return findUnescapedSeparators(argString, '/');\n    }\n\n    function splitBySeparator(argString, separator) {\n      var slashes = findUnescapedSeparators(argString, separator) || [];\n      if (!slashes.length) return [];\n      var tokens = [];\n      // in case of strings like foo/bar\n      if (slashes[0] !== 0) return;\n      for (var i = 0; i < slashes.length; i++) {\n        if (typeof slashes[i] == 'number')\n          tokens.push(argString.substring(slashes[i] + 1, slashes[i+1]));\n      }\n      return tokens;\n    }\n\n    function findUnescapedSeparators(str, separator) {\n      if (!separator)\n        separator = '/';\n\n      var escapeNextChar = false;\n      var slashes = [];\n      for (var i = 0; i < str.length; i++) {\n        var c = str.charAt(i);\n        if (!escapeNextChar && c == separator) {\n          slashes.push(i);\n        }\n        escapeNextChar = !escapeNextChar && (c == '\\\\');\n      }\n      return slashes;\n    }\n\n    // Translates a search string from ex (vim) syntax into javascript form.\n    function translateRegex(str) {\n      // When these match, add a '\\' if unescaped or remove one if escaped.\n      var specials = '|(){';\n      // Remove, but never add, a '\\' for these.\n      var unescape = '}';\n      var escapeNextChar = false;\n      var out = [];\n      for (var i = -1; i < str.length; i++) {\n        var c = str.charAt(i) || '';\n        var n = str.charAt(i+1) || '';\n        var specialComesNext = (n && specials.indexOf(n) != -1);\n        if (escapeNextChar) {\n          if (c !== '\\\\' || !specialComesNext) {\n            out.push(c);\n          }\n          escapeNextChar = false;\n        } else {\n          if (c === '\\\\') {\n            escapeNextChar = true;\n            // Treat the unescape list as special for removing, but not adding '\\'.\n            if (n && unescape.indexOf(n) != -1) {\n              specialComesNext = true;\n            }\n            // Not passing this test means removing a '\\'.\n            if (!specialComesNext || n === '\\\\') {\n              out.push(c);\n            }\n          } else {\n            out.push(c);\n            if (specialComesNext && n !== '\\\\') {\n              out.push('\\\\');\n            }\n          }\n        }\n      }\n      return out.join('');\n    }\n\n    // Translates the replace part of a search and replace from ex (vim) syntax into\n    // javascript form.  Similar to translateRegex, but additionally fixes back references\n    // (translates '\\[0..9]' to '$[0..9]') and follows different rules for escaping '$'.\n    var charUnescapes = {'\\\\n': '\\n', '\\\\r': '\\r', '\\\\t': '\\t'};\n    function translateRegexReplace(str) {\n      var escapeNextChar = false;\n      var out = [];\n      for (var i = -1; i < str.length; i++) {\n        var c = str.charAt(i) || '';\n        var n = str.charAt(i+1) || '';\n        if (charUnescapes[c + n]) {\n          out.push(charUnescapes[c+n]);\n          i++;\n        } else if (escapeNextChar) {\n          // At any point in the loop, escapeNextChar is true if the previous\n          // character was a '\\' and was not escaped.\n          out.push(c);\n          escapeNextChar = false;\n        } else {\n          if (c === '\\\\') {\n            escapeNextChar = true;\n            if ((isNumber(n) || n === '$')) {\n              out.push('$');\n            } else if (n !== '/' && n !== '\\\\') {\n              out.push('\\\\');\n            }\n          } else {\n            if (c === '$') {\n              out.push('$');\n            }\n            out.push(c);\n            if (n === '/') {\n              out.push('\\\\');\n            }\n          }\n        }\n      }\n      return out.join('');\n    }\n\n    // Unescape \\ and / in the replace part, for PCRE mode.\n    var unescapes = {'\\\\/': '/', '\\\\\\\\': '\\\\', '\\\\n': '\\n', '\\\\r': '\\r', '\\\\t': '\\t', '\\\\&':'&'};\n    function unescapeRegexReplace(str) {\n      var stream = new CodeMirror.StringStream(str);\n      var output = [];\n      while (!stream.eol()) {\n        // Search for \\.\n        while (stream.peek() && stream.peek() != '\\\\') {\n          output.push(stream.next());\n        }\n        var matched = false;\n        for (var matcher in unescapes) {\n          if (stream.match(matcher, true)) {\n            matched = true;\n            output.push(unescapes[matcher]);\n            break;\n          }\n        }\n        if (!matched) {\n          // Don't change anything\n          output.push(stream.next());\n        }\n      }\n      return output.join('');\n    }\n\n    /**\n     * Extract the regular expression from the query and return a Regexp object.\n     * Returns null if the query is blank.\n     * If ignoreCase is passed in, the Regexp object will have the 'i' flag set.\n     * If smartCase is passed in, and the query contains upper case letters,\n     *   then ignoreCase is overridden, and the 'i' flag will not be set.\n     * If the query contains the /i in the flag part of the regular expression,\n     *   then both ignoreCase and smartCase are ignored, and 'i' will be passed\n     *   through to the Regex object.\n     */\n    function parseQuery(query, ignoreCase, smartCase) {\n      // First update the last search register\n      var lastSearchRegister = vimGlobalState.registerController.getRegister('/');\n      lastSearchRegister.setText(query);\n      // Check if the query is already a regex.\n      if (query instanceof RegExp) { return query; }\n      // First try to extract regex + flags from the input. If no flags found,\n      // extract just the regex. IE does not accept flags directly defined in\n      // the regex string in the form /regex/flags\n      var slashes = findUnescapedSlashes(query);\n      var regexPart;\n      var forceIgnoreCase;\n      if (!slashes.length) {\n        // Query looks like 'regexp'\n        regexPart = query;\n      } else {\n        // Query looks like 'regexp/...'\n        regexPart = query.substring(0, slashes[0]);\n        var flagsPart = query.substring(slashes[0]);\n        forceIgnoreCase = (flagsPart.indexOf('i') != -1);\n      }\n      if (!regexPart) {\n        return null;\n      }\n      if (!getOption('pcre')) {\n        regexPart = translateRegex(regexPart);\n      }\n      if (smartCase) {\n        ignoreCase = (/^[^A-Z]*$/).test(regexPart);\n      }\n      var regexp = new RegExp(regexPart,\n          (ignoreCase || forceIgnoreCase) ? 'i' : undefined);\n      return regexp;\n    }\n    function showConfirm(cm, text) {\n      if (cm.openNotification) {\n        cm.openNotification('<span style=\"color: red\">' + text + '</span>',\n                            {bottom: true, duration: 5000});\n      } else {\n        alert(text);\n      }\n    }\n    function makePrompt(prefix, desc) {\n      var raw = '<span style=\"font-family: monospace; white-space: pre\">' +\n          (prefix || \"\") + '<input type=\"text\" autocorrect=\"off\" ' +\n          'autocapitalize=\"off\" spellcheck=\"false\"></span>';\n      if (desc)\n        raw += ' <span style=\"color: #888\">' + desc + '</span>';\n      return raw;\n    }\n    var searchPromptDesc = '(Javascript regexp)';\n    function showPrompt(cm, options) {\n      var shortText = (options.prefix || '') + ' ' + (options.desc || '');\n      var prompt = makePrompt(options.prefix, options.desc);\n      dialog(cm, prompt, shortText, options.onClose, options);\n    }\n    function regexEqual(r1, r2) {\n      if (r1 instanceof RegExp && r2 instanceof RegExp) {\n          var props = ['global', 'multiline', 'ignoreCase', 'source'];\n          for (var i = 0; i < props.length; i++) {\n              var prop = props[i];\n              if (r1[prop] !== r2[prop]) {\n                  return false;\n              }\n          }\n          return true;\n      }\n      return false;\n    }\n    // Returns true if the query is valid.\n    function updateSearchQuery(cm, rawQuery, ignoreCase, smartCase) {\n      if (!rawQuery) {\n        return;\n      }\n      var state = getSearchState(cm);\n      var query = parseQuery(rawQuery, !!ignoreCase, !!smartCase);\n      if (!query) {\n        return;\n      }\n      highlightSearchMatches(cm, query);\n      if (regexEqual(query, state.getQuery())) {\n        return query;\n      }\n      state.setQuery(query);\n      return query;\n    }\n    function searchOverlay(query) {\n      if (query.source.charAt(0) == '^') {\n        var matchSol = true;\n      }\n      return {\n        token: function(stream) {\n          if (matchSol && !stream.sol()) {\n            stream.skipToEnd();\n            return;\n          }\n          var match = stream.match(query, false);\n          if (match) {\n            if (match[0].length == 0) {\n              // Matched empty string, skip to next.\n              stream.next();\n              return 'searching';\n            }\n            if (!stream.sol()) {\n              // Backtrack 1 to match \\b\n              stream.backUp(1);\n              if (!query.exec(stream.next() + match[0])) {\n                stream.next();\n                return null;\n              }\n            }\n            stream.match(query);\n            return 'searching';\n          }\n          while (!stream.eol()) {\n            stream.next();\n            if (stream.match(query, false)) break;\n          }\n        },\n        query: query\n      };\n    }\n    var highlightTimeout = 0;\n    function highlightSearchMatches(cm, query) {\n      clearTimeout(highlightTimeout);\n      highlightTimeout = setTimeout(function() {\n        var searchState = getSearchState(cm);\n        var overlay = searchState.getOverlay();\n        if (!overlay || query != overlay.query) {\n          if (overlay) {\n            cm.removeOverlay(overlay);\n          }\n          overlay = searchOverlay(query);\n          cm.addOverlay(overlay);\n          if (cm.showMatchesOnScrollbar) {\n            if (searchState.getScrollbarAnnotate()) {\n              searchState.getScrollbarAnnotate().clear();\n            }\n            searchState.setScrollbarAnnotate(cm.showMatchesOnScrollbar(query));\n          }\n          searchState.setOverlay(overlay);\n        }\n      }, 50);\n    }\n    function findNext(cm, prev, query, repeat) {\n      if (repeat === undefined) { repeat = 1; }\n      return cm.operation(function() {\n        var pos = cm.getCursor();\n        var cursor = cm.getSearchCursor(query, pos);\n        for (var i = 0; i < repeat; i++) {\n          var found = cursor.find(prev);\n          if (i == 0 && found && cursorEqual(cursor.from(), pos)) { found = cursor.find(prev); }\n          if (!found) {\n            // SearchCursor may have returned null because it hit EOF, wrap\n            // around and try again.\n            cursor = cm.getSearchCursor(query,\n                (prev) ? Pos(cm.lastLine()) : Pos(cm.firstLine(), 0) );\n            if (!cursor.find(prev)) {\n              return;\n            }\n          }\n        }\n        return cursor.from();\n      });\n    }\n    function clearSearchHighlight(cm) {\n      var state = getSearchState(cm);\n      cm.removeOverlay(getSearchState(cm).getOverlay());\n      state.setOverlay(null);\n      if (state.getScrollbarAnnotate()) {\n        state.getScrollbarAnnotate().clear();\n        state.setScrollbarAnnotate(null);\n      }\n    }\n    /**\n     * Check if pos is in the specified range, INCLUSIVE.\n     * Range can be specified with 1 or 2 arguments.\n     * If the first range argument is an array, treat it as an array of line\n     * numbers. Match pos against any of the lines.\n     * If the first range argument is a number,\n     *   if there is only 1 range argument, check if pos has the same line\n     *       number\n     *   if there are 2 range arguments, then check if pos is in between the two\n     *       range arguments.\n     */\n    function isInRange(pos, start, end) {\n      if (typeof pos != 'number') {\n        // Assume it is a cursor position. Get the line number.\n        pos = pos.line;\n      }\n      if (start instanceof Array) {\n        return inArray(pos, start);\n      } else {\n        if (end) {\n          return (pos >= start && pos <= end);\n        } else {\n          return pos == start;\n        }\n      }\n    }\n    function getUserVisibleLines(cm) {\n      var scrollInfo = cm.getScrollInfo();\n      var occludeToleranceTop = 6;\n      var occludeToleranceBottom = 10;\n      var from = cm.coordsChar({left:0, top: occludeToleranceTop + scrollInfo.top}, 'local');\n      var bottomY = scrollInfo.clientHeight - occludeToleranceBottom + scrollInfo.top;\n      var to = cm.coordsChar({left:0, top: bottomY}, 'local');\n      return {top: from.line, bottom: to.line};\n    }\n\n    function getMarkPos(cm, vim, markName) {\n      if (markName == '\\'' || markName == '`') {\n        return vimGlobalState.jumpList.find(cm, -1) || Pos(0, 0);\n      } else if (markName == '.') {\n        return getLastEditPos(cm);\n      }\n\n      var mark = vim.marks[markName];\n      return mark && mark.find();\n    }\n\n    function getLastEditPos(cm) {\n      var done = cm.doc.history.done;\n      for (var i = done.length; i--;) {\n        if (done[i].changes) {\n          return copyCursor(done[i].changes[0].to);\n        }\n      }\n    }\n\n    var ExCommandDispatcher = function() {\n      this.buildCommandMap_();\n    };\n    ExCommandDispatcher.prototype = {\n      processCommand: function(cm, input, opt_params) {\n        var that = this;\n        cm.operation(function () {\n          cm.curOp.isVimOp = true;\n          that._processCommand(cm, input, opt_params);\n        });\n      },\n      _processCommand: function(cm, input, opt_params) {\n        var vim = cm.state.vim;\n        var commandHistoryRegister = vimGlobalState.registerController.getRegister(':');\n        var previousCommand = commandHistoryRegister.toString();\n        if (vim.visualMode) {\n          exitVisualMode(cm);\n        }\n        var inputStream = new CodeMirror.StringStream(input);\n        // update \": with the latest command whether valid or invalid\n        commandHistoryRegister.setText(input);\n        var params = opt_params || {};\n        params.input = input;\n        try {\n          this.parseInput_(cm, inputStream, params);\n        } catch(e) {\n          showConfirm(cm, e);\n          throw e;\n        }\n        var command;\n        var commandName;\n        if (!params.commandName) {\n          // If only a line range is defined, move to the line.\n          if (params.line !== undefined) {\n            commandName = 'move';\n          }\n        } else {\n          command = this.matchCommand_(params.commandName);\n          if (command) {\n            commandName = command.name;\n            if (command.excludeFromCommandHistory) {\n              commandHistoryRegister.setText(previousCommand);\n            }\n            this.parseCommandArgs_(inputStream, params, command);\n            if (command.type == 'exToKey') {\n              // Handle Ex to Key mapping.\n              for (var i = 0; i < command.toKeys.length; i++) {\n                CodeMirror.Vim.handleKey(cm, command.toKeys[i], 'mapping');\n              }\n              return;\n            } else if (command.type == 'exToEx') {\n              // Handle Ex to Ex mapping.\n              this.processCommand(cm, command.toInput);\n              return;\n            }\n          }\n        }\n        if (!commandName) {\n          showConfirm(cm, 'Not an editor command \":' + input + '\"');\n          return;\n        }\n        try {\n          exCommands[commandName](cm, params);\n          // Possibly asynchronous commands (e.g. substitute, which might have a\n          // user confirmation), are responsible for calling the callback when\n          // done. All others have it taken care of for them here.\n          if ((!command || !command.possiblyAsync) && params.callback) {\n            params.callback();\n          }\n        } catch(e) {\n          showConfirm(cm, e);\n          throw e;\n        }\n      },\n      parseInput_: function(cm, inputStream, result) {\n        inputStream.eatWhile(':');\n        // Parse range.\n        if (inputStream.eat('%')) {\n          result.line = cm.firstLine();\n          result.lineEnd = cm.lastLine();\n        } else {\n          result.line = this.parseLineSpec_(cm, inputStream);\n          if (result.line !== undefined && inputStream.eat(',')) {\n            result.lineEnd = this.parseLineSpec_(cm, inputStream);\n          }\n        }\n\n        // Parse command name.\n        var commandMatch = inputStream.match(/^(\\w+|!!|@@|[!#&*<=>@~])/);\n        if (commandMatch) {\n          result.commandName = commandMatch[1];\n        } else {\n          result.commandName = inputStream.match(/.*/)[0];\n        }\n\n        return result;\n      },\n      parseLineSpec_: function(cm, inputStream) {\n        var numberMatch = inputStream.match(/^(\\d+)/);\n        if (numberMatch) {\n          // Absolute line number plus offset (N+M or N-M) is probably a typo,\n          // not something the user actually wanted. (NB: vim does allow this.)\n          return parseInt(numberMatch[1], 10) - 1;\n        }\n        switch (inputStream.next()) {\n          case '.':\n            return this.parseLineSpecOffset_(inputStream, cm.getCursor().line);\n          case '$':\n            return this.parseLineSpecOffset_(inputStream, cm.lastLine());\n          case '\\'':\n            var markName = inputStream.next();\n            var markPos = getMarkPos(cm, cm.state.vim, markName);\n            if (!markPos) throw new Error('Mark not set');\n            return this.parseLineSpecOffset_(inputStream, markPos.line);\n          case '-':\n          case '+':\n            inputStream.backUp(1);\n            // Offset is relative to current line if not otherwise specified.\n            return this.parseLineSpecOffset_(inputStream, cm.getCursor().line);\n          default:\n            inputStream.backUp(1);\n            return undefined;\n        }\n      },\n      parseLineSpecOffset_: function(inputStream, line) {\n        var offsetMatch = inputStream.match(/^([+-])?(\\d+)/);\n        if (offsetMatch) {\n          var offset = parseInt(offsetMatch[2], 10);\n          if (offsetMatch[1] == \"-\") {\n            line -= offset;\n          } else {\n            line += offset;\n          }\n        }\n        return line;\n      },\n      parseCommandArgs_: function(inputStream, params, command) {\n        if (inputStream.eol()) {\n          return;\n        }\n        params.argString = inputStream.match(/.*/)[0];\n        // Parse command-line arguments\n        var delim = command.argDelimiter || /\\s+/;\n        var args = trim(params.argString).split(delim);\n        if (args.length && args[0]) {\n          params.args = args;\n        }\n      },\n      matchCommand_: function(commandName) {\n        // Return the command in the command map that matches the shortest\n        // prefix of the passed in command name. The match is guaranteed to be\n        // unambiguous if the defaultExCommandMap's shortNames are set up\n        // correctly. (see @code{defaultExCommandMap}).\n        for (var i = commandName.length; i > 0; i--) {\n          var prefix = commandName.substring(0, i);\n          if (this.commandMap_[prefix]) {\n            var command = this.commandMap_[prefix];\n            if (command.name.indexOf(commandName) === 0) {\n              return command;\n            }\n          }\n        }\n        return null;\n      },\n      buildCommandMap_: function() {\n        this.commandMap_ = {};\n        for (var i = 0; i < defaultExCommandMap.length; i++) {\n          var command = defaultExCommandMap[i];\n          var key = command.shortName || command.name;\n          this.commandMap_[key] = command;\n        }\n      },\n      map: function(lhs, rhs, ctx) {\n        if (lhs != ':' && lhs.charAt(0) == ':') {\n          if (ctx) { throw Error('Mode not supported for ex mappings'); }\n          var commandName = lhs.substring(1);\n          if (rhs != ':' && rhs.charAt(0) == ':') {\n            // Ex to Ex mapping\n            this.commandMap_[commandName] = {\n              name: commandName,\n              type: 'exToEx',\n              toInput: rhs.substring(1),\n              user: true\n            };\n          } else {\n            // Ex to key mapping\n            this.commandMap_[commandName] = {\n              name: commandName,\n              type: 'exToKey',\n              toKeys: rhs,\n              user: true\n            };\n          }\n        } else {\n          if (rhs != ':' && rhs.charAt(0) == ':') {\n            // Key to Ex mapping.\n            var mapping = {\n              keys: lhs,\n              type: 'keyToEx',\n              exArgs: { input: rhs.substring(1) }\n            };\n            if (ctx) { mapping.context = ctx; }\n            defaultKeymap.unshift(mapping);\n          } else {\n            // Key to key mapping\n            var mapping = {\n              keys: lhs,\n              type: 'keyToKey',\n              toKeys: rhs\n            };\n            if (ctx) { mapping.context = ctx; }\n            defaultKeymap.unshift(mapping);\n          }\n        }\n      },\n      unmap: function(lhs, ctx) {\n        if (lhs != ':' && lhs.charAt(0) == ':') {\n          // Ex to Ex or Ex to key mapping\n          if (ctx) { throw Error('Mode not supported for ex mappings'); }\n          var commandName = lhs.substring(1);\n          if (this.commandMap_[commandName] && this.commandMap_[commandName].user) {\n            delete this.commandMap_[commandName];\n            return;\n          }\n        } else {\n          // Key to Ex or key to key mapping\n          var keys = lhs;\n          for (var i = 0; i < defaultKeymap.length; i++) {\n            if (keys == defaultKeymap[i].keys\n                && defaultKeymap[i].context === ctx) {\n              defaultKeymap.splice(i, 1);\n              return;\n            }\n          }\n        }\n        throw Error('No such mapping.');\n      }\n    };\n\n    var exCommands = {\n      colorscheme: function(cm, params) {\n        if (!params.args || params.args.length < 1) {\n          showConfirm(cm, cm.getOption('theme'));\n          return;\n        }\n        cm.setOption('theme', params.args[0]);\n      },\n      map: function(cm, params, ctx) {\n        var mapArgs = params.args;\n        if (!mapArgs || mapArgs.length < 2) {\n          if (cm) {\n            showConfirm(cm, 'Invalid mapping: ' + params.input);\n          }\n          return;\n        }\n        exCommandDispatcher.map(mapArgs[0], mapArgs[1], ctx);\n      },\n      imap: function(cm, params) { this.map(cm, params, 'insert'); },\n      nmap: function(cm, params) { this.map(cm, params, 'normal'); },\n      vmap: function(cm, params) { this.map(cm, params, 'visual'); },\n      unmap: function(cm, params, ctx) {\n        var mapArgs = params.args;\n        if (!mapArgs || mapArgs.length < 1) {\n          if (cm) {\n            showConfirm(cm, 'No such mapping: ' + params.input);\n          }\n          return;\n        }\n        exCommandDispatcher.unmap(mapArgs[0], ctx);\n      },\n      move: function(cm, params) {\n        commandDispatcher.processCommand(cm, cm.state.vim, {\n            type: 'motion',\n            motion: 'moveToLineOrEdgeOfDocument',\n            motionArgs: { forward: false, explicitRepeat: true,\n              linewise: true },\n            repeatOverride: params.line+1});\n      },\n      set: function(cm, params) {\n        var setArgs = params.args;\n        // Options passed through to the setOption/getOption calls. May be passed in by the\n        // local/global versions of the set command\n        var setCfg = params.setCfg || {};\n        if (!setArgs || setArgs.length < 1) {\n          if (cm) {\n            showConfirm(cm, 'Invalid mapping: ' + params.input);\n          }\n          return;\n        }\n        var expr = setArgs[0].split('=');\n        var optionName = expr[0];\n        var value = expr[1];\n        var forceGet = false;\n\n        if (optionName.charAt(optionName.length - 1) == '?') {\n          // If post-fixed with ?, then the set is actually a get.\n          if (value) { throw Error('Trailing characters: ' + params.argString); }\n          optionName = optionName.substring(0, optionName.length - 1);\n          forceGet = true;\n        }\n        if (value === undefined && optionName.substring(0, 2) == 'no') {\n          // To set boolean options to false, the option name is prefixed with\n          // 'no'.\n          optionName = optionName.substring(2);\n          value = false;\n        }\n\n        var optionIsBoolean = options[optionName] && options[optionName].type == 'boolean';\n        if (optionIsBoolean && value == undefined) {\n          // Calling set with a boolean option sets it to true.\n          value = true;\n        }\n        // If no value is provided, then we assume this is a get.\n        if (!optionIsBoolean && value === undefined || forceGet) {\n          var oldValue = getOption(optionName, cm, setCfg);\n          if (oldValue instanceof Error) {\n            showConfirm(cm, oldValue.message);\n          } else if (oldValue === true || oldValue === false) {\n            showConfirm(cm, ' ' + (oldValue ? '' : 'no') + optionName);\n          } else {\n            showConfirm(cm, '  ' + optionName + '=' + oldValue);\n          }\n        } else {\n          var setOptionReturn = setOption(optionName, value, cm, setCfg);\n          if (setOptionReturn instanceof Error) {\n            showConfirm(cm, setOptionReturn.message);\n          }\n        }\n      },\n      setlocal: function (cm, params) {\n        // setCfg is passed through to setOption\n        params.setCfg = {scope: 'local'};\n        this.set(cm, params);\n      },\n      setglobal: function (cm, params) {\n        // setCfg is passed through to setOption\n        params.setCfg = {scope: 'global'};\n        this.set(cm, params);\n      },\n      registers: function(cm, params) {\n        var regArgs = params.args;\n        var registers = vimGlobalState.registerController.registers;\n        var regInfo = '----------Registers----------<br><br>';\n        if (!regArgs) {\n          for (var registerName in registers) {\n            var text = registers[registerName].toString();\n            if (text.length) {\n              regInfo += '\"' + registerName + '    ' + text + '<br>';\n            }\n          }\n        } else {\n          var registerName;\n          regArgs = regArgs.join('');\n          for (var i = 0; i < regArgs.length; i++) {\n            registerName = regArgs.charAt(i);\n            if (!vimGlobalState.registerController.isValidRegister(registerName)) {\n              continue;\n            }\n            var register = registers[registerName] || new Register();\n            regInfo += '\"' + registerName + '    ' + register.toString() + '<br>';\n          }\n        }\n        showConfirm(cm, regInfo);\n      },\n      sort: function(cm, params) {\n        var reverse, ignoreCase, unique, number, pattern;\n        function parseArgs() {\n          if (params.argString) {\n            var args = new CodeMirror.StringStream(params.argString);\n            if (args.eat('!')) { reverse = true; }\n            if (args.eol()) { return; }\n            if (!args.eatSpace()) { return 'Invalid arguments'; }\n            var opts = args.match(/([dinuox]+)?\\s*(\\/.+\\/)?\\s*/);\n            if (!opts && !args.eol()) { return 'Invalid arguments'; }\n            if (opts[1]) {\n              ignoreCase = opts[1].indexOf('i') != -1;\n              unique = opts[1].indexOf('u') != -1;\n              var decimal = opts[1].indexOf('d') != -1 || opts[1].indexOf('n') != -1 && 1;\n              var hex = opts[1].indexOf('x') != -1 && 1;\n              var octal = opts[1].indexOf('o') != -1 && 1;\n              if (decimal + hex + octal > 1) { return 'Invalid arguments'; }\n              number = decimal && 'decimal' || hex && 'hex' || octal && 'octal';\n            }\n            if (opts[2]) {\n              pattern = new RegExp(opts[2].substr(1, opts[2].length - 2), ignoreCase ? 'i' : '');\n            }\n          }\n        }\n        var err = parseArgs();\n        if (err) {\n          showConfirm(cm, err + ': ' + params.argString);\n          return;\n        }\n        var lineStart = params.line || cm.firstLine();\n        var lineEnd = params.lineEnd || params.line || cm.lastLine();\n        if (lineStart == lineEnd) { return; }\n        var curStart = Pos(lineStart, 0);\n        var curEnd = Pos(lineEnd, lineLength(cm, lineEnd));\n        var text = cm.getRange(curStart, curEnd).split('\\n');\n        var numberRegex = pattern ? pattern :\n           (number == 'decimal') ? /(-?)([\\d]+)/ :\n           (number == 'hex') ? /(-?)(?:0x)?([0-9a-f]+)/i :\n           (number == 'octal') ? /([0-7]+)/ : null;\n        var radix = (number == 'decimal') ? 10 : (number == 'hex') ? 16 : (number == 'octal') ? 8 : null;\n        var numPart = [], textPart = [];\n        if (number || pattern) {\n          for (var i = 0; i < text.length; i++) {\n            var matchPart = pattern ? text[i].match(pattern) : null;\n            if (matchPart && matchPart[0] != '') {\n              numPart.push(matchPart);\n            } else if (!pattern && numberRegex.exec(text[i])) {\n              numPart.push(text[i]);\n            } else {\n              textPart.push(text[i]);\n            }\n          }\n        } else {\n          textPart = text;\n        }\n        function compareFn(a, b) {\n          if (reverse) { var tmp; tmp = a; a = b; b = tmp; }\n          if (ignoreCase) { a = a.toLowerCase(); b = b.toLowerCase(); }\n          var anum = number && numberRegex.exec(a);\n          var bnum = number && numberRegex.exec(b);\n          if (!anum) { return a < b ? -1 : 1; }\n          anum = parseInt((anum[1] + anum[2]).toLowerCase(), radix);\n          bnum = parseInt((bnum[1] + bnum[2]).toLowerCase(), radix);\n          return anum - bnum;\n        }\n        function comparePatternFn(a, b) {\n          if (reverse) { var tmp; tmp = a; a = b; b = tmp; }\n          if (ignoreCase) { a[0] = a[0].toLowerCase(); b[0] = b[0].toLowerCase(); }\n          return (a[0] < b[0]) ? -1 : 1;\n        }\n        numPart.sort(pattern ? comparePatternFn : compareFn);\n        if (pattern) {\n          for (var i = 0; i < numPart.length; i++) {\n            numPart[i] = numPart[i].input;\n          }\n        } else if (!number) { textPart.sort(compareFn); }\n        text = (!reverse) ? textPart.concat(numPart) : numPart.concat(textPart);\n        if (unique) { // Remove duplicate lines\n          var textOld = text;\n          var lastLine;\n          text = [];\n          for (var i = 0; i < textOld.length; i++) {\n            if (textOld[i] != lastLine) {\n              text.push(textOld[i]);\n            }\n            lastLine = textOld[i];\n          }\n        }\n        cm.replaceRange(text.join('\\n'), curStart, curEnd);\n      },\n      global: function(cm, params) {\n        // a global command is of the form\n        // :[range]g/pattern/[cmd]\n        // argString holds the string /pattern/[cmd]\n        var argString = params.argString;\n        if (!argString) {\n          showConfirm(cm, 'Regular Expression missing from global');\n          return;\n        }\n        // range is specified here\n        var lineStart = (params.line !== undefined) ? params.line : cm.firstLine();\n        var lineEnd = params.lineEnd || params.line || cm.lastLine();\n        // get the tokens from argString\n        var tokens = splitBySlash(argString);\n        var regexPart = argString, cmd;\n        if (tokens.length) {\n          regexPart = tokens[0];\n          cmd = tokens.slice(1, tokens.length).join('/');\n        }\n        if (regexPart) {\n          // If regex part is empty, then use the previous query. Otherwise\n          // use the regex part as the new query.\n          try {\n           updateSearchQuery(cm, regexPart, true /** ignoreCase */,\n             true /** smartCase */);\n          } catch (e) {\n           showConfirm(cm, 'Invalid regex: ' + regexPart);\n           return;\n          }\n        }\n        // now that we have the regexPart, search for regex matches in the\n        // specified range of lines\n        var query = getSearchState(cm).getQuery();\n        var matchedLines = [], content = '';\n        for (var i = lineStart; i <= lineEnd; i++) {\n          var matched = query.test(cm.getLine(i));\n          if (matched) {\n            matchedLines.push(i+1);\n            content+= cm.getLine(i) + '<br>';\n          }\n        }\n        // if there is no [cmd], just display the list of matched lines\n        if (!cmd) {\n          showConfirm(cm, content);\n          return;\n        }\n        var index = 0;\n        var nextCommand = function() {\n          if (index < matchedLines.length) {\n            var command = matchedLines[index] + cmd;\n            exCommandDispatcher.processCommand(cm, command, {\n              callback: nextCommand\n            });\n          }\n          index++;\n        };\n        nextCommand();\n      },\n      substitute: function(cm, params) {\n        if (!cm.getSearchCursor) {\n          throw new Error('Search feature not available. Requires searchcursor.js or ' +\n              'any other getSearchCursor implementation.');\n        }\n        var argString = params.argString;\n        var tokens = argString ? splitBySeparator(argString, argString[0]) : [];\n        var regexPart, replacePart = '', trailing, flagsPart, count;\n        var confirm = false; // Whether to confirm each replace.\n        var global = false; // True to replace all instances on a line, false to replace only 1.\n        if (tokens.length) {\n          regexPart = tokens[0];\n          if (getOption('pcre') && regexPart !== '') {\n              regexPart = new RegExp(regexPart).source; //normalize not escaped characters\n          }\n          replacePart = tokens[1];\n          if (regexPart && regexPart[regexPart.length - 1] === '$') {\n            regexPart = regexPart.slice(0, regexPart.length - 1) + '\\\\n';\n            replacePart = replacePart ? replacePart + '\\n' : '\\n';\n          }\n          if (replacePart !== undefined) {\n            if (getOption('pcre')) {\n              replacePart = unescapeRegexReplace(replacePart.replace(/([^\\\\])&/g,\"$1$$&\"));\n            } else {\n              replacePart = translateRegexReplace(replacePart);\n            }\n            vimGlobalState.lastSubstituteReplacePart = replacePart;\n          }\n          trailing = tokens[2] ? tokens[2].split(' ') : [];\n        } else {\n          // either the argString is empty or its of the form ' hello/world'\n          // actually splitBySlash returns a list of tokens\n          // only if the string starts with a '/'\n          if (argString && argString.length) {\n            showConfirm(cm, 'Substitutions should be of the form ' +\n                ':s/pattern/replace/');\n            return;\n          }\n        }\n        // After the 3rd slash, we can have flags followed by a space followed\n        // by count.\n        if (trailing) {\n          flagsPart = trailing[0];\n          count = parseInt(trailing[1]);\n          if (flagsPart) {\n            if (flagsPart.indexOf('c') != -1) {\n              confirm = true;\n              flagsPart.replace('c', '');\n            }\n            if (flagsPart.indexOf('g') != -1) {\n              global = true;\n              flagsPart.replace('g', '');\n            }\n            if (getOption('pcre')) {\n               regexPart = regexPart + '/' + flagsPart;\n            } else {\n               regexPart = regexPart.replace(/\\//g, \"\\\\/\") + '/' + flagsPart;\n            }\n          }\n        }\n        if (regexPart) {\n          // If regex part is empty, then use the previous query. Otherwise use\n          // the regex part as the new query.\n          try {\n            updateSearchQuery(cm, regexPart, true /** ignoreCase */,\n              true /** smartCase */);\n          } catch (e) {\n            showConfirm(cm, 'Invalid regex: ' + regexPart);\n            return;\n          }\n        }\n        replacePart = replacePart || vimGlobalState.lastSubstituteReplacePart;\n        if (replacePart === undefined) {\n          showConfirm(cm, 'No previous substitute regular expression');\n          return;\n        }\n        var state = getSearchState(cm);\n        var query = state.getQuery();\n        var lineStart = (params.line !== undefined) ? params.line : cm.getCursor().line;\n        var lineEnd = params.lineEnd || lineStart;\n        if (lineStart == cm.firstLine() && lineEnd == cm.lastLine()) {\n          lineEnd = Infinity;\n        }\n        if (count) {\n          lineStart = lineEnd;\n          lineEnd = lineStart + count - 1;\n        }\n        var startPos = clipCursorToContent(cm, Pos(lineStart, 0));\n        var cursor = cm.getSearchCursor(query, startPos);\n        doReplace(cm, confirm, global, lineStart, lineEnd, cursor, query, replacePart, params.callback);\n      },\n      redo: CodeMirror.commands.redo,\n      undo: CodeMirror.commands.undo,\n      write: function(cm) {\n        if (CodeMirror.commands.save) {\n          // If a save command is defined, call it.\n          CodeMirror.commands.save(cm);\n        } else if (cm.save) {\n          // Saves to text area if no save command is defined and cm.save() is available.\n          cm.save();\n        }\n      },\n      nohlsearch: function(cm) {\n        clearSearchHighlight(cm);\n      },\n      yank: function (cm) {\n        var cur = copyCursor(cm.getCursor());\n        var line = cur.line;\n        var lineText = cm.getLine(line);\n        vimGlobalState.registerController.pushText(\n          '0', 'yank', lineText, true, true);\n      },\n      delmarks: function(cm, params) {\n        if (!params.argString || !trim(params.argString)) {\n          showConfirm(cm, 'Argument required');\n          return;\n        }\n\n        var state = cm.state.vim;\n        var stream = new CodeMirror.StringStream(trim(params.argString));\n        while (!stream.eol()) {\n          stream.eatSpace();\n\n          // Record the streams position at the beginning of the loop for use\n          // in error messages.\n          var count = stream.pos;\n\n          if (!stream.match(/[a-zA-Z]/, false)) {\n            showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));\n            return;\n          }\n\n          var sym = stream.next();\n          // Check if this symbol is part of a range\n          if (stream.match('-', true)) {\n            // This symbol is part of a range.\n\n            // The range must terminate at an alphabetic character.\n            if (!stream.match(/[a-zA-Z]/, false)) {\n              showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));\n              return;\n            }\n\n            var startMark = sym;\n            var finishMark = stream.next();\n            // The range must terminate at an alphabetic character which\n            // shares the same case as the start of the range.\n            if (isLowerCase(startMark) && isLowerCase(finishMark) ||\n                isUpperCase(startMark) && isUpperCase(finishMark)) {\n              var start = startMark.charCodeAt(0);\n              var finish = finishMark.charCodeAt(0);\n              if (start >= finish) {\n                showConfirm(cm, 'Invalid argument: ' + params.argString.substring(count));\n                return;\n              }\n\n              // Because marks are always ASCII values, and we have\n              // determined that they are the same case, we can use\n              // their char codes to iterate through the defined range.\n              for (var j = 0; j <= finish - start; j++) {\n                var mark = String.fromCharCode(start + j);\n                delete state.marks[mark];\n              }\n            } else {\n              showConfirm(cm, 'Invalid argument: ' + startMark + '-');\n              return;\n            }\n          } else {\n            // This symbol is a valid mark, and is not part of a range.\n            delete state.marks[sym];\n          }\n        }\n      }\n    };\n\n    var exCommandDispatcher = new ExCommandDispatcher();\n\n    /**\n    * @param {CodeMirror} cm CodeMirror instance we are in.\n    * @param {boolean} confirm Whether to confirm each replace.\n    * @param {Cursor} lineStart Line to start replacing from.\n    * @param {Cursor} lineEnd Line to stop replacing at.\n    * @param {RegExp} query Query for performing matches with.\n    * @param {string} replaceWith Text to replace matches with. May contain $1,\n    *     $2, etc for replacing captured groups using Javascript replace.\n    * @param {function()} callback A callback for when the replace is done.\n    */\n    function doReplace(cm, confirm, global, lineStart, lineEnd, searchCursor, query,\n        replaceWith, callback) {\n      // Set up all the functions.\n      cm.state.vim.exMode = true;\n      var done = false;\n      var lastPos = searchCursor.from();\n      function replaceAll() {\n        cm.operation(function() {\n          while (!done) {\n            replace();\n            next();\n          }\n          stop();\n        });\n      }\n      function replace() {\n        var text = cm.getRange(searchCursor.from(), searchCursor.to());\n        var newText = text.replace(query, replaceWith);\n        searchCursor.replace(newText);\n      }\n      function next() {\n        // The below only loops to skip over multiple occurrences on the same\n        // line when 'global' is not true.\n        while(searchCursor.findNext() &&\n              isInRange(searchCursor.from(), lineStart, lineEnd)) {\n          if (!global && lastPos && searchCursor.from().line == lastPos.line) {\n            continue;\n          }\n          cm.scrollIntoView(searchCursor.from(), 30);\n          cm.setSelection(searchCursor.from(), searchCursor.to());\n          lastPos = searchCursor.from();\n          done = false;\n          return;\n        }\n        done = true;\n      }\n      function stop(close) {\n        if (close) { close(); }\n        cm.focus();\n        if (lastPos) {\n          cm.setCursor(lastPos);\n          var vim = cm.state.vim;\n          vim.exMode = false;\n          vim.lastHPos = vim.lastHSPos = lastPos.ch;\n        }\n        if (callback) { callback(); }\n      }\n      function onPromptKeyDown(e, _value, close) {\n        // Swallow all keys.\n        CodeMirror.e_stop(e);\n        var keyName = CodeMirror.keyName(e);\n        switch (keyName) {\n          case 'Y':\n            replace(); next(); break;\n          case 'N':\n            next(); break;\n          case 'A':\n            // replaceAll contains a call to close of its own. We don't want it\n            // to fire too early or multiple times.\n            var savedCallback = callback;\n            callback = undefined;\n            cm.operation(replaceAll);\n            callback = savedCallback;\n            break;\n          case 'L':\n            replace();\n            // fall through and exit.\n          case 'Q':\n          case 'Esc':\n          case 'Ctrl-C':\n          case 'Ctrl-[':\n            stop(close);\n            break;\n        }\n        if (done) { stop(close); }\n        return true;\n      }\n\n      // Actually do replace.\n      next();\n      if (done) {\n        showConfirm(cm, 'No matches for ' + query.source);\n        return;\n      }\n      if (!confirm) {\n        replaceAll();\n        if (callback) { callback(); }\n        return;\n      }\n      showPrompt(cm, {\n        prefix: 'replace with <strong>' + replaceWith + '</strong> (y/n/a/q/l)',\n        onKeyDown: onPromptKeyDown\n      });\n    }\n\n    CodeMirror.keyMap.vim = {\n      attach: attachVimMap,\n      detach: detachVimMap,\n      call: cmKey\n    };\n\n    function exitInsertMode(cm) {\n      var vim = cm.state.vim;\n      var macroModeState = vimGlobalState.macroModeState;\n      var insertModeChangeRegister = vimGlobalState.registerController.getRegister('.');\n      var isPlaying = macroModeState.isPlaying;\n      var lastChange = macroModeState.lastInsertModeChanges;\n      if (!isPlaying) {\n        cm.off('change', onChange);\n        CodeMirror.off(cm.getInputField(), 'keydown', onKeyEventTargetKeyDown);\n      }\n      if (!isPlaying && vim.insertModeRepeat > 1) {\n        // Perform insert mode repeat for commands like 3,a and 3,o.\n        repeatLastEdit(cm, vim, vim.insertModeRepeat - 1,\n            true /** repeatForInsert */);\n        vim.lastEditInputState.repeatOverride = vim.insertModeRepeat;\n      }\n      delete vim.insertModeRepeat;\n      vim.insertMode = false;\n      cm.setCursor(cm.getCursor().line, cm.getCursor().ch-1);\n      cm.setOption('keyMap', 'vim');\n      cm.setOption('disableInput', true);\n      cm.toggleOverwrite(false); // exit replace mode if we were in it.\n      // update the \". register before exiting insert mode\n      insertModeChangeRegister.setText(lastChange.changes.join(''));\n      CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"normal\"});\n      if (macroModeState.isRecording) {\n        logInsertModeChange(macroModeState);\n      }\n    }\n\n    function _mapCommand(command) {\n      defaultKeymap.unshift(command);\n    }\n\n    function mapCommand(keys, type, name, args, extra) {\n      var command = {keys: keys, type: type};\n      command[type] = name;\n      command[type + \"Args\"] = args;\n      for (var key in extra)\n        command[key] = extra[key];\n      _mapCommand(command);\n    }\n\n    // The timeout in milliseconds for the two-character ESC keymap should be\n    // adjusted according to your typing speed to prevent false positives.\n    defineOption('insertModeEscKeysTimeout', 200, 'number');\n\n    CodeMirror.keyMap['vim-insert'] = {\n      // TODO: override navigation keys so that Esc will cancel automatic\n      // indentation from o, O, i_<CR>\n      fallthrough: ['default'],\n      attach: attachVimMap,\n      detach: detachVimMap,\n      call: cmKey\n    };\n\n    CodeMirror.keyMap['vim-replace'] = {\n      'Backspace': 'goCharLeft',\n      fallthrough: ['vim-insert'],\n      attach: attachVimMap,\n      detach: detachVimMap,\n      call: cmKey\n    };\n\n    function executeMacroRegister(cm, vim, macroModeState, registerName) {\n      var register = vimGlobalState.registerController.getRegister(registerName);\n      if (registerName == ':') {\n        // Read-only register containing last Ex command.\n        if (register.keyBuffer[0]) {\n          exCommandDispatcher.processCommand(cm, register.keyBuffer[0]);\n        }\n        macroModeState.isPlaying = false;\n        return;\n      }\n      var keyBuffer = register.keyBuffer;\n      var imc = 0;\n      macroModeState.isPlaying = true;\n      macroModeState.replaySearchQueries = register.searchQueries.slice(0);\n      for (var i = 0; i < keyBuffer.length; i++) {\n        var text = keyBuffer[i];\n        var match, key;\n        while (text) {\n          // Pull off one command key, which is either a single character\n          // or a special sequence wrapped in '<' and '>', e.g. '<Space>'.\n          match = (/<\\w+-.+?>|<\\w+>|./).exec(text);\n          key = match[0];\n          text = text.substring(match.index + key.length);\n          CodeMirror.Vim.handleKey(cm, key, 'macro');\n          if (vim.insertMode) {\n            var changes = register.insertModeChanges[imc++].changes;\n            vimGlobalState.macroModeState.lastInsertModeChanges.changes =\n                changes;\n            repeatInsertModeChanges(cm, changes, 1);\n            exitInsertMode(cm);\n          }\n        }\n      }\n      macroModeState.isPlaying = false;\n    }\n\n    function logKey(macroModeState, key) {\n      if (macroModeState.isPlaying) { return; }\n      var registerName = macroModeState.latestRegister;\n      var register = vimGlobalState.registerController.getRegister(registerName);\n      if (register) {\n        register.pushText(key);\n      }\n    }\n\n    function logInsertModeChange(macroModeState) {\n      if (macroModeState.isPlaying) { return; }\n      var registerName = macroModeState.latestRegister;\n      var register = vimGlobalState.registerController.getRegister(registerName);\n      if (register && register.pushInsertModeChanges) {\n        register.pushInsertModeChanges(macroModeState.lastInsertModeChanges);\n      }\n    }\n\n    function logSearchQuery(macroModeState, query) {\n      if (macroModeState.isPlaying) { return; }\n      var registerName = macroModeState.latestRegister;\n      var register = vimGlobalState.registerController.getRegister(registerName);\n      if (register && register.pushSearchQuery) {\n        register.pushSearchQuery(query);\n      }\n    }\n\n    /**\n     * Listens for changes made in insert mode.\n     * Should only be active in insert mode.\n     */\n    function onChange(cm, changeObj) {\n      var macroModeState = vimGlobalState.macroModeState;\n      var lastChange = macroModeState.lastInsertModeChanges;\n      if (!macroModeState.isPlaying) {\n        while(changeObj) {\n          lastChange.expectCursorActivityForChange = true;\n          if (lastChange.ignoreCount > 1) {\n            lastChange.ignoreCount--;\n          } else if (changeObj.origin == '+input' || changeObj.origin == 'paste'\n              || changeObj.origin === undefined /* only in testing */) {\n            var selectionCount = cm.listSelections().length;\n            if (selectionCount > 1)\n              lastChange.ignoreCount = selectionCount;\n            var text = changeObj.text.join('\\n');\n            if (lastChange.maybeReset) {\n              lastChange.changes = [];\n              lastChange.maybeReset = false;\n            }\n            if (text) {\n              if (cm.state.overwrite && !/\\n/.test(text)) {\n                lastChange.changes.push([text]);\n              } else {\n                lastChange.changes.push(text);\n              }\n            }\n          }\n          // Change objects may be chained with next.\n          changeObj = changeObj.next;\n        }\n      }\n    }\n\n    /**\n    * Listens for any kind of cursor activity on CodeMirror.\n    */\n    function onCursorActivity(cm) {\n      var vim = cm.state.vim;\n      if (vim.insertMode) {\n        // Tracking cursor activity in insert mode (for macro support).\n        var macroModeState = vimGlobalState.macroModeState;\n        if (macroModeState.isPlaying) { return; }\n        var lastChange = macroModeState.lastInsertModeChanges;\n        if (lastChange.expectCursorActivityForChange) {\n          lastChange.expectCursorActivityForChange = false;\n        } else {\n          // Cursor moved outside the context of an edit. Reset the change.\n          lastChange.maybeReset = true;\n        }\n      } else if (!cm.curOp.isVimOp) {\n        handleExternalSelection(cm, vim);\n      }\n      if (vim.visualMode) {\n        updateFakeCursor(cm);\n      }\n    }\n    /**\n     * Keeps track of a fake cursor to support visual mode cursor behavior.\n     */\n    function updateFakeCursor(cm) {\n      var className = 'cm-animate-fat-cursor';\n      var vim = cm.state.vim;\n      var from = clipCursorToContent(cm, copyCursor(vim.sel.head));\n      var to = offsetCursor(from, 0, 1);\n      clearFakeCursor(vim);\n      // In visual mode, the cursor may be positioned over EOL.\n      if (from.ch == cm.getLine(from.line).length) {\n        var widget = document.createElement(\"span\");\n        widget.textContent = \"\\u00a0\";\n        widget.className = className;\n        vim.fakeCursorBookmark = cm.setBookmark(from, {widget: widget});\n      } else {\n        vim.fakeCursor = cm.markText(from, to, {className: className});\n      }\n    }\n    function clearFakeCursor(vim) {\n      if (vim.fakeCursor) {\n        vim.fakeCursor.clear();\n        vim.fakeCursor = null;\n      }\n      if (vim.fakeCursorBookmark) {\n        vim.fakeCursorBookmark.clear();\n        vim.fakeCursorBookmark = null;\n      }\n    }\n    function handleExternalSelection(cm, vim) {\n      var anchor = cm.getCursor('anchor');\n      var head = cm.getCursor('head');\n      // Enter or exit visual mode to match mouse selection.\n      if (vim.visualMode && !cm.somethingSelected()) {\n        exitVisualMode(cm, false);\n      } else if (!vim.visualMode && !vim.insertMode && cm.somethingSelected()) {\n        vim.visualMode = true;\n        vim.visualLine = false;\n        CodeMirror.signal(cm, \"vim-mode-change\", {mode: \"visual\"});\n      }\n      if (vim.visualMode) {\n        // Bind CodeMirror selection model to vim selection model.\n        // Mouse selections are considered visual characterwise.\n        var headOffset = !cursorIsBefore(head, anchor) ? -1 : 0;\n        var anchorOffset = cursorIsBefore(head, anchor) ? -1 : 0;\n        head = offsetCursor(head, 0, headOffset);\n        anchor = offsetCursor(anchor, 0, anchorOffset);\n        vim.sel = {\n          anchor: anchor,\n          head: head\n        };\n        updateMark(cm, vim, '<', cursorMin(head, anchor));\n        updateMark(cm, vim, '>', cursorMax(head, anchor));\n      } else if (!vim.insertMode) {\n        // Reset lastHPos if selection was modified by something outside of vim mode e.g. by mouse.\n        vim.lastHPos = cm.getCursor().ch;\n      }\n    }\n\n    /** Wrapper for special keys pressed in insert mode */\n    function InsertModeKey(keyName) {\n      this.keyName = keyName;\n    }\n\n    /**\n    * Handles raw key down events from the text area.\n    * - Should only be active in insert mode.\n    * - For recording deletes in insert mode.\n    */\n    function onKeyEventTargetKeyDown(e) {\n      var macroModeState = vimGlobalState.macroModeState;\n      var lastChange = macroModeState.lastInsertModeChanges;\n      var keyName = CodeMirror.keyName(e);\n      if (!keyName) { return; }\n      function onKeyFound() {\n        if (lastChange.maybeReset) {\n          lastChange.changes = [];\n          lastChange.maybeReset = false;\n        }\n        lastChange.changes.push(new InsertModeKey(keyName));\n        return true;\n      }\n      if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) {\n        CodeMirror.lookupKey(keyName, 'vim-insert', onKeyFound);\n      }\n    }\n\n    /**\n     * Repeats the last edit, which includes exactly 1 command and at most 1\n     * insert. Operator and motion commands are read from lastEditInputState,\n     * while action commands are read from lastEditActionCommand.\n     *\n     * If repeatForInsert is true, then the function was called by\n     * exitInsertMode to repeat the insert mode changes the user just made. The\n     * corresponding enterInsertMode call was made with a count.\n     */\n    function repeatLastEdit(cm, vim, repeat, repeatForInsert) {\n      var macroModeState = vimGlobalState.macroModeState;\n      macroModeState.isPlaying = true;\n      var isAction = !!vim.lastEditActionCommand;\n      var cachedInputState = vim.inputState;\n      function repeatCommand() {\n        if (isAction) {\n          commandDispatcher.processAction(cm, vim, vim.lastEditActionCommand);\n        } else {\n          commandDispatcher.evalInput(cm, vim);\n        }\n      }\n      function repeatInsert(repeat) {\n        if (macroModeState.lastInsertModeChanges.changes.length > 0) {\n          // For some reason, repeat cw in desktop VIM does not repeat\n          // insert mode changes. Will conform to that behavior.\n          repeat = !vim.lastEditActionCommand ? 1 : repeat;\n          var changeObject = macroModeState.lastInsertModeChanges;\n          repeatInsertModeChanges(cm, changeObject.changes, repeat);\n        }\n      }\n      vim.inputState = vim.lastEditInputState;\n      if (isAction && vim.lastEditActionCommand.interlaceInsertRepeat) {\n        // o and O repeat have to be interlaced with insert repeats so that the\n        // insertions appear on separate lines instead of the last line.\n        for (var i = 0; i < repeat; i++) {\n          repeatCommand();\n          repeatInsert(1);\n        }\n      } else {\n        if (!repeatForInsert) {\n          // Hack to get the cursor to end up at the right place. If I is\n          // repeated in insert mode repeat, cursor will be 1 insert\n          // change set left of where it should be.\n          repeatCommand();\n        }\n        repeatInsert(repeat);\n      }\n      vim.inputState = cachedInputState;\n      if (vim.insertMode && !repeatForInsert) {\n        // Don't exit insert mode twice. If repeatForInsert is set, then we\n        // were called by an exitInsertMode call lower on the stack.\n        exitInsertMode(cm);\n      }\n      macroModeState.isPlaying = false;\n    }\n\n    function repeatInsertModeChanges(cm, changes, repeat) {\n      function keyHandler(binding) {\n        if (typeof binding == 'string') {\n          CodeMirror.commands[binding](cm);\n        } else {\n          binding(cm);\n        }\n        return true;\n      }\n      var head = cm.getCursor('head');\n      var visualBlock = vimGlobalState.macroModeState.lastInsertModeChanges.visualBlock;\n      if (visualBlock) {\n        // Set up block selection again for repeating the changes.\n        selectForInsert(cm, head, visualBlock + 1);\n        repeat = cm.listSelections().length;\n        cm.setCursor(head);\n      }\n      for (var i = 0; i < repeat; i++) {\n        if (visualBlock) {\n          cm.setCursor(offsetCursor(head, i, 0));\n        }\n        for (var j = 0; j < changes.length; j++) {\n          var change = changes[j];\n          if (change instanceof InsertModeKey) {\n            CodeMirror.lookupKey(change.keyName, 'vim-insert', keyHandler);\n          } else if (typeof change == \"string\") {\n            var cur = cm.getCursor();\n            cm.replaceRange(change, cur, cur);\n          } else {\n            var start = cm.getCursor();\n            var end = offsetCursor(start, 0, change[0].length);\n            cm.replaceRange(change[0], start, end);\n          }\n        }\n      }\n      if (visualBlock) {\n        cm.setCursor(offsetCursor(head, 0, 1));\n      }\n    }\n\n    resetVimGlobalState();\n    return vimApi;\n  };\n  // Initialize Vim and make it available as an API.\n  CodeMirror.Vim = Vim();\n});\n"]}