Add definitions to editor docs

This commit is contained in:
Igor Támara 2025-11-06 15:12:48 -05:00 committed by CJ van den Berg
parent 0cf7a4ead5
commit 1bb3b70864
2 changed files with 167 additions and 113 deletions

View file

@ -113,13 +113,12 @@ pub const goto_line_meta: Meta = .{ .arguments = &.{.integer} };
and to actually receiving the integer parameter, `goto_line` will and to actually receiving the integer parameter, `goto_line` will
extract from the context like this: extract from the context like this:
>[]($block.attrs('line-numbers-js')) ```zig
>```zig pub fn goto_line(self: *Self, ctx: Context) Result {
>pub fn goto_line(self: *Self, ctx: Context) Result { var line: usize = 0;
> var line: usize = 0; if (!try ctx.args.match(.{tp.extract(&line)}))
> if (!try ctx.args.match(.{tp.extract(&line)})) return error.InvalidGotoLineArgument;
> return error.InvalidGotoLineArgument; ```
>```
To send a parameter to a command, make sure that the type is exactly 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 the same when retrieving it. We will refer as encode and decode when

View file

@ -6,154 +6,209 @@
.draft = true, .draft = true,
.custom = { .custom = {
.githubedit = "docs/architecture/editor.smd", .githubedit = "docs/architecture/editor.smd",
.codepath ="src/tui/editor.zig", .codepath = "src/tui/editor.zig",
}, },
--- ---
The `editor` coordinates visualization and modification of To get the most of this section, it's recommended to have read the
buffer contents, multiple cursors, selections and marks. [architecture briefing](/docs/architecture), about
To get the most of this section, it's recommended to have
read the [architecture briefing](/docs/architecture), about
[commands](/docs/architecture/command) and [commands](/docs/architecture/command) and
[keybinds](/docs/architecture/keybind). [keybinds](/docs/architecture/keybind).
[]($section.id("concepts")) []($section.id("concepts"))
## Some concepts ## Some concepts
The `primary Cursor` is presented always in the `Editor`, The [editor](#editor_concept) coordinates visualization and
signaling the part of the `Buffer` that can be modified and modification of buffer contents, multiple cursors, selections and
manipulated as you see it. It scrolls on the current visible marks.
portion of the buffer.
Other cursors can be in the `View` or in regions outside the We will delve in editor concepts, buffer inner manipulation with ropes
current view, depending on the size of both the buffer and is not covered here.
[]($section.id("tui_editor"))
### Editor and TUI
During this section we will refer to the concept of the editor as the
one capable of modifying buffer contents, the visible gutters and
line numbers as other terminal user interface (TUI) is covered in
another chapter.
[]($section.id("view_concept"))
### View
`View` holds the information about the area of the buffer that is
currently visible in the screen by the user. Is related to the
[primary cursor](#cursor_concept).
[]($section.id("cursor_concept"))
### Cursor
The `primary Cursor` holds a position in the Buffer, the `Editor`
makes the link between both of them, signaling the part of the `Buffer`
that can be modified and manipulated as you see it. It scrolls on the
current visible portion [view](#view_concept) of the buffer, when
manipulated with the keyboard, the mouse can change the move the view
while the primary mouse is offscreen; when keystrokes arrive to the
editor, the view focuses to the primary cursor to make it visible and
available to be used.
Flow has multiple cursors each one holding the relative position to the
buffer with `row`, `col` and `target`, the last one used to make the
cursor jump to a possibly next movement,for example, when moving
between lines, this is a way to "remember" where to jump back. When
creating multiple cursors they signal many buffer places and a subset
is seen inside the [view](#view_concept).
Cursors visibility depends on the size of both the buffer contents and
the editor in your device. the editor in your device.
A `Selection` has two cursors that are not visible, they mark Most of editors operations act on the set of CurSels and the Primary
the begin and the end of the selection, and CurSels are actually Cursor is a [CurSel](#cursel_concept).
what allow to have the concept of a cursor with a selection. A
`Cursel` is composed by a cursor and optionally a Selection.
Most of editors operations act on the set of CurSels and the []($section.id("selection_concept"))
Primary Cursor is a particular case of the general case. And ### Selection
as a note, the Primary Cursor is in fact a CurSel.
To complete the editor scenario, `Marks` have the potential A selection is represented by begin and end [cursors](#cursor_concept)
to become selections; the marks become evident to the eye and offers basic functions that will consitute the changes needed with
when in search mode, they are seen as the primary cursor deletions, insert replacements handled by the[editor](#tui_editor)
is positioned over an occurrence with a different color services and [commands](/docs/architecture/command).
according to the theme.
The Editor will be acting on Buffer.Root which is the root of A `Selection` has two cursors that are not visible, they mark the begin
the tree representing the document that is being edited. The API and the end of the selection.
of the Buffer.Root is stable and offers the necessary to insert,
delete and move along the buffer, knowing if the end or the
beginning of the document have been reached when interacting
with a Cursor.
Cursors, Selections and Cursels don't know about the buffer, and
they need to receive a reference to them to have positions and []($section.id("cursel_concept"))
also sometimes receive metrics from the editor that help determine ### CurSel
if a cursor is about to exit boundaries of the buffer and have
everything "in place". The CurSel is what is presented to user, holding a
[cursor](#cursor_concept) and optionally a
[selection](#selection_concept).
[]($section.id("mark_concept"))
### Mark
what allow to have the concept of a cursor with a selection. A `Cursel`
is composed by a cursor and optionally a Selection.
To complete the editor scenario, `Marks` have the potential to become
selections; the marks become 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.
[]($section.id("editor_concept"))
### Editor
The Editor will be acting on Buffer.Root which is the root of the tree
representing the document that is being edited. API Buffer.Root is
stable and offers the necessary to insert, delete and move along the
buffer, knowing if the end or the beginning of the document have been
reached when interacting with a Cursor.
Cursors, Selections and Cursels don't know about the buffer, and they
need to receive a reference to them to have positions and also
sometimes receive metrics from the editor that help determine if a
cursor is about to exit boundaries of the buffer and have everything
"in place".
[]($section.id("commands")) []($section.id("commands"))
## Editor Commands ## Editor Commands
We mentioned earlier that most of the operations work on all We mentioned earlier that most of the operations work on all the
the cursors and selections, moreover, there are various cursors and selections, moreover, there are various commands acting
commands acting over the set of cursors, selections, cursels over the set of cursors, selections, cursels or marks. Given said
or marks. Given said this, we will be using functions as this, we will be using functions as parameters in most of the
parameters in most of the situations. Functional programming situations. Functional programming languages are popular in these
languages are popular in these scenarios, to name a prominent scenarios, to name a prominent one, Emacs and emacs lisp.
one, Emacs and emacs lisp.
If the buffer is not to be modified, we will be using the If the buffer is not to be modified, we will be using the method
method `buf_root` to get the root of the buffer to find and `buf_root` to get the root of the buffer to find and position the
position the cursors. In the other hand, we will use cursors. In the other hand, we will use `buf_for_update` when the
`buf_for_update()` when the buffer is to be modified. buffer is to be modified.
The benefit of sending functions as parameters is that code The benefit of sending functions as parameters is that code is reused
is reused and the codebase can grow without much sacrifice and the codebase can grow without much sacrifice when adding new
when adding new functionalities, because one would be functionalities, because one would be thinking only in the current
thinking only in the current cursor and if required, the cursor and if required, the operation will be applied to all the
operation will be applied to all the cursors, the same applies cursors, the same applies to selections, cursels and marks.
to selections, cursels and marks.
[]($section.id("moving")) []($section.id("moving"))
## Moving ## Moving
For example, to move the cursors a page up, we can look at For example, to move the cursors a page up, we can look at the command
the command `move_page_up`, which uses the method `move_page_up`, which uses the method `with_cursors_and_view_const`
`with_cursors_and_view_const` sending the function sending the function `move_cursor_page_up`.
`move_cursor_page_up`.
Looking inside `with_cursors_and_view_const`, it iterates Looking inside `with_cursors_and_view_const`, it iterates over all the
over all the cursors and invokes `with_cursor_and_view_const`, cursors and invokes `with_cursor_and_view_const`, sending a cursor as
sending a cursor as a parameter, that function, will invoke a parameter, that function, will invoke `move_cursor_page_up` whose
`move_cursor_page_up` whose commitment is to use the method commitment is to use the method `move_page_up` from the cursor,
`move_page_up` from the cursor, sending the view and the sending the view and the metrics of the editor.
metrics of the editor.
The family of `move` functions is big, look for the methods The family of `move` functions is big, look for the methods whose name
whose name has the word move in them. with the command palette has the word move in them. with the command palette is possible to get
is possible to get a glimpse of them. a glimpse of them.
[]($section.id("selecting")) []($section.id("selecting"))
## Selections ## Selections
There are naming conventions for the functions that help There are naming conventions for the functions that help understanding
understanding what each one is doing, there has been taken what each one is doing, there has been taken great deal of care to
great deal of care to maintain consistency that needs to be maintain consistency that needs to be followed to make it easier to
followed to make it easier to continue extending on continue extending on functionalities.
functionalities.
Look at the following set of functions, all of them act on Look at the following set of functions, all of them act on cursors,
cursors, cursels and selections, in singular and plural, and cursels and selections, in singular and plural, and some of them
some of them receive arguments, the repeat functions act receive arguments, the repeat functions act many times over the set of
many times over the set of the group that they are intended the group that they are intended to do so. The parameters and
to do so. The parameters and following the calls from one following the calls from one to another will let you navigate and get
to another will let you navigate and get the hang of their the hang of their usage.
usage.
```zig
fn with_cursor_const
fn with_cursel_const
fn with_cursels_const
fn with_selection_const
fn with_cursor_const_arg
fn with_cursors_const_arg
fn with_cursors_const_once
fn with_selection_const_arg
fn with_cursors_const_repeat
fn with_selections_const_arg
fn with_cursor_and_view_const
fn with_selections_const_once
fn with_cursors_and_view_const
fn with_selections_const_repeat
fn with_selection_and_view_const
fn with_selections_and_view_const
```
[]($section.id("modifying")) []($section.id("modifying"))
## Modifying the buffer ## Modifying the buffer
The `select` family of functions is bigger than the set of `move` The `select` family of functions is bigger than the set of `move`
functions, in contrast, the `cut`, `delete`, `insert`, `paste` functions, in contrast, the `cut`, `delete`, `insert`, `paste` looks
looks smaller, and this is accomplished making composition of smaller, and this is accomplished making composition of functions.
functions. Usually when modifying something, first there is Usually when modifying something, first there is a process to locate
a process to locate the cursor, cursel o selection in the proper the cursor, cursel o selection in the proper place and then applying
place and then applying the modification. the modification.
[Discord](https://discord.com/invite/4wvteUPphx) and [Discord](https://discord.com/invite/4wvteUPphx) and
[Github issues](https://github.com/neurocyte/flow/issues) are the [Github issues](https://github.com/neurocyte/flow/issues) are the main
main channels to do so. channels to do so.
## Helper function
When creating commands and services for the editor, sometimes is handy
where are the cursels. It's possible to use `log_cursel`:
>[]($block.attrs('line-numbers-js'))
>```zig
>pub fn log_cursel(self: *Self, cursel: CurSel) void {
> if (cursel.selection) |sel| {
> self.logger.print("[{}:{}.{}] {}:{}.{} - {}:{}.{}", .{
> cursel.cursor.row, cursel.cursor.col, cursel.cursor.target,
> sel.begin.row, sel.begin.col, sel.begin.target,
> sel.end.row, sel.end.col, sel.end.target,
> });
> } else {
> self.logger.print("[{}:{}.{}] no selection", .{
> cursel.cursor.row,
> cursel.cursor.col,
> cursel.cursor.target
> });
> }
>}
>```
[]($section.id("next")) []($section.id("next"))
## Next steps ## Next steps
* [minimodes](/docs/architecture/minimode) invoke commands defined in the editor * [minimodes](/docs/architecture/minimode) invoke
* [palettes](/docs/architecture/palette) are open by commands and when selected an item, a command [commands](/docs/architecture/minimode) defined in the editor
is invoked. * [palettes](/docs/architecture/palette) are open by commands and when
* Plenty of [commands](/docs/architecture/command) are defined in the editor. selected an item, a command is invoked
* Plenty of [commands](/docs/architecture/command) are defined in the
editor
* [Passing parameters](/docs/architecture/inner_data_exchange) between
commands and functions