diff --git a/dev/cm5/index.js b/dev/cm5/index.js index 9b114ee..2d1dd39 100644 --- a/dev/cm5/index.js +++ b/dev/cm5/index.js @@ -1,6 +1,128 @@ import { initVim as initVimInternal } from "../../src/vim.js"; -export function initVim(CodeMirror5) { - CodeMirror5.Vim = initVimInternal(CodeMirror5); - return CodeMirror5.Vim; +export function initVim(CodeMirror) { + var Vim = CodeMirror.Vim = initVimInternal(CodeMirror); + var Pos = CodeMirror.Pos; + + function transformCursor(cm, range) { + var vim = cm.state.vim; + if (!vim || vim.insertMode) return range.head; + var head = vim.sel.head; + if (!head) return range.head; + + if (vim.visualBlock) { + if (range.head.line != head.line) { + return; + } + } + if (range.from() == range.anchor && !range.empty()) { + if (range.head.line == head.line && range.head.ch != head.ch) + return new Pos(range.head.line, range.head.ch - 1); + } + + return range.head; + } + + CodeMirror.keyMap['vim-insert'] = { + // TODO: override navigation keys so that Esc will cancel automatic + // indentation from o, O, i_ + fallthrough: ['default'], + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + CodeMirror.keyMap['vim-replace'] = { + 'Backspace': 'goCharLeft', + fallthrough: ['vim-insert'], + attach: attachVimMap, + detach: detachVimMap + }; + + + CodeMirror.keyMap.vim = { + attach: attachVimMap, + detach: detachVimMap, + call: cmKey + }; + + // Deprecated, simply setting the keymap works again. + CodeMirror.defineOption('vimMode', false, function(cm, val, prev) { + if (val && cm.getOption("keyMap") != "vim") + cm.setOption("keyMap", "vim"); + else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap"))) + cm.setOption("keyMap", "default"); + }); + + function cmKey(key, cm) { + if (!cm) { return undefined; } + if (this[key]) { return this[key]; } + var vimKey = cmKeyToVimKey(key); + if (!vimKey) { + return false; + } + var cmd = Vim.findKey(cm, vimKey); + if (typeof cmd == 'function') { + CodeMirror.signal(cm, 'vim-keypress', vimKey); + } + return cmd; + } + + var modifiers = {Shift:'S',Ctrl:'C',Alt:'A',Cmd:'D',Mod:'A',CapsLock:''}; + var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del',Insert:'Ins'}; + + function cmKeyToVimKey(key) { + if (key.charAt(0) == '\'') { + // Keypress character binding of format "'a'" + return key.charAt(1); + } + var pieces = key.split(/-(?!$)/); + var lastPiece = pieces[pieces.length - 1]; + if (pieces.length == 1 && pieces[0].length == 1) { + // No-modifier bindings use literal character bindings above. Skip. + return false; + } else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) { + // Ignore Shift+char bindings as they should be handled by literal character. + return false; + } + var hasCharacter = false; + for (var i = 0; i < pieces.length; i++) { + var piece = pieces[i]; + if (piece in modifiers) { pieces[i] = modifiers[piece]; } + else { hasCharacter = true; } + if (piece in specialKeys) { pieces[i] = specialKeys[piece]; } + } + if (!hasCharacter) { + // Vim does not support modifier only keys. + return false; + } + // TODO: Current bindings expect the character to be lower case, but + // it looks like vim key notation uses upper case. + if (/^[A-Z]$/.test(lastPiece)) + pieces[pieces.length - 1] = lastPiece.toLowerCase(); + + return '<' + pieces.join('-') + '>'; + } + + function detachVimMap(cm, next) { + if (this == CodeMirror.keyMap.vim) { + cm.options.$customCursor = null; + CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor"); + } + + if (!next || next.attach != attachVimMap) + Vim.leaveVimMode(cm); + } + function attachVimMap(cm, prev) { + if (this == CodeMirror.keyMap.vim) { + if (cm.curOp) cm.curOp.selectionChanged = true; + cm.options.$customCursor = transformCursor; + CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor"); + } + + if (!prev || prev.attach != attachVimMap) + Vim.enterVimMode(cm); + } + + return CodeMirror.Vim; } diff --git a/src/cm_adapter.ts b/src/cm_adapter.ts index 3fb5332..d74836b 100644 --- a/src/cm_adapter.ts +++ b/src/cm_adapter.ts @@ -66,15 +66,6 @@ function signalTo(handlers: any, ...args: any[]) { for (var i = 0; i < handlers.length; ++i) { handlers[i](...args); } } -var specialKey: any = { - Return: 'CR', Backspace: 'BS', 'Delete': 'Del', Escape: 'Esc', Insert: 'Ins', - ArrowLeft: 'Left', ArrowRight: 'Right', ArrowUp: 'Up', ArrowDown: 'Down', - Enter: 'CR', ' ': 'Space' -}; -var ignoredKeys: any = { Shift: 1, Alt: 1, Command: 1, Control: 1, - CapsLock: 1, AltGraph: 1, Dead: 1, Unidentified: 1 }; - - let wordChar: RegExp try { wordChar = new RegExp("[\\w\\p{Alphabetic}\\p{Number}_]", "u") @@ -170,45 +161,6 @@ export class CodeMirror { e?.stopPropagation?.() e?.preventDefault?.() }; - static keyName = function (e: KeyboardEvent) { - var key = e.key; - if (ignoredKeys[key]) return; - if (key == "Escape") key = "Esc"; - if (key == " ") key = "Space"; - if (key.length > 1) { - key = key.replace(/Numpad|Arrow/, ""); - } - if (key.length == 1) key = key.toUpperCase(); - var name = ''; - if (e.ctrlKey) { name += 'Ctrl-'; } - if (e.altKey) { name += 'Alt-'; } - if ((name || key.length > 1) && e.shiftKey) { name += 'Shift-'; } - name += key; - return name; - }; - static vimKey = function vimKey(e: KeyboardEvent) { - var key = e.key; - if (ignoredKeys[key]) return; - if (key.length > 1 && key[0] == "n") { - key = key.replace("Numpad", ""); - } - key = specialKey[key] || key; - var name = ''; - if (e.ctrlKey) { name += 'C-'; } - if (e.altKey) { name += 'A-'; } - if (e.metaKey) { name += 'M-'; } - // on mac many characters are entered as option- combos - // (e.g. on swiss keyboard { is option-8) - // so we ignore lonely A- modifier for keypress event on mac - if (CodeMirror.isMac && e.altKey && !e.metaKey && !e.ctrlKey) { - name = name.slice(2); - } - if ((name || key.length > 1) && e.shiftKey) { name += 'S-'; } - - name += key; - if (name.length > 1) { name = '<' + name + '>'; } - return name; - }; static lookupKey = function lookupKey(key: string, map: string, handle: Function) { var result = CodeMirror.keys[key]; diff --git a/src/index.ts b/src/index.ts index d652311..366f4a2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -197,14 +197,12 @@ const vimPlugin = ViewPlugin.fromClass( decorations = Decoration.none; waitForCopy = false; handleKey(e: KeyboardEvent, view: EditorView) { - const rawKey = CodeMirror.vimKey(e); - if (!rawKey) return; - const cm = this.cm; let vim = cm.state.vim; if (!vim) return; - const key = vim.expectLiteralNext ? rawKey : Vim.langmapRemapKey(rawKey); + const key = Vim.vimKeyFromEvent(e, vim); + if (!key) return; // clear search highlight if ( @@ -253,6 +251,7 @@ const vimPlugin = ViewPlugin.fromClass( } lastKeydown = '' useNextTextInput = false + compositionText = '' }, { eventHandlers: { @@ -307,6 +306,20 @@ const vimPlugin = ViewPlugin.fromClass( return true; } if (text.length == 1 && vimPlugin.useNextTextInput) { + if (vim.expectLiteralNext && view.composing) { + vimPlugin.compositionText = text; + return false + } + if (vimPlugin.compositionText) { + var toRemove = vimPlugin.compositionText; + vimPlugin.compositionText = ''; + var head = view.state.selection.main.head + var textInDoc = view.state.sliceDoc(head - toRemove.length, head); + if (toRemove === textInDoc) { + var pos = cm.getCursor(); + cm.replaceRange('', cm.posFromIndex(head - toRemove.length), pos); + } + } vimPlugin.handleKey({ key: text, preventDefault: ()=>{}, diff --git a/src/vim.js b/src/vim.js index 9d243cc..7e30de3 100644 --- a/src/vim.js +++ b/src/vim.js @@ -38,25 +38,6 @@ export function initVim(CodeMirror) { var Pos = CodeMirror.Pos; - function transformCursor(cm, range) { - var vim = cm.state.vim; - if (!vim || vim.insertMode) return range.head; - var head = vim.sel.head; - if (!head) return range.head; - - if (vim.visualBlock) { - if (range.head.line != head.line) { - return; - } - } - if (range.from() == range.anchor && !range.empty()) { - if (range.head.line == head.line && range.head.ch != head.ch) - return new Pos(range.head.line, range.head.ch - 1); - } - - return range.head; - } - function updateSelectionForSurrogateCharacters(cm, curStart, curEnd) { // start and character position when no selection // is the same in visual mode, and differs in 1 character in normal mode @@ -308,8 +289,7 @@ export function initVim(CodeMirror) { * Determines how to interpret keystrokes in Normal and Visual mode. * Useful for people who use a different keyboard layout than QWERTY */ - var langmap; - updateLangmap(''); + var langmap = parseLangmap(''); function enterVimMode(cm) { cm.setOption('disableInput', true); @@ -328,88 +308,6 @@ export function initVim(CodeMirror) { if (highlightTimeout) clearTimeout(highlightTimeout); } - function detachVimMap(cm, next) { - if (this == CodeMirror.keyMap.vim) { - cm.options.$customCursor = null; - CodeMirror.rmClass(cm.getWrapperElement(), "cm-fat-cursor"); - } - - if (!next || next.attach != attachVimMap) - leaveVimMode(cm); - } - function attachVimMap(cm, prev) { - if (this == CodeMirror.keyMap.vim) { - if (cm.curOp) cm.curOp.selectionChanged = true; - cm.options.$customCursor = transformCursor; - CodeMirror.addClass(cm.getWrapperElement(), "cm-fat-cursor"); - } - - if (!prev || prev.attach != attachVimMap) - enterVimMode(cm); - } - - // Deprecated, simply setting the keymap works again. - CodeMirror.defineOption('vimMode', false, function(cm, val, prev) { - if (val && cm.getOption("keyMap") != "vim") - cm.setOption("keyMap", "vim"); - else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap"))) - cm.setOption("keyMap", "default"); - }); - - function cmKey(key, cm) { - if (!cm) { return undefined; } - if (this[key]) { return this[key]; } - var vimKey = cmKeyToVimKey(key); - if (!vimKey) { - return false; - } - var cmd = vimApi.findKey(cm, vimKey); - if (typeof cmd == 'function') { - CodeMirror.signal(cm, 'vim-keypress', vimKey); - } - return cmd; - } - - var modifiers = {Shift:'S',Ctrl:'C',Alt:'A',Cmd:'D',Mod:'A',CapsLock:''}; - var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del',Insert:'Ins'}; - var vimToCmKeyMap = {}; - 'Left|Right|Up|Down|End|Home'.split('|').concat(Object.keys(specialKeys)).forEach(function(x) { - vimToCmKeyMap[(specialKeys[x] || '').toLowerCase()] - = vimToCmKeyMap[x.toLowerCase()] = x; - }); - function cmKeyToVimKey(key) { - if (key.charAt(0) == '\'') { - // Keypress character binding of format "'a'" - return key.charAt(1); - } - var pieces = key.split(/-(?!$)/); - var lastPiece = pieces[pieces.length - 1]; - if (pieces.length == 1 && pieces[0].length == 1) { - // No-modifier bindings use literal character bindings above. Skip. - return false; - } else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) { - // Ignore Shift+char bindings as they should be handled by literal character. - return false; - } - var hasCharacter = false; - for (var i = 0; i < pieces.length; i++) { - var piece = pieces[i]; - if (piece in modifiers) { pieces[i] = modifiers[piece]; } - else { hasCharacter = true; } - if (piece in specialKeys) { pieces[i] = specialKeys[piece]; } - } - if (!hasCharacter) { - // Vim does not support modifier only keys. - return false; - } - // TODO: Current bindings expect the character to be lower case, but - // it looks like vim key notation uses upper case. - if (isUpperCase(lastPiece)) { - pieces[pieces.length - 1] = lastPiece.toLowerCase(); - } - return '<' + pieces.join('-') + '>'; - } - function getOnPasteFn(cm) { var vim = cm.state.vim; if (!vim.onPasteFn) { @@ -429,18 +327,9 @@ export function initVim(CodeMirror) { }], bigWordCharTest = [function(ch) { return /\S/.test(ch); }]; - function makeKeyRange(start, size) { - var keys = []; - for (var i = start; i < start + size; i++) { - keys.push(String.fromCharCode(i)); - } - return keys; - } - var upperCaseAlphabet = makeKeyRange(65, 26); - var lowerCaseAlphabet = makeKeyRange(97, 26); - var numbers = makeKeyRange(48, 10); - var validMarks = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['<', '>']); - var validRegisters = [].concat(upperCaseAlphabet, lowerCaseAlphabet, numbers, ['-', '"', '.', ':', '_', '/', '+']); + var validMarks = ['<', '>']; + var validRegisters = ['-', '"', '.', ':', '_', '/', '+']; + var latinCharRegex = /^\w$/ var upperCaseChars; try { upperCaseChars = new RegExp("^[\\p{Lu}]$", "u"); } catch (_) { upperCaseChars = /^[A-Z]$/; } @@ -848,12 +737,8 @@ export function initVim(CodeMirror) { } } }, - langmap: function(langmapString, remapCtrl = true) { - updateLangmap(langmapString, remapCtrl); - }, - langmapRemapKey: function(key) { - return langmapRemapKey(key); - }, + langmap: updateLangmap, + vimKeyFromEvent: vimKeyFromEvent, // TODO: Expose setOption and getOption as instance methods. Need to decide how to namespace // them, or somehow make them work with the existing CodeMirror setOption/getOption API. setOption: setOption, @@ -1125,7 +1010,7 @@ export function initVim(CodeMirror) { else if (lowerKey == 'space') key = ' '; else if (lowerKey == 'cr') key = '\n'; else if (vimToCmKeyMap.hasOwnProperty(lowerKey)) { - // todo support codemirror keys in insertmode vimToCmKeyMap + // todo support codemirror keys in insertmode vimToCmKeyMap key = vimToCmKeyMap[lowerKey]; sendCmKey(cm, key); continue; @@ -1148,19 +1033,64 @@ export function initVim(CodeMirror) { } } + var specialKey = { + Return: 'CR', Backspace: 'BS', 'Delete': 'Del', Escape: 'Esc', Insert: 'Ins', + ArrowLeft: 'Left', ArrowRight: 'Right', ArrowUp: 'Up', ArrowDown: 'Down', + Enter: 'CR', ' ': 'Space' + }; + var ignoredKeys = { Shift: 1, Alt: 1, Command: 1, Control: 1, + CapsLock: 1, AltGraph: 1, Dead: 1, Unidentified: 1 }; + + var vimToCmKeyMap = {}; + 'Left|Right|Up|Down|End|Home'.split('|').concat(Object.keys(specialKey)).forEach(function(x) { + vimToCmKeyMap[(specialKey[x] || '').toLowerCase()] + = vimToCmKeyMap[x.toLowerCase()] = x; + }); + + function vimKeyFromEvent(e, vim) { + var key = e.key; + if (ignoredKeys[key]) return; + if (key.length > 1 && key[0] == "n") { + key = key.replace("Numpad", ""); + } + key = specialKey[key] || key; + + var name = ''; + if (e.ctrlKey) { name += 'C-'; } + if (e.altKey) { name += 'A-'; } + if (e.metaKey) { name += 'M-'; } + // on mac many characters are entered as option- combos + // (e.g. on swiss keyboard { is option-8) + // so we ignore lonely A- modifier for keypress event on mac + if (CodeMirror.isMac && e.altKey && !e.metaKey && !e.ctrlKey) { + name = name.slice(2); + } + if ((name || key.length > 1) && e.shiftKey) { name += 'S-'; } + + if (vim && !vim.expectLiteralNext && key.length == 1) { + if (langmap.keymap && key in langmap.keymap) { + if (langmap.remapCtrl != false || !name) + key = langmap.keymap[key]; + } else if (key.charCodeAt(0) > 255) { + var code = e.code?.slice(-1) || ""; + if (!e.shiftKey) code = code.toLowerCase(); + if (code) key = code; + } + } + + name += key; + if (name.length > 1) { name = '<' + name + '>'; } + return name; + }; + // langmap support - function updateLangmap(langmapString, remapCtrl = true) { - if (langmap != null && langmap.string == langmapString) { - langmap.remapCtrl = remapCtrl; - return; + function updateLangmap(langmapString, remapCtrl) { + if (langmap.string !== langmapString) { + langmap = parseLangmap(langmapString); } - langmap = parseLangmap(langmapString, remapCtrl); - } - function langmapIsLiteralMode(vim) { - // Determine if keystrokes should be interpreted literally - return vim.insertMode; + langmap.remapCtrl = remapCtrl; } - function parseLangmap(langmapString, remapCtrl) { + function parseLangmap(langmapString) { // From :help langmap /* The 'langmap' option is a list of parts, separated with commas. Each @@ -1172,7 +1102,7 @@ export function initVim(CodeMirror) { */ let keymap = {}; - if (langmapString == '') return { keymap: keymap, string: '', remapCtrl: remapCtrl }; + if (!langmapString) return { keymap: keymap, string: '' }; function getEscaped(list) { return list.split(/\\?(.)/).filter(Boolean); @@ -1192,18 +1122,17 @@ export function initVim(CodeMirror) { } }); - return { keymap: keymap, string: langmapString, remapCtrl: remapCtrl }; + return { keymap: keymap, string: langmapString }; } - function langmapRemapKey(key) { - console.log(`remapCtrl: ${langmap.remapCtrl}`);; - if (key.length == 1) { - return key in langmap.keymap ? langmap.keymap[key] : key; - } else if (langmap.remapCtrl && key.match(//)) { - return key[3] in langmap.keymap ? `` : key; + + defineOption('langmap', undefined, 'string', ['lmap'], function(name, cm) { + // The 'filetype' option proxies to the CodeMirror 'mode' option. + if (name === undefined) { + return langmap.string; } else { - return key; + updateLangmap(name); } - } + }); // Represents the current input state. function InputState() { @@ -1396,7 +1325,7 @@ export function initVim(CodeMirror) { return this.registers[name]; }, isValidRegister: function(name) { - return name && inArray(name, validRegisters); + return name && (inArray(name, validRegisters) || latinCharRegex.test(name)); }, shiftNumericRegisters_: function() { for (var i = 9; i >= 2; i--) { @@ -1607,16 +1536,15 @@ export function initVim(CodeMirror) { } } function onPromptKeyUp(e, query, close) { - var keyName = CodeMirror.keyName(e), up, offset; - if (keyName == 'Up' || keyName == 'Down') { - up = keyName == 'Up' ? true : false; + var keyName = vimKeyFromEvent(e), up, offset; + if (keyName == '' || keyName == '') { + up = keyName == '' ? true : false; offset = e.target ? e.target.selectionEnd : 0; query = vimGlobalState.searchHistoryController.nextMatch(query, up) || ''; close(query); if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); - } else { - if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') - vimGlobalState.searchHistoryController.reset(); + } else if (keyName && keyName != '' && keyName != '') { + vimGlobalState.searchHistoryController.reset(); } var parsedQuery; try { @@ -1633,9 +1561,9 @@ export function initVim(CodeMirror) { } } function onPromptKeyDown(e, query, close) { - var keyName = CodeMirror.keyName(e); - if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' || - (keyName == 'Backspace' && query == '')) { + var keyName = vimKeyFromEvent(e); + if (keyName == '' || keyName == '' || keyName == '' || + (keyName == '' && query == '')) { vimGlobalState.searchHistoryController.pushInput(query); vimGlobalState.searchHistoryController.reset(); updateSearchQuery(cm, originalQuery); @@ -1645,9 +1573,9 @@ export function initVim(CodeMirror) { clearInputState(cm); close(); cm.focus(); - } else if (keyName == 'Up' || keyName == 'Down') { + } else if (keyName == '' || keyName == '') { CodeMirror.e_stop(e); - } else if (keyName == 'Ctrl-U') { + } else if (keyName == '') { // Ctrl-U clears input. CodeMirror.e_stop(e); close(''); @@ -1709,9 +1637,9 @@ export function initVim(CodeMirror) { if (cm.state.vim) clearInputState(cm); } function onPromptKeyDown(e, input, close) { - var keyName = CodeMirror.keyName(e), up, offset; - if (keyName == 'Esc' || keyName == 'Ctrl-C' || keyName == 'Ctrl-[' || - (keyName == 'Backspace' && input == '')) { + var keyName = vimKeyFromEvent(e), up, offset; + if (keyName == '' || keyName == '' || keyName == '' || + (keyName == '' && input == '')) { vimGlobalState.exCommandHistoryController.pushInput(input); vimGlobalState.exCommandHistoryController.reset(); CodeMirror.e_stop(e); @@ -1719,19 +1647,18 @@ export function initVim(CodeMirror) { close(); cm.focus(); } - if (keyName == 'Up' || keyName == 'Down') { + if (keyName == '' || keyName == '') { CodeMirror.e_stop(e); - up = keyName == 'Up' ? true : false; + up = keyName == '' ? true : false; offset = e.target ? e.target.selectionEnd : 0; input = vimGlobalState.exCommandHistoryController.nextMatch(input, up) || ''; close(input); if (offset && e.target) e.target.selectionEnd = e.target.selectionStart = Math.min(offset, e.target.value.length); - } else if (keyName == 'Ctrl-U') { + } else if (keyName == '') { // Ctrl-U clears input. CodeMirror.e_stop(e); close(''); - } else { - if ( keyName != 'Left' && keyName != 'Right' && keyName != 'Ctrl' && keyName != 'Alt' && keyName != 'Shift') + } else if (keyName && keyName != '' && keyName != '') { vimGlobalState.exCommandHistoryController.reset(); } } @@ -4071,7 +3998,7 @@ export function initVim(CodeMirror) { } function updateMark(cm, vim, markName, pos) { - if (!inArray(markName, validMarks)) { + if (!inArray(markName, validMarks) && !latinCharRegex.test(markName)) { return; } if (vim.marks[markName]) { @@ -5926,13 +5853,13 @@ export function initVim(CodeMirror) { function onPromptKeyDown(e, _value, close) { // Swallow all keys. CodeMirror.e_stop(e); - var keyName = CodeMirror.keyName(e); + var keyName = vimKeyFromEvent(e); switch (keyName) { - case 'Y': + case 'y': replace(); next(); break; - case 'N': + case 'n': next(); break; - case 'A': + case 'a': // replaceAll contains a call to close of its own. We don't want it // to fire too early or multiple times. var savedCallback = callback; @@ -5940,13 +5867,13 @@ export function initVim(CodeMirror) { cm.operation(replaceAll); callback = savedCallback; break; - case 'L': + case 'l': replace(); // fall through and exit. - case 'Q': - case 'Esc': - case 'Ctrl-C': - case 'Ctrl-[': + case 'q': + case '': + case '': + case '': stop(close); break; } @@ -5971,12 +5898,6 @@ export function initVim(CodeMirror) { }); } - CodeMirror.keyMap.vim = { - attach: attachVimMap, - detach: detachVimMap, - call: cmKey - }; - function exitInsertMode(cm, keepCursor) { var vim = cm.state.vim; var macroModeState = vimGlobalState.macroModeState; @@ -6028,21 +5949,6 @@ export function initVim(CodeMirror) { // adjusted according to your typing speed to prevent false positives. defineOption('insertModeEscKeysTimeout', 200, 'number'); - CodeMirror.keyMap['vim-insert'] = { - // TODO: override navigation keys so that Esc will cancel automatic - // indentation from o, O, i_ - fallthrough: ['default'], - attach: attachVimMap, - detach: detachVimMap, - call: cmKey - }; - - CodeMirror.keyMap['vim-replace'] = { - 'Backspace': 'goCharLeft', - fallthrough: ['vim-insert'], - attach: attachVimMap, - detach: detachVimMap - }; function executeMacroRegister(cm, vim, macroModeState, registerName) { var register = vimGlobalState.registerController.getRegister(registerName); @@ -6208,8 +6114,13 @@ export function initVim(CodeMirror) { } /** Wrapper for special keys pressed in insert mode */ - function InsertModeKey(keyName) { + function InsertModeKey(keyName, e) { this.keyName = keyName; + this.key = e.key; + this.ctrlKey = e.ctrlKey; + this.altKey = e.altKey; + this.metaKey = e.metaKey; + this.shiftKey = e.shiftKey; } /** @@ -6220,18 +6131,15 @@ export function initVim(CodeMirror) { function onKeyEventTargetKeyDown(e) { var macroModeState = vimGlobalState.macroModeState; var lastChange = macroModeState.lastInsertModeChanges; - var keyName = CodeMirror.keyName(e); + var keyName = CodeMirror.keyName ? CodeMirror.keyName(e) : e.key; if (!keyName) { return; } - function onKeyFound() { + + if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) { if (lastChange.maybeReset) { lastChange.changes = []; lastChange.maybeReset = false; } - lastChange.changes.push(new InsertModeKey(keyName)); - return true; - } - if (keyName.indexOf('Delete') != -1 || keyName.indexOf('Backspace') != -1) { - CodeMirror.lookupKey(keyName, 'vim-insert', onKeyFound); + lastChange.changes.push(new InsertModeKey(keyName, e)); } } @@ -6317,7 +6225,7 @@ export function initVim(CodeMirror) { for (var j = 0; j < changes.length; j++) { var change = changes[j]; if (change instanceof InsertModeKey) { - sendCmKey(cm, change.keyName); + sendCmKey(cm, change.keyName, change); } else if (typeof change == "string") { cm.replaceSelection(change); } else { diff --git a/test/vim_test.js b/test/vim_test.js index 4a7314f..f1bcb61 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -5562,7 +5562,7 @@ testVim('_insert_mode', function(cm, vim, helpers) { // const dvorakLangmap = "'q,\\,w,.e,pr,yt,fy,gu,ci,ro,lp,/[,=],aa,os,ed,uf,ig,dh,hj,tk,nl,s\\;,-',\\;z,qx,jc,kv,xb,bn,mm,w\\,,v.,z/,[-,]=,\"Q,E,PR,YT,FY,GU,CI,RO,LP,?{,+},AA,OS,ED,UF,IG,DH,HJ,TK,NL,S:,_\",:Z,QX,JC,KV,XB,BN,MM,W<,V>,Z?"; // this test makes sure that remapping works on an example binding -testVim('langmap_dd', function(cm, vim, helpers) { +isOldCodeMirror || testVim('langmap_dd', function(cm, vim, helpers) { CodeMirror.Vim.langmap(dvorakLangmap); cm.setCursor(0, 3); @@ -5581,7 +5581,7 @@ testVim('langmap_dd', function(cm, vim, helpers) { // this test serves two functions: // - make sure that "dd" is **not** interpreted as delete line (correct unmapping) // - make sure that "dd" **is** interpreted as move left twice (correct mapping) -testVim('langmap_hh', function(cm, vim, helpers) { +isOldCodeMirror || testVim('langmap_hh', function(cm, vim, helpers) { CodeMirror.Vim.langmap(dvorakLangmap); const startPos = word1.end; @@ -5594,7 +5594,7 @@ testVim('langmap_hh', function(cm, vim, helpers) { // this test serves two functions: // - make sure tha the register is properly remapped so that special registers aren't mixed up // - make sure that recording and replaying macros works without "double remapping" -testVim('langmap_qqddq@q', function(cm, vim, helpers) { +isOldCodeMirror || testVim('langmap_qqddq@q', function(cm, vim, helpers) { CodeMirror.Vim.langmap(dvorakLangmap); cm.setCursor(0, 3); @@ -5611,7 +5611,7 @@ testVim('langmap_qqddq@q', function(cm, vim, helpers) { helpers.assertCursorAt(0, lines[2].textStart); }); // this test makes sure that directives are interpreted literally -testVim('langmap_fd', function(cm, vim, helpers) { +isOldCodeMirror || testVim('langmap_fd', function(cm, vim, helpers) { CodeMirror.Vim.langmap(dvorakLangmap); cm.setCursor(0, 0); @@ -5619,7 +5619,7 @@ testVim('langmap_fd', function(cm, vim, helpers) { helpers.assertCursorAt(0, 4); }); // this test makes sure that markers work properly -testVim('langmap_mark', function(cm, vim, helpers) { +isOldCodeMirror || testVim('langmap_mark', function(cm, vim, helpers) { CodeMirror.Vim.langmap(dvorakLangmap); cm.setCursor(2, 2); @@ -5634,7 +5634,7 @@ testVim('langmap_mark', function(cm, vim, helpers) { helpers.assertCursorAt(2, 3); }); // check that ctrl remapping works properly -testVim('langmap_visual_block', function(cm, vim, helpers) { +isOldCodeMirror || testVim('langmap_visual_block', function(cm, vim, helpers) { CodeMirror.Vim.langmap(dvorakLangmap); cm.setCursor(0, 1); @@ -5648,7 +5648,7 @@ testVim('langmap_visual_block', function(cm, vim, helpers) { eq('1hworld\n5hworld\nahworld', cm.getValue()); }, {value: '1234\n5678\nabcdefg'}); // check that ctrl remapping can be disabled -testVim('langmap_visual_block_no_ctrl_remap', function(cm, vim, helpers) { +isOldCodeMirror || testVim('langmap_visual_block_no_ctrl_remap', function(cm, vim, helpers) { CodeMirror.Vim.langmap(dvorakLangmap, false); cm.setCursor(0, 1);