flow-website/content/docs/architecture/keybind.smd
2025-11-03 22:56:17 +01:00

212 lines
7.1 KiB
Text

---
.title = "Keybinding",
.date = @date("2025-10-19T00:00:00"),
.author = "Igor Támara",
.layout = "tutorial.shtml",
.draft = false,
.custom = {
.githubedit = "/docs/architecture/keybind.smd",
.codepath ="src/keybind/builtin/",
},
---
If you are here, maybe is because you want to make flow behave according
to your key presses preferences or possibly you already have edited your
own keybinds to suit your use cases and make everything easier, faster
and more fluid when in flow.
First make sure you are aware of the
[existence of ctrl+f2 palette](/docs#key_controls) which
exposes a list of commands available for you to use, and when you select
a command, it's pasted in your current cursor position.
Using the command palette `Ctrl+Shift+p` and typing **Edit key
bindings**, takes you to a json file to extend flow, configuring
keybindings to suit your needs. According to the mode you are in, your
personal mode's file configuration will be opened. Explore the
the file to discover how commands are bound to some combos, key presses
and the different [imodes](#hierarchy) present.
Command palette can also be reached left clicking on the current
mode in the status bar.
[]($section.id('tldr'))
## ;TLDR;
Once you open the corresponding json file, locate inside the
[imode](#hierarchy)(internal mode) that will accept the key or
key/combos and add an array, where the first element is the combination
to map to the commands that will be invoked, the array accepts strings
like in
```zig
["ctrl+alt+shift+p", "open_command_palette"]
```
To avoid screwing up the combinations, and putting flow in an unusable
state derived from a wrong mapping of key combinations, read on.
[]($section.id('defaults'))
## Resetting keys to factory defaults
User configured keybindings are stored in Flow's configuration directory
under `keys/mode.json` where mode can be `flow`, `emacs`, `vim`, `helix`
or customized ones. Removing the keys directory or the particular mode
file can take you out from a broken state.
[]($section.id('modes'))
## Keybinds for each mode
Keybinds are edited per mode, and other modes inherit what is defined
in your `flow.json` keybindings. Each mode override keybindings of its
parent mode. For example, if you are in **emacs** mode you will be
redirected to `emacs.json` and it will override the keybindings from
flow, and the default ones defined for emacs mode.
[introducing keybindings](/devlog/2024#2024-12-05T20:55:00) showcases
how to get to edit keybindings.
[]($section.id('hierarchy'))
## Keybindings hierarchy
Some terminology
* **Mode**: Stored in a json file, like flow mode declared in
`flow.json`.
* **Imode**: under the json file.
* **Major Imode**: `project` or descendant from `project`.
* **Minimodes**: To be used momentarily and do not inherit from
`project`.
In general a keybinding json shows this hierarchy:
>[]($block.attrs('tree'))
>`flow.json` `<-- keybindings for flow mode`
>`{`
>* "project": { `<-- imode`
> * "press": [ `<-- react when press`
> * ["ctrl+alt+shift+r", "restart"], `<-- the keys with commands`
> * 
> * ]
>* },
>* "normal": [ `<-- imode`
> * "inherit": "project" `<-- Inherits all the keypresses and reactions from project`
> * "press": [ `<- custom actions for normal imode`
> * ["ctrl+z", "undo"],
> * 
> * ],
> * "release": [ `<-- normal imode also reacts when some keys are released`
> * ["left_control", "disable_jump_mode"], `<-- no more jumping when left control is released`
> * ]
>* ],
>* "select": {  "cursor":"block"  }, `<-- imode with a cursor change`
>* "home": {  "on_match_failure": "ignore"  }, `<-- imode`
>* "overlay/palette": {  } `<-- keys are handled by a palette`
>* "mini/numeric": {  } `<-- minimodes also handle actions`
>*  `}`
`project` is the main imode in `flow.json`, mapping many combo key down
presses.
Notice that `normal` imode `inherits` from `project`, meaning all the
key presses handled by project react the same way in normal, which also
extends with other keypresses. `normal` also captures key
releases, we show a sample when the control key is released,
stopping jumping mode inside flow.json.
`SELECT` imode inherits from normal and shows a different cursor to
remind it is the current one.
`home` mode is shown when no buffer is open and if the user presses
keys that are not explicitly handled to bring mental peace to the
user.
`overlay/palette` gets active when a
[palette](/docs/architecture) is active.
Looking further, it can be seen that
[minimodes](/docs/architecture/minimode) have their own keybinding
mappings defined in a particular imode, the same as palettes.
As stated previously, there is a mode hierarchy, the main mode is flow
and other modes inherit from it. Each mode inherits, extends and
overrides actions and define their internal imodes extending as
required each minimode.
[]($section.id('adding'))
## Adding a Keybinding
The most basic case to map a keybind to a command was covered in
[TLDR](#tldr) which used the combination of three keys pressed
simultaneously `ctrl`, `shift` and `p`, all of them where combined with
`+` to execute the command `open_command_palette`.
A common use case is to add a keybinding to invoke an already existing
command and chain it to another, making Flow more suited to your own
needs.
[]($section.id('shell'))
## Running shell commands
For example, `f5` by default is used to run `zig build test` outputting
its results to a *scratch buffer* called `test`.
The original definition is:
```zig
["f5", ["create_scratch_buffer", "*test*"], ["shell_execute_insert", "zig", "build", "test"]],
```
Note that:
The keybind is `f5`, which maps to the keycode generated by pressing
the `f5` key.
`create_scratchbuffer` is invoked receiving the parameter `*test*`
which results in creating a scratch buffer if didn't exist. And then
executing the command `shell_execute_insert` that receives the
parameters `zig`, `build`, `test`. This latter command is executing
a shell command called `zig` with the parameters `build` and `test`;
if you don't have zig installed, it will not work, and you might
want to remap `f5` to a different shell command.
```zig
[
"f5",
[
"create_scratch_buffer",
"*test*"
],
[
"shell_execute_insert",
"zig",
"build",
"test"
]
]
```
Observe [tasks running](/devlog/2025#2025-01-26T22:11:00) and maybe
consider using more keybindings or running tasks for your projects.
[]($section.id('next'))
## Next steps
If you realized that there is a handy combination that others can
benefit from or that a mode lacks the combination and it might be
included in flow, look at the
[contribution guidelines](/docs/contributing) to submit your findings
and solutions.
Probably binding commands is good, but maybe there is a feature in other
text editors that you miss and would love to have at your fingertips.
Then it's Zig time: [Adding commands](/docs/architecture/command) to
flow.
* Making flow even better with [tests](/docs/testing)
* Adding [new commands](/docs/architecture/command)
* [Contributing](/docs/contributing)
* [Getting in touch](https://discord.com/invite/4wvteUPphx) to share
your combos