-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Custom keymaps (incl. Helix keymap) #299
Comments
Hey! Thanks for the link, somehow I had missed that part of the documentation and never understood how to grow selections in Helix. Knowing about
I agree, especially since a lot of commands are shared (and Dance has many utilities for implementing the remaining commands). 38001b1 adds the ability to use Tree Sitter trees within Dance (internally), with the intention to implement more Helix keybindings (see #297). With that said I'm fairly busy nowadays, so I mostly implemented this with the hope that users could send PRs adding commands based on this API.
IMO that's a necessary step anyway (as mentioned in the comment you linked). In theory that's a "nice to have" feature, but it's actually necessary to support non-US/Mac keyboards. |
This is really cool news. The most impressive thing is the tree-sitter implementation using WebAssembly. I see that you wondered what the most important Helix features are. The Man, I'd really love to get involved and help if I had more free time, but the amount of other projects I am part of is too overwhelming already. :( Edit: I am already on the pre-release channel all the time, by the way (currently |
IIRC I haven't released (at all) the version with Tree Sitter support, so you'd need to clone + debug the repository to try it out (+ debug, + add features). With that said, in theory
For solution 2., you'd go through Dance commands whose Kakoune and Helix keybindings are different, and add new Line 184 in 73d32ad
-| Extend to next word start | `word.extend` | `s-w` (kakoune: normal) | `[".seek.word", { shift: "extend", ... }]` |
+| Extend to next word start | `word.extend` | `s-w` (kakoune: normal), `w` (helix: extend) | `[".seek.word", { shift: "extend", ... }]` | |
Hi ! There's already a fork of dance that's achieved some good outcomes (the Besides The latter two could perhaps be done by just reusing VSCode's builtin symbol navigation and/or outline view. |
I see there have been some Helix-esque additions/options to dance, is there some doc that explains how to "enable" these? |
#301 adds the {
"key": "v",
"command": "dance.modes.set.select",
"when": "editorTextFocus && dance.mode == 'normal'",
},
// And to avoid conflicts:
{
"key": "v",
"command": "-dance.openMenu",
"when": "editorTextFocus && dance.mode == 'normal'"
}, 38001b1 adds a couple of Tree-Sitter based commands, but requires https://github.com/71/vscode-tree-sitter-api to be installed for the commands to be shown. Similarly, no keybindings exist by default, so you have to define them yourself or to use the command palette. They're also very basic; among other things, Dance doesn't have the Helix library of textobjects used by Helix for seeking to specific syntax nodes. |
What about adding the next line down to the selection when the user hits 'x' again? How easy would that be to add via keybindings.json? |
@alxpettit Here's what I use in recent versions of kakoune (for I can't remember why
|
Seems very script-y. I imagine there must be some way to embed js into keybindings in VSCode? |
@alxpettit Dance already has commands with equivalent functionality: { "key": "x", "command": "dance.select.line.below.extend", "when": "editorTextFocus && dance.mode == 'normal' || editorTextFocus && dance.mode == 'select'" },
{ "key": "shift+x", "command": "dance.selections.expandToLines", "when": "editorTextFocus && dance.mode == 'normal' || editorTextFocus && dance.mode == 'select'" }, PS: Here's my config trying to imitate helix' keybindings: Edit:
Also I have added some surround-bindings which are not present in the commits linked above: "match-hx": {
"title": "Match",
"items": {
...
"s": { "text": "Surround add", "command": "dance.run", "args": [{ "code": [
"let pairs = ['()', '{}', '[]', '<>'];",
"let x = vscode.commands.executeCommand",
"let c = await keypress(Context.current);",
"let p = pairs.find((p) => p.includes(c));",
"await x('dance.selections.save');",
"Selections.updateWithFallbackByIndex((i, sel) => new vscode.Selection(sel.anchor, Positions.at(sel.active.line, sel.active.character + (sel.isReversed ? -1 : 1))));",
"await x('editor.action.insertSnippet', { 'snippet': (p?.at(0) || c) + '${TM_SELECTED_TEXT}' + (p?.at(1) || c) });",
"await x('dance.selections.restore');",
] }] },
"r": { "text": "Surround replace", "command": "dance.run", "args": [{ "code": [
"let pairs = ['()', '{}', '[]', '<>'];",
"let x = vscode.commands.executeCommand",
"let c = await keypress(Context.current);",
"let p = pairs.find((p) => p.includes(c));",
"await x('dance.selections.save');",
"await x('dance.selections.faceBackward');",
"await x('dance.seek.included.extend.backward', { 'input': p?.at(0) || c });",
"await x('dance.selections.changeDirection');",
"await x('dance.seek.included.extend', { 'input': p?.at(1) || c });",
"await x('dance.selections.save', { 'register': 'surround' });",
"await x('dance.selections.reduce.edges');",
"c = await keypress(Context.current);",
"p = pairs.find((p) => p.includes(c));",
"await x('dance.edit.delete');",
"await x('dance.selections.restore', { 'register': 'surround' });",
"await x('dance.select.right.extend');",
"await x('editor.action.insertSnippet', { 'snippet': (p?.at(0) || c) + '${TM_SELECTED_TEXT}' + (p?.at(1) || c) });",
"await x('dance.selections.restore');",
] }] },
"d": { "text": "Surround delete", "command": "dance.run", "args": [{ "code": [
"let pairs = ['()', '{}', '[]', '<>'];",
"let x = vscode.commands.executeCommand",
"let c = await keypress(Context.current);",
"let p = pairs.find((p) => p.includes(c));",
"await x('dance.selections.save');",
"await x('dance.selections.faceBackward');",
"await x('dance.seek.included.extend.backward', { 'input': p?.at(0) || c });",
"await x('dance.selections.changeDirection');",
"await x('dance.seek.included.extend', { 'input': p?.at(1) || c });",
"await x('dance.selections.reduce.edges');",
"await x('dance.edit.delete');",
"await x('dance.selections.restore');",
] }] },
...
},
}, |
@imawizard Great thanks for the sharing for config. Do you have any suggestion on the command mode disparity, say |
Not really, sorry. You could use custom menus, however, Dance's prompt-functions work with item keys of length 1, so you'd need to split e.g. "wq" among multiple menus or use I have mapped Btw. I have updated some menu entries/keybindings: vscode/data/user-data/User |
Sorry for cluttering up this issue with a not-really related comment 😅, it possibly answers @cloudhan latest question, and I was wondering the same thing.. I found a workaround for missing commands that I'm used to (i.e. So adding something like this to settings.json, in addition to having "command aliases": {
"workbench.action.files.saveAll": "write-all, wall",
"workbench.action.files.save": "write, w",
"workbench.action.closeAllEditors": "quit-all, qall",
"workbench.action.closeActiveEditor": "quit, q"
}, |
Actually, I solved that awhile ago myself! You don't need anything besides Dance itself.
{
"args": {
"menu": "cmd-hx"
},
"command": "dance.openMenu",
"key": "shift+;",
"when": "editorTextFocus && (dance.mode != 'insert')"
},
{
"dance": {
"menus": {
"cmd-hx": {
"items": {
"w": {
"command": "saveAll",
"text": "Save document"
}
},
"title": "Quick command"
},
},
},
} |
Thanks for your work to add some Helix-flavored options. I think Helix has a great workflow and would love to standardize some muscle memory. Down the line, it'd be awesome to have the option to select "classic" Kakoune mode or Helix mode. |
Is this mature enough to replace the Dance - Helix Alpha extension? And if yes, what do I have to do to set it up? Thanks for any help :) |
@LU15W1R7H IMO, yeah, it's good enough as a replacement. You just need to import @imawizard's keybindings and settings into your own. I made a few tweaks of my own for a hybrid cursor/block mode that fits vscode's native selection logic better though (IMO, of course), and a few personal preferences. keybindings.json, settings.json |
Is there some quick way to disable dance, without having to remove the keybindings? |
One way is to create a dance "mode" that does nothing, and add commands to switch to and from that mode. I do wish Dance had built-in support for this, though. I'll post a config here if I find it. |
Defining and switching to a "disabled" mode that doesn't do anything is the recommended way to disable Dance, indeed, though I'm open to making this a first-class feature (which was actually the case some time ago, but I removed that feature when adding support for custom modes) or to include the "disabled" mode in the built-in Dance config (possibly with built-in commands to toggle it easily). @LU15W1R7H Typically keybindings use |
https://github.com/71/dance/wiki/Helix-support
|
I just wanna say that it's insane that things like this comment are possible, you've essentially built a scriptable editor within VSCode this is insane (as in insanely cool) thank you so much for all your work. this is my endgame setup |
@imawizard thank you for the awesome bindings. I'm having a problem with using Could there be some workaround for this? perhaps if there are no LSP suggestions, |
I had exactly the same problem. Open keybindings.json (CMD + K CMD +S), then comment out the tab bindings in insert mode.
|
I'm on the latest commit for those { "key": "tab", "command": "dance.run", "args": { "code": [
"let x = vscode.commands.executeCommand;",
"let _ = Context.current;",
"let ts = _.extension.treeSitter;",
"let pos = _.mainSelection.start;",
"if (pos.character <= _.document.lineAt(pos).firstNonWhitespaceCharacterIndex) {",
"await x('tab');",
"} else if (ts?.determineLanguage(_.document)) {",
"await x('dance.seek.syntax.parent.experimental');",
"await x('dance.selections.reduce');",
"} else {",
"await x('cursorLineEnd');",
"}",
] }, "when": "editorTextFocus && dance.mode == 'insert'" }, and Co-pilot and normal LSP autocompletions work as expected, but I don't know what this piece of code was supposed to do 🤷 |
Hi, I noticed that the project creator, @71, is considering custom keymaps and Helix bindings:
#281 (comment)
I've been looking into ways of getting Helix editing in Vscode. While Kakoune is definitely better than Vim (which I used for 15 years), thanks to the ability to preview the motions BEFORE you commit the action, I noticed that Helix improves on Kakoune by fixing some very awkward keybinds (shift/alt gymnastics):
https://github.com/helix-editor/helix/wiki/Differences-from#kakoune
The biggest improvement for me is how easy it is to make multiple selections. In Kakoune, selecting a bunch of words means holding shift while tapping w/b until the correct length. If you release "shift" at any moment, your selection is LOST.
In Helix, you instead press "v" to enter "visual mode" (vim-like), and tap as much w/b as you want without needing to hold anything else. When you're done, just hit the action (such as d (delete)). Much easier than Kakoune.
I think Dance is in the best spot to implement Helix-style tweaks for Kakoune, given the fact that the project is already of extremely high quality, and Helix bindings are just a few small tweaks of Kakoune's movements. Although I suspect that refactoring Dance into a keymap-based system is the limiting factor here, not Helix's small tweaks themselves.
The text was updated successfully, but these errors were encountered: