181 lines
No EOL
6 KiB
Text
181 lines
No EOL
6 KiB
Text
---
|
|
.title = "Commands",
|
|
.date = @date("2025-10-15T00:00:00"),
|
|
.author = "Igor Támara",
|
|
.layout = "tutorial.shtml",
|
|
.draft = false,
|
|
.custom = {
|
|
.githubedit = "/docs/architecture/command.smd",
|
|
.codepath = "src/tui/editor.zig",
|
|
},
|
|
---
|
|
|
|
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.
|
|
|
|
[]($section.id('notes'))
|
|
## 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.
|
|
|
|
[]($section.id('creating'))
|
|
## 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.
|
|
|
|
[]($section.id('calling'))
|
|
## 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 command.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.
|
|
|
|
[]($section.id('tldr'))
|
|
## 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)" };
|
|
```
|
|
|
|
`cmd` is in charge of finding a command given its name, and parameters
|
|
sent to commands vary for each command.
|
|
|
|
Sometimes [keybinding](/docs/architecture/keybind) is enough to
|
|
accomplish a compound of already present commands.
|
|
|
|
[]($section.id('command_arguments'))
|
|
### Sending parameters to commands
|
|
|
|
`goto_line` (in the case of vim and helix mode, you first type the
|
|
number and then the action, `gg`) is a command that exemplifies
|
|
receiving an integer parameter. As stated in its meta:
|
|
|
|
```zig
|
|
pub const goto_line_meta: Meta = .{ .arguments = &.{.integer} };
|
|
```
|
|
|
|
and to actually receiving the integer parameter, `goto_line` will
|
|
extract from the context like this:
|
|
|
|
```zig
|
|
pub fn goto_line(self: *Self, ctx: Context) Result {
|
|
var line: usize = 0;
|
|
if (!try ctx.args.match(.{tp.extract(&line)}))
|
|
return error.InvalidGotoLineArgument;
|
|
```
|
|
|
|
To send a parameter to a command, make sure that the type is exactly
|
|
the same when retrieving it. We will refer as encode and decode when
|
|
packing parameters in the context. To pack the `command.fmt` we will
|
|
encode it like this, when invoking `goto_line`.
|
|
|
|
```zig
|
|
var the_line: usize = 43;
|
|
try command.cmd("goto_line", command.fmt(.{the_line - 1}));
|
|
```
|
|
|
|
Or calling the command directly, if we have a reference to the object
|
|
that holds the command.
|
|
|
|
```zig
|
|
var the_line: usize = 43;
|
|
try ed.goto_line(command.fmt(.{the_line - 1}));
|
|
```
|
|
|
|
It's possible to pass multiple parameters to commands, including arrays
|
|
and json, packing all of them in Command.Context.
|
|
|
|
A deeper explanation of the rules about parameter passing is exposed in
|
|
[inner data exchange](/docs/architecture/inner_data_exchange), given
|
|
that parameters can be sent not only to commands, but other broader
|
|
use cases.
|
|
|
|
[]($section.id('deepen'))
|
|
## Code organization
|
|
|
|
Is common to define private functions in a given module meant to be
|
|
invoked from commands. As usual, reusing code with functions
|
|
help organize code.
|
|
|
|
For example, in hx mode `src/tui/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);
|
|
}
|
|
```
|
|
|
|
[]($section.id('next'))
|
|
## Next steps
|
|
|
|
[Minimodes](/docs/architecture/minimode) pass arguments to the editor,
|
|
if you wonder how to go beyond the current buffer window, when there
|
|
are actions like going to a specific line or when searching or
|
|
replacing a character,this is the place.
|
|
|
|
[Palettes](/docs/architecture/palette) are built to open files, change
|
|
buffers and also pass parameters to commands. Diving out from the
|
|
buffer and editor.
|
|
|
|
* [Add tests](/docs/testing) to harden your code
|
|
* [Sending parameters across](/docs/architecture/inner_data_exchange)
|
|
* [Back to architecture](/docs/architecture) |