Add initial docs for command, editor, keybind, palette
This commit is contained in:
parent
1964cb7fd6
commit
ca131d2135
4 changed files with 366 additions and 0 deletions
121
content/docs/architecture/command.smd
Normal file
121
content/docs/architecture/command.smd
Normal file
|
|
@ -0,0 +1,121 @@
|
||||||
|
---
|
||||||
|
.title = "Commands",
|
||||||
|
.date = @date("2025-10-15T00:00:00"),
|
||||||
|
.author = "Igor Támara",
|
||||||
|
.layout = "tutorial.shtml",
|
||||||
|
.draft = false,
|
||||||
|
.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/command.md"},
|
||||||
|
---
|
||||||
|
|
||||||
|
Commands are actions triggered to operate on buffers primarily. They
|
||||||
|
are present in `editor`, `tui`, `mode` and `minimodes`, it's possible
|
||||||
|
to find commands in other places, which will become evident when the
|
||||||
|
need arises.
|
||||||
|
|
||||||
|
## Previous notes
|
||||||
|
|
||||||
|
Note: Flow is programmed with [zig](https://ziglang.org/), if you are familiar
|
||||||
|
with C, C++, Rust, there are differences and reasonings that
|
||||||
|
might find useful when [learning Zig](https://ziglang.org/learn/). If you
|
||||||
|
are coming from higher level programming languages such as Python, Ruby,
|
||||||
|
C#, Java, Golang, Typescript it will be an opportunity to learn about trades
|
||||||
|
of managing memory and fast responses and some lower level concepts present
|
||||||
|
in Zig. If you are brand new to programming, some general concepts will be
|
||||||
|
needed and practice in another language before getting into flow development.
|
||||||
|
|
||||||
|
If you are new to Zig, it's a good idea to take a look at
|
||||||
|
[ziglings](https://ziglings.org/) to practice, as you learn the language.
|
||||||
|
|
||||||
|
Maybe there is a [shell command invoked](/docs/architecture/keybind#shell) with a
|
||||||
|
keybinding that can help in the task you are aiming at before developing
|
||||||
|
flow itself.
|
||||||
|
|
||||||
|
## Understanding and creating commands
|
||||||
|
|
||||||
|
A command is a function with a type like
|
||||||
|
|
||||||
|
```zig
|
||||||
|
pub fn copy(self: *Self, _: Context) Result
|
||||||
|
```
|
||||||
|
|
||||||
|
and a `Meta` definition with the same name and suffix `_meta`.
|
||||||
|
|
||||||
|
```zig
|
||||||
|
pub const copy_meta: Meta = .{ .description = "Copy selection to clipboard" };
|
||||||
|
```
|
||||||
|
|
||||||
|
`copy` command is defined in `editor.zig`, which copies the current
|
||||||
|
selections into the pimp internal clipboard. Commands are available
|
||||||
|
to all the modes if defined as pub.
|
||||||
|
|
||||||
|
`meta` holds the description appearing in the command palette and optionally
|
||||||
|
has arguments, the most common, an integer, that usually constitutes a
|
||||||
|
repetition parameter, targeting vim, emacs and helix modes. As you dig in,
|
||||||
|
there might be particularities on the parameters accepted for a given
|
||||||
|
command.
|
||||||
|
|
||||||
|
## Invoking another command
|
||||||
|
|
||||||
|
Commands can be bound to mnemonics in modes by convention. For example, in
|
||||||
|
Vim Mode `vim.zig`, `q` corresponds to (quit), the most famous one.
|
||||||
|
|
||||||
|
```zig
|
||||||
|
pub fn q(_: *void, _: Ctx) Result {
|
||||||
|
try cmd("quit", .{});
|
||||||
|
}
|
||||||
|
pub const q_meta: Meta = .{ .description = "q (quit)" };
|
||||||
|
```
|
||||||
|
|
||||||
|
Looking more closely, the first parameter in this case is of `*void` type,
|
||||||
|
given that this command is defined in `vim.zig` which is calling the `quit`
|
||||||
|
command defined in `editor.zig`. `cmd` takes care of routing and finding
|
||||||
|
the command wherever it is defined.
|
||||||
|
|
||||||
|
## Chaining commands
|
||||||
|
|
||||||
|
Chaining commands is also common, and, by the way, swift. This is a sample
|
||||||
|
of applying first `save_file` command and then, the command `quit`.
|
||||||
|
|
||||||
|
```zig
|
||||||
|
pub fn wq(_: *void, _: Ctx) Result {
|
||||||
|
try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } }));
|
||||||
|
}
|
||||||
|
pub const wq_meta: Meta = .{ .description = "wq (write file and quit)" };
|
||||||
|
```
|
||||||
|
|
||||||
|
Sometimes [keybinding](/docs/architecture/keybind) is enough to accomplish
|
||||||
|
a compound of already present commands, in others, zig programming is the
|
||||||
|
path to be taken.
|
||||||
|
|
||||||
|
# More in depth commands
|
||||||
|
|
||||||
|
Is common to define private functions in a given module that are invoked from
|
||||||
|
commands, as usual, functions are meant to be reused and help organize code.
|
||||||
|
|
||||||
|
For example, in hx mode `helix.zig` the `select_to_char_left_helix` command
|
||||||
|
uses the functions `helix_with_selections_const_arg` which iterates over all
|
||||||
|
cursels and applies the `select_cursel_to_char_left_helix` function.
|
||||||
|
|
||||||
|
```zig
|
||||||
|
pub fn select_to_char_left_helix(_: *void, ctx: Ctx) Result {
|
||||||
|
try helix_with_selections_const_arg(ctx, &select_cursel_to_char_left_helix);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sending parameters to commands
|
||||||
|
|
||||||
|
`cmd` is in charge of finding a command given its name, and parameters sent
|
||||||
|
to commands are vary for each command, for example, when interacting with
|
||||||
|
the clipboard, the messages sent are multiple chunks of information, for
|
||||||
|
now an example of such usage can be seen in a function that fetches contents
|
||||||
|
from the clipboard.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
There are more advanced topics related to commands that are covered in the
|
||||||
|
[editor](/docs/architecture/editor), that deeps in specific details of
|
||||||
|
the editor and its interaction with cursors, selections and buffers
|
||||||
|
modifications, among others.
|
||||||
|
|
||||||
|
Learning about interactions with the buffer and editor is present in
|
||||||
|
[minimodes](/docs/architecture/minimode).
|
||||||
76
content/docs/architecture/editor.smd
Normal file
76
content/docs/architecture/editor.smd
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
---
|
||||||
|
.title = "Editor",
|
||||||
|
.date = @date("2025-10-19T00:00:00"),
|
||||||
|
.author = "Igor Támara",
|
||||||
|
.layout = "tutorial.shtml",
|
||||||
|
.draft = false,
|
||||||
|
.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/editor.md"},
|
||||||
|
---
|
||||||
|
|
||||||
|
The `editor` coordinates visualization and modification of
|
||||||
|
buffer contents, multiple cursors, selections and marks.
|
||||||
|
|
||||||
|
To get the most of this section, it's recommended to have
|
||||||
|
read the [architecture briefing](/docs/architecture), about
|
||||||
|
[commands](/docs/architecture/command) and
|
||||||
|
[keybinds](/docs/architecture/keybind).
|
||||||
|
|
||||||
|
## Some concepts
|
||||||
|
|
||||||
|
The `primary Cursor` is presented always in the `Editor`,
|
||||||
|
signaling the part of the `Buffer` that can be modified and
|
||||||
|
manipulated as you see it. It scrolls on the current visible
|
||||||
|
portion of the buffer.
|
||||||
|
|
||||||
|
Other cursors can be in the `View` or in regions outside the
|
||||||
|
current view, depending on the size of both the buffer and
|
||||||
|
the editor view.
|
||||||
|
|
||||||
|
A `Selection` has two cursors that are not visible, they mark
|
||||||
|
the begin and the end of the selection, and CurSels are actually
|
||||||
|
what allow to have the concept of a cursor with a selection. A
|
||||||
|
`Cursel` has a cursor and optionally a Selection.
|
||||||
|
|
||||||
|
Most of editor operations act on the set of CurSels, the Primary
|
||||||
|
Cursor is in fact a CurSel, as opposed to what we previously
|
||||||
|
mentioned.
|
||||||
|
|
||||||
|
To complete the editor scenario, `Marks` have the potential
|
||||||
|
to become selections, and behind the scenes CurSels and are
|
||||||
|
evident to the eye when in search mode, they are seen as
|
||||||
|
the primary cursor is positioned over an occurrence with a
|
||||||
|
different color according to the theme.
|
||||||
|
|
||||||
|
The Editor will be acting on Buffer.Root which is the root of
|
||||||
|
the tree representing the document that is being edited. The API
|
||||||
|
of the Buffer.Root is stable and offers the necessary to insert,
|
||||||
|
delete and move along the buffer, knowing if the end, the
|
||||||
|
beginning has been reached when interacting with a Cursor.
|
||||||
|
|
||||||
|
## Editor Commands
|
||||||
|
|
||||||
|
We mentioned earlier that most of the operations work on all
|
||||||
|
the cursors and selections, there are various commands that
|
||||||
|
will use functions that iterate over cursors, selections, cursels
|
||||||
|
or marks. Given said this, we will be using functions as
|
||||||
|
parameters in most of the situations. Functional programming
|
||||||
|
languages are popular in these scenarios, to name a prominent
|
||||||
|
one, Emacs and emacs lisp.
|
||||||
|
|
||||||
|
If the buffer is not to be modified, we will be using `` to
|
||||||
|
get the root of it to find and position the cursors. While
|
||||||
|
we will use `` when the buffer is to be modified.
|
||||||
|
|
||||||
|
## Moving
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Selections
|
||||||
|
|
||||||
|
## Modifying the buffer
|
||||||
|
|
||||||
|
|
||||||
|
[Discord](https://discord.com/invite/4wvteUPphx) and
|
||||||
|
[Github issues](https://github.com/neurocyte/flow/issues) are the
|
||||||
|
main channels to do so.
|
||||||
|
|
||||||
145
content/docs/architecture/keybind.smd
Normal file
145
content/docs/architecture/keybind.smd
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
---
|
||||||
|
.title = "Keybinding",
|
||||||
|
.date = @date("2025-10-19T00:00:00"),
|
||||||
|
.author = "Igor Támara",
|
||||||
|
.layout = "tutorial.shtml",
|
||||||
|
.draft = false,
|
||||||
|
.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/keybind.md"},
|
||||||
|
---
|
||||||
|
|
||||||
|
If you are here, it's possible that you already have edited your
|
||||||
|
own keybinds to suit your needs and are looking for some advanced
|
||||||
|
topics to extend your use cases and make everything easier and
|
||||||
|
fluid when in Flow. If you have not, take a peek to learning how
|
||||||
|
to do it.
|
||||||
|
|
||||||
|
Using the command palette `Ctrl+Shift+p` and typing **Edit key bindings**,
|
||||||
|
takes you to the json file to extend Flow configuring
|
||||||
|
keybindings to suit your needs.
|
||||||
|
|
||||||
|
[]($section.id('tldr'))
|
||||||
|
## ;TLDR;
|
||||||
|
|
||||||
|
Once you open the corresponding json file, locate inside the imode
|
||||||
|
(internal mode) that will accept the key or keys/combo and add an
|
||||||
|
array, where the first element is the combination to map to the
|
||||||
|
commands that will happen, the array accepts strings like in
|
||||||
|
|
||||||
|
```js
|
||||||
|
["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.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
[introducing keybindings](/devlog/2024#2024-12-05T20:55:00) showcases
|
||||||
|
how to get to edit keybindings.
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
```
|
||||||
|
Mode > Imode > press > Key and commands
|
||||||
|
map > map > array > array(array(string,numbers),strings,numbers)
|
||||||
|
```
|
||||||
|
|
||||||
|
`Mode` is the json file that holds a map, where each
|
||||||
|
entry has a map called `press` that is an array of
|
||||||
|
arrays.
|
||||||
|
|
||||||
|
`project` is the main imode in `flow.json` and it can be
|
||||||
|
noticed that `normal` imode `inherit`s from `project`,
|
||||||
|
some modes have `release`, usually one will be using
|
||||||
|
only `press` inside `normal` imode or the specific mode
|
||||||
|
if inside `vim`, `helix` or `emacs` modes.
|
||||||
|
|
||||||
|
Looking further, it can be seen that
|
||||||
|
[minimodes](/docs/architecture/minimode) have their
|
||||||
|
keybinding mappings defined in a particular imode.
|
||||||
|
|
||||||
|
As stated previously, there is a mode hierarchy, the main mode
|
||||||
|
is flow and other modes inherit from it. We remind that also
|
||||||
|
imodes have a hierarchy and it's common for major imodes to be
|
||||||
|
descendants from `project`.
|
||||||
|
|
||||||
|
## 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`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
["f5", ["create_scratch_buffer", "*test*"], ["shell_execute_insert", "zig", "build", "test"]],
|
||||||
|
```
|
||||||
|
|
||||||
|
Note that:
|
||||||
|
|
||||||
|
The keybind is `f5`, which maps to the `f5` keycode. is invoking
|
||||||
|
`create_scratchbuffer`, 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 paramaters `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.
|
||||||
|
|
||||||
|
```
|
||||||
|
[
|
||||||
|
"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.
|
||||||
|
|
||||||
|
Probably binding commands is good, but maybe there is a feature in
|
||||||
|
other texts editors that you miss and would love to have it at
|
||||||
|
your fingertips. Then it's Zig time:
|
||||||
|
[Adding commands](/docs/architecture/command) to flow.
|
||||||
|
|
||||||
24
content/docs/architecture/palette.smd
Normal file
24
content/docs/architecture/palette.smd
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
---
|
||||||
|
.title = "Palettes",
|
||||||
|
.date = @date("2025-10-20T00:00:00"),
|
||||||
|
.author = "Igor Támara",
|
||||||
|
.layout = "tutorial.shtml",
|
||||||
|
.draft = false,
|
||||||
|
.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/palette.md"},
|
||||||
|
---
|
||||||
|
|
||||||
|
Palettes are overlay menus that allow to select an item from the
|
||||||
|
presented list, applying a command with the selected element,
|
||||||
|
optionally deleting the selected item; it's possible to close
|
||||||
|
the palette without selecting(cancel), filter the elements, and
|
||||||
|
having special elements that trigger different actions.
|
||||||
|
|
||||||
|
To get the most of this section, it's recommended to have
|
||||||
|
read about [commands](/docs/architecture/command), and optionally
|
||||||
|
[minimodes](/docs/architecture/minimode).
|
||||||
|
|
||||||
|
See
|
||||||
|
[clipboard history palette](https://github.com/neurocyte/flow/commit/634a18cb5685a3c3fcfc08301306e628d33c3256)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue