update vim.js

This commit is contained in:
nightwing 2014-12-13 00:43:30 +04:00
commit 5a03993f65
2 changed files with 264 additions and 136 deletions

View file

@ -167,7 +167,7 @@ define(function(require, exports, module) {
this.removeOverlay();
};
this.virtualSelectionMode = function() {
return this.ace.inVirtualSelectionMode && this.ace.selection.index
return this.ace.inVirtualSelectionMode && this.ace.selection.index;
};
this.onChange = function(delta) {
var oldDelta = delta.data;
@ -356,7 +356,7 @@ define(function(require, exports, module) {
point.row = start.row;
point.column = start.column;
if (cmp2 === 0)
point.bias = 1
point.bias = 1;
}
}
};
@ -421,9 +421,6 @@ define(function(require, exports, module) {
throw "not implemented";
}
};
this.openDialog = function() {
debugger
};
this.getSearchCursor = function(query, pos, caseFold) {
var caseSensitive = false;
var isRegexp = false;
@ -566,12 +563,11 @@ define(function(require, exports, module) {
var row = delta.start.row;
if (row == delta.end.row) highlight.cache[row] = undefined;
else highlight.cache.splice(row, highlight.cache.length);
}
};
highlight.session.on("changeEditor", highlight.destroy);
highlight.session.on("change", highlight.updateOnChange);
}
var re = new RegExp(o.query.source, "gmi");
console.log(re)
this.$searchHighlight = o.highlight = highlight;
this.$searchHighlight.setRegexp(re);
this.ace.renderer.updateBackMarkers();
@ -866,11 +862,11 @@ dom.importCssString(".normal-mode .ace_cursor{\
{ keys: '<Up>', type: 'keyToKey', toKeys: 'k' },
{ keys: '<Down>', type: 'keyToKey', toKeys: 'j' },
{ keys: '<Space>', type: 'keyToKey', toKeys: 'l' },
{ keys: '<BS>', type: 'keyToKey', toKeys: 'h' },
{ keys: '<BS>', type: 'keyToKey', toKeys: 'h', context: 'normal'},
{ keys: '<C-Space>', type: 'keyToKey', toKeys: 'W' },
{ keys: '<C-BS>', type: 'keyToKey', toKeys: 'B' },
{ keys: '<C-BS>', type: 'keyToKey', toKeys: 'B', context: 'normal' },
{ keys: '<S-Space>', type: 'keyToKey', toKeys: 'w' },
{ keys: '<S-BS>', type: 'keyToKey', toKeys: 'b' },
{ keys: '<S-BS>', type: 'keyToKey', toKeys: 'b', context: 'normal' },
{ keys: '<C-n>', type: 'keyToKey', toKeys: 'j' },
{ keys: '<C-p>', type: 'keyToKey', toKeys: 'k' },
{ keys: '<C-[>', type: 'keyToKey', toKeys: '<Esc>' },
@ -1018,55 +1014,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
var Pos = CodeMirror.Pos;
var modifierCodes = [16, 17, 18, 91];
var specialKey = {Enter:'CR',Backspace:'BS',Delete:'Del'};
var mac = /Mac/.test(navigator.platform);
var Vim = function() { return vimApi; } //{
function lookupKey(e) {
var keyCode = e.keyCode;
if (modifierCodes.indexOf(keyCode) != -1) { return; }
var hasModifier = e.ctrlKey || e.metaKey;
var key = CodeMirror.keyNames[keyCode];
key = specialKey[key] || key;
var name = '';
if (e.ctrlKey) { name += 'C-'; }
if (e.altKey) { name += 'A-'; }
if (mac && e.metaKey || (!hasModifier && e.shiftKey) && key.length < 2) {
// Shift key bindings can only specified for special characters.
return;
} else if (e.shiftKey && !/^[A-Za-z]$/.test(key)) {
name += 'S-';
}
if (key.length == 1) { key = key.toLowerCase(); }
name += key;
if (name.length > 1) { name = '<' + name + '>'; }
return name;
}
// Keys with modifiers are handled using keydown due to limitations of
// keypress event.
function handleKeyDown(cm, e) {
var name = lookupKey(e);
if (!name) { return; }
CodeMirror.signal(cm, 'vim-keypress', name);
if (CodeMirror.Vim.handleKey(cm, name, 'user')) {
CodeMirror.e_stop(e);
}
}
// Keys without modifiers are handled using keypress to work best with
// non-standard keyboard layouts.
function handleKeyPress(cm, e) {
var code = e.charCode || e.keyCode;
if (e.ctrlKey || e.metaKey || e.altKey ||
e.shiftKey && code < 32) { return; }
var name = String.fromCharCode(code);
CodeMirror.signal(cm, 'vim-keypress', name);
if (CodeMirror.Vim.handleKey(cm, name, 'user')) {
CodeMirror.e_stop(e);
}
}
function enterVimMode(cm) {
cm.setOption('disableInput', true);
cm.setOption('showCursorWhenSelecting', false);
@ -1074,8 +1022,6 @@ dom.importCssString(".normal-mode .ace_cursor{\
cm.on('cursorActivity', onCursorActivity);
maybeInitVimState(cm);
CodeMirror.on(cm.getInputField(), 'paste', getOnPasteFn(cm));
cm.on('keypress', handleKeyPress);
cm.on('keydown', handleKeyDown);
}
function leaveVimMode(cm) {
@ -1083,8 +1029,6 @@ dom.importCssString(".normal-mode .ace_cursor{\
cm.off('cursorActivity', onCursorActivity);
CodeMirror.off(cm.getInputField(), 'paste', getOnPasteFn(cm));
cm.state.vim = null;
cm.off('keypress', handleKeyPress);
cm.off('keydown', handleKeyDown);
}
function detachVimMap(cm, next) {
@ -1109,6 +1053,60 @@ dom.importCssString(".normal-mode .ace_cursor{\
else if (!val && prev != CodeMirror.Init && /^vim/.test(cm.getOption("keyMap")))
cm.setOption("keyMap", "default");
});
function cmKey(key, cm) {
if (!cm) { return undefined; }
var vimKey = cmKeyToVimKey(key);
if (!vimKey) {
return false;
}
var cmd = CodeMirror.Vim.findKey(cm, vimKey);
if (typeof cmd == 'function') {
CodeMirror.signal(cm, 'vim-keypress', vimKey);
}
return cmd;
}
var modifiers = {'Shift': 'S', 'Ctrl': 'C', 'Alt': 'A', 'Cmd': 'D', 'Mod': 'A'};
var specialKeys = {Enter:'CR',Backspace:'BS',Delete:'Del'};
function cmKeyToVimKey(key) {
if (key.charAt(0) == '\'') {
// Keypress character binding of format "'a'"
return key.charAt(1);
}
var pieces = key.split('-');
if (/-$/.test(key)) {
// If the - key was typed, split will result in 2 extra empty strings
// in the array. Replace them with 1 '-'.
pieces.splice(-2, 2, '-');
}
var lastPiece = pieces[pieces.length - 1];
if (pieces.length == 1 && pieces[0].length == 1) {
// No-modifier bindings use literal character bindings above. Skip.
return false;
} else if (pieces.length == 2 && pieces[0] == 'Shift' && lastPiece.length == 1) {
// Ignore Shift+char bindings as they should be handled by literal character.
return false;
}
var hasCharacter = false;
for (var i = 0; i < pieces.length; i++) {
var piece = pieces[i];
if (piece in modifiers) { pieces[i] = modifiers[piece]; }
else { hasCharacter = true; }
if (piece in specialKeys) { pieces[i] = specialKeys[piece]; }
}
if (!hasCharacter) {
// Vim does not support modifier only keys.
return false;
}
// TODO: Current bindings expect the character to be lower case, but
// it looks like vim key notation uses upper case.
if (isUpperCase(lastPiece)) {
pieces[pieces.length - 1] = lastPiece.toLowerCase();
}
return '<' + pieces.join('-') + '>';
}
function getOnPasteFn(cm) {
var vim = cm.state.vim;
if (!vim.onPasteFn) {
@ -1168,15 +1166,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
function defineOption(name, defaultValue, type) {
if (defaultValue === undefined) { throw Error('defaultValue is required'); }
if (!type) { type = 'string'; }
var opt = name;
if (typeof name == "string")
opt = {
type: type,
defaultValue: defaultValue
};
else
name = opt.name;
options[name] = opt;
options[name] = {
type: type,
defaultValue: defaultValue
};
setOption(name, defaultValue);
}
@ -1193,8 +1186,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
value = true;
}
}
option.value = value;
if (option.set) option.set(value, cm);
option.value = option.type == 'boolean' ? !!value : value;
}
function getOption(name) {
@ -1428,9 +1420,23 @@ dom.importCssString(".normal-mode .ace_cursor{\
exCommands[name]=func;
exCommandDispatcher.commandMap_[prefix]={name:name, shortName:prefix, type:'api'};
},
// This is the outermost function called by CodeMirror, after keys have
// been mapped to their Vim equivalents.
handleKey: function(cm, key, origin) {
handleKey: function (cm, key, origin) {
var command = this.findKey(cm, key, origin);
if (typeof command === 'function') {
return command();
}
},
/**
* This is the outermost function called by CodeMirror, after keys have
* been mapped to their Vim equivalents.
*
* Finds a command based on the key (and cached keys if there is a
* multi-key sequence). Returns `undefined` if no key is matched, a noop
* function if a partial match is found (multi-key), and a function to
* execute the bound command if a a key is matched. The function always
* returns true.
*/
findKey: function(cm, key, origin) {
var vim = maybeInitVimState(cm);
function handleMacroRecording() {
var macroModeState = vimGlobalState.macroModeState;
@ -1496,13 +1502,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
cm.replaceRange('', offsetCursor(here, 0, -(keys.length - 1)), here, '+input');
}
clearInputState(cm);
var command = match.command;
if (command.type == 'keyToKey') {
doKeyToKey(command.toKeys);
} else {
commandDispatcher.processCommand(cm, vim, command);
}
return true;
return match.command;
}
function handleKeyNonInsertMode() {
@ -1520,31 +1520,44 @@ dom.importCssString(".normal-mode .ace_cursor{\
else if (match.type == 'partial') { return true; }
vim.inputState.keyBuffer = '';
var command = match.command;
var keysMatcher = /^(\d*)(.*)$/.exec(keys);
if (keysMatcher[1] && keysMatcher[1] != '0') {
vim.inputState.pushRepeatDigit(keysMatcher[1]);
}
if (command.type == 'keyToKey') {
doKeyToKey(command.toKeys);
} else {
commandDispatcher.processCommand(cm, vim, command);
}
return true;
return match.command;
}
return cm.operation(function() {
cm.curOp.isVimOp = true;
try {
if (vim.insertMode) { return handleKeyInsertMode(); }
else { return handleKeyNonInsertMode(); }
} catch (e) {
// clear VIM state in case it's in a bad state.
cm.state.vim = undefined;
maybeInitVimState(cm);
throw e;
}
});
var command;
if (vim.insertMode) { command = handleKeyInsertMode(); }
else { command = handleKeyNonInsertMode(); }
if (command === false) {
return undefined;
} else if (command === true) {
// TODO: Look into using CodeMirror's multi-key handling.
// Return no-op since we are caching the key. Counts as handled, but
// don't want act on it just yet.
return function() {};
} else {
return function() {
return cm.operation(function() {
cm.curOp.isVimOp = true;
try {
if (command.type == 'keyToKey') {
doKeyToKey(command.toKeys);
} else {
commandDispatcher.processCommand(cm, vim, command);
}
} catch (e) {
// clear VIM state in case it's in a bad state.
cm.state.vim = undefined;
maybeInitVimState(cm);
console['log'](e);
throw e;
}
return true;
});
};
}
},
handleEx: function(cm, input) {
exCommandDispatcher.processCommand(cm, input);
@ -2105,7 +2118,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
newHead = copyCursor(origHead);
}
if (vim.visualMode) {
newHead = clipCursorToContent(cm, newHead, true);
newHead = clipCursorToContent(cm, newHead, vim.visualBlock);
if (newAnchor) {
newAnchor = clipCursorToContent(cm, newAnchor, true);
}
@ -2409,20 +2422,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
return cm.findPosV(curStart, (motionArgs.forward ? repeat : -repeat), 'page');
},
moveByParagraph: function(cm, head, motionArgs) {
var line = head.line;
var repeat = motionArgs.repeat;
var inc = motionArgs.forward ? 1 : -1;
for (var i = 0; i < repeat; i++) {
if ((!motionArgs.forward && line === cm.firstLine() ) ||
(motionArgs.forward && line == cm.lastLine())) {
break;
}
line += inc;
while (line !== cm.firstLine() && line != cm.lastLine() && cm.getLine(line)) {
line += inc;
}
}
return Pos(line, 0);
var dir = motionArgs.forward ? 1 : -1;
return findParagraph(cm, head, motionArgs.repeat, dir);
},
moveByScroll: function(cm, head, motionArgs, vim) {
var scrollbox = cm.getScrollInfo();
@ -2522,7 +2523,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
return Pos(lineNum,
findFirstNonWhiteSpaceCharacter(cm.getLine(lineNum)));
},
textObjectManipulation: function(cm, head, motionArgs) {
textObjectManipulation: function(cm, head, motionArgs, vim) {
// TODO: lots of possible exceptions that can be thrown here. Try da(
// outside of a () block.
@ -2561,8 +2562,15 @@ dom.importCssString(".normal-mode .ace_cursor{\
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
false /** bigWord */);
} else if (character === 'p') {
tmp = expandParagraphUnderCursor(cm, inclusive, true /** forward */,
false /** bigWord */);
tmp = findParagraph(cm, head, motionArgs.repeat, 0, inclusive);
motionArgs.linewise = true;
if (vim.visualMode) {
if (!vim.visualLine) { vim.visualLine = true; }
} else {
var operatorArgs = vim.inputState.operatorArgs;
if (operatorArgs) { operatorArgs.linewise = true; }
tmp.end.line--;
}
} else {
// No text object defined for this, don't move.
return null;
@ -4070,6 +4078,54 @@ dom.importCssString(".normal-mode .ace_cursor{\
return idx;
}
function findParagraph(cm, head, repeat, dir, inclusive) {
var line = head.line;
var min = cm.firstLine();
var max = cm.lastLine();
var start, end, i = line;
function isEmpty(i) { return !cm.getLine(i); }
function isBoundary(i, dir, any) {
if (any) { return isEmpty(i) != isEmpty(i + dir); }
return !isEmpty(i) && isEmpty(i + dir);
}
if (dir) {
while (min <= i && i <= max && repeat > 0) {
if (isBoundary(i, dir)) { repeat--; }
i += dir;
}
return new Pos(i, 0);
}
var vim = cm.state.vim;
if (vim.visualLine && isBoundary(line, 1, true)) {
var anchor = vim.sel.anchor;
if (isBoundary(anchor.line, -1, true)) {
if (!inclusive || anchor.line != line) {
line += 1;
}
}
}
var startState = isEmpty(line);
for (i = line; i <= max && repeat; i++) {
if (isBoundary(i, 1, true)) {
if (!inclusive || isEmpty(i) != startState) {
repeat--;
}
}
}
end = new Pos(i, 0);
// select boundary before paragraph for the last one
if (i > max && !startState) { startState = true; }
else { inclusive = false; }
for (i = line; i > min; i--) {
if (!inclusive || isEmpty(i) == startState || i == line) {
if (isBoundary(i, -1, true)) { break; }
}
}
start = new Pos(i, 0);
return { start: start, end: end };
}
// TODO: perhaps this finagling of start and end positions belonds
// in codmirror/replaceRange?
function selectCompanionObject(cm, head, symb, inclusive) {
@ -5276,7 +5332,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
CodeMirror.keyMap.vim = {
attach: attachVimMap,
detach: detachVimMap
detach: detachVimMap,
call: cmKey
};
function exitInsertMode(cm) {
@ -5349,20 +5406,16 @@ dom.importCssString(".normal-mode .ace_cursor{\
},
fallthrough: ['default'],
attach: attachVimMap,
detach: detachVimMap
};
CodeMirror.keyMap['await-second'] = {
fallthrough: ['vim-insert'],
attach: attachVimMap,
detach: detachVimMap
detach: detachVimMap,
call: cmKey
};
CodeMirror.keyMap['vim-replace'] = {
'Backspace': 'goCharLeft',
fallthrough: ['vim-insert'],
attach: attachVimMap,
detach: detachVimMap
detach: detachVimMap,
call: cmKey
};
function executeMacroRegister(cm, vim, macroModeState, registerName) {
@ -5628,7 +5681,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
Vim = CodeMirror.Vim;
specialKey = {'return':'CR',backspace:'BS','delete':'Del',esc:'Esc',
var specialKey = {'return':'CR',backspace:'BS','delete':'Del',esc:'Esc',
left:'Left',right:'Right',up:'Up',down:'Down',space: 'Space',
home:'Home',end:'End',pageup:'PageUp',pagedown:'PageDown', enter: 'CR'
};
@ -5646,7 +5699,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
if (name.length > 1) { name = '<' + name + '>'; }
return name;
}
var handleKey = Vim.handleKey
var handleKey = Vim.handleKey.bind(Vim);
Vim.handleKey = function(cm, key, origin) {
return cm.operation(function() {
return handleKey(cm, key, origin);
@ -5750,7 +5803,6 @@ dom.importCssString(".normal-mode .ace_cursor{\
});
return {command: "null", passEvent: true};
}
return {command: coreCommands.stop};
} else if (!vim.insertMode) {
if (useragent.isMac && this.handleMacRepeat(data, hashId, key)) {
hashId = -1;
@ -5925,10 +5977,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
{ keys: 'zf', type: 'action', action: 'fold', actionArgs: { open: true, all: true } },
{ keys: 'zd', type: 'action', action: 'fold', actionArgs: { open: true, all: true } },
{ keys: '<C-A-j>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAbove" } },
{ keys: '<C-A-k>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelow" } },
{ keys: '<C-A-S-j>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAboveSkipCurrent" } },
{ keys: '<C-A-S-k>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelowSkipCurrent" } },
{ keys: '<C-A-k>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAbove" } },
{ keys: '<C-A-j>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelow" } },
{ keys: '<C-A-S-k>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorAboveSkipCurrent" } },
{ keys: '<C-A-S-j>', type: 'action', action: 'aceCommand', actionArgs: { name: "addCursorBelowSkipCurrent" } },
{ keys: '<C-A-h>', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreBefore" } },
{ keys: '<C-A-l>', type: 'action', action: 'aceCommand', actionArgs: { name: "selectMoreAfter" } },
{ keys: '<C-A-S-h>', type: 'action', action: 'aceCommand', actionArgs: { name: "selectNextBefore" } },
@ -5955,6 +6007,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
},
exports.handler.defaultKeymap = defaultKeymap;
exports.handler.actions = actions;
exports.Vim = Vim;
Vim.map("Y", "yy");
});

View file

@ -592,6 +592,80 @@ testVim('{', function(cm, vim, helpers) {
helpers.doKeys('6', '{');
helpers.assertCursorAt(0, 0);
}, { value: 'a\n\nb\nc\n\nd' });
testVim('paragraph motions', function(cm, vim, helpers) {
cm.setCursor(10, 0);
helpers.doKeys('{');
helpers.assertCursorAt(4, 0);
helpers.doKeys('{');
helpers.assertCursorAt(0, 0);
helpers.doKeys('2', '}');
helpers.assertCursorAt(7, 0);
helpers.doKeys('2', '}');
helpers.assertCursorAt(16, 0);
cm.setCursor(9, 0);
helpers.doKeys('}');
helpers.assertCursorAt(14, 0);
cm.setCursor(6, 0);
helpers.doKeys('}');
helpers.assertCursorAt(7, 0);
// ip inside empty space
cm.setCursor(10, 0);
helpers.doKeys('v', 'i', 'p');
eqPos(Pos(7, 0), cm.getCursor('anchor'));
eqPos(Pos(12, 0), cm.getCursor('head'));
helpers.doKeys('i', 'p');
eqPos(Pos(7, 0), cm.getCursor('anchor'));
eqPos(Pos(13, 1), cm.getCursor('head'));
helpers.doKeys('2', 'i', 'p');
eqPos(Pos(7, 0), cm.getCursor('anchor'));
eqPos(Pos(16, 1), cm.getCursor('head'));
// should switch to visualLine mode
cm.setCursor(14, 0);
helpers.doKeys('<Esc>', 'v', 'i', 'p');
helpers.assertCursorAt(14, 0);
cm.setCursor(14, 0);
helpers.doKeys('<Esc>', 'V', 'i', 'p');
eqPos(Pos(16, 1), cm.getCursor('head'));
// ap inside empty space
cm.setCursor(10, 0);
helpers.doKeys('<Esc>', 'v', 'a', 'p');
eqPos(Pos(7, 0), cm.getCursor('anchor'));
eqPos(Pos(13, 1), cm.getCursor('head'));
helpers.doKeys('a', 'p');
eqPos(Pos(7, 0), cm.getCursor('anchor'));
eqPos(Pos(16, 1), cm.getCursor('head'));
cm.setCursor(13, 0);
helpers.doKeys('v', 'a', 'p');
eqPos(Pos(13, 0), cm.getCursor('anchor'));
eqPos(Pos(14, 0), cm.getCursor('head'));
cm.setCursor(16, 0);
helpers.doKeys('v', 'a', 'p');
eqPos(Pos(14, 0), cm.getCursor('anchor'));
eqPos(Pos(16, 1), cm.getCursor('head'));
cm.setCursor(0, 0);
helpers.doKeys('v', 'a', 'p');
eqPos(Pos(0, 0), cm.getCursor('anchor'));
eqPos(Pos(4, 0), cm.getCursor('head'));
cm.setCursor(0, 0);
helpers.doKeys('d', 'i', 'p');
var register = helpers.getRegisterController().getRegister();
eq('a\na\n', register.toString());
is(register.linewise);
helpers.doKeys('3', 'j', 'p');
helpers.doKeys('y', 'i', 'p');
is(register.linewise);
eq('b\na\na\nc\n', register.toString());
}, { value: 'a\na\n\n\n\nb\nc\n\n\n\n\n\n\nd\n\ne\nf' });
// Operator tests
testVim('dl', function(cm, vim, helpers) {