diff --git a/src/types.d.ts b/src/types.d.ts index 289957b..9cd1cda 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -192,7 +192,8 @@ type allCommands = { interlaceInsertRepeat?: boolean, exitVisualBlock?: boolean, isEdit?: boolean, - repeatOverride?: number + repeatOverride?: number, + noremap?: boolean, } export type motionCommand = allCommands & { type: 'motion', @@ -223,7 +224,7 @@ export type operatorMotionCommand = allCommands & { operator: string, motionArgs?: MotionArgsPartial, operatorArgs?: OperatorArgs, - operatorMotionArgs?: { [arg: string]: boolean | string } + operatorMotionArgs?: { [arg: string]: boolean | string }, } export type idleCommand = allCommands & { type: 'idle' } export type exCommand = allCommands & { type: 'ex' } diff --git a/src/vim.js b/src/vim.js index 31e5f61..f4252ab 100644 --- a/src/vim.js +++ b/src/vim.js @@ -133,9 +133,9 @@ export function initVim(CodeMirror) { { keys: '', type: 'motion', motion: 'moveByScroll', motionArgs: { forward: false, explicitRepeat: true }}, { keys: 'gg', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: false, explicitRepeat: true, linewise: true, toJumplist: true }}, { keys: 'G', type: 'motion', motion: 'moveToLineOrEdgeOfDocument', motionArgs: { forward: true, explicitRepeat: true, linewise: true, toJumplist: true }}, - {keys: "g$", type: "motion", motion: "moveToEndOfDisplayLine"}, - {keys: "g^", type: "motion", motion: "moveToStartOfDisplayLine"}, - {keys: "g0", type: "motion", motion: "moveToStartOfDisplayLine"}, + { keys: "g$", type: "motion", motion: "moveToEndOfDisplayLine" }, + { keys: "g^", type: "motion", motion: "moveToStartOfDisplayLine" }, + { keys: "g0", type: "motion", motion: "moveToStartOfDisplayLine" }, { keys: '0', type: 'motion', motion: 'moveToStartOfLine' }, { keys: '^', type: 'motion', motion: 'moveToFirstNonWhiteSpaceCharacter' }, { keys: '+', type: 'motion', motion: 'moveByLines', motionArgs: { forward: true, toFirstChar:true }}, @@ -256,6 +256,7 @@ export function initVim(CodeMirror) { // Ex command { keys: ':', type: 'ex' } ]; + var usedKeys = Object.create(null); var defaultKeymapLength = defaultKeymap.length; /** @@ -971,7 +972,7 @@ export function initVim(CodeMirror) { if (vim.insertMode) { command = handleKeyInsertMode(); } else { command = handleKeyNonInsertMode(); } if (command === false) { - return !vim.insertMode && key.length === 1 ? function() { return true; } : undefined; + return !vim.insertMode && (key.length === 1 || (CodeMirror.isMac && //.test(key)))? function() { return true; } : undefined; } else if (command === true) { // TODO: Look into using CodeMirror's multi-key handling. // Return no-op since we are caching the key. Counts as handled, but @@ -1149,7 +1150,7 @@ export function initVim(CodeMirror) { // 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) { + if (CodeMirror.isMac && name == "A-" && key.length == 1) { name = name.slice(2); } if ((name || key.length > 1) && e.shiftKey) { name += 'S-'; } @@ -1158,10 +1159,16 @@ export function initVim(CodeMirror) { 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; + } else if (key.charCodeAt(0) > 128) { + if (!usedKeys[key]) { + var code = e.code?.slice(-1) || ""; + if (!e.shiftKey) code = code.toLowerCase(); + if (code) { + key = code; + // also restore A- for mac + if (!name && e.altKey) name = 'A-' + } + } } } @@ -5597,6 +5604,7 @@ export function initVim(CodeMirror) { } } else { // Key to key or ex mapping + /**@type {vimKey} */ var mapping = { keys: lhs, type: 'keyToKey', @@ -5604,8 +5612,7 @@ export function initVim(CodeMirror) { noremap: !!noremap }; if (ctx) { mapping.context = ctx; } - // @ts-ignore - defaultKeymap.unshift(mapping); + _mapCommand(mapping); } } /**@type {(lhs: string, ctx: string) => boolean|void} */ @@ -5625,6 +5632,7 @@ export function initVim(CodeMirror) { if (keys == defaultKeymap[i].keys && defaultKeymap[i].context === ctx) { defaultKeymap.splice(i, 1); + removeUsedKeys(keys); return true; } } @@ -6378,6 +6386,25 @@ export function initVim(CodeMirror) { /** @arg {vimKey} command*/ function _mapCommand(command) { defaultKeymap.unshift(command); + if (command.keys) addUsedKeys(command.keys); + } + + /** @arg {string} keys */ + function addUsedKeys(keys) { + keys.split(/(<(?:[CSMA]-)*\w+>|.)/i).forEach(function(part) { + if (part) { + if (!usedKeys[part]) usedKeys[part] = 0; + usedKeys[part]++; + } + }); + } + + /** @arg {string} keys */ + function removeUsedKeys(keys) { + keys.split(/(<(?:[CSMA]-)*\w+>|.)/i).forEach(function(part) { + if (usedKeys[part]) + usedKeys[part]--; + }); } /** diff --git a/test/vim_test.js b/test/vim_test.js index 563fd33..54e6233 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -5541,6 +5541,41 @@ testVim('option_key_on_mac', function(cm, vim, helpers) { helpers.assertCursorAt(3, 0); typeKey.optionTextInput('8', '{'); helpers.assertCursorAt(0, 0); + + typeKey.utfTextInput('d', 'д'); + typeKey.utfTextInput('l', 'л'); + typeKey.utfTextInput('d', 'д'); + typeKey.utfTextInput('G', 'Г'); + eq('', cm.getValue()); + helpers.doKeys('"-p'); + eq('0', cm.getValue()); + //TODO bug in paste + helpers.doKeys('l'); + helpers.assertCursorAt(0, 0); + + // map A-v + helpers.doEx(':map iA-v>'); + + // verify that replace still works + typeKey.utfTextInput('r', 'Ռ'); + typeKey.optionTextInput('v', '√'); + eq('√', cm.getValue()); + + typeKey.optionTextInput('v', '√'); + eq('√', cm.getValue()); + + helpers.doEx(':map √ i√G'); + typeKey.optionTextInput('v', '√'); + eq('√', cm.getValue()); + + helpers.doEx(':unmap √'); + typeKey.optionTextInput('v', '√'); + eq('G>√', cm.getValue()); + + helpers.doEx(':unmap '); + typeKey.optionTextInput('v', '√'); + eq('G>√', cm.getValue()); + CodeMirror.isMac = false; }, { value: '0\n1\n2\n\n\n3\n4\n' }); @@ -5810,9 +5845,9 @@ var typeKey = function() { } var key = keyCodeToKey[(shift ? "s-" : "") + keyCode]; - if (options && options.macAltText) { - alt = true; - text = key = options.macAltText; + if (options && options.text) { + alt = options.altKey; + text = key = options.text; isTextInput = true; } @@ -5926,7 +5961,11 @@ var typeKey = function() { // emulates option-9 inputting } on mac swiss keyboard type.optionTextInput = function(letter, altText) { reset(); - sendKey(letter, {macAltText: altText}); + sendKey(letter, {text: altText, altKey: true}); + }; + + type.utfTextInput = function(letter, altText) { + sendKey(letter, {text: altText}); }; type.clipboard = {};