Add basic emacs keybinding.

This commit is contained in:
Julian Viereck 2010-12-23 00:06:17 +01:00
commit b16bc6abc4
5 changed files with 217 additions and 23 deletions

View file

@ -38,6 +38,7 @@
define(function(require, exports, module) {
var lang = require("pilot/lang");
var canon = require("pilot/canon");
canon.addCommand({
@ -249,5 +250,12 @@ canon.addCommand({
name: "indent",
exec: function(env, args, request) { env.editor.indent(); }
});
canon.addCommand({
name: "inserttext",
exec: function(env, args, request) {
env.editor.onTextInput(lang.stringRepeat(args.text || "",
args.times || 1));
}
});
});

View file

@ -42,10 +42,12 @@ var useragent = require("pilot/useragent");
var event = require("pilot/event");
var default_mac = require("ace/conf/keybindings/default_mac").bindings;
var default_win = require("ace/conf/keybindings/default_win").bindings;
var vim_mode = require("ace/mode/vim");
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 KeyBinding = function(element, editor, config) {
this.setConfig(config);
var data = { };
@ -60,13 +62,25 @@ var KeyBinding = function(element, editor, config) {
var hashId = 0 | (e.ctrlKey ? 1 : 0) | (e.altKey ? 2 : 0)
| (e.shiftKey ? 4 : 0) | (e.metaKey ? 8 : 0);
var key = (_self.keyNames[e.keyCode] ||
console.log(hashId, e.keyCode);
var key;
var keyCode = e.keyCode;
// 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);
// 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.

View file

@ -80,7 +80,7 @@ KeyboardStateMapper.prototype = {
if (hashId & 8) keyArray.push("Command");
if (hashId & 2) keyArray.push("Option");
if (hashId & 4) keyArray.push("Shift");
keyArray.push(key);
if (key) keyArray.push(key);
var symbolicName = keyArray.join("-").toLowerCase();
var bufferToUse = data.buffer + symbolicName;
@ -130,7 +130,7 @@ KeyboardStateMapper.prototype = {
if (binding.disallowMatches) {
for (var i = 0; i < binding.disallowMatches.length; i++) {
if (!!match[binding.disallowMatches[i]]) {
return true;
return false;
}
}
}
@ -172,10 +172,16 @@ KeyboardStateMapper.prototype = {
result.command = "null";
}
console.log("KeyboardStateMapper#find", binding);
return true;
});
return result.command ? result : false;
if (result.command) {
return result;
} else {
data.buffer = "";
return false;
}
},
match: function(data, hashId, key) {
@ -191,5 +197,32 @@ KeyboardStateMapper.prototype = {
}
}
/**
* This is a useful matching function and therefore is defined here so that
* users of KeyboardStateMapper can use it.
*
* @return boolean
* If no command key (Command|Option|Shift|Ctrl) is pressed, it
* returns true. If the only the Shift key is pressed + a character
* true is returned as well. Otherwise, false is returned.
* Summing up, the function returns true whenever the user typed
* a normal character on the keyboard and no shortcut.
*/
exports.matchCharacterOnly = function(buffer, hashId, key, symbolicName) {
// If no command keys are pressed, then catch the input.
if (hashId == 0) {
return true;
}
// If only the shift key is pressed and a character key, then
// catch that input as well.
else if ((hashId == 4) && key.length == 1) {
return true;
}
// Otherwise, we let the input got through.
else {
return false;
}
};
exports.KeyboardStateMapper = KeyboardStateMapper;
});
});

152
lib/ace/mode/emacs.js Normal file
View file

@ -0,0 +1,152 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Julian Viereck (julian.viereck@gmail.com)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var KeyboardStateMapper = require("ace/keyboardstate").KeyboardStateMapper;
var matchCharacterOnly = require("ace/keyboardstate").matchCharacterOnly;
var emacsState = {
start: [
{
key: "ctrl-x",
then: "c-x"
},
{
regex: [ "(?:command-([0-9]*))*", "(down|ctrl-n)" ],
exec: "golinedown",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "(?:command-([0-9]*))*", "(right|ctrl-f)" ],
exec: "gotoright",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "(?:command-([0-9]*))*", "(up|ctrl-p)" ],
exec: "golineup",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "(?:command-([0-9]*))*", "(left|ctrl-b)" ],
exec: "gotoleft",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
comment: "This binding matches all printable characters except numbers as long as they are no numbers and print them n times.",
regex: [ "(?:command-([0-9]*))", "([^0-9]+)*" ],
match: matchCharacterOnly,
exec: "inserttext",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: "1"
},
{
name: "text",
match: 2
}
]
},
{
comment: "This binding matches numbers as long as there is no meta_number in the buffer.",
regex: [ "(command-[0-9]*)*", "([0-9]+)" ],
match: matchCharacterOnly,
disallowMatches: [ 1 ],
exec: "inserttext",
params: [
{
name: "text",
match: 2,
type: "text"
}
]
},
{
regex: [ "command-([0-9]*)", "(command-[0-9]|[0-9])" ],
comment: "Stops execution if the regex /meta_[0-9]+/ matches to avoid resetting the buffer."
}
],
"c-x": [
{
key: "ctrl-g",
then: "start"
},
{
key: "ctrl-s",
exec: "save",
then: "start"
}
]
};
var emacsKeyboardStateMapper = new KeyboardStateMapper(emacsState);
exports.handleKeyboard = function(data, hashId, key, e) {
return emacsKeyboardStateMapper.match(data, hashId, key);
}
});

View file

@ -38,6 +38,7 @@
define(function(require, exports, module) {
var KeyboardStateMapper = require("ace/keyboardstate").KeyboardStateMapper;
var matchCharacterOnly = require("ace/keyboardstate").matchCharacterOnly;
var vimStates = {
start: [
@ -95,21 +96,7 @@ var vimStates = {
},
{
comment: "Catch some keyboard input to stop it here",
match: function(buffer, hashId, key, symbolicName) {
// If no command keys are pressed, then catch the input.
if (hashId == 0) {
return true;
}
// If only the shift key is pressed and a character key, then
// catch that input as well.
else if ((hashId == 4) && key.length == 1) {
return true;
}
// Otherwise, we let the input got through.
else {
return false;
}
}
match: matchCharacterOnly
}
],
insertMode: [
@ -125,4 +112,4 @@ var vimKeyboardStateMapper = new KeyboardStateMapper(vimStates);
exports.handleKeyboard = function(data, hashId, key, e) {
return vimKeyboardStateMapper.match(data, hashId, key);
}
});
});