Add definitions to editor docs
This commit is contained in:
parent
0cf7a4ead5
commit
1bb3b70864
2 changed files with 167 additions and 113 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
Loading…
Add table
Add a link
Reference in a new issue