import vim keybinding from cloud9
This commit is contained in:
parent
f67fc8c9eb
commit
adf7420b85
7 changed files with 1228 additions and 0 deletions
500
lib/ace/keyboard/vim/commands.js
Normal file
500
lib/ace/keyboard/vim/commands.js
Normal file
|
|
@ -0,0 +1,500 @@
|
|||
/**
|
||||
* Vim mode for the Cloud9 IDE
|
||||
*
|
||||
* @author Sergi Mansilla <sergi AT c9 DOT io>
|
||||
* @copyright 2011, Ajax.org B.V.
|
||||
* @license GPLv3 <http://www.gnu.org/licenses/gpl.txt>
|
||||
*/
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var Editors = require("ext/editors/editors");
|
||||
var util = require("ext/vim/maps/util");
|
||||
var motions = require("ext/vim/maps/motions");
|
||||
var operators = require("ext/vim/maps/operators");
|
||||
var alias = require("ext/vim/maps/aliases");
|
||||
var registers = require("ext/vim/registers");
|
||||
|
||||
var NUMBER = 1;
|
||||
var OPERATOR = 2;
|
||||
var MOTION = 3;
|
||||
var ACTION = 4;
|
||||
|
||||
//var NORMAL_MODE = 0;
|
||||
//var INSERT_MODE = 1;
|
||||
//var VISUAL_MODE = 2;
|
||||
//getSelectionLead
|
||||
|
||||
exports.searchStore = {
|
||||
current: "",
|
||||
options: {
|
||||
needle: "",
|
||||
backwards: false,
|
||||
wrap: true,
|
||||
caseSensitive: false,
|
||||
wholeWord: false,
|
||||
regExp: false
|
||||
}
|
||||
};
|
||||
|
||||
var repeat = function repeat(fn, count, args) {
|
||||
count = parseInt(count);
|
||||
while (0 < count--)
|
||||
fn.apply(this, args);
|
||||
};
|
||||
|
||||
var actions = {
|
||||
"z": {
|
||||
param: true,
|
||||
fn: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "z":
|
||||
editor.centerSelection();
|
||||
break;
|
||||
case "t":
|
||||
editor.scrollToRow(editor.getCursorPosition().row);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"r": {
|
||||
param: true,
|
||||
fn: function(editor, range, count, param) {
|
||||
param = util.toRealChar(param);
|
||||
if (param && param.length) {
|
||||
repeat(function() { editor.insert(param); }, count || 1);
|
||||
editor.navigateLeft();
|
||||
}
|
||||
}
|
||||
},
|
||||
// "~" HACK
|
||||
"shift-`": {
|
||||
fn: function(editor, range, count) {
|
||||
repeat(function() {
|
||||
var pos = editor.getCursorPosition();
|
||||
var line = editor.session.getLine(pos.row);
|
||||
var ch = line[pos.column];
|
||||
editor.insert(toggleCase(ch));
|
||||
}, count || 1);
|
||||
}
|
||||
},
|
||||
"*": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectWord();
|
||||
editor.findNext();
|
||||
var cursor = editor.selection.getCursor();
|
||||
var range = editor.session.getWordRange(cursor.row, cursor.column);
|
||||
editor.selection.setSelectionRange(range, true);
|
||||
}
|
||||
},
|
||||
"#": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectWord();
|
||||
editor.findPrevious();
|
||||
var cursor = editor.selection.getCursor();
|
||||
var range = editor.session.getWordRange(cursor.row, cursor.column);
|
||||
editor.selection.setSelectionRange(range, true);
|
||||
}
|
||||
},
|
||||
"n": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.findNext(editor.getLastSearchOptions());
|
||||
editor.selection.clearSelection();
|
||||
//editor.navigateWordLeft();
|
||||
}
|
||||
},
|
||||
"shift-n": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.findPrevious(editor.getLastSearchOptions());
|
||||
editor.selection.clearSelection();
|
||||
//editor.navigateWordLeft();
|
||||
}
|
||||
},
|
||||
"v": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.selection.selectRight();
|
||||
util.onVisualMode = true;
|
||||
util.onVisualLineMode = false;
|
||||
var cursor = document.getElementsByClassName("ace_cursor")[0];
|
||||
cursor.style.display = "none";
|
||||
}
|
||||
},
|
||||
"shift-v": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.onVisualLineMode = true;
|
||||
//editor.selection.selectLine();
|
||||
//editor.selection.selectLeft();
|
||||
var row = editor.getCursorPosition().row;
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(row, 0);
|
||||
editor.selection.selectLineEnd();
|
||||
editor.selection.visualLineStart = row;
|
||||
}
|
||||
},
|
||||
"shift-y": {
|
||||
fn: function(editor, range, count, param) {
|
||||
util.copyLine(editor);
|
||||
}
|
||||
},
|
||||
"p": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var defaultReg = registers._default;
|
||||
|
||||
editor.setOverwrite(false);
|
||||
if (defaultReg.isLine) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lines = defaultReg.text.split("\n");
|
||||
editor.session.getDocument().insertLines(pos.row + 1, lines);
|
||||
editor.moveCursorTo(pos.row + 1, 0);
|
||||
}
|
||||
else {
|
||||
editor.navigateRight();
|
||||
editor.insert(defaultReg.text);
|
||||
editor.navigateLeft();
|
||||
}
|
||||
editor.setOverwrite(true);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"shift-p": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var defaultReg = registers._default;
|
||||
editor.setOverwrite(false);
|
||||
|
||||
if (defaultReg.isLine) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lines = defaultReg.text.split("\n");
|
||||
editor.session.getDocument().insertLines(pos.row, lines);
|
||||
editor.moveCursorTo(pos.row, 0);
|
||||
}
|
||||
else {
|
||||
editor.insert(defaultReg.text);
|
||||
}
|
||||
editor.setOverwrite(true);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"shift-j": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var pos = editor.getCursorPosition();
|
||||
|
||||
if (editor.session.getLength() === pos.row + 1)
|
||||
return;
|
||||
|
||||
var nextLine = editor.session.getLine(pos.row + 1);
|
||||
var cleanLine = /^\s*(.*)$/.exec(nextLine)[1];
|
||||
|
||||
editor.navigateDown();
|
||||
editor.removeLines();
|
||||
|
||||
if (editor.session.getLength() > editor.getCursorPosition().row + 1)
|
||||
editor.navigateUp();
|
||||
|
||||
editor.navigateLineEnd();
|
||||
editor.insert(" " + (cleanLine || ""));
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
|
||||
}
|
||||
},
|
||||
"u": {
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.undo();
|
||||
}
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
"ctrl-r": {
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.redo();
|
||||
}
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
},
|
||||
":": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.blur();
|
||||
txtConsoleInput.focus();
|
||||
txtConsoleInput.setValue(":");
|
||||
}
|
||||
},
|
||||
"/": {
|
||||
fn: function(editor, range, count, param) {
|
||||
editor.blur();
|
||||
txtConsoleInput.focus();
|
||||
txtConsoleInput.setValue("/");
|
||||
}
|
||||
},
|
||||
".": {
|
||||
fn: function(editor, range, count, param) {
|
||||
var previous = inputBuffer.previous;
|
||||
util.onInsertReplaySequence = inputBuffer.lastInsertCommands;
|
||||
inputBuffer.exec(editor, previous.action, previous.param);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var inputBuffer = exports.inputBuffer = {
|
||||
accepting: [NUMBER, OPERATOR, MOTION, ACTION],
|
||||
currentCmd: null,
|
||||
//currentMode: 0,
|
||||
currentCount: "",
|
||||
|
||||
// Types
|
||||
operator: null,
|
||||
motion: null,
|
||||
|
||||
lastInsertCommands: [],
|
||||
|
||||
push: function(editor, char, keyId) {
|
||||
if (char && char.length > 1) { // There is a modifier key
|
||||
if (!char[char.length - 1].match(/[A-za-z]/) && keyId) // It is a letter
|
||||
char = keyId;
|
||||
}
|
||||
|
||||
this.idle = false;
|
||||
var wObj = this.waitingForParam;
|
||||
if (wObj) {
|
||||
this.exec(editor, wObj, char);
|
||||
}
|
||||
// If input is a number (that doesn't start with 0)
|
||||
else if (!(char === "0" && !this.currentCount.length) &&
|
||||
(char.match(/^\d+$/) && this.isAccepting(NUMBER))) {
|
||||
// Assuming that char is always of type String, and not Number
|
||||
this.currentCount += char;
|
||||
this.currentCmd = NUMBER;
|
||||
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
|
||||
}
|
||||
else if (!this.operator && this.isAccepting(OPERATOR) && operators[char]) {
|
||||
this.operator = {
|
||||
char: char,
|
||||
count: this.getCount()
|
||||
};
|
||||
this.currentCmd = OPERATOR;
|
||||
this.accepting = [NUMBER, MOTION, ACTION];
|
||||
this.exec(editor, { operator: this.operator });
|
||||
}
|
||||
else if (motions[char] && this.isAccepting(MOTION)) {
|
||||
this.currentCmd = MOTION;
|
||||
|
||||
var ctx = {
|
||||
operator: this.operator,
|
||||
motion: {
|
||||
char: char,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (motions[char].param)
|
||||
this.waitForParam(ctx);
|
||||
else
|
||||
this.exec(editor, ctx);
|
||||
}
|
||||
else if (alias[char] && this.isAccepting(MOTION)) {
|
||||
alias[char].operator.count = this.getCount();
|
||||
this.exec(editor, alias[char]);
|
||||
}
|
||||
else if (actions[char] && this.isAccepting(ACTION)) {
|
||||
var actionObj = {
|
||||
action: {
|
||||
fn: actions[char].fn,
|
||||
count: this.getCount()
|
||||
}
|
||||
};
|
||||
|
||||
if (actions[char].param) {
|
||||
this.waitForParam(actionObj);
|
||||
}
|
||||
else {
|
||||
this.exec(editor, actionObj);
|
||||
}
|
||||
}
|
||||
else if (this.operator) {
|
||||
this.exec(editor, { operator: this.operator }, char);
|
||||
}
|
||||
else {
|
||||
this.reset();
|
||||
}
|
||||
},
|
||||
|
||||
waitForParam: function(cmd) {
|
||||
this.waitingForParam = cmd;
|
||||
},
|
||||
|
||||
getCount: function() {
|
||||
var count = this.currentCount;
|
||||
this.currentCount = "";
|
||||
return count;
|
||||
},
|
||||
|
||||
exec: function(editor, action, param) {
|
||||
var m = action.motion;
|
||||
var o = action.operator;
|
||||
var a = action.action;
|
||||
|
||||
if(o) {
|
||||
this.previous = {
|
||||
action: action,
|
||||
param: param
|
||||
};
|
||||
}
|
||||
|
||||
if (o && !editor.selection.isEmpty()) {
|
||||
if (operators[o.char].selFn) {
|
||||
operators[o.char].selFn(editor, editor.getSelectionRange(), o.count, param);
|
||||
this.reset();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// There is an operator, but no motion or action. We try to pass the
|
||||
// current char to the operator to see if it responds to it (an example
|
||||
// of this is the 'dd' operator).
|
||||
else if (!m && !a && o && param) {
|
||||
operators[o.char].fn(editor, null, o.count, param);
|
||||
this.reset();
|
||||
}
|
||||
else if (m) {
|
||||
var run = function(fn) {
|
||||
if (fn && typeof fn === "function") { // There should always be a motion
|
||||
if (m.count)
|
||||
repeat(fn, m.count, [editor, null, m.count, param]);
|
||||
else
|
||||
fn(editor, null, m.count, param);
|
||||
}
|
||||
};
|
||||
|
||||
var motionObj = motions[m.char];
|
||||
var selectable = motionObj.sel;
|
||||
|
||||
if (!o) {
|
||||
if ((util.onVisualMode || util.onVisualLineMode) && selectable)
|
||||
run(motionObj.sel);
|
||||
else
|
||||
run(motionObj.nav);
|
||||
}
|
||||
else if (selectable) {
|
||||
repeat(function() {
|
||||
run(motionObj.sel);
|
||||
operators[o.char].fn(editor, editor.getSelectionRange(), o.count, param);
|
||||
}, o.count || 1);
|
||||
}
|
||||
this.reset();
|
||||
}
|
||||
else if (a) {
|
||||
a.fn(editor, editor.getSelectionRange(), a.count, param);
|
||||
this.reset();
|
||||
}
|
||||
handleCursorMove();
|
||||
},
|
||||
|
||||
isAccepting: function(type) {
|
||||
return this.accepting.indexOf(type) !== -1;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.operator = null;
|
||||
this.motion = null;
|
||||
this.currentCount = "";
|
||||
this.accepting = [NUMBER, OPERATOR, MOTION, ACTION];
|
||||
this.idle = true;
|
||||
this.waitingForParam = null;
|
||||
}
|
||||
};
|
||||
|
||||
function setPreviousCommand(fn) {
|
||||
inputBuffer.previous = { action: { action: { fn: fn } } };
|
||||
}
|
||||
|
||||
exports.commands = {
|
||||
start: {
|
||||
exec: function start(editor) {
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(start);
|
||||
}
|
||||
},
|
||||
startBeginning: {
|
||||
exec: function startBeginning(editor) {
|
||||
editor.navigateLineStart();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(startBeginning);
|
||||
}
|
||||
},
|
||||
// Stop Insert mode as soon as possible. Works like typing <Esc> in
|
||||
// insert mode.
|
||||
stop: {
|
||||
exec: function stop(editor) {
|
||||
inputBuffer.reset();
|
||||
util.onVisualMode = false;
|
||||
util.onVisualLineMode = false;
|
||||
inputBuffer.lastInsertCommands = util.normalMode(editor);
|
||||
}
|
||||
},
|
||||
append: {
|
||||
exec: function append(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
if (lineLen)
|
||||
editor.navigateRight();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(append);
|
||||
}
|
||||
},
|
||||
appendEnd: {
|
||||
exec: function appendEnd(editor) {
|
||||
editor.navigateLineEnd();
|
||||
util.insertMode(editor);
|
||||
setPreviousCommand(appendEnd);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var handleCursorMove = exports.onCursorMove = function() {
|
||||
var editor = Editors.currentEditor.amlEditor.$editor;
|
||||
|
||||
if(util.currentMode === 'insert' || handleCursorMove.running)
|
||||
return;
|
||||
else if(!editor.selection.isEmpty()) {
|
||||
handleCursorMove.running = true;
|
||||
if(util.onVisualLineMode) {
|
||||
var originRow = editor.selection.visualLineStart;
|
||||
var cursorRow = editor.getCursorPosition().row;
|
||||
if(originRow <= cursorRow) {
|
||||
var endLine = editor.session.getLine(cursorRow);
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(originRow, 0);
|
||||
editor.selection.selectTo(cursorRow, endLine.length);
|
||||
} else {
|
||||
var endLine = editor.session.getLine(originRow);
|
||||
editor.selection.clearSelection();
|
||||
editor.selection.moveCursorTo(originRow, endLine.length);
|
||||
editor.selection.selectTo(cursorRow, 0);
|
||||
}
|
||||
}
|
||||
handleCursorMove.running = false;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
handleCursorMove.running = true;
|
||||
var pos = editor.getCursorPosition();
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
|
||||
if (lineLen && pos.column === lineLen)
|
||||
editor.navigateLeft();
|
||||
handleCursorMove.running = false;
|
||||
}
|
||||
};
|
||||
|
||||
function toggleCase(ch) {
|
||||
if(ch.toUpperCase() === ch)
|
||||
return ch.toLowerCase();
|
||||
else
|
||||
return ch.toUpperCase();
|
||||
}
|
||||
|
||||
});
|
||||
92
lib/ace/keyboard/vim/keyboard.js
Normal file
92
lib/ace/keyboard/vim/keyboard.js
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var StateHandler = require("ace/keyboard/state_handler").StateHandler;
|
||||
var cmds = require("ext/vim/commands");
|
||||
var editors = require("ext/editors/editors");
|
||||
|
||||
var matchChar = function(buffer, hashId, key, symbolicName, keyId) {
|
||||
// If no command keys are pressed, then catch the input.
|
||||
// If only the shift key is pressed and a character key, then
|
||||
// catch that input as well.
|
||||
// Otherwise, we let the input got through.
|
||||
var matched = ((hashId === 0) || (((hashId === 1) || (hashId === 4)) && key.length === 1));
|
||||
//console.log("INFO", arguments)
|
||||
|
||||
if (matched) {
|
||||
if (keyId) {
|
||||
keyId = String.fromCharCode(parseInt(keyId.replace("U+", "0x"), 10));
|
||||
}
|
||||
|
||||
var editor = editors.currentEditor.amlEditor.$editor;
|
||||
editor.commands.addCommand({
|
||||
name: "builder",
|
||||
exec: function(editor) {
|
||||
cmds.inputBuffer.push.call(cmds.inputBuffer, editor, symbolicName, keyId);
|
||||
}
|
||||
});
|
||||
}
|
||||
return matched;
|
||||
};
|
||||
|
||||
var inIdleState = function() {
|
||||
if (cmds.inputBuffer.idle) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var states = exports.states = {
|
||||
start: [ // normal mode
|
||||
{
|
||||
key: "esc",
|
||||
exec: "stop",
|
||||
then: "start"
|
||||
},
|
||||
{
|
||||
regex: "^i$",
|
||||
match: inIdleState,
|
||||
exec: "start",
|
||||
then: "insertMode"
|
||||
},
|
||||
{
|
||||
regex: "^shift-i$",
|
||||
match: inIdleState,
|
||||
exec: "startBeginning",
|
||||
then: "insertMode"
|
||||
},
|
||||
{
|
||||
regex: "^a$",
|
||||
match: inIdleState,
|
||||
exec: "append",
|
||||
then: "insertMode"
|
||||
},
|
||||
{
|
||||
regex: "^shift-a$",
|
||||
match: inIdleState,
|
||||
exec: "appendEnd",
|
||||
then: "insertMode"
|
||||
},
|
||||
{
|
||||
// The rest of input will be processed here
|
||||
match: matchChar,
|
||||
exec: "builder"
|
||||
}
|
||||
],
|
||||
insertMode: [
|
||||
{
|
||||
key: "esc",
|
||||
exec: "stop",
|
||||
then: "start"
|
||||
},
|
||||
{
|
||||
key: "backspace",
|
||||
exec: "backspace"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
exports.handler = new StateHandler(states);
|
||||
});
|
||||
67
lib/ace/keyboard/vim/maps/aliases.js
Normal file
67
lib/ace/keyboard/vim/maps/aliases.js
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
"use strict"
|
||||
|
||||
define(function(require, exports, module) {
|
||||
module.exports = {
|
||||
"x": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "l",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"shift-x": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "h",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"shift-d": {
|
||||
operator: {
|
||||
char: "d",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "$",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"shift-c": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "$",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"s": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "l",
|
||||
count: 1
|
||||
}
|
||||
},
|
||||
"shift-s": {
|
||||
operator: {
|
||||
char: "c",
|
||||
count: 1
|
||||
},
|
||||
motion: {
|
||||
char: "l",
|
||||
count: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
285
lib/ace/keyboard/vim/maps/motions.js
Normal file
285
lib/ace/keyboard/vim/maps/motions.js
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
"use strict"
|
||||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
var util = require("ext/vim/maps/util");
|
||||
|
||||
var keepScrollPosition = function(editor, fn) {
|
||||
var scrollTopRow = editor.renderer.getScrollTopRow();
|
||||
var initialRow = editor.getCursorPosition().row;
|
||||
var diff = initialRow - scrollTopRow;
|
||||
fn && fn.call(editor);
|
||||
editor.renderer.scrollToRow(editor.getCursorPosition().row - diff);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
"w": {
|
||||
nav: function(editor) {
|
||||
editor.navigateWordRight();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectWordRight();
|
||||
}
|
||||
},
|
||||
"b": {
|
||||
nav: function(editor) {
|
||||
editor.navigateWordLeft();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectWordLeft();
|
||||
}
|
||||
},
|
||||
"l": {
|
||||
nav: function(editor) {
|
||||
editor.navigateRight();
|
||||
},
|
||||
sel: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
var col = pos.column;
|
||||
var lineLen = editor.session.getLine(pos.row).length;
|
||||
|
||||
// Solving the behavior at the end of the line due to the
|
||||
// different 0 index-based colum positions in ACE.
|
||||
if (lineLen && col !== lineLen) //In selection mode you can select the newline
|
||||
editor.selection.selectRight();
|
||||
}
|
||||
},
|
||||
"h": {
|
||||
nav: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.navigateLeft();
|
||||
},
|
||||
sel: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.selection.selectLeft();
|
||||
}
|
||||
},
|
||||
"k": {
|
||||
nav: function(editor) {
|
||||
editor.navigateUp();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectUp();
|
||||
}
|
||||
},
|
||||
"j": {
|
||||
nav: function(editor) {
|
||||
editor.navigateDown();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectDown();
|
||||
}
|
||||
},
|
||||
"i": {
|
||||
param: true,
|
||||
sel: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "w":
|
||||
editor.selection.selectWord();
|
||||
}
|
||||
}
|
||||
},
|
||||
"a": {
|
||||
param: true,
|
||||
sel: function(editor, range, count, param) {
|
||||
switch (param) {
|
||||
case "w":
|
||||
editor.selection.selectAWord();
|
||||
}
|
||||
}
|
||||
},
|
||||
"f": {
|
||||
param: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10) || 1;
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10) || 1;
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column + 1);
|
||||
}
|
||||
}
|
||||
},
|
||||
"t": {
|
||||
param: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10) || 1;
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.selection.clearSelection(); // Why does it select in the first place?
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10) || 1;
|
||||
var ed = editor;
|
||||
var cursor = ed.getCursorPosition();
|
||||
var column = util.getRightNthChar(editor, cursor, param, count);
|
||||
|
||||
if (typeof column === "number") {
|
||||
ed.moveCursorTo(cursor.row, column + cursor.column);
|
||||
}
|
||||
}
|
||||
},
|
||||
"^": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineStart();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineStart();
|
||||
}
|
||||
},
|
||||
"$": {
|
||||
nav: function(editor) {
|
||||
editor.navigateLineEnd();
|
||||
},
|
||||
sel: function(editor) {
|
||||
editor.selection.selectLineEnd();
|
||||
}
|
||||
},
|
||||
"0": {
|
||||
nav: function(editor) {
|
||||
var ed = editor;
|
||||
ed.navigateTo(ed.selection.selectionLead.row, 0);
|
||||
},
|
||||
sel: function(editor) {
|
||||
var ed = editor;
|
||||
ed.selectTo(ed.selection.selectionLead.row, 0);
|
||||
}
|
||||
},
|
||||
"shift-g": {
|
||||
nav: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10);
|
||||
if (!count && count !== 0) { // Stupid JS
|
||||
count = editor.session.getLength();
|
||||
}
|
||||
editor.gotoLine(count);
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
count = parseInt(count, 10);
|
||||
if (!count && count !== 0) { // Stupid JS
|
||||
count = editor.session.getLength();
|
||||
}
|
||||
editor.selection.selectTo(count, 0);
|
||||
}
|
||||
},
|
||||
"ctrl-d": {
|
||||
nav: function(editor, range, count, param) {
|
||||
editor.selection.clearSelection();
|
||||
keepScrollPosition(editor, editor.gotoPageDown);
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
keepScrollPosition(editor, editor.selectPageDown);
|
||||
}
|
||||
},
|
||||
"ctrl-u": {
|
||||
nav: function(editor, range, count, param) {
|
||||
editor.selection.clearSelection();
|
||||
keepScrollPosition(editor, editor.gotoPageUp);
|
||||
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
keepScrollPosition(editor, editor.selectPageUp);
|
||||
}
|
||||
},
|
||||
"g": {
|
||||
param: true,
|
||||
nav: function(editor, range, count, param) {
|
||||
switch(param) {
|
||||
case "m":
|
||||
console.log("Middle line");
|
||||
break;
|
||||
case "e":
|
||||
console.log("End of prev word");
|
||||
break;
|
||||
case "g":
|
||||
editor.gotoLine(count || 0);
|
||||
}
|
||||
},
|
||||
sel: function(editor, range, count, param) {
|
||||
switch(param) {
|
||||
case "m":
|
||||
console.log("Middle line");
|
||||
break;
|
||||
case "e":
|
||||
console.log("End of prev word");
|
||||
break;
|
||||
case "g":
|
||||
editor.selection.selectTo(count || 0, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
"o": {
|
||||
nav: function(editor, range, count, param) {
|
||||
count = count || 1;
|
||||
var content = "";
|
||||
while (0 < count--)
|
||||
content += "\n";
|
||||
|
||||
if (content.length) {
|
||||
editor.navigateLineEnd()
|
||||
editor.insert(content);
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
},
|
||||
"shift-o": {
|
||||
nav: function(editor, range, count, param) {
|
||||
var row = editor.getCursorPosition().row;
|
||||
count = count || 1;
|
||||
var content = "";
|
||||
while (0 < count--)
|
||||
content += "\n";
|
||||
|
||||
if (content.length) {
|
||||
if(row > 0) {
|
||||
editor.navigateUp();
|
||||
editor.navigateLineEnd()
|
||||
editor.insert(content);
|
||||
} else {
|
||||
editor.session.insert({row: 0, column: 0}, content);
|
||||
editor.navigateUp();
|
||||
}
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
},
|
||||
"%": {
|
||||
nav: function(editor, range, count, param) {
|
||||
var cursor = editor.getCursorPosition();
|
||||
var match = editor.session.findMatchingBracket({
|
||||
row: cursor.row,
|
||||
column: cursor.column + 1
|
||||
});
|
||||
|
||||
if (match)
|
||||
editor.moveCursorTo(match.row, match.column);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports.backspace = module.exports.left = module.exports.h;
|
||||
module.exports.right = module.exports.l;
|
||||
module.exports.up = module.exports.k;
|
||||
module.exports.down = module.exports.j;
|
||||
module.exports.pagedown = module.exports["ctrl-d"];
|
||||
module.exports.pageup = module.exports["ctrl-u"];
|
||||
|
||||
});
|
||||
154
lib/ace/keyboard/vim/maps/operators.js
Normal file
154
lib/ace/keyboard/vim/maps/operators.js
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
define(function(require, exports, module) {
|
||||
|
||||
"use strict";
|
||||
|
||||
var util = require("ext/vim/maps/util");
|
||||
var registers = require("ext/vim/registers");
|
||||
|
||||
module.exports = {
|
||||
"d": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = util.onVisualLineMode;
|
||||
if(util.onVisualLineMode)
|
||||
editor.removeLines();
|
||||
else
|
||||
editor.session.remove(range);
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
switch (param) {
|
||||
case "d":
|
||||
registers._default.text = "";
|
||||
registers._default.isLine = true;
|
||||
for (var i=0; i<count; i++) {
|
||||
editor.selection.selectLine();
|
||||
registers._default.text += editor.getCopyText();
|
||||
var selRange = editor.getSelectionRange();
|
||||
editor.session.remove(selRange);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
registers._default.text = registers._default.text.replace(/\n$/, "");
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
editor.selection.setSelectionRange(range);
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = false;
|
||||
editor.session.remove(range);
|
||||
editor.selection.clearSelection();
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"c": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
editor.session.remove(range);
|
||||
util.insertMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
switch (param) {
|
||||
case "c":
|
||||
for (var i=0; i < count; i++) {
|
||||
editor.removeLines();
|
||||
util.insertMode(editor);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
editor.session.remove(range);
|
||||
util.insertMode(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"y": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = util.onVisualLineMode;
|
||||
editor.selection.clearSelection();
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
switch (param) {
|
||||
case "y":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
registers._default.text = editor.getCopyText().replace(/\n$/, "");
|
||||
editor.selection.clearSelection();
|
||||
registers._default.isLine = true;
|
||||
editor.moveCursorToPosition(pos);
|
||||
break;
|
||||
default:
|
||||
if (range) {
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.setSelectionRange(range);
|
||||
registers._default.text = editor.getCopyText();
|
||||
registers._default.isLine = false;
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
">": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.indent();
|
||||
}
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
switch (param) {
|
||||
case ">":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
editor.indent();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.navigateLineEnd();
|
||||
editor.navigateLineStart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
"<": {
|
||||
selFn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
for (var i = 0; i < count; i++) {
|
||||
editor.blockOutdent();
|
||||
}
|
||||
util.normalMode(editor);
|
||||
},
|
||||
fn: function(editor, range, count, param) {
|
||||
count = parseInt(count || 1, 10);
|
||||
switch (param) {
|
||||
case "<":
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.selectLine();
|
||||
for (var i = 0; i < count - 1; i++) {
|
||||
editor.selection.moveCursorDown();
|
||||
}
|
||||
editor.blockOutdent();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorToPosition(pos);
|
||||
editor.navigateLineEnd();
|
||||
editor.navigateLineStart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
117
lib/ace/keyboard/vim/maps/util.js
Normal file
117
lib/ace/keyboard/vim/maps/util.js
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
"use strict";
|
||||
|
||||
define(function(require, exports, module) {
|
||||
var registers = require("ext/vim/registers");
|
||||
|
||||
module.exports = {
|
||||
onVisualMode: false,
|
||||
onVisualLineMode: false,
|
||||
currentMode: 'normal',
|
||||
insertMode: function(editor) {
|
||||
var _self = this;
|
||||
var theme = editor && editor.getTheme() || "ace/theme/textmate";
|
||||
|
||||
require(["require", theme], function (require) {
|
||||
var isDarkTheme = require(theme).isDark;
|
||||
|
||||
_self.currentMode = 'insert';
|
||||
// Switch editor to insert mode
|
||||
editor.unsetStyle('insert-mode');
|
||||
|
||||
var cursor = document.getElementsByClassName("ace_cursor")[0];
|
||||
if (cursor) {
|
||||
cursor.style.display = null;
|
||||
cursor.style.backgroundColor = null;
|
||||
cursor.style.opacity = null;
|
||||
cursor.style.border = null;
|
||||
cursor.style.borderLeftColor = isDarkTheme? "#eeeeee" : "#333333";
|
||||
cursor.style.borderLeftStyle = "solid";
|
||||
cursor.style.borderLeftWidth = "2px";
|
||||
}
|
||||
|
||||
editor.setOverwrite(false);
|
||||
editor.keyBinding.$data.buffer = "";
|
||||
editor.keyBinding.$data.state = "insertMode";
|
||||
_self.onVisualMode = false;
|
||||
_self.onVisualLineMode = false;
|
||||
if(_self.onInsertReplaySequence) {
|
||||
// Ok, we're apparently replaying ("."), so let's do it
|
||||
editor.commands.macro = _self.onInsertReplaySequence;
|
||||
editor.commands.replay(editor);
|
||||
_self.onInsertReplaySequence = null;
|
||||
_self.normalMode(editor);
|
||||
} else {
|
||||
// Record any movements, insertions in insert mode
|
||||
if(!editor.commands.recording)
|
||||
editor.commands.toggleRecording();
|
||||
}
|
||||
});
|
||||
},
|
||||
normalMode: function(editor) {
|
||||
// Switch editor to normal mode
|
||||
this.currentMode = 'normal';
|
||||
|
||||
editor.setStyle('normal-mode');
|
||||
editor.clearSelection();
|
||||
|
||||
var cursor = document.getElementsByClassName("ace_cursor")[0];
|
||||
if (cursor) {
|
||||
cursor.style.display = null;
|
||||
cursor.style.backgroundColor = "red";
|
||||
cursor.style.opacity = ".5";
|
||||
cursor.style.border = "0";
|
||||
}
|
||||
|
||||
var pos;
|
||||
if (!editor.getOverwrite()) {
|
||||
pos = editor.getCursorPosition();
|
||||
if (pos.column > 0)
|
||||
editor.navigateLeft();
|
||||
}
|
||||
editor.setOverwrite(true);
|
||||
editor.keyBinding.$data.buffer = "";
|
||||
editor.keyBinding.$data.state = "start";
|
||||
this.onVisualMode = false;
|
||||
this.onVisualLineMode = false;
|
||||
// Save recorded keystrokes
|
||||
if(editor.commands.recording) {
|
||||
editor.commands.toggleRecording();
|
||||
return editor.commands.macro;
|
||||
}
|
||||
else {
|
||||
return [];
|
||||
}
|
||||
},
|
||||
getRightNthChar: function(editor, cursor, char, n) {
|
||||
var line = editor.getSession().getLine(cursor.row);
|
||||
var matches = line.substr(cursor.column + 1).split(char);
|
||||
|
||||
return n < matches.length ? matches.slice(0, n).join(char).length : 0;
|
||||
},
|
||||
getLeftNthChar: function(editor, cursor, char, n) {
|
||||
var line = editor.getSession().getLine(cursor.row);
|
||||
var matches = line.substr(0, cursor.column + 1).split(char);
|
||||
|
||||
return n < matches.length ? matches.slice(-1 * n).join(char).length + 1: 0;
|
||||
},
|
||||
toRealChar: function(char) {
|
||||
if (char.length === 1)
|
||||
return char;
|
||||
|
||||
if (/^shift-./.test(char))
|
||||
return char[char.length - 1].toUpperCase();
|
||||
else
|
||||
return "";
|
||||
},
|
||||
copyLine: function(editor) {
|
||||
var pos = editor.getCursorPosition();
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
editor.selection.selectLine();
|
||||
registers._default.isLine = true;
|
||||
registers._default.text = editor.getCopyText().replace(/\n$/, "");
|
||||
editor.selection.clearSelection();
|
||||
editor.moveCursorTo(pos.row, pos.column);
|
||||
}
|
||||
};
|
||||
});
|
||||
13
lib/ace/keyboard/vim/registers.js
Normal file
13
lib/ace/keyboard/vim/registers.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
define(function(require, exports, module) {
|
||||
|
||||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
_default: {
|
||||
text: "",
|
||||
isLine: false
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue