Closed brillout closed 3 years ago
I can see your point of why this would be useful. The bindings become verbose quickly, if you have to write each of them separately. Luckily there is another way; I have implemented delete, yank, and change commands a bit differently using selectBetween
command. I have bound selection to v
key. For example vi(
selects the text inside parenthesis.
"v": {
"help": "Select [j|l] left|right, [w] word [d] line [f|b] forwards|backwards [i|a] inside|around",
...
"a,i": {
"help": "Select around/inside _",
...
"(,)": [
"modaledit.cancelSelection",
{
"command": "modaledit.selectBetween",
"args": "{ from: '(', to: ')', inclusive: __rkeys[1] == 'a' }"
}
],
So, basically I use JS only in args
property. The same binding also implements select around ca(
. As in your example, I examine the second character in the key sequence, and set the inclusive
argument based on that. Now, I can implement ci(
like this:
"c": {
"help": "Change [j|l] left|right, [w] word [f|b] forwards|backwards [i|a] inside|around",
...
"a,i": {
"help": "Delete around/inside _",
"w, -/,:-@,[-`,{-~": [
{
"command": "modaledit.typeNormalKeys",
"args": "{ keys: ['v', ...__keys.slice(-2)].join('') }"
},
"editor.action.clipboardCutAction"
]
}
I basically call the vi(
command by using the typeNormalKeys
command, and then just cut the selected text to clipboard. You can find bindings using the same trick for change and yank commands in my bindings.
Coming back to your original request, there is a way to define the bindings in JS too, but that involves you creating your own VS code extension and including ModalEdit as a dependency. The extension would be very simple; you can just set your bindings in the activation event using JS/TS. See issue #6 for more information. The requestor of that issue tested that the idea works.
Neat, this seems to be working, thanks!
To the original request: using JS instead of JSON could open up new interesting possibilities, beyond defining the c
, d
and y
commands.
For example:
const keybindings = {
'H': args => jumpToWhitespace(args, true),
'L': args => jumpToWhitespace(args, false),
};
function jumpToWhitespace({line, cursorPosition}, backwards) {
let column;
if( backwards ){
const line__relevant = line.slice(0, cursorPosition.column);
column = line__relevant.split('').lastIndexOf(' ');
} else {
const line__relevant = line.slice(cursorPosition.column, line.length);
column = line__relevant.split('').indexOf(' ');
}
if( column===-1 ){
return {
warningMessage: 'No whitespace on the '+(backwards?'left':'right')+' found.',
};
}
return {
cursorPosition: {
column,
},
};
}
module.exports = {keybindings};
And this is just one example; even only a tiny ModalEdit JS API would enable ModalEdit users to achieve all kinds of keybindings.
I have couple of keybindings in mind that I would be thrilled to implement that way :blush:.
Thoughts?
Well, in principle having the bindings in JS file would be relatively easy to implement. There are some consequences of having the bindings outside the settings.json
file though.
The bindings would not be automatically refreshed when you save the JS file. The event for that triggers only when settings.json
file changes. So, there would have to be some kind of file watcher for the JS file as well. And of course, if you save a file that has any errors, the bindings would disappear.
Also a question arises, where the JS file should be located? Under workspace, or in the user home directory, or in a VS Code's system directory? This is more of a user problem than problem of ModalEdit, if we just require to have the absolute path of the JS file in the settings. Nevertheless, there should be probably be some recommendations, at least.
The support for multiple settings levels would break. Currently you can define bindings in three levels: workspace, user, and default. The keybindings defined in these files are actually merged. If a same key is bound in multiple files, the precedence (lowest to highest) is: default, user, workspace. This merging and overriding of key bindings would not work. Effectively, bindings would exist only in one place.
A way to get around problem 1. would be to put JS code inside a setting.json
file as a string, but editing code there would be cumbersome. Also problem 2. would still exist with this solution. In my opinion, creating a new extension is a cleaner approach when you want to have this option. You avoid the problems above, and have a nicer experience editing the code as "normal" TypeScript file.
In version 2.0 you can import keybindings from a JS file. I think it is cleaner solution than messing with the settings.json
file. The JS code is run at import time, so effectively you can "compile" or expand your bindings into the global settings.json
where they are stored in normal JSON format.
One of my favorite VIM feature are the "c", "d", and "y" keys, e.g. "ci(" or "y$", which I'm currently implementing with ModalEdit.
What would help enormously would be able to use JavaScript to define keybindings.
For example:
What do you think?