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:
commit
18adea4251
26 changed files with 2725 additions and 127 deletions
|
|
@ -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));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
149
lib/ace/keyboard/emacs.js
Normal 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);
|
||||
|
||||
});
|
||||
|
|
@ -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;
|
||||
});
|
||||
108
lib/ace/keyboard/keybinding.js
Normal file
108
lib/ace/keyboard/keybinding.js
Normal 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;
|
||||
});
|
||||
239
lib/ace/keyboard/state_handler.js
Normal file
239
lib/ace/keyboard/state_handler.js
Normal 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;
|
||||
});
|
||||
|
|
@ -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
112
lib/ace/keyboard/vim.js
Normal 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);
|
||||
|
||||
});
|
||||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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+)";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue