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
extract from the context like this:
>[]($block.attrs('line-numbers-js'))
>```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;
>```
```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

View file

@ -6,154 +6,209 @@
.draft = true,
.custom = {
.githubedit = "docs/architecture/editor.smd",
.codepath ="src/tui/editor.zig",
.codepath = "src/tui/editor.zig",
},
---
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
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).
[]($section.id("concepts"))
## 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.
The [editor](#editor_concept) coordinates visualization and
modification of buffer contents, multiple cursors, selections and
marks.
Other cursors can be in the `View` or in regions outside the
current view, depending on the size of both the buffer and
We will delve in editor concepts, buffer inner manipulation with ropes
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.
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` is composed by a cursor and optionally a Selection.
Most of editors operations act on the set of CurSels and the Primary
Cursor is a [CurSel](#cursel_concept).
Most of editors operations act on the set of CurSels and the
Primary Cursor is a particular case of the general case. And
as a note, the Primary Cursor is in fact a CurSel.
[]($section.id("selection_concept"))
### 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.
A selection is represented by begin and end [cursors](#cursor_concept)
and offers basic functions that will consitute the changes needed with
deletions, insert replacements handled by the[editor](#tui_editor)
services and [commands](/docs/architecture/command).
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 or the
beginning of the document have been reached when interacting
with a Cursor.
A `Selection` has two cursors that are not visible, they mark the begin
and the end of the selection.
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("cursel_concept"))
### CurSel
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"))
## Editor Commands
We mentioned earlier that most of the operations work on all
the cursors and selections, moreover, there are various
commands acting over the set of 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.
We mentioned earlier that most of the operations work on all the
cursors and selections, moreover, there are various commands acting
over the set of 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 the
method `buf_root` to get the root of the buffer to find and
position the cursors. In the other hand, we will use
`buf_for_update()` when the buffer is to be modified.
If the buffer is not to be modified, we will be using the method
`buf_root` to get the root of the buffer to find and position the
cursors. In the other hand, we will use `buf_for_update` when the
buffer is to be modified.
The benefit of sending functions as parameters is that code
is reused and the codebase can grow without much sacrifice
when adding new functionalities, because one would be
thinking only in the current cursor and if required, the
operation will be applied to all the cursors, the same applies
to selections, cursels and marks.
The benefit of sending functions as parameters is that code is reused
and the codebase can grow without much sacrifice when adding new
functionalities, because one would be thinking only in the current
cursor and if required, the operation will be applied to all the
cursors, the same applies to selections, cursels and marks.
[]($section.id("moving"))
## Moving
For example, to move the cursors a page up, we can look at
the command `move_page_up`, which uses the method
`with_cursors_and_view_const` sending the function
`move_cursor_page_up`.
For example, to move the cursors a page up, we can look at the command
`move_page_up`, which uses the method `with_cursors_and_view_const`
sending the function `move_cursor_page_up`.
Looking inside `with_cursors_and_view_const`, it iterates
over all the cursors and invokes `with_cursor_and_view_const`,
sending a cursor as a parameter, that function, will invoke
`move_cursor_page_up` whose commitment is to use the method
`move_page_up` from the cursor, sending the view and the
metrics of the editor.
Looking inside `with_cursors_and_view_const`, it iterates over all the
cursors and invokes `with_cursor_and_view_const`, sending a cursor as
a parameter, that function, will invoke `move_cursor_page_up` whose
commitment is to use the method `move_page_up` from the cursor,
sending the view and the metrics of the editor.
The family of `move` functions is big, look for the methods
whose name has the word move in them. with the command palette
is possible to get a glimpse of them.
The family of `move` functions is big, look for the methods whose name
has the word move in them. with the command palette is possible to get
a glimpse of them.
[]($section.id("selecting"))
## Selections
There are naming conventions for the functions that help
understanding what each one is doing, there has been taken
great deal of care to maintain consistency that needs to be
followed to make it easier to continue extending on
functionalities.
There are naming conventions for the functions that help understanding
what each one is doing, there has been taken great deal of care to
maintain consistency that needs to be followed to make it easier to
continue extending on functionalities.
Look at the following set of functions, all of them act on
cursors, cursels and selections, in singular and plural, and
some of them receive arguments, the repeat functions act
many times over the set of the group that they are intended
to do so. The parameters and following the calls from one
to another will let you navigate and get the hang of their
usage.
Look at the following set of functions, all of them act on cursors,
cursels and selections, in singular and plural, and some of them
receive arguments, the repeat functions act many times over the set of
the group that they are intended to do so. The parameters and
following the calls from one to another will let you navigate and get
the hang of their 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"))
## Modifying the buffer
The `select` family of functions is bigger than the set of `move`
functions, in contrast, the `cut`, `delete`, `insert`, `paste`
looks smaller, and this is accomplished making composition of
functions. Usually when modifying something, first there is
a process to locate the cursor, cursel o selection in the proper
place and then applying the modification.
functions, in contrast, the `cut`, `delete`, `insert`, `paste` looks
smaller, and this is accomplished making composition of functions.
Usually when modifying something, first there is a process to locate
the cursor, cursel o selection in the proper place and then applying
the modification.
[Discord](https://discord.com/invite/4wvteUPphx) and
[Github issues](https://github.com/neurocyte/flow/issues) are the
main channels to do so.
[Github issues](https://github.com/neurocyte/flow/issues) are the main
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"))
## Next steps
* [minimodes](/docs/architecture/minimode) invoke commands defined in the editor
* [palettes](/docs/architecture/palette) are open by commands and when selected an item, a command
is invoked.
* Plenty of [commands](/docs/architecture/command) are defined in the editor.
* [minimodes](/docs/architecture/minimode) invoke
[commands](/docs/architecture/minimode) defined in the editor
* [palettes](/docs/architecture/palette) are open by commands and when
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