add support for multiple selections

This commit is contained in:
nightwing 2014-11-04 17:43:57 +04:00
commit 068c950517

View file

@ -1161,14 +1161,19 @@ dom.importCssString(".normal-mode .ace_cursor{\
function defineOption(name, defaultValue, type) {
if (defaultValue === undefined) { throw Error('defaultValue is required'); }
if (!type) { type = 'string'; }
options[name] = {
type: type,
defaultValue: defaultValue
};
var opt = name;
if (typeof name == "string")
opt = {
type: type,
defaultValue: defaultValue
};
else
name = opt.name;
options[name] = opt;
setOption(name, defaultValue);
}
function setOption(name, value) {
function setOption(name, value, cm) {
var option = options[name];
if (!option) {
throw Error('Unknown option: ' + name);
@ -1181,7 +1186,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
value = true;
}
}
option.value = option.type == 'boolean' ? !!value : value;
option.value = value;
if (option.set) option.set(value, cm);
}
function getOption(name) {
@ -2564,6 +2570,9 @@ dom.importCssString(".normal-mode .ace_cursor{\
} else if (character === 'w') {
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
false /** bigWord */);
} else if (character === 'p') {
tmp = expandParagraphUnderCursor(cm, inclusive, true /** forward */,
false /** bigWord */);
} else {
// No text object defined for this, don't move.
return null;
@ -4867,7 +4876,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
showConfirm(cm, ' ' + optionName + '=' + oldValue);
}
} else {
setOption(optionName, value);
setOption(optionName, value, cm);
}
},
registers: function(cm,params) {
@ -5657,18 +5666,61 @@ dom.importCssString(".normal-mode .ace_cursor{\
if (name.length > 1) { name = '<' + name + '>'; }
return name;
}
var handleKey = CodeMirror.Vim.handleKey
CodeMirror.Vim.handleKey = function(cm, key, origin) {
var handleKey = Vim.handleKey
Vim.handleKey = function(cm, key, origin) {
return cm.operation(function() {
return handleKey(cm, key, origin);
}, true);
}
function cloneVimState(state) {
var n = new state.constructor();
Object.keys(state).forEach(function(key) {
var o = state[key];
if (Array.isArray(o))
o = o.slice();
else if (o && typeof o == "object" && o.constructor != Object)
o = cloneVimState(o);
n[key] = o;
});
return n;
}
function multiSelectHandleKey(cm, key, origin) {
var isHandled = false;
var vim = Vim.maybeInitVimState_(cm);
var visualBlock = vim.visualBlock || vim.wasInVisualBlock;
if (vim.wasInVisualBlock && !cm.ace.inMultiSelectMode) {
vim.wasInVisualBlock = false;
} else if (cm.ace.inMultiSelectMode && vim.visualBlock) {
vim.wasInVisualBlock = true;
}
if (key == '<Esc>' && !vim.insertMode && !vim.visualMode && cm.ace.inMultiSelectMode) {
cm.ace.exitMultiSelectMode();
} else if (visualBlock || !cm.ace.inMultiSelectMode || cm.ace.inVirtualSelectionMode) {
isHandled = Vim.handleKey(cm, key, origin);
} else {
var old = cloneVimState(vim);
cm.operation(function() {
cm.ace.forEachSelection(function() {
var sel = cm.ace.selection;
cm.state.vim.lastHPos = sel.$desiredColumn == null ? sel.lead.column : sel.$desiredColumn;
isHandled = handleKey(cm, key, origin);
sel.$desiredColumn = cm.state.vim.lastHPos == -1 ? null : cm.state.vim.lastHPos;
if (cm.virtualSelectionMode()) {
cm.state.vim = cloneVimState(old);
}
});
if (cm.curOp.cursorActivity && !isHandled)
cm.curOp.cursorActivity = false;
}, true);
}
return isHandled;
};
exports.CodeMirror = CodeMirror;
var getVim = Vim.maybeInitVimState_;
exports.handler = {
cm: null,
drawCursor: function(style, pixelPos, config, sel, session) {
var vim = this.cm.state.vim;
var vim = this.state.vim || {};
var w = config.characterWidth;
var h = config.lineHeight;
var top = pixelPos.top;
@ -5698,7 +5750,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
var name = lookupKey(hashId, key, e || {});
if (vim.status == null)
vim.status = "";
var isHandled = CodeMirror.Vim.handleKey(cm, name, 'user');
var isHandled = multiSelectHandleKey(cm, name, 'user');
vim = getVim(cm); // may be changed by multiSelectHandleKey
if (isHandled && vim.status != null)
vim.status += name;
else if (vim.status == null)
@ -5713,25 +5766,27 @@ dom.importCssString(".normal-mode .ace_cursor{\
if (!editor.state) editor.state = {};
var cm = new CodeMirror(editor);
editor.state.cm = cm;
editor.$vimModeHandler = Object.create(this);
editor.$vimModeHandler.cm = editor.state.cm;
var vim = CodeMirror.Vim.maybeInitVimState_(cm);
editor.$vimModeHandler = this;
CodeMirror.keyMap.vim.attach(cm);
vim.status = null;
getVim(cm).status = null;
cm.on('vim-command-done', function() {
vim.status = null;
if (cm.virtualSelectionMode()) return;
getVim(cm).status = null;
cm.ace._signal("changeStatus");
cm.ace.session.markUndoGroup();
});
cm.on("changeStatus", function() {
cm.ace.renderer.updateCursor();
cm.ace._signal("changeStatus");
});
cm.on("vim-mode-change", function() {
cm.ace.renderer.setStyle("normal-mode", !vim.insertMode);
if (cm.virtualSelectionMode()) return;
cm.ace.renderer.setStyle("normal-mode", !getVim(cm).insertMode);
cm._signal("changeStatus");
});
cm.ace.renderer.setStyle("normal-mode", !vim.insertMode);
editor.renderer.$cursorLayer.drawCursor = this.drawCursor.bind(editor.$vimModeHandler);
cm.ace.renderer.setStyle("normal-mode", !getVim(cm).insertMode);
editor.renderer.$cursorLayer.drawCursor = this.drawCursor.bind(cm);
renderVirtualNumbers.attach(editor);
},
detach: function(editor) {
var cm = editor.state.cm;
@ -5741,6 +5796,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
editor.$vimModeHandler = null;
editor.renderer.$cursorLayer.drawCursor = null;
editor.renderer.setStyle("normal-mode", false);
renderVirtualNumbers.detach(editor);
},
getStatusText: function(editor) {
var cm = editor.state.cm;
@ -5760,4 +5816,68 @@ dom.importCssString(".normal-mode .ace_cursor{\
return status;
}
}
var renderVirtualNumbers = {
getText: function(session, row) {
return (Math.abs(session.selection.lead.row - row) || (row + 1 + (row < 9? "\xb7" : "" ))) + ""
},
getWidth: function(session, lastLineNumber, config) {
return session.getLength().toString().length * config.characterWidth;
},
update: function(e, editor) {
editor.renderer.$loop.schedule(editor.renderer.CHANGE_GUTTER)
},
attach: function(editor) {
editor.renderer.$gutterLayer.$renderer = this;
editor.on("changeSelection", this.update);
},
detach: function(editor) {
editor.renderer.$gutterLayer.$renderer = null;
editor.off("changeSelection", this.update);
}
};
Vim.defineOption({
name: "wrap",
set: function(value, cm) {
if (cm) {cm.ace.setOption("wrap", value)}
},
type: "boolean"
}, false);
defaultKeymap.push(
{ keys: 'zc', type: 'action', action: 'fold', actionArgs: { open: false } },
{ keys: 'zC', type: 'action', action: 'fold', actionArgs: { open: false, all: true } },
{ keys: 'zo', type: 'action', action: 'fold', actionArgs: { open: true, } },
{ keys: 'zO', type: 'action', action: 'fold', actionArgs: { open: true, all: true } },
{ keys: 'za', type: 'action', action: 'fold', actionArgs: { toggle: true } },
{ keys: 'zA', type: 'action', action: 'fold', actionArgs: { toggle: true, all: true } },
{ 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-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" } },
{ keys: '<C-A-S-l>', type: 'action', action: 'aceCommand', actionArgs: { name: "selectNextAfter" } }
);
actions.aceCommand = function(cm, actionArgs, vim) {
cm.vimCmd = actionArgs;
if (cm.ace.inVirtualSelectionMode)
cm.ace.on("beforeEndOperation", delayedExecAceCommand);
else
delayedExecAceCommand(null, cm.ace)
};
function delayedExecAceCommand(op, ace) {
ace.off("beforeEndOperation", delayedExecAceCommand);
var cmd = ace.state.cm.vimCmd;
if (cmd) {
ace.execCommand(cmd.name, cmd.args);
}
ace.curOp = ace.prevOp;
}
actions.fold = function(cm, actionArgs, vim) {
cm.ace.execCommand(['toggleFoldWidget', 'toggleFoldWidget', 'foldOther', 'unfoldall'
][(actionArgs.all ? 2 : 0) + (actionArgs.open ? 1 : 0)]);
}
});