add support for multiple selections
This commit is contained in:
parent
bd7de6b43b
commit
068c950517
1 changed files with 140 additions and 20 deletions
|
|
@ -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)]);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue