diff --git a/lib/ace/keyboard/keybinding.js b/lib/ace/keyboard/keybinding.js index 3cd0ef89..11d3c901 100644 --- a/lib/ace/keyboard/keybinding.js +++ b/lib/ace/keyboard/keybinding.js @@ -78,14 +78,14 @@ var KeyBinding = function(editor) { if (hashId != 0 || keyCode != 0) { toExecute = { command: canon.findKeyCommand(env, "editor", hashId, keyOrText) - } + }; } else { toExecute = { command: "inserttext", args: { text: keyOrText } - } + }; } } @@ -105,9 +105,133 @@ var KeyBinding = function(editor) { this.onTextInput = function(text) { this.$callKeyboardHandler({}, 0, text, 0); - } + }; }).call(KeyBinding.prototype); exports.KeyBinding = KeyBinding; + + +/** +* A lookup has for command key bindings that use a string as sender. +*/ +var commmandKeyBinding = {}; + +/** +* Array with command key bindings that use a function to determine the sender. +*/ +var commandKeyBindingFunc = { }; + +function splitSafe(s, separator, limit, bLowerCase) { + return (bLowerCase && s.toLowerCase() || s) + .replace(/(?:^\s+|\n|\s+$)/g, "") + .split(new RegExp("[\\s ]*" + separator + "[\\s ]*", "g"), limit || 999); +} + +function parseKeys(keys, val, ret) { + var key, + hashId = 0, + parts = splitSafe(keys, "\\-", null, true), + i = 0, + l = parts.length; + + for (; i < l; ++i) { + if (keyUtil.KEY_MODS[parts[i]]) + hashId = hashId | keyUtil.KEY_MODS[parts[i]]; + else + key = parts[i] || "-"; //when empty, the splitSafe removed a '-' + } + + if (ret == null) { + return { + key: key, + hashId: hashId + }; + } else { + (ret[hashId] || (ret[hashId] = {}))[key] = val; + } +} + +var platform = useragent.isMac ? "mac" : "win"; +function buildKeyHash(command) { + var binding = command.bindKey, + key = binding[platform], + ckb = commmandKeyBinding, + ckbf = commandKeyBindingFunc; + + if (!binding.sender) { + throw new Error('All key bindings must have a sender'); + } + if (!binding.mac && binding.mac !== null) { + throw new Error('All key bindings must have a mac key binding'); + } + if (!binding.win && binding.win !== null) { + throw new Error('All key bindings must have a windows key binding'); + } + if(!binding[platform]) { + // No key mapping for this platform. + return; + } + if (typeof binding.sender == 'string') { + var targets = splitSafe(binding.sender, "\\|", null, true); + targets.forEach(function(target) { + if (!ckb[target]) { + ckb[target] = { }; + } + key.split("|").forEach(function(keyPart) { + parseKeys(keyPart, command, ckb[target]); + }); + }); + } else if (typecheck.isFunction(binding.sender)) { + var val = { + command: command, + sender: binding.sender + }; + + keyData = parseKeys(key); + if (!ckbf[keyData.hashId]) { + ckbf[keyData.hashId] = { }; + } + if (!ckbf[keyData.hashId][keyData.key]) { + ckbf[keyData.hashId][keyData.key] = [ val ]; + } else { + ckbf[keyData.hashId][keyData.key].push(val); + } + } else { + throw new Error('Key binding must have a sender that is a string or function'); + } +} + +function findKeyCommand(env, sender, hashId, textOrKey) { + // Convert keyCode to the string representation. + if (typecheck.isNumber(textOrKey)) { + textOrKey = keyUtil.keyCodeToString(textOrKey); + } + + // Check bindings with functions as sender first. + var bindFuncs = (commandKeyBindingFunc[hashId] || {})[textOrKey] || []; + for (var i = 0; i < bindFuncs.length; i++) { + if (bindFuncs[i].sender(env, sender, hashId, textOrKey)) { + return bindFuncs[i].command; + } + } + + var ckbr = commmandKeyBinding[sender]; + return ckbr && ckbr[hashId] && ckbr[hashId][textOrKey]; +} + +exports.findKeyCommand = findKeyCommand; + +function execKeyCommand(env, sender, hashId, textOrKey) { + var command = findKeyCommand(env, sender, hashId, textOrKey); + if (command) { + return exec(command, env, sender, { }); + } else { + return false; + } +} + +exports.execKeyCommand = execKeyCommand; + + });