Merge remote branch 'jviereck/keymapping'

Conflicts:
	.gitignore
	.gitmodules
	LICENSE
	demo/boot.js
	demo/startup.js
	lib/ace/editor.js
	support/cockpit
This commit is contained in:
Fabian Jakobs 2011-01-14 15:21:38 +01:00
commit 18adea4251
26 changed files with 2725 additions and 127 deletions

View file

@ -20,6 +20,7 @@
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* 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
@ -37,8 +38,14 @@
define(function(require, exports, module) {
var lang = require("pilot/lang");
var canon = require("pilot/canon");
canon.addCommand({
name: "null",
exec: function(env, args, request) { }
});
canon.addCommand({
name: "selectall",
exec: function(env, args, request) { env.editor.getSelection().selectAll(); }
@ -113,7 +120,7 @@ canon.addCommand({
});
canon.addCommand({
name: "golineup",
exec: function(env, args, request) { env.editor.navigateUp(); }
exec: function(env, args, request) { env.editor.navigateUp(args.times); }
});
canon.addCommand({
name: "copylinesdown",
@ -136,8 +143,8 @@ canon.addCommand({
exec: function(env, args, request) { env.editor.getSelection().selectDown(); }
});
canon.addCommand({
name: "godown",
exec: function(env, args, request) { env.editor.navigateDown(); }
name: "golinedown",
exec: function(env, args, request) { env.editor.navigateDown(args.times); }
});
canon.addCommand({
name: "selectwordleft",
@ -161,7 +168,7 @@ canon.addCommand({
});
canon.addCommand({
name: "gotoleft",
exec: function(env, args, request) { env.editor.navigateLeft(); }
exec: function(env, args, request) { env.editor.navigateLeft(args.times); }
});
canon.addCommand({
name: "selectwordright",
@ -185,7 +192,7 @@ canon.addCommand({
});
canon.addCommand({
name: "gotoright",
exec: function(env, args, request) { env.editor.navigateRight(); }
exec: function(env, args, request) { env.editor.navigateRight(args.times); }
});
canon.addCommand({
name: "selectpagedown",
@ -243,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.insert(lang.stringRepeat(args.text || "",
args.times || 1));
}
});
});

View file

@ -60,7 +60,7 @@ exports.bindings = {
"selecttoend": "Command-Shift-Down",
"gotoend": "Command-End|Command-Down",
"selectdown": "Shift-Down",
"godown": "Down",
"golinedown": "Down",
"selectwordleft": "Option-Shift-Left",
"gotowordleft": "Option-Left",
"selecttolinestart": "Command-Shift-Left",

View file

@ -60,7 +60,7 @@ exports.bindings = {
"selecttoend": "Alt-Shift-Down",
"gotoend": "Ctrl-End|Ctrl-Down",
"selectdown": "Shift-Down",
"godown": "Down",
"golinedown": "Down",
"selectwordleft": "Ctrl-Shift-Left",
"gotowordleft": "Ctrl-Left",
"selecttolinestart": "Alt-Shift-Left",

View file

@ -87,10 +87,12 @@ var Document = function(text, mode) {
this.modified = true;
this.fireChangeEvent(0);
};
this.toString = function() {
return this.$lines.join(this.$getNewLineCharacter());
};
this.getValue = this.toString;
this.getSelection = function() {
return this.selection;

View file

@ -40,8 +40,8 @@ define(function(require, exports, module) {
var oop = require("pilot/oop");
var event = require("pilot/event");
var lang = require("pilot/lang");
var TextInput = require("ace/textinput").TextInput;
var KeyBinding = require("ace/keybinding").KeyBinding;
var TextInput = require("ace/keyboard/textinput").TextInput;
var KeyBinding = require("ace/keyboard/keybinding").KeyBinding;
var Document = require("ace/document").Document;
var Search = require("ace/search").Search;
var BackgroundTokenizer = require("ace/background_tokenizer").BackgroundTokenizer;
@ -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));
@ -110,6 +110,14 @@ var Editor =function(renderer, doc) {
}
};
this.setKeyboardHandler = function(keyboardHandler) {
this.keyBinding.setKeyboardHandler(keyboardHandler);
};
this.getKeyboardHandler = function() {
return this.keyBinding.getKeyboardHandler();
}
this.setDocument = function(doc) {
if (this.doc == doc) return;
@ -403,7 +411,7 @@ var Editor =function(renderer, doc) {
}
};
this.onTextInput = function(text) {
this.insert = function(text) {
if (this.$readOnly)
return;
@ -477,6 +485,14 @@ var Editor =function(renderer, doc) {
this.moveCursorToPosition(end);
this.renderer.scrollCursorIntoView();
}
this.onTextInput = function(text) {
this.keyBinding.onTextInput.call(this.keyBinding, text);
};
this.onCommandKey = function(e, hashId, keyCode) {
this.keyBinding.onCommandKey(e, hashId, keyCode);
};
this.$overwrite = false;
@ -589,7 +605,7 @@ var Editor =function(renderer, doc) {
if (this.selection.isEmpty())
this.selection.selectLeft();
this.moveCursorToPosition(this.doc.remove(this.getSelectionRange()));
this.clearSelection();
};
@ -852,9 +868,9 @@ var Editor =function(renderer, doc) {
this.$updateDesiredColumn(column);
};
this.navigateUp = function() {
this.navigateUp = function(times) {
this.selection.clearSelection();
this.selection.moveCursorBy(-1, 0);
this.selection.moveCursorBy(-(times || 1), 0);
if (this.$desiredColumn) {
var cursor = this.getCursorPosition();
@ -863,9 +879,9 @@ var Editor =function(renderer, doc) {
}
};
this.navigateDown = function() {
this.navigateDown = function(times) {
this.selection.clearSelection();
this.selection.moveCursorBy(1, 0);
this.selection.moveCursorBy(times || 1, 0);
if (this.$desiredColumn) {
var cursor = this.getCursorPosition();
@ -879,24 +895,30 @@ var Editor =function(renderer, doc) {
this.$desiredColumn = this.doc.documentToScreenColumn(cursor.row, cursor.column);
};
this.navigateLeft = function() {
this.navigateLeft = function(times) {
if (!this.selection.isEmpty()) {
var selectionStart = this.getSelectionRange().start;
this.moveCursorToPosition(selectionStart);
}
else {
this.selection.moveCursorLeft();
times = times || 1;
while (times--) {
this.selection.moveCursorLeft();
}
}
this.clearSelection();
};
this.navigateRight = function() {
this.navigateRight = function(times) {
if (!this.selection.isEmpty()) {
var selectionEnd = this.getSelectionRange().end;
this.moveCursorToPosition(selectionEnd);
}
else {
this.selection.moveCursorRight();
times = times || 1;
while (times--) {
this.selection.moveCursorRight();
}
}
this.clearSelection();
};

149
lib/ace/keyboard/emacs.js Normal file
View file

@ -0,0 +1,149 @@
/* ***** 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 StateHandler = require("ace/keyboard/state_handler").StateHandler;
var matchCharacterOnly = require("ace/keyboard/state_handler").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"
}
]
};
exports.Emacs = new StateHandler(emacsState);
});

View file

@ -11,15 +11,16 @@
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Ajax.org Code Editor (ACE).
* The Original Code is Mozilla Skywriter.
*
* The Initial Developer of the Original Code is
* Ajax.org Services B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* Fabian Jakobs <fabian AT ajax DOT org>
* 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
@ -37,72 +38,13 @@
define(function(require, exports, module) {
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 canon = require("pilot/canon");
require("ace/commands/default_commands");
var keyUtil = require("pilot/keys");
var KeyBinding = function(element, editor, config) {
function HashHandler(config) {
this.setConfig(config);
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);
var key = _self.keyNames[e.keyCode];
var commandName = (_self.config.reverse[hashId] || {})[(key
|| String.fromCharCode(e.keyCode)).toLowerCase()];
var success = canon.exec(commandName, {editor: editor});
if (success) {
return event.stopEvent(e);
}
});
};
}
(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, "")
@ -117,8 +59,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 '-'
}
@ -145,14 +87,30 @@ var KeyBinding = function(element, editor, config) {
}
this.setConfig = function(config) {
this.config = config || (useragent.isMac
? default_mac
: default_win);
if (typeof this.config.reverse == "undefined")
this.config.reverse = objectReverse.call(this, this.config, "|");
this.$config = config;
if (typeof this.$config.reverse == "undefined")
this.$config.reverse = objectReverse.call(this, this.$config, "|");
};
}).call(KeyBinding.prototype);
/**
* This function is called by keyBinding.
*/
this.handleKeyboard = function(data, hashId, textOrKey, keyCode) {
// Figure out if a commandKey was pressed or just some text was insert.
if (hashId != 0 || keyCode != 0) {
return {
command: (this.$config.reverse[hashId] || {})[textOrKey]
}
} else {
return {
command: "inserttext",
args: {
text: textOrKey
}
}
}
}
}).call(HashHandler.prototype)
exports.KeyBinding = KeyBinding;
exports.HashHandler = HashHandler;
});

View file

@ -0,0 +1,108 @@
/* ***** 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 Ajax.org Code Editor (ACE).
*
* The Initial Developer of the Original Code is
* Ajax.org Services B.V.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Fabian Jakobs <fabian AT ajax DOT org>
* 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 useragent = require("pilot/useragent");
var keyUtil = require("pilot/keys");
var event = require("pilot/event");
var settings = require("pilot/settings").settings;
var HashHandler = require("ace/keyboard/hash_handler").HashHandler;
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 KeyBinding = function(editor, config) {
this.$editor = editor;
this.$data = { };
this.$keyboardHandler = null;
this.$defaulKeyboardHandler = new HashHandler(config || (useragent.isMac
? default_mac
: default_win));
};
(function() {
this.setKeyboardHandler = function(keyboardHandler) {
if (this.$keyboardHandler != keyboardHandler) {
this.$data = { };
this.$keyboardHandler = keyboardHandler;
}
};
this.getKeyboardHandler = function() {
return this.$keyboardHandler;
};
this.$callKeyboardHandler = function (e, hashId, keyOrText, keyCode) {
var toExecute;
if (this.$keyboardHandler) {
toExecute =
this.$keyboardHandler.handleKeyboard(this.$data, hashId, keyOrText, keyCode, e);
}
// If there is nothing to execute yet, then use the default keymapping.
if (!toExecute || !toExecute.command) {
toExecute = this.$defaulKeyboardHandler.
handleKeyboard(this.$data, hashId, keyOrText, keyCode, e);
}
if (toExecute) {
var success = canon.exec(toExecute.command,
{editor: this.$editor}, toExecute.args);
if (success) {
return event.stopEvent(e);
}
}
};
this.onCommandKey = function(e, hashId, keyCode) {
key = (keyUtil[keyCode] ||
String.fromCharCode(keyCode)).toLowerCase();
this.$callKeyboardHandler(e, hashId, key, keyCode);
};
this.onTextInput = function(text) {
this.$callKeyboardHandler({}, 0, text, 0);
}
}).call(KeyBinding.prototype);
exports.KeyBinding = KeyBinding;
});

View file

@ -0,0 +1,239 @@
/* ***** 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) {
// If you're developing a new keymapping and want to get an idea what's going
// on, then enable debugging.
var DEBUG = false;
function StateHandler(keymapping) {
this.keymapping = this.$buildKeymappingRegex(keymapping);
}
StateHandler.prototype = {
/**
* Build the RegExp from the keymapping as RegExp can't stored directly
* in the metadata JSON and as the RegExp used to match the keys/buffer
* need to be adapted.
*/
$buildKeymappingRegex: function(keymapping) {
for (state in keymapping) {
this.$buildBindingsRegex(keymapping[state]);
}
return keymapping;
},
$buildBindingsRegex: function(bindings) {
// Escape a given Regex string.
bindings.forEach(function(binding) {
if (binding.key) {
binding.key = new RegExp('^' + binding.key + '$');
} else if (Array.isArray(binding.regex)) {
binding.key = new RegExp('^' + binding.regex[1] + '$');
binding.regex = new RegExp(binding.regex.join('') + '$');
} else if (binding.regex) {
binding.regex = new RegExp(binding.regex + '$');
}
});
},
$composeBuffer: function(data, hashId, key) {
// Initialize the data object.
if (data.state == null || data.buffer == null) {
data.state = "start";
data.buffer = "";
}
var keyArray = [];
if (hashId & 1) keyArray.push("Ctrl");
if (hashId & 8) keyArray.push("Command");
if (hashId & 2) keyArray.push("Option");
if (hashId & 4) keyArray.push("Shift");
if (key) keyArray.push(key);
var symbolicName = keyArray.join("-").toLowerCase();
var bufferToUse = data.buffer + symbolicName;
// Don't add the symbolic name to the key buffer if the alt_ key is
// part of the symbolic name. If it starts with alt_, this means
// that the user hit an alt keycombo and there will be a single,
// new character detected after this event, which then will be
// added to the buffer (e.g. alt_j will result in ∆).
//
// We test for 2 and not for & 2 as we only want to exclude the case where
// the option key is pressed alone.
if (hashId != 2) {
data.buffer = bufferToUse;
}
return {
bufferToUse: bufferToUse,
symbolicName: symbolicName
};
},
$find: function(data, buffer, symbolicName, hashId, key) {
// Holds the command to execute and the args if a command matched.
var result = {};
// Loop over all the bindings of the keymapp until a match is found.
this.keymapping[data.state].some(function(binding) {
var match;
// Check if the key matches.
if (binding.key && !binding.key.test(symbolicName)) {
return false;
}
// Check if the regex matches.
if (binding.regex && !(match = binding.regex.exec(buffer))) {
return false;
}
// Check if the match function matches.
if (binding.match && !binding.match(buffer, hashId, key, symbolicName)) {
return false;
}
// Check for disallowed matches.
if (binding.disallowMatches) {
for (var i = 0; i < binding.disallowMatches.length; i++) {
if (!!match[binding.disallowMatches[i]]) {
return false;
}
}
}
// If there is a command to execute, then figure out the
// comand and the arguments.
if (binding.exec) {
result.command = binding.exec;
// Bulid the arguments.
if (binding.params) {
var value;
result.args = {};
binding.params.forEach(function(param) {
if (param.match != null && match != null) {
value = match[param.match] || param.defaultValue;
} else {
value = param.defaultValue;
}
if (param.type === 'number') {
value = parseInt(value);
}
result.args[param.name] = value;
});
}
data.buffer = "";
}
// Handle the 'then' property.
if (binding.then) {
data.state = binding.then;
data.buffer = "";
}
// If no command is set, then execute the "null" fake command.
if (result.command == null) {
result.command = "null";
}
if (DEBUG) {
console.log("KeyboardStateMapper#find", binding);
}
return true;
});
if (result.command) {
return result;
} else {
data.buffer = "";
return false;
}
},
/**
* This function is called by keyBinding.
*/
handleKeyboard: function(data, hashId, key) {
// Compute the current value of the keyboard input buffer.
var r = this.$composeBuffer(data, hashId, key);
var buffer = r.bufferToUse;
var symbolicName = r.symbolicName;
r = this.$find(data, buffer, symbolicName, hashId, key);
if (DEBUG) {
console.log("KeyboardStateMapper#match", buffer, symbolicName, r);
}
return r;
}
}
/**
* 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.StateHandler = StateHandler;
});

View file

@ -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", function(e) {

112
lib/ace/keyboard/vim.js Normal file
View file

@ -0,0 +1,112 @@
/* ***** 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 StateHandler = require("ace/keyboard/state_handler").StateHandler;
var matchCharacterOnly = require("ace/keyboard/state_handler").matchCharacterOnly;
var vimStates = {
start: [
{
key: "i",
then: "insertMode"
},
{
regex: [ "([0-9]*)", "(k|up)" ],
exec: "golineup",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "([0-9]*)", "(j|down|enter)" ],
exec: "golinedown",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "([0-9]*)", "(l|right)" ],
exec: "gotoright",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
regex: [ "([0-9]*)", "(h|left)" ],
exec: "gotoleft",
params: [
{
name: "times",
match: 1,
type: "number",
defaultValue: 1
}
]
},
{
comment: "Catch some keyboard input to stop it here",
match: matchCharacterOnly
}
],
insertMode: [
{
key: "esc",
then: "start"
}
]
};
exports.Vim = new StateHandler(vimStates);
});

View file

@ -34,15 +34,15 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("pilot/oop");
var TextMode = require("./text").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var PhpHighlightRules = require("./php_highlight_rules").PhpHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var Range = require("../range").Range;
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var PhpHighlightRules = require("ace/mode/php_highlight_rules").PhpHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var Mode = function() {
this.$tokenizer = new Tokenizer(new PhpHighlightRules().getRules());

View file

@ -34,15 +34,15 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
var oop = require("pilot/oop");
var TextMode = require("./text").Mode;
var Tokenizer = require("../tokenizer").Tokenizer;
var PythonHighlightRules = require("./python_highlight_rules").PythonHighlightRules;
var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
var Range = require("../range").Range;
var TextMode = require("ace/mode/text").Mode;
var Tokenizer = require("ace/tokenizer").Tokenizer;
var PythonHighlightRules = require("ace/mode/python_highlight_rules").PythonHighlightRules;
var MatchingBraceOutdent = require("ace/mode/matching_brace_outdent").MatchingBraceOutdent;
var Range = require("ace/range").Range;
var Mode = function() {
this.$tokenizer = new Tokenizer(new PythonHighlightRules().getRules());

View file

@ -33,7 +33,7 @@
* 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 *****
* ***** END LICENSE BLOCK *****
*
* TODO: python delimiters
*/
@ -42,7 +42,7 @@ define(function(require, exports, module) {
var oop = require("pilot/oop");
var lang = require("pilot/lang");
var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
var TextHighlightRules = require("ace/mode/text_highlight_rules").TextHighlightRules;
PythonHighlightRules = function() {
@ -50,12 +50,12 @@ PythonHighlightRules = function() {
("and|as|assert|break|class|continue|def|del|elif|else|except|exec|" +
"finally|for|from|global|if|import|in|is|lambda|not|or|pass|print|" +
"raise|return|try|while|with|yield").split("|")
);
);
var builtinConstants = lang.arrayToMap(
("True|False|None|NotImplemented|Ellipsis|__debug__").split("|")
);
var builtinFunctions = lang.arrayToMap(
("abs|divmod|input|open|staticmethod|all|enumerate|int|ord|str|any|" +
"eval|isinstance|pow|sum|basestring|execfile|issubclass|print|super|" +
@ -66,19 +66,19 @@ PythonHighlightRules = function() {
"__import__|complex|hash|min|set|apply|delattr|help|next|setattr|" +
"buffer|dict|hex|object|slice|coerce|dir|id|oct|sorted|intern").split("|")
);
var futureReserved = lang.arrayToMap(
("").split("|")
);
var strPre = "(?:(?:[rubRUB])|(?:[ubUB][rR]))?";
var decimalInteger = "(?:(?:[1-9]\\d*)|(?:0))";
var octInteger = "(?:0[oO]?[0-7]+)";
var hexInteger = "(?:0[xX][\\dA-Fa-f]+)";
var binInteger = "(?:0[bB][01]+)";
var integer = "(?:" + decimalInteger + "|" + octInteger + "|" + hexInteger + "|" + binInteger + ")";
var exponent = "(?:[eE][+-]?\\d+)";
var fraction = "(?:\\.\\d+)";
var intPart = "(?:\\d+)";