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) {
|
function defineOption(name, defaultValue, type) {
|
||||||
if (defaultValue === undefined) { throw Error('defaultValue is required'); }
|
if (defaultValue === undefined) { throw Error('defaultValue is required'); }
|
||||||
if (!type) { type = 'string'; }
|
if (!type) { type = 'string'; }
|
||||||
options[name] = {
|
var opt = name;
|
||||||
type: type,
|
if (typeof name == "string")
|
||||||
defaultValue: defaultValue
|
opt = {
|
||||||
};
|
type: type,
|
||||||
|
defaultValue: defaultValue
|
||||||
|
};
|
||||||
|
else
|
||||||
|
name = opt.name;
|
||||||
|
options[name] = opt;
|
||||||
setOption(name, defaultValue);
|
setOption(name, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setOption(name, value) {
|
function setOption(name, value, cm) {
|
||||||
var option = options[name];
|
var option = options[name];
|
||||||
if (!option) {
|
if (!option) {
|
||||||
throw Error('Unknown option: ' + name);
|
throw Error('Unknown option: ' + name);
|
||||||
|
|
@ -1181,7 +1186,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
value = true;
|
value = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
option.value = option.type == 'boolean' ? !!value : value;
|
option.value = value;
|
||||||
|
if (option.set) option.set(value, cm);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOption(name) {
|
function getOption(name) {
|
||||||
|
|
@ -2564,6 +2570,9 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
} else if (character === 'w') {
|
} else if (character === 'w') {
|
||||||
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
tmp = expandWordUnderCursor(cm, inclusive, true /** forward */,
|
||||||
false /** bigWord */);
|
false /** bigWord */);
|
||||||
|
} else if (character === 'p') {
|
||||||
|
tmp = expandParagraphUnderCursor(cm, inclusive, true /** forward */,
|
||||||
|
false /** bigWord */);
|
||||||
} else {
|
} else {
|
||||||
// No text object defined for this, don't move.
|
// No text object defined for this, don't move.
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -4867,7 +4876,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
showConfirm(cm, ' ' + optionName + '=' + oldValue);
|
showConfirm(cm, ' ' + optionName + '=' + oldValue);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setOption(optionName, value);
|
setOption(optionName, value, cm);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
registers: function(cm,params) {
|
registers: function(cm,params) {
|
||||||
|
|
@ -5657,18 +5666,61 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
if (name.length > 1) { name = '<' + name + '>'; }
|
if (name.length > 1) { name = '<' + name + '>'; }
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
var handleKey = CodeMirror.Vim.handleKey
|
var handleKey = Vim.handleKey
|
||||||
CodeMirror.Vim.handleKey = function(cm, key, origin) {
|
Vim.handleKey = function(cm, key, origin) {
|
||||||
return cm.operation(function() {
|
return cm.operation(function() {
|
||||||
return handleKey(cm, key, origin);
|
return handleKey(cm, key, origin);
|
||||||
}, true);
|
}, 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;
|
exports.CodeMirror = CodeMirror;
|
||||||
var getVim = Vim.maybeInitVimState_;
|
var getVim = Vim.maybeInitVimState_;
|
||||||
exports.handler = {
|
exports.handler = {
|
||||||
cm: null,
|
|
||||||
drawCursor: function(style, pixelPos, config, sel, session) {
|
drawCursor: function(style, pixelPos, config, sel, session) {
|
||||||
var vim = this.cm.state.vim;
|
var vim = this.state.vim || {};
|
||||||
var w = config.characterWidth;
|
var w = config.characterWidth;
|
||||||
var h = config.lineHeight;
|
var h = config.lineHeight;
|
||||||
var top = pixelPos.top;
|
var top = pixelPos.top;
|
||||||
|
|
@ -5698,7 +5750,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
var name = lookupKey(hashId, key, e || {});
|
var name = lookupKey(hashId, key, e || {});
|
||||||
if (vim.status == null)
|
if (vim.status == null)
|
||||||
vim.status = "";
|
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)
|
if (isHandled && vim.status != null)
|
||||||
vim.status += name;
|
vim.status += name;
|
||||||
else if (vim.status == null)
|
else if (vim.status == null)
|
||||||
|
|
@ -5713,25 +5766,27 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
if (!editor.state) editor.state = {};
|
if (!editor.state) editor.state = {};
|
||||||
var cm = new CodeMirror(editor);
|
var cm = new CodeMirror(editor);
|
||||||
editor.state.cm = cm;
|
editor.state.cm = cm;
|
||||||
editor.$vimModeHandler = Object.create(this);
|
editor.$vimModeHandler = this;
|
||||||
editor.$vimModeHandler.cm = editor.state.cm;
|
|
||||||
var vim = CodeMirror.Vim.maybeInitVimState_(cm);
|
|
||||||
CodeMirror.keyMap.vim.attach(cm);
|
CodeMirror.keyMap.vim.attach(cm);
|
||||||
vim.status = null;
|
getVim(cm).status = null;
|
||||||
cm.on('vim-command-done', function() {
|
cm.on('vim-command-done', function() {
|
||||||
vim.status = null;
|
if (cm.virtualSelectionMode()) return;
|
||||||
|
getVim(cm).status = null;
|
||||||
cm.ace._signal("changeStatus");
|
cm.ace._signal("changeStatus");
|
||||||
|
cm.ace.session.markUndoGroup();
|
||||||
});
|
});
|
||||||
cm.on("changeStatus", function() {
|
cm.on("changeStatus", function() {
|
||||||
cm.ace.renderer.updateCursor();
|
cm.ace.renderer.updateCursor();
|
||||||
cm.ace._signal("changeStatus");
|
cm.ace._signal("changeStatus");
|
||||||
});
|
});
|
||||||
cm.on("vim-mode-change", function() {
|
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._signal("changeStatus");
|
||||||
});
|
});
|
||||||
cm.ace.renderer.setStyle("normal-mode", !vim.insertMode);
|
cm.ace.renderer.setStyle("normal-mode", !getVim(cm).insertMode);
|
||||||
editor.renderer.$cursorLayer.drawCursor = this.drawCursor.bind(editor.$vimModeHandler);
|
editor.renderer.$cursorLayer.drawCursor = this.drawCursor.bind(cm);
|
||||||
|
renderVirtualNumbers.attach(editor);
|
||||||
},
|
},
|
||||||
detach: function(editor) {
|
detach: function(editor) {
|
||||||
var cm = editor.state.cm;
|
var cm = editor.state.cm;
|
||||||
|
|
@ -5741,6 +5796,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
editor.$vimModeHandler = null;
|
editor.$vimModeHandler = null;
|
||||||
editor.renderer.$cursorLayer.drawCursor = null;
|
editor.renderer.$cursorLayer.drawCursor = null;
|
||||||
editor.renderer.setStyle("normal-mode", false);
|
editor.renderer.setStyle("normal-mode", false);
|
||||||
|
renderVirtualNumbers.detach(editor);
|
||||||
},
|
},
|
||||||
getStatusText: function(editor) {
|
getStatusText: function(editor) {
|
||||||
var cm = editor.state.cm;
|
var cm = editor.state.cm;
|
||||||
|
|
@ -5760,4 +5816,68 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
||||||
return status;
|
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