diff --git a/lib/ace/commands/default_commands.js b/lib/ace/commands/default_commands.js index e02dd9bd..817e8fab 100644 --- a/lib/ace/commands/default_commands.js +++ b/lib/ace/commands/default_commands.js @@ -253,8 +253,8 @@ canon.addCommand({ canon.addCommand({ name: "inserttext", exec: function(env, args, request) { - env.editor.onTextInput(lang.stringRepeat(args.text || "", - args.times || 1)); + env.editor.insert(lang.stringRepeat(args.text || "", + args.times || 1)); } }); diff --git a/lib/ace/editor.js b/lib/ace/editor.js index 00e7e30a..953620d0 100644 --- a/lib/ace/editor.js +++ b/lib/ace/editor.js @@ -54,7 +54,7 @@ var Editor =function(renderer, doc) { this.renderer = renderer; this.textInput = new TextInput(container, this); - this.keyBinding = new KeyBinding(container, this); + this.keyBinding = new KeyBinding(this); var self = this; event.addListener(container, "mousedown", function(e) { setTimeout(function() {self.focus();}); @@ -64,7 +64,7 @@ var Editor =function(renderer, doc) { return event.preventDefault(e); }); - var mouseTarget = renderer.getMouseEventTarget(); + var mouseTarget = renderer.getMouseEventTarget(); event.addListener(mouseTarget, "mousedown", this.onMouseDown.bind(this)); event.addMultiMouseDownListener(mouseTarget, 0, 2, 500, this.onMouseDoubleClick.bind(this)); event.addMultiMouseDownListener(mouseTarget, 0, 3, 600, this.onMouseTripleClick.bind(this)); @@ -403,7 +403,7 @@ var Editor =function(renderer, doc) { } }; - this.onTextInput = function(text) { + this.insert = function(text) { if (this.$readOnly) return; @@ -480,6 +480,14 @@ var Editor =function(renderer, doc) { _self.renderer.scrollCursorIntoView(); }); }); + } + + this.onTextInput = function(text) { + this.keyBinding.onTextInput(text); + }; + + this.onCommandKey = function(e, hashId, keyCode) { + this.keyBinding.onCommandKey(e, hashId, keyCode); }; this.$overwrite = false; @@ -592,7 +600,7 @@ var Editor =function(renderer, doc) { if (this.selection.isEmpty()) this.selection.selectLeft(); - + this.moveCursorToPosition(this.doc.remove(this.getSelectionRange())); this.clearSelection(); }; @@ -892,7 +900,7 @@ var Editor =function(renderer, doc) { else { times = times || 1; while (times--) { - this.selection.moveCursorLeft(); + this.selection.moveCursorLeft(); } } this.clearSelection(); diff --git a/lib/ace/keybinding.js b/lib/ace/keybinding.js index 35699456..3f0b931d 100644 --- a/lib/ace/keybinding.js +++ b/lib/ace/keybinding.js @@ -39,102 +39,45 @@ define(function(require, exports, module) { var useragent = require("pilot/useragent"); +var keyUtil = require("pilot/keys"); var event = require("pilot/event"); +var settings = require("pilot/settings").settings; var default_mac = require("ace/conf/keybindings/default_mac").bindings; var default_win = require("ace/conf/keybindings/default_win").bindings; var canon = require("pilot/canon"); require("ace/commands/default_commands"); -var vim_mode = require("ace/mode/vim"); -var emacs_mode = require("ace/mode/emacs"); +var inputModes = { + vim: require("ace/mode/vim"), + emacs: require("ace/mode/emacs") +}; -var KeyBinding = function(element, editor, config) { +var KeyBinding = function(editor, config) { + this.$editor = editor; + this.$data = { }; this.setConfig(config); - var data = { }; - var _self = this; - event.addKeyListener(element, function(e) { - // opera on mac swaps ctrl and meta keys - if (useragent.isOpera && useragent.isMac) - var hashId = 0 | (e.metaKey ? 1 : 0) | (e.altKey ? 2 : 0) - | (e.shiftKey ? 4 : 0) | (e.ctrlKey ? 8 : 0); - else - var hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0) - | (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0); + // PROBLEM: When this file is loaded via require.js, the types are already + // declaired, BUT the startup() function is not called in pilot/types/basic. + // Therefore the settings are not declaired. As a workaround, the setting + // is declaired when the KeyBinding is created. + var InputModeSetting = { + name: "inputMode", + description: "Which input mode do you want to use?", + type: "text", + defaultValue: "standard" + }; - console.log(hashId, e.keyCode); - var key; - var keyCode = e.keyCode; + this.$inputMode = null; + settings.addSetting(InputModeSetting); - // TODO: Pressing the command key on Chrome/Mac causes the keyCode - // to be 91, which is the "[" character, without pressing this actually. - // Invastigate more further and make a proper work around. - if (hashId & 8 && keyCode == 91) { - key = ""; - } else { - key = (_self.keyNames[e.keyCode] || - String.fromCharCode(e.keyCode)).toLowerCase(); - } - - var toExecute; - if (true) { - var toExecute = - // vim_mode.handleKeyboard(data, hashId, key, e); - emacs_mode.handleKeyboard(data, hashId, key, e); - } - - // If there is nothing to execute yet, then use the default keymapping. - if (!toExecute) { - toExecute = { - command: (_self.config.reverse[hashId] || {})[key] - }; - } - - // If there is something to execute, then go for it. - if (toExecute) { - var success = canon.exec(toExecute.command, - {editor: editor}, toExecute.args); - if (success) { - return event.stopEvent(e); - } - } - }); + settings.getSetting("inputMode").addEventListener("change", function(e) { + this.$inputMode = inputModes[e.value]; + this.$data = { }; + }.bind(this)); }; (function() { - this.keyMods = {"ctrl": 1, "alt": 2, "option" : 2, "shift": 4, "meta": 8, "command": 8}; - - this.keyNames = { - "8" : "Backspace", - "9" : "Tab", - "13" : "Enter", - "27" : "Esc", - "32" : "Space", - "33" : "PageUp", - "34" : "PageDown", - "35" : "End", - "36" : "Home", - "37" : "Left", - "38" : "Up", - "39" : "Right", - "40" : "Down", - "45" : "Insert", - "46" : "Delete", - "107": "+", - "112": "F1", - "113": "F2", - "114": "F3", - "115": "F4", - "116": "F5", - "117": "F6", - "118": "F7", - "119": "F8", - "120": "F9", - "121": "F10", - "122": "F11", - "123": "F12" - }; - function splitSafe(s, separator, limit, bLowerCase) { return (bLowerCase && s.toLowerCase() || s) .replace(/(?:^\s+|\n|\s+$)/g, "") @@ -149,8 +92,8 @@ var KeyBinding = function(element, editor, config) { l = parts.length; for (; i < l; ++i) { - if (this.keyMods[parts[i]]) - hashId = hashId | this.keyMods[parts[i]]; + if (keyUtil.KEY_MODS[parts[i]]) + hashId = hashId | keyUtil.KEY_MODS[parts[i]]; else key = parts[i] || "-"; //when empty, the splitSafe removed a '-' } @@ -184,6 +127,47 @@ var KeyBinding = function(element, editor, config) { this.config.reverse = objectReverse.call(this, this.config, "|"); }; + + this.onCommandKey = function(e, hashId, keyCode) { + key = (keyUtil[keyCode] || + String.fromCharCode(keyCode)).toLowerCase(); + + var toExecute; + if (this.$inputMode) { + toExecute = + this.$inputMode.handleKeyboard(this.$data, hashId, key, e); + } + + // If there is nothing to execute yet, then use the default keymapping. + if (!toExecute) { + toExecute = { + command: (this.config.reverse[hashId] || {})[key] + }; + } + + // If there is something to execute, then go for it. + if (toExecute) { + var success = canon.exec(toExecute.command, + {editor: this.$editor}, toExecute.args); + if (success) { + return event.stopEvent(e); + } + } + }; + + this.onTextInput = function(text) { + if (this.$inputMode) { + var toExecute = + this.$inputMode.handleKeyboard(this.$data, 0, text, {}); + var success = canon.exec(toExecute.command, + {editor: this.$editor}, toExecute.args); + if (success) { + return; + } + } + this.$editor.insert(text); + } + }).call(KeyBinding.prototype); exports.KeyBinding = KeyBinding; diff --git a/lib/ace/keyboardstate.js b/lib/ace/keyboardstate.js index 600447d5..7a76563a 100644 --- a/lib/ace/keyboardstate.js +++ b/lib/ace/keyboardstate.js @@ -37,6 +37,10 @@ define(function(require, exports, module) { +// If you're developing a new keymapping and want to get an idea what's going +// on, then enable debugging. +var DEBUG = false; + function KeyboardStateMapper(keymapping) { this.keymapping = this.$buildKeymappingRegex(keymapping); } @@ -172,7 +176,9 @@ KeyboardStateMapper.prototype = { result.command = "null"; } - console.log("KeyboardStateMapper#find", binding); + if (DEBUG) { + console.log("KeyboardStateMapper#find", binding); + } return true; }); @@ -191,7 +197,9 @@ KeyboardStateMapper.prototype = { var symbolicName = r.symbolicName; r = this.$find(data, buffer, symbolicName, hashId, key); - console.log("KeyboardStateMapper#match", buffer, symbolicName, r); + if (DEBUG) { + console.log("KeyboardStateMapper#match", buffer, symbolicName, r); + } return r; } diff --git a/lib/ace/textinput.js b/lib/ace/textinput.js index 076f7875..6b4a673f 100644 --- a/lib/ace/textinput.js +++ b/lib/ace/textinput.js @@ -114,6 +114,7 @@ var TextInput = function(parentNode, host) { setTimeout(sendText, 0); }; + event.addCommandKeyListener(text, host.onCommandKey.bind(host)); event.addListener(text, "keypress", onTextInput); event.addListener(text, "textInput", onTextInput); event.addListener(text, "paste", onTextInput); diff --git a/support/cockpit b/support/cockpit index 36c55c39..cd074fd3 160000 --- a/support/cockpit +++ b/support/cockpit @@ -1 +1 @@ -Subproject commit 36c55c39e8ede94e964364e01ab5308f3f51c2eb +Subproject commit cd074fd37a02bc40300aa7b120d395525767b156