manual merge of ace++ branch

This commit is contained in:
nightwing 2012-04-22 14:28:10 +04:00
commit a2a3043907
11 changed files with 599 additions and 326 deletions

View file

@ -116,7 +116,7 @@ var KeyBinding = function(editor) {
if (toExecute.command != "null") if (toExecute.command != "null")
success = commands.exec(toExecute.command, this.$editor, toExecute.args, e); success = commands.exec(toExecute.command, this.$editor, toExecute.args, e);
else else
success = true; success = toExecute.stopEvent == true;
if (success && e) if (success && e)
event.stopEvent(e); event.stopEvent(e);
@ -130,9 +130,7 @@ var KeyBinding = function(editor) {
}; };
this.onTextInput = function(text) { this.onTextInput = function(text) {
var success = false; var success = this.$callKeyboardHandlers(-1, text);
if (text.length == 1)
success = this.$callKeyboardHandlers(0, text);
if (!success) if (!success)
this.$editor.commands.exec("insertstring", this.$editor, text); this.$editor.commands.exec("insertstring", this.$editor, text);
}; };

View file

@ -202,6 +202,8 @@ StateHandler.prototype = {
* This function is called by keyBinding. * This function is called by keyBinding.
*/ */
handleKeyboard: function(data, hashId, key, keyCode, e) { handleKeyboard: function(data, hashId, key, keyCode, e) {
if (hashId == -1)
hashId = 0
// If we pressed any command key but no other key, then ignore the input. // If we pressed any command key but no other key, then ignore the input.
// Otherwise "shift-" is added to the buffer, and later on "shift-g" // Otherwise "shift-" is added to the buffer, and later on "shift-g"
// which results in "shift-shift-g" which doesn't make sense. // which results in "shift-shift-g" which doesn't make sense.

View file

@ -1,5 +1,4 @@
define(function(require, exports, module) { define(function(require, exports, module) {
"use strict";
"never use strict"; "never use strict";
@ -9,7 +8,7 @@ var util = require("./vim/maps/util");
exports.handler = require("./vim/keyboard").handler; exports.handler = require("./vim/keyboard").handler;
exports.onCursorMove = function(e) { exports.onCursorMove = function(e) {
commands.onCursorMove(e.editor); commands.onCursorMove(e.editor, e);
exports.onCursorMove.scheduled = false; exports.onCursorMove.scheduled = false;
}; };
@ -21,7 +20,7 @@ exports.handler.attach = function(editor) {
exports.handler.detach = function(editor) { exports.handler.detach = function(editor) {
editor.removeListener("click", exports.onCursorMove); editor.removeListener("click", exports.onCursorMove);
commands.coreCommands.start.exec(editor); util.noMode(editor);
util.currentMode = "normal"; util.currentMode = "normal";
}; };

View file

@ -35,7 +35,6 @@ exports.searchStore = {
}; };
var repeat = function repeat(fn, count, args) { var repeat = function repeat(fn, count, args) {
count = parseInt(count, 10);
while (0 < count--) while (0 < count--)
fn.apply(this, args); fn.apply(this, args);
}; };
@ -48,19 +47,22 @@ var toggleCase = function toggleCase(ch) {
}; };
var ensureScrollMargin = function(editor) { var ensureScrollMargin = function(editor) {
setTimeout(function() { var renderer = editor.renderer
var curPos = editor.getCursorPosition().row; var pos = renderer.$cursorLayer.getPixelPosition();
var topRow = editor.renderer.layerConfig.firstRow;
var linesToBottom = editor.renderer.layerConfig.lastRow - curPos;
var linesToTop = curPos - topRow;
if (linesToBottom >= 0 && linesToBottom < HMARGIN) { var top = pos.top;
editor.scrollToRow(topRow + (HMARGIN - linesToBottom));
} var margin = HMARGIN * renderer.layerConfig.lineHeight;
else if (linesToTop >= 0 && linesToTop < HMARGIN) { if (2 * margin > renderer.$size.scrollerHeight)
editor.scrollToRow(topRow - (HMARGIN - linesToTop)); margin = renderer.$size.scrollerHeight / 2
}
}, 20); // Delay introduced to ensure scroll after async find operation. if (renderer.scrollTop > top - margin) {
renderer.session.setScrollTop(top - margin);
}
if (renderer.scrollTop + renderer.$size.scrollerHeight < top + margin + renderer.lineHeight) {
renderer.session.setScrollTop(top + margin + renderer.lineHeight - renderer.$size.scrollerHeight);
}
}; };
var actions = { var actions = {
@ -69,10 +71,13 @@ var actions = {
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
switch (param) { switch (param) {
case "z": case "z":
editor.centerSelection(); editor.alignCursor(null, 0.5);
break; break;
case "t": case "t":
editor.scrollToRow(editor.getCursorPosition().row); editor.alignCursor(null, 0);
break;
case "b":
editor.alignCursor(null, 1);
break; break;
} }
} }
@ -80,21 +85,30 @@ var actions = {
"r": { "r": {
param: true, param: true,
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
param = util.toRealChar(param);
if (param && param.length) { if (param && param.length) {
repeat(function() { editor.insert(param); }, count || 1); repeat(function() { editor.insert(param); }, count || 1);
editor.navigateLeft(); editor.navigateLeft();
} }
} }
}, },
// "~" HACK "R": {
"shift-`": { fn: function(editor, range, count, param) {
util.insertMode(editor);
editor.setOverwrite(true);
}
},
"~": {
fn: function(editor, range, count) { fn: function(editor, range, count) {
repeat(function() { repeat(function() {
var pos = editor.getCursorPosition(); var range = editor.selection.getRange();
var line = editor.session.getLine(pos.row); if (range.isEmpty())
var ch = line[pos.column]; range.end.column++
editor.insert(toggleCase(ch)); var text = editor.session.getTextRange(range)
var toggled = text.toUpperCase()
if (toggled == text)
editor.navigateRight()
else
editor.session.replace(range, toggled);
}, count || 1); }, count || 1);
} }
}, },
@ -103,9 +117,8 @@ var actions = {
editor.selection.selectWord(); editor.selection.selectWord();
editor.findNext(); editor.findNext();
ensureScrollMargin(editor); ensureScrollMargin(editor);
var cursor = editor.selection.getCursor(); var r = editor.selection.getRange();
range = editor.session.getWordRange(cursor.row, cursor.column); editor.selection.setSelectionRange(r, true);
editor.selection.setSelectionRange(range, true);
} }
}, },
"#": { "#": {
@ -113,9 +126,8 @@ var actions = {
editor.selection.selectWord(); editor.selection.selectWord();
editor.findPrevious(); editor.findPrevious();
ensureScrollMargin(editor); ensureScrollMargin(editor);
var cursor = editor.selection.getCursor(); var r = editor.selection.getRange();
range = editor.session.getWordRange(cursor.row, cursor.column); editor.selection.setSelectionRange(r, true);
editor.selection.setSelectionRange(range, true);
} }
}, },
"n": { "n": {
@ -123,35 +135,39 @@ var actions = {
var options = editor.getLastSearchOptions(); var options = editor.getLastSearchOptions();
options.backwards = false; options.backwards = false;
editor.selection.moveCursorRight();
editor.selection.clearSelection();
editor.findNext(options); editor.findNext(options);
ensureScrollMargin(editor); ensureScrollMargin(editor);
editor.selection.clearSelection(); var r = editor.selection.getRange();
r.end.row = r.start.row;
r.end.column = r.start.column
editor.selection.setSelectionRange(r, true);
} }
}, },
"shift-n": { "N": {
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
var options = editor.getLastSearchOptions(); var options = editor.getLastSearchOptions();
options.backwards = true; options.backwards = true;
editor.navigateWordLeft();
editor.findPrevious(options); editor.findPrevious(options);
ensureScrollMargin(editor); ensureScrollMargin(editor);
editor.selection.clearSelection(); var r = editor.selection.getRange();
r.end.row = r.start.row;
r.end.column = r.start.column
editor.selection.setSelectionRange(r, true);
} }
}, },
"v": { "v": {
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
editor.selection.selectRight(); editor.selection.selectRight();
util.onVisualMode = true; util.visualMode(editor, false);
util.onVisualLineMode = false; },
var cursor = document.getElementsByClassName("ace_cursor")[0]; acceptsMotion: true
cursor.style.display = "none";
}
}, },
"shift-v": { "V": {
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
util.onVisualLineMode = true;
//editor.selection.selectLine(); //editor.selection.selectLine();
//editor.selection.selectLeft(); //editor.selection.selectLeft();
var row = editor.getCursorPosition().row; var row = editor.getCursorPosition().row;
@ -159,9 +175,12 @@ var actions = {
editor.selection.moveCursorTo(row, 0); editor.selection.moveCursorTo(row, 0);
editor.selection.selectLineEnd(); editor.selection.selectLineEnd();
editor.selection.visualLineStart = row; editor.selection.visualLineStart = row;
}
util.visualMode(editor, true);
},
acceptsMotion: true
}, },
"shift-y": { "Y": {
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
util.copyLine(editor); util.copyLine(editor);
} }
@ -186,7 +205,7 @@ var actions = {
editor.selection.clearSelection(); editor.selection.clearSelection();
} }
}, },
"shift-p": { "P": {
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
var defaultReg = registers._default; var defaultReg = registers._default;
editor.setOverwrite(false); editor.setOverwrite(false);
@ -204,26 +223,26 @@ var actions = {
editor.selection.clearSelection(); editor.selection.clearSelection();
} }
}, },
"shift-j": { "J": {
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
var pos = editor.getCursorPosition(); var session = editor.session
range = editor.getSelectionRange();
var pos = {row: range.start.row, column: range.start.column};
count = count || range.end.row - range.start.row;
var maxRow = Math.min(pos.row + (count || 1), session.getLength() - 1);
if (editor.session.getLength() === pos.row + 1) range.start.column = session.getLine(pos.row).length;
return; range.end.column = session.getLine(maxRow).length;
range.end.row = maxRow;
var nextLine = editor.session.getLine(pos.row + 1); var text = ""
var cleanLine = /^\s*(.*)$/.exec(nextLine)[1]; for (var i = pos.row; i < maxRow; i++) {
var nextLine = session.getLine(i + 1);
text += " " + /^\s*(.*)$/.exec(nextLine)[1] || "";
}
editor.navigateDown(); session.replace(range, text);
editor.removeLines();
if (editor.session.getLength() > editor.getCursorPosition().row + 1)
editor.navigateUp();
editor.navigateLineEnd();
editor.insert(" " + (cleanLine || ""));
editor.moveCursorTo(pos.row, pos.column); editor.moveCursorTo(pos.row, pos.column);
} }
}, },
"u": { "u": {
@ -281,11 +300,6 @@ var inputBuffer = exports.inputBuffer = {
lastInsertCommands: [], lastInsertCommands: [],
push: function(editor, char, keyId) { 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; this.idle = false;
var wObj = this.waitingForParam; var wObj = this.waitingForParam;
if (wObj) { if (wObj) {
@ -342,6 +356,9 @@ var inputBuffer = exports.inputBuffer = {
else { else {
this.exec(editor, actionObj); this.exec(editor, actionObj);
} }
if (actions[char].acceptsMotion)
this.idle = false;
} }
else if (this.operator) { else if (this.operator) {
this.exec(editor, { operator: this.operator }, char); this.exec(editor, { operator: this.operator }, char);
@ -358,7 +375,7 @@ var inputBuffer = exports.inputBuffer = {
getCount: function() { getCount: function() {
var count = this.currentCount; var count = this.currentCount;
this.currentCount = ""; this.currentCount = "";
return count; return count && parseInt(count, 10);
}, },
exec: function(editor, action, param) { exec: function(editor, action, param) {
@ -366,6 +383,9 @@ var inputBuffer = exports.inputBuffer = {
var o = action.operator; var o = action.operator;
var a = action.action; var a = action.action;
if (!param)
param = action.param;
if (o) { if (o) {
this.previous = { this.previous = {
action: action, action: action,
@ -391,7 +411,7 @@ var inputBuffer = exports.inputBuffer = {
else if (m) { else if (m) {
var run = function(fn) { var run = function(fn) {
if (fn && typeof fn === "function") { // There should always be a motion if (fn && typeof fn === "function") { // There should always be a motion
if (m.count) if (m.count && !motionObj.handlesCount)
repeat(fn, m.count, [editor, null, m.count, param]); repeat(fn, m.count, [editor, null, m.count, param]);
else else
fn(editor, null, m.count, param); fn(editor, null, m.count, param);
@ -480,18 +500,15 @@ exports.coreCommands = {
util.insertMode(editor); util.insertMode(editor);
setPreviousCommand(appendEnd); setPreviousCommand(appendEnd);
} }
},
builder: {
exec: function builder(editor) {}
} }
}; };
var handleCursorMove = exports.onCursorMove = function(editor) { var handleCursorMove = exports.onCursorMove = function(editor, e) {
if(util.currentMode === 'insert' || handleCursorMove.running) if (util.currentMode === 'insert' || handleCursorMove.running)
return; return;
else if(!editor.selection.isEmpty()) { else if(!editor.selection.isEmpty()) {
handleCursorMove.running = true; handleCursorMove.running = true;
if(util.onVisualLineMode) { if (util.onVisualLineMode) {
var originRow = editor.selection.visualLineStart; var originRow = editor.selection.visualLineStart;
var cursorRow = editor.getCursorPosition().row; var cursorRow = editor.getCursorPosition().row;
if(originRow <= cursorRow) { if(originRow <= cursorRow) {
@ -510,6 +527,11 @@ var handleCursorMove = exports.onCursorMove = function(editor) {
return; return;
} }
else { else {
if (e && (util.onVisualLineMode || util.onVisualMode)) {
editor.selection.clearSelection();
util.normalMode(editor)
}
handleCursorMove.running = true; handleCursorMove.running = true;
var pos = editor.getCursorPosition(); var pos = editor.getCursorPosition();
var lineLen = editor.session.getLine(pos.row).length; var lineLen = editor.session.getLine(pos.row).length;

View file

@ -1,88 +1,61 @@
define(function(require, exports, module) { define(function(require, exports, module) {
"never use strict";
var StateHandler = require("ace/keyboard/state_handler").StateHandler; var keyUtil = require("../../lib/keys");
var cmds = require("./commands"); var cmds = require("./commands");
var coreCommands = cmds.coreCommands; var coreCommands = cmds.coreCommands;
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) { var startCommands = {
if (keyId) { 'i': {
keyId = String.fromCharCode(parseInt(keyId.replace("U+", "0x"), 10)); command: coreCommands.start
} },
'I': {
command: coreCommands.startBeginning,
},
'a': {
command: coreCommands.append
},
'A': {
command: coreCommands.appendEnd
}
};
coreCommands.builder.exec = function(editor) { exports.handler = {
cmds.inputBuffer.push.call(cmds.inputBuffer, editor, symbolicName, keyId); handleKeyboard: function(data, hashId, key, keyCode, e) {
// ignore command keys (shift, ctrl etc.)
// Otherwise "shift-" is added to the buffer, and later on "shift-g"
// which results in "shift-shift-g" which doesn't make sense.
if (hashId != 0 && (key == "" || key == "\x00"))
return null;
if (hashId == 1)
key = 'ctrl-' + key;
if (data.state == 'start') {
if (hashId == -1 || hashId == 1) {
if (cmds.inputBuffer.idle && startCommands[key])
return startCommands[key];
return { command: {
exec: function(editor) {cmds.inputBuffer.push(editor, key);}
} };
} // wait for input
else if (key.length === 1 && (hashId == 0 || hashId === 4)) { //no modifier || shift
return {command: "null", stopEvent: false}
} else if (key == 'esc') {
return {command: coreCommands.stop};
}
} else {
if (key == 'esc' || key == 'ctrl-[') {
data.state = 'start'
return {command: coreCommands.stop}
}
} }
} }
return matched; }
};
var inIdleState = function() {
if (cmds.inputBuffer.idle) {
return true;
}
return false;
};
var states = exports.states = {
start: [ // normal mode
{
key: "esc",
exec: coreCommands.stop,
then: "start"
},
{
regex: "^i$",
match: inIdleState,
exec: coreCommands.start,
then: "insertMode"
},
{
regex: "^shift-i$",
match: inIdleState,
exec: coreCommands.startBeginning,
then: "insertMode"
},
{
regex: "^a$",
match: inIdleState,
exec: coreCommands.append,
then: "insertMode"
},
{
regex: "^shift-a$",
match: inIdleState,
exec: coreCommands.appendEnd,
then: "insertMode"
},
{
// The rest of input will be processed here
match: matchChar,
exec: coreCommands.builder
}
],
insertMode: [
{
key: "esc",
exec: coreCommands.stop,
then: "start"
},
{
key: "backspace",
exec: "backspace"
}
]
};
exports.handler = new StateHandler(states); });
});

View file

@ -12,7 +12,7 @@ module.exports = {
count: 1 count: 1
} }
}, },
"shift-x": { "X": {
operator: { operator: {
char: "d", char: "d",
count: 1 count: 1
@ -22,7 +22,7 @@ module.exports = {
count: 1 count: 1
} }
}, },
"shift-d": { "D": {
operator: { operator: {
char: "d", char: "d",
count: 1 count: 1
@ -32,7 +32,7 @@ module.exports = {
count: 1 count: 1
} }
}, },
"shift-c": { "C": {
operator: { operator: {
char: "c", char: "c",
count: 1 count: 1
@ -52,15 +52,12 @@ module.exports = {
count: 1 count: 1
} }
}, },
"shift-s": { "S": {
operator: { operator: {
char: "c", char: "c",
count: 1 count: 1
}, },
motion: { param: "c"
char: "l",
count: 1
}
} }
}; };
}); });

View file

@ -1,4 +1,4 @@
"use strict" "never use strict"
define(function(require, exports, module) { define(function(require, exports, module) {
@ -12,23 +12,199 @@ var keepScrollPosition = function(editor, fn) {
editor.renderer.scrollToRow(editor.getCursorPosition().row - diff); editor.renderer.scrollToRow(editor.getCursorPosition().row - diff);
}; };
function Motion(getRange, type){
if (type == 'extend')
var extend = true
else
var reverse = type
this.nav = function(editor) {
var r = getRange(editor);
if (!r)
return
if (!r.end)
var a = r
else if (reverse)
var a = r.start
else
var a = r.end
editor.clearSelection()
editor.moveCursorTo(a.row, a.column);
}
this.sel = function(editor){
var r = getRange(editor);
if (!r)
return
if (extend)
return editor.selection.setSelectionRange(r);
if (!r.end)
var a = r
else if (reverse)
var a = r.start
else
var a = r.end
editor.selection.selectTo(a.row, a.column);
}
}
var nonWordRe = /[\s.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
var wordSeparatorRe = /[.\/\\()\"'-:,.;<>~!@#$%^&*|+=\[\]{}`~?]/;
var whiteRe = /\s/;
var StringStream = function(editor, cursor) {
var sel = editor.selection
this.range = sel.getRange()
cursor = cursor || sel.selectionLead
this.row = cursor.row;
this.col = cursor.column;
var line = editor.session.getLine(this.row);
var maxRow = editor.session.getLength()
this.ch = line[this.col] || '\n'
this.skippedLines = 0
this.next = function() {
this.ch = line[++this.col] || this.handleNewLine(1)
//this.debug()
return this.ch
}
this.prev = function() {
this.ch = line[--this.col] || this.handleNewLine(-1)
//this.debug()
return this.ch
}
this.peek = function(dir) {
var ch = line[this.col + dir]
if (ch)
return ch
if (dir == -1)
return '\n'
if (this.col == line.length - 1)
return '\n'
return editor.session.getLine(this.row + 1)[0] || '\n'
}
this.handleNewLine = function(dir) {
if (dir == 1){
if (this.col == line.length)
return '\n'
if (this.row == maxRow - 1)
return ''
this.col = 0
this.row ++
line = editor.session.getLine(this.row)
this.skippedLines++
return line[0] || '\n'
}
if (dir == -1) {
if (this.row == 0)
return ''
this.row --
line = editor.session.getLine(this.row)
this.col = line.length;
this.skippedLines--
return '\n'
}
}
this.debug = function() {
console.log(line.substring(0, this.col)+'|'+this.ch+'\''+this.col+'\''+line.substr(this.col+1))
}
}
var Search = require("ace/search").Search;
var search = new Search();
function find(editor, needle, dir) {
search.$options.needle = needle
search.$options.backwards = dir == -1
return search.find(editor.session)
}
var lang = require("ace/lib/lang");
var Range = require("ace/range").Range;
module.exports = { module.exports = {
"w": { "w": new Motion(function(editor) {
nav: function(editor) { var str = new StringStream(editor)
editor.navigateWordRight();
}, if (str.ch && wordSeparatorRe.test(str.ch)) {
sel: function(editor) { while (str.ch && wordSeparatorRe.test(str.ch))
editor.selection.selectWordRight(); str.next()
} else {
while (str.ch && !nonWordRe.test(str.ch))
str.next()
} }
}, while (str.ch && whiteRe.test(str.ch) && str.skippedLines < 2)
"b": { str.next()
nav: function(editor) {
editor.navigateWordLeft(); str.skippedLines == 2 && str.prev()
}, return {column: str.col, row: str.row}
sel: function(editor) { }),
editor.selection.selectWordLeft(); "W": new Motion(function(editor) {
var str = new StringStream(editor)
while(str.ch && !(whiteRe.test(str.ch) && !whiteRe.test(str.peek(1))) && str.skippedLines < 2)
str.next()
if (str.skippedLines == 2)
str.prev()
else
str.next()
return {column: str.col, row: str.row}
}),
"b": new Motion(function(editor) {
var str = new StringStream(editor)
str.prev()
while (str.ch && whiteRe.test(str.ch) && str.skippedLines > -2)
str.prev()
if (str.ch && wordSeparatorRe.test(str.ch)) {
while (str.ch && wordSeparatorRe.test(str.ch))
str.prev()
} else {
while (str.ch && !nonWordRe.test(str.ch))
str.prev()
} }
}, str.ch && str.next();
return {column: str.col, row: str.row}
}),
"B": new Motion(function(editor) {
var str = new StringStream(editor)
str.prev()
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(-1))) && str.skippedLines > -2)
str.prev()
if (str.skippedLines == -2)
str.next()
return {column: str.col, row: str.row}
}, true),
"e": new Motion(function(editor) {
var str = new StringStream(editor)
str.next()
while (str.ch && whiteRe.test(str.ch))
str.next()
if (str.ch && wordSeparatorRe.test(str.ch)) {
while (str.ch && wordSeparatorRe.test(str.ch))
str.next()
} else {
while (str.ch && !nonWordRe.test(str.ch))
str.next()
}
str.ch && str.prev()
return {column: str.col, row: str.row}
}),
"E": new Motion(function(editor) {
var str = new StringStream(editor)
str.next()
while(str.ch && !(!whiteRe.test(str.ch) && whiteRe.test(str.peek(1))))
str.next()
return {column: str.col, row: str.row}
}),
"l": { "l": {
nav: function(editor) { nav: function(editor) {
editor.navigateRight(); editor.navigateRight();
@ -72,12 +248,41 @@ module.exports = {
editor.selection.selectDown(); editor.selection.selectDown();
} }
}, },
"i": { "i": {
param: true, param: true,
sel: function(editor, range, count, param) { sel: function(editor, range, count, param) {
switch (param) { switch (param) {
case "w": case "w":
editor.selection.selectWord(); editor.selection.selectWord();
break;
case "W":
editor.selection.selectAWord();
break;
case "(":
case "{":
case "[":
var cursor = editor.getCursorPosition()
var end = editor.session.$findClosingBracket(param, cursor, /paren/)
if (!end)
return
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/)
if (!start)
return
start.column ++;
editor.selection.setSelectionRange(Range.fromPoints(start, end))
break
case "'":
case "\"":
case "/":
var end = find(editor, param, 1)
if (!end)
return
var start = find(editor, param, -1)
if (!start)
return
editor.selection.setSelectionRange(Range.fromPoints(start.end, end.start))
break
} }
} }
}, },
@ -87,16 +292,46 @@ module.exports = {
switch (param) { switch (param) {
case "w": case "w":
editor.selection.selectAWord(); editor.selection.selectAWord();
break;
case "W":
editor.selection.selectAWord();
break;
case "(":
case "{":
case "[":
var cursor = editor.getCursorPosition()
var end = editor.session.$findClosingBracket(param, cursor, /paren/)
if (!end)
return
var start = editor.session.$findOpeningBracket(editor.session.$brackets[param], cursor, /paren/)
if (!start)
return
end.column ++;
editor.selection.setSelectionRange(Range.fromPoints(start, end))
break
case "'":
case "\"":
case "/":
var end = find(editor, param, 1)
if (!end)
return
var start = find(editor, param, -1)
if (!start)
return
end.column ++;
editor.selection.setSelectionRange(Range.fromPoints(start.start, end.end))
break
} }
} }
}, },
"f": { "f": {
param: true, param: true,
handlesCount: true,
nav: function(editor, range, count, param) { nav: function(editor, range, count, param) {
count = parseInt(count, 10) || 1;
var ed = editor; var ed = editor;
var cursor = ed.getCursorPosition(); var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count); var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") { if (typeof column === "number") {
ed.selection.clearSelection(); // Why does it select in the first place? ed.selection.clearSelection(); // Why does it select in the first place?
@ -104,18 +339,18 @@ module.exports = {
} }
}, },
sel: function(editor, range, count, param) { sel: function(editor, range, count, param) {
count = parseInt(count, 10) || 1;
var ed = editor; var ed = editor;
var cursor = ed.getCursorPosition(); var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count); var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") { if (typeof column === "number") {
ed.moveCursorTo(cursor.row, column + cursor.column + 1); ed.moveCursorTo(cursor.row, column + cursor.column + 1);
} }
} }
}, },
"shift-f": { "F": {
param: true, param: true,
handlesCount: true,
nav: function(editor, range, count, param) { nav: function(editor, range, count, param) {
count = parseInt(count, 10) || 1; count = parseInt(count, 10) || 1;
var ed = editor; var ed = editor;
@ -124,27 +359,26 @@ module.exports = {
if (typeof column === "number") { if (typeof column === "number") {
ed.selection.clearSelection(); // Why does it select in the first place? ed.selection.clearSelection(); // Why does it select in the first place?
ed.moveCursorTo(cursor.row, cursor.column - column + 1); ed.moveCursorTo(cursor.row, cursor.column - column - 1);
} }
}, },
sel: function(editor, range, count, param) { sel: function(editor, range, count, param) {
count = parseInt(count, 10) || 1;
var ed = editor; var ed = editor;
var cursor = ed.getCursorPosition(); var cursor = ed.getCursorPosition();
var column = util.getLeftNthChar(editor, cursor, param, count); var column = util.getLeftNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") { if (typeof column === "number") {
ed.moveCursorTo(cursor.row, cursor.column - column + 1); ed.moveCursorTo(cursor.row, cursor.column - column - 1);
} }
} }
}, },
"t": { "t": {
param: true, param: true,
handlesCount: true,
nav: function(editor, range, count, param) { nav: function(editor, range, count, param) {
count = parseInt(count, 10) || 1;
var ed = editor; var ed = editor;
var cursor = ed.getCursorPosition(); var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count); var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") { if (typeof column === "number") {
ed.selection.clearSelection(); // Why does it select in the first place? ed.selection.clearSelection(); // Why does it select in the first place?
@ -152,16 +386,39 @@ module.exports = {
} }
}, },
sel: function(editor, range, count, param) { sel: function(editor, range, count, param) {
count = parseInt(count, 10) || 1;
var ed = editor; var ed = editor;
var cursor = ed.getCursorPosition(); var cursor = ed.getCursorPosition();
var column = util.getRightNthChar(editor, cursor, param, count); var column = util.getRightNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") { if (typeof column === "number") {
ed.moveCursorTo(cursor.row, column + cursor.column); ed.moveCursorTo(cursor.row, column + cursor.column);
} }
} }
}, },
"T": {
param: true,
handlesCount: true,
nav: function(editor, range, count, param) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
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) {
var ed = editor;
var cursor = ed.getCursorPosition();
var column = util.getLeftNthChar(editor, cursor, param, count || 1);
if (typeof column === "number") {
ed.moveCursorTo(cursor.row, -column + cursor.column);
}
}
},
"^": { "^": {
nav: function(editor) { nav: function(editor) {
editor.navigateLineStart(); editor.navigateLineStart();
@ -188,41 +445,20 @@ module.exports = {
ed.selectTo(ed.selection.selectionLead.row, 0); ed.selectTo(ed.selection.selectionLead.row, 0);
} }
}, },
"shift-g": { "G": {
nav: function(editor, range, count, param) { nav: function(editor, range, count, param) {
count = parseInt(count, 10);
if (!count && count !== 0) { // Stupid JS if (!count && count !== 0) { // Stupid JS
count = editor.session.getLength(); count = editor.session.getLength();
} }
editor.gotoLine(count); editor.gotoLine(count);
}, },
sel: function(editor, range, count, param) { sel: function(editor, range, count, param) {
count = parseInt(count, 10);
if (!count && count !== 0) { // Stupid JS if (!count && count !== 0) { // Stupid JS
count = editor.session.getLength(); count = editor.session.getLength();
} }
editor.selection.selectTo(count, 0); 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": { "g": {
param: true, param: true,
nav: function(editor, range, count, param) { nav: function(editor, range, count, param) {
@ -235,6 +471,10 @@ module.exports = {
break; break;
case "g": case "g":
editor.gotoLine(count || 0); editor.gotoLine(count || 0);
case "u":
editor.gotoLine(count || 0);
case "U":
editor.gotoLine(count || 0);
} }
}, },
sel: function(editor, range, count, param) { sel: function(editor, range, count, param) {
@ -264,7 +504,7 @@ module.exports = {
} }
} }
}, },
"shift-o": { "O": {
nav: function(editor, range, count, param) { nav: function(editor, range, count, param) {
var row = editor.getCursorPosition().row; var row = editor.getCursorPosition().row;
count = count || 1; count = count || 1;
@ -285,18 +525,42 @@ module.exports = {
} }
} }
}, },
"%": { "%": new Motion(function(editor){
nav: function(editor, range, count, param) { var brRe = /[\[\]{}()]/g;
var cursor = editor.getCursorPosition(); var cursor = editor.getCursorPosition();
var match = editor.session.findMatchingBracket({ var ch = editor.session.getLine(cursor.row)[cursor.column]
row: cursor.row, if (!brRe.test(ch)){
column: cursor.column + 1 var range = find(editor, brRe)
}); if (!range)
return
if (match) cursor = range.start
editor.moveCursorTo(match.row, match.column);
} }
} var match = editor.session.findMatchingBracket({
row: cursor.row,
column: cursor.column + 1
});
return match
}),
"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);
}
},
}; };
module.exports.backspace = module.exports.left = module.exports.h; module.exports.backspace = module.exports.left = module.exports.h;

View file

@ -7,63 +7,65 @@ var registers = require("../registers");
module.exports = { module.exports = {
"d": { "d": {
selFn: function(editor, range, count, param) { selFn: function(editor, range, count, param) {
registers._default.text = editor.getCopyText(); registers._default.text = editor.getCopyText();
registers._default.isLine = util.onVisualLineMode; registers._default.isLine = util.onVisualLineMode;
if(util.onVisualLineMode) if(util.onVisualLineMode)
editor.removeLines(); editor.removeLines();
else else
editor.session.remove(range); editor.session.remove(range);
util.normalMode(editor); util.normalMode(editor);
}, },
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
count = parseInt(count || 1, 10); count = count || 1;
switch (param) { switch (param) {
case "d": case "d":
registers._default.text = ""; registers._default.text = "";
registers._default.isLine = true; registers._default.isLine = true;
for (var i=0; i<count; i++) { for (var i = 0; i < count; i++) {
editor.selection.selectLine(); editor.selection.selectLine();
registers._default.text += editor.getCopyText(); registers._default.text += editor.getCopyText();
var selRange = editor.getSelectionRange(); var selRange = editor.getSelectionRange();
editor.session.remove(selRange); editor.session.remove(selRange);
editor.selection.clearSelection(); editor.selection.clearSelection();
} }
registers._default.text = registers._default.text.replace(/\n$/, ""); registers._default.text = registers._default.text.replace(/\n$/, "");
break; break;
default: default:
if (range) { if (range) {
editor.selection.setSelectionRange(range); editor.selection.setSelectionRange(range);
registers._default.text = editor.getCopyText(); registers._default.text = editor.getCopyText();
registers._default.isLine = false; registers._default.isLine = false;
editor.session.remove(range); editor.session.remove(range);
editor.selection.clearSelection(); editor.selection.clearSelection();
} }
}
} }
}
}, },
"c": { "c": {
selFn: function(editor, range, count, param) { selFn: function(editor, range, count, param) {
editor.session.remove(range); editor.session.remove(range);
util.insertMode(editor); util.insertMode(editor);
}, },
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
count = parseInt(count || 1, 10); count = count || 1;
switch (param) { switch (param) {
case "c": case "c":
for (var i=0; i < count; i++) { for (var i = 0; i < count; i++) {
editor.removeLines(); editor.removeLines();
util.insertMode(editor); util.insertMode(editor);
} }
break; break;
default: default:
if (range) { if (range) {
editor.session.remove(range);
util.insertMode(editor); // range.end.column ++;
} editor.session.remove(range);
} util.insertMode(editor);
}
} }
}
}, },
"y": { "y": {
selFn: function(editor, range, count, param) { selFn: function(editor, range, count, param) {
@ -73,7 +75,7 @@ module.exports = {
util.normalMode(editor); util.normalMode(editor);
}, },
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
count = parseInt(count || 1, 10); count = count || 1;
switch (param) { switch (param) {
case "y": case "y":
var pos = editor.getCursorPosition(); var pos = editor.getCursorPosition();
@ -100,7 +102,7 @@ module.exports = {
}, },
">": { ">": {
selFn: function(editor, range, count, param) { selFn: function(editor, range, count, param) {
count = parseInt(count || 1, 10); count = count || 1;
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
editor.indent(); editor.indent();
} }
@ -126,14 +128,14 @@ module.exports = {
}, },
"<": { "<": {
selFn: function(editor, range, count, param) { selFn: function(editor, range, count, param) {
count = parseInt(count || 1, 10); count = count || 1;
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
editor.blockOutdent(); editor.blockOutdent();
} }
util.normalMode(editor); util.normalMode(editor);
}, },
fn: function(editor, range, count, param) { fn: function(editor, range, count, param) {
count = parseInt(count || 1, 10); count = count || 1;
switch (param) { switch (param) {
case "<": case "<":
var pos = editor.getCursorPosition(); var pos = editor.getCursorPosition();

View file

@ -1,78 +1,75 @@
define(function(require, exports, module) { define(function(require, exports, module) {
var registers = require("../registers"); var registers = require("../registers");
var dom = require("ace/lib/dom");
dom.importCssString('.insert-mode. ace_cursor{\
border-left: 2px solid #333333;\
}\
.ace_dark.insert-mode .ace_cursor{\
border-left: 2px solid #eeeeee;\
}\
.normal-mode .ace_cursor{\
border: 0!important;\
background-color: red;\
opacity: 0.5;\
}', 'vimMode');
module.exports = { module.exports = {
onVisualMode: false, onVisualMode: false,
onVisualLineMode: false, onVisualLineMode: false,
currentMode: 'normal', currentMode: 'normal',
noMode: function(editor) {
editor.unsetStyle('insert-mode');
editor.unsetStyle('normal-mode');
if (editor.commands.recording)
editor.commands.toggleRecording();
},
insertMode: function(editor) { insertMode: function(editor) {
var _self = this; this.currentMode = 'insert';
var theme = editor && editor.getTheme() || "ace/theme/textmate"; // Switch editor to insert mode
editor.setStyle('insert-mode');
editor.unsetStyle('normal-mode');
require(["require", theme], function (require) {
var isDarkTheme = require(theme).isDark;
_self.currentMode = 'insert'; editor.setOverwrite(false);
// Switch editor to insert mode editor.keyBinding.$data.buffer = "";
editor.unsetStyle('insert-mode'); editor.keyBinding.$data.state = "insertMode";
this.onVisualMode = false;
var cursor = document.getElementsByClassName("ace_cursor")[0]; this.onVisualLineMode = false;
if (cursor) { if(this.onInsertReplaySequence) {
cursor.style.display = null; // Ok, we're apparently replaying ("."), so let's do it
cursor.style.backgroundColor = null; editor.commands.macro = this.onInsertReplaySequence;
cursor.style.opacity = null; editor.commands.replay(editor);
cursor.style.border = null; this.onInsertReplaySequence = null;
cursor.style.borderLeftColor = isDarkTheme? "#eeeeee" : "#333333"; this.normalMode(editor);
cursor.style.borderLeftStyle = "solid"; } else {
cursor.style.borderLeftWidth = "2px"; // Record any movements, insertions in insert mode
} if(!editor.commands.recording)
editor.commands.toggleRecording();
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) { normalMode: function(editor) {
// Switch editor to normal mode // Switch editor to normal mode
this.currentMode = 'normal'; this.currentMode = 'normal';
editor.unsetStyle('insert-mode');
editor.setStyle('normal-mode'); editor.setStyle('normal-mode');
editor.clearSelection(); 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; var pos;
if (!editor.getOverwrite()) { if (!editor.getOverwrite()) {
pos = editor.getCursorPosition(); pos = editor.getCursorPosition();
if (pos.column > 0) if (pos.column > 0)
editor.navigateLeft(); editor.navigateLeft();
} }
editor.setOverwrite(true); editor.setOverwrite(true);
editor.keyBinding.$data.buffer = ""; editor.keyBinding.$data.buffer = "";
editor.keyBinding.$data.state = "start"; editor.keyBinding.$data.state = "start";
this.onVisualMode = false; this.onVisualMode = false;
this.onVisualLineMode = false; this.onVisualLineMode = false;
// Save recorded keystrokes // Save recorded keystrokes
if(editor.commands.recording) { if (editor.commands.recording) {
editor.commands.toggleRecording(); editor.commands.toggleRecording();
return editor.commands.macro; return editor.commands.macro;
} }
@ -80,17 +77,36 @@ module.exports = {
return []; return [];
} }
}, },
visualMode: function(editor, lineMode) {
if (
(this.onVisualLineMode && lineMode)
|| (this.onVisualMode && !lineMode)
) {
this.normalMode(editor);
return;
}
editor.setStyle('insert-mode');
editor.unsetStyle('normal-mode');
if (lineMode) {
this.onVisualLineMode = true;
} else {
this.onVisualMode = true;
this.onVisualLineMode = false;
}
},
getRightNthChar: function(editor, cursor, char, n) { getRightNthChar: function(editor, cursor, char, n) {
var line = editor.getSession().getLine(cursor.row); var line = editor.getSession().getLine(cursor.row);
var matches = line.substr(cursor.column + 1).split(char); var matches = line.substr(cursor.column + 1).split(char);
return n < matches.length ? matches.slice(0, n).join(char).length : 0; return n < matches.length ? matches.slice(0, n).join(char).length : null;
}, },
getLeftNthChar: function(editor, cursor, char, n) { getLeftNthChar: function(editor, cursor, char, n) {
var line = editor.getSession().getLine(cursor.row); var line = editor.getSession().getLine(cursor.row);
var matches = line.substr(0, cursor.column).split(char); var matches = line.substr(0, cursor.column).split(char);
return n < matches.length ? matches.slice(-1 * n).join(char).length + 2 : 0; return n < matches.length ? matches.slice(-1 * n).join(char).length : null;
}, },
toRealChar: function(char) { toRealChar: function(char) {
if (char.length === 1) if (char.length === 1)

View file

@ -102,7 +102,7 @@ var Keys = (function() {
80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v', 80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',
87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.', 87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',
188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\', 188: ',', 190: '.', 191: '/', 192: '`', 219: '[', 220: '\\',
221: ']', 222: '\"' 221: ']', 222: '\''
} }
}; };

View file

@ -40,7 +40,7 @@ define(function(require, exports, module) {
"use strict"; "use strict";
var oop = require("../../lib/oop"); var oop = require("../../lib/oop");
var Behaviour = require('../behaviour').Behaviour; var Behaviour = require("../behaviour").Behaviour;
var CstyleBehaviour = function () { var CstyleBehaviour = function () {