Marked editor as draft

All the docs contained in this group of commits are marked as not draft,
except for editor, which I will be working as I get more experience and
get more precise on the various topics related to the editor and groups
of functions.
This commit is contained in:
Igor Támara 2025-10-30 23:35:53 -05:00 committed by CJ van den Berg
parent e837a66b97
commit 0494574c36
9 changed files with 234 additions and 188 deletions

View file

@ -44,7 +44,7 @@ offers services around the set of projects.
[]($section.id("commands"))
## Editor commands and modes
When a buffer is active, it has an [Editor](/docs/architecture/editor)
When a buffer is active, it has an Editor
attached to it; an editor might have associated tree-sitter support,
given the file type detected, and offers common services that are aimed
to be used by `Commands` to manipulate the contents of a buffer at a

View file

@ -11,23 +11,26 @@
---
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.
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.
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.
[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
@ -49,20 +52,20 @@ 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.
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.
`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.
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 {
@ -71,16 +74,17 @@ pub fn q(_: *void, _: Ctx) Result {
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.
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`.
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 {
@ -89,20 +93,23 @@ pub fn wq(_: *void, _: Ctx) Result {
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.
`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('deepen'))
## More in depth commands
## Code organization
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.
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.
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 {
@ -113,18 +120,16 @@ pub fn select_to_char_left_helix(_: *void, ctx: Ctx) Result {
[]($section.id('command_arguments'))
### Sending parameters to commands
`cmd` is in charge of finding a command given its name, and parameters sent
to commands vary for each command.
The command `goto_line`, which receives as parameter an integer(in the case
of vim and helix mode, you first type the number and then the action, gg)
as stated in its meta:
`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:
and to actually receiving the integer parameter, `goto_line` will
extract it like this:
```zig
pub fn goto_line(self: *Self, ctx: Context) Result {
@ -134,16 +139,28 @@ pub fn goto_line(self: *Self, ctx: Context) Result {
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. Hence
for our terminology to send an integer parameter to a command, we
will encode it using `command.fmt` like in
```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, they all will be packed in Command.Context.
A deeper explanation of the rules about parameter passing is exposed in
[inner data exchange](/docs/architecture/inner_data_exchange).
[]($section.id('next'))
## Next steps
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).
* [Add tests](/docs/testing) to harden your code
* [minimode](/docs/architecture/minimode) shows argument passing to
commands in reaction to keypresses.
* [Palettes](/docs/architecture/palette) invoke commands and pass
parameters to them.
* [Add tests](/docs/testing) to harden your code
* [Back to architecture](/docs/architecture)

View file

@ -3,7 +3,7 @@
.date = @date("2025-10-19T00:00:00"),
.author = "Igor Támara",
.layout = "tutorial.shtml",
.draft = false,
.draft = true,
.custom = {
.githubedit = "docs/architecture/editor.smd",
.codepath ="src/tui/editor.zig",

View file

@ -13,13 +13,14 @@
Flow uses actor model to offer an snappy experience when working with
projects that have tens of thousands of source files, also features
async communication with the threads that are working in independent
tasks that contribute to have vcs, lsp and tree-sitter integration,
apart from the directory introspection to make available what is
expected from an IDE. The command arguments travel to the target
command and are en/decoded powered by
[cbor](https://github.com/neurocyte/cbor), the same as the parameters
that are sent from one thread to another. The process management is
provided by [thespian](https://github.com/neurocyte/thespian).
tasks supporting git interface, lsp and tree-sitter integration,
apart from the directory introspection to make available all the
files of the project, all of them expected s from an IDE. The
command arguments travel to the target command and are en/decoded
powered by [cbor](https://github.com/neurocyte/cbor), the same as the
parameters that are sent from one thread to another. The process
management is provided by
[thespian](https://github.com/neurocyte/thespian).
This chapter describes the mechanisms that flow has to pass arguments
between components.
@ -41,20 +42,20 @@ variables
message is encoded and must be copied somewhere for more permanent
storage, or possibly sent somewhere via thespian.
* Decoding happens via the `cbor.match`, `cbor.extract` and
`cbor.extractAlloc` group of functions. `cbor.extract` functions do not
allocate and cannot be used to extract some types that require allocation.
`cbor.extractAlloc` group of functions. `cbor.extract` functions do
not allocate and cannot be used to extract some types that require allocation.
`cbor.extractAlloc` functions _do_ allocate and can extract arrays and
structures that require allocation. Both `cbor.extract` and
`cbor.extractAlloc` produce strings that **reference** the original CBOR
data buffer. `thespian.message.match` and `thespian.extract` functions
are fairly simple wrappers.
The most basic example on deserialization of an integer value can is shown
The most basic example on deserialization of an integer value is shown
in [commands](/docs/architecture/command#command_arguments).
Cbor features en/decoding arrays, json and compounds of basic types and the
only requirement is to decode in the same order as encoding the data, more
samples on using cbor can be seen in
Cbor features en/decoding arrays, json and compounds of basic types and
the only requirement is to decode in the same order as encoding the
data, more samples on using cbor can be seen in
[cbor tests](https://github.com/neurocyte/cbor/blob/master/test/tests.zig).
For example, when interacting with the clipboard, the messages sent are
@ -64,9 +65,9 @@ multiple chunks of information,
[]($section.id('scoping'))
## Buffer scoping
CBOR structures are mostly stored in a way that avoids allocation entirely.
This is really fast, but requires that you always know where the CBOR data
you are working with is stored.
CBOR structures are mostly stored in a way that avoids allocation
entirely. This is really fast, but requires that you always know where
the CBOR data you are working with is stored.
* Received messages are read directly from the thespian process (actor)
receive buffer and remain in scope only for the duration of an actor's
@ -86,30 +87,27 @@ All of this implies several things worth keeping in mind:
* `thespian.pid.send` will encode it's parameters to
`thespian.message_buffer` and then send them to the destination actor's
receive buffer. This will invalidate the contents of
`thespian.message_buffer` and destroy any message previously encoded with
`thespian.message.fmt` (on the same thread).
* Calling `command.fmt` inside a command that uses `command.Context.args`
will possibly invalidate the command's own arguments. I say _possibly_
because the `ctx.arg` may come from somewhere else entirely, like the
actor's receive buffer if the command was called remotely, or some other
explicitly allocated buffer.
`thespian.message_buffer` and destroy any message previously encoded
with `thespian.message.fmt` (on the same thread).
* Calling `command.fmt` inside a command that uses
`command.Context.args` will possibly invalidate the command's own
arguments. I say _possibly_ because the `ctx.arg` may come from
somewhere else entirely, like the actor's receive buffer if the command
was called remotely, or some other explicitly allocated buffer.
* Use `*.fmtbuf` to encode to different buffer if there may be scoping
issues. You can allocate and scope this buffer any way you want.
* Calling `thespian.exit_message` while propagating an error up the stack
that was previously created with `thespian.exit_message` will overwrite the
original error
* Don't ever try to free a CBOR buffer unless you know exactly where it came
from.
* Strings extracted from CBOR buffers are **references** into the original
CBOR data and will be invalidated implicitly when the CBOR buffer they came
from is invalidated/overwritten.
* Calling `thespian.exit_message` while propagating an error up the
stack that was previously created with `thespian.exit_message` will
overwrite the original error
* Don't ever try to free a CBOR buffer unless you know exactly where it
came from.
* Strings extracted from CBOR buffers are **references** into the
original CBOR data and will be invalidated implicitly when the CBOR
buffer they came from is invalidated/overwritten.
[]($section.id('next'))
## Next steps
Serialization and deserialization occurs almost everywhere
* [Editor](/docs/architecture/editor)
* [Commands](/docs/architecture/command)
* [Minimodes](/docs/architecture/minimode)
* [Architecture](/docs/architecture)

View file

@ -13,11 +13,11 @@
If you are here, maybe is because you want to make flow behave according
to your key presses preferences or possibly you already have edited your
own keybinds to suit your needs and are looking for some advanced
topics to cope your use cases and make everything easier and
topics to cope your use cases and make everything easier, faster and
fluid when in Flow.
Using the command palette `Ctrl+Shift+p` and typing **Edit key
bindings**, takes you to the json file to extend Flow configuring
bindings**, takes you to a json file to extend Flow, configuring
keybindings to suit your needs. According to the mode you are in, the
corresponding file will be opened. The palette can also be reached left
clicking on the current mode in the status bar.
@ -26,9 +26,9 @@ clicking on the current mode in the status bar.
## ;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,
(internal mode) that will accept the key or key/combos 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
will be invoked, the array accepts strings like in
```js
["ctrl+alt+shift+p", "open_command_palette"]
@ -52,7 +52,7 @@ 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.
flow, and the default ones defined for emacs mode.
[introducing keybindings](/devlog/2024#2024-12-05T20:55:00) showcases
how to get to edit keybindings.
@ -73,20 +73,20 @@ In general a keybinding json shows this hierarchy:
```
Mode > Imode > press > Key and commands
map > map > array > array(array(string,numbers),strings,numbers)
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`,
`normal` imode `inherits` 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.
[minimodes](/docs/architecture/minimode) have their own 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
@ -111,20 +111,24 @@ needs.
For example, `f5` by default is used to run `zig build test` outputting
its results to a *scratch buffer* called `test`.
The original definition is:
```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.
The keybind is `f5`, which maps to the keycode generated by pressing
the `f5` key.
`create_scratchbuffer` is invoked 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.
```
[
@ -155,8 +159,8 @@ to submit your findings and solution.
Probably binding commands is good, but maybe there is a feature in other
text 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.
Then it's Zig time: [Adding commands](/docs/architecture/command) to
flow.
* Making flow even better with [tests](/docs/testing)

View file

@ -10,13 +10,12 @@
},
---
Minimodes can be used by other modes adding functionality
to the editor, they have their own set of keybindings and
are used momentarily for an specific action, i.e. find
something in the current buffer or in project files,
open/save a file, and, in modal modes(like vim and helix).
An example of the latter is using numeric prefixes to
repeat an action many times.
Minimodes commitment is to add functionality to the editor, are opened
for short periods of time and have their own set of keybindings to
execute an specific action, i.e. find something in the current buffer
or in project files, open/save a file, and, in modal modes(like vim
and helix), as receiving a number as a prefix to repeat an action many
times.
[]($section.id("anatomy"))
## Anatomy of minimodes
@ -30,51 +29,46 @@ To create a minimode it's needed:
[]($section.id("keybind"))
### Keybinding
When a key or a keystroke(set of keys) are pressed, the
associated minimode gets activated and will start to
capture the key/strokes until a special keybinding
makes it exit, or an specific action exits the minimode.
Head to `src/keybind/builtin/flow.json`(flow keybinds)
and look for `mini_find`, where you will know which
specific actions are triggered by the keybindings of the
minimode.
When a key or a keystroke(set of keys) are pressed, the associated
minimode gets activated and will start to capture the key/strokes
until a special keybinding makes it exit, or an specific action exits
the minimode. Head to `src/keybind/builtin/flow.json`(flow keybinds)
and look for `mini_find`, where you will know which specific actions
are triggered by the keybindings of the `find` minimode.
[]($section.id("mapping"))
### Action mapping
Actions executed by each minimode are stored one per
file under `src/tui/mode/mini/`. The command that
opens opens the door to the minimode is linked from
`src/tui/tui.zig` which calls the minimodes dynamically
Actions executed by each minimode are stored one per file under
`src/tui/mode/mini/`. The command that opens the door to the minimode
is linked from `src/tui/tui.zig` which calls the minimodes dynamically
when needed.
Look for `mini` inside `tui.zig` to find out which minimodes
are present and where to look to learn how each minimode
does its own task.
Look for `mini` inside `tui.zig` to find out which minimodes are present
and where to look, to learn how each minimode does its own task.
[]($section.id("definition"))
### Minimode definition
Possibly the simplest minimode that does not require
defining a particular widget is the `replace` minimode,
used in [helix](/docs/mode/helix) and vim mode. To enter the
minimode in Helix while in `NOR` or `INS` use the keybind
**r**; it consumes another key and replaces the current
character under the main cursor with the immediately pressed
key after **r**. If there are multiple selections, all the
characters are replaced by the one typed after **r**.
Possibly the simplest minimode that does not require defining a
particular widget is the `replace` minimode, used in
[helix](/docs/mode/helix) and vim mode. To enter the minimode in
Helix while in `NOR` or `INS` use the keybind **r**; it consumes
another key and replaces the current character under the main cursor
with the immediately pressed key after **r**. If there are multiple
selections, all the characters are replaced by the one typed after
**r**.
- The minimode needs to expose a `create` function with
type
- The minimode needs to expose a `create` function with type
```zig
pub fn create(Allocator,command.Context) !struct { tui.Mode, tui.MiniMode }
```
Which is in charge of registering the minimode to be able
to receive events and will offer the minimode name, the
one that appears in the lower status bar while it is active,
to let it be known that the minimode is active. This is
where all the instatiations are made. Which leads to
Which is in charge of registering the minimode to be able to receive
events and will offer the minimode name, the one that appears in the
lower status bar while it is active, to let it be known that the
minimode is active. This is where all the instatiations are made. Which
leads to
- The `deinit` function whose type is
@ -82,29 +76,29 @@ where all the instatiations are made. Which leads to
pub fn deinit(*Self)
```
- A `receive` function that will route events received
casting the type:
- A `receive` function that will route events received casting the
type:
```zig
pub fn receive(*Self, tp.pid_ref, tp.message) error{Exit}!bool
```
- A `commands` field that will expose the minimode `Collection`
of `Commands`.
- A `commands` field that will expose the minimode `Collection` of
`Commands`.
- An special command `mini_mode_insert_code_point` as an element
of the commands collection with type:
- An special command `mini_mode_insert_code_point` as an element of the
commands collection with type:
```zig
pub fn mini_mode_insert_code_point(*Self, Ctx) Result
```
acting as the default handler of the key presses that the minimode
will receive when there is no other keybind defined for the minimode.
acting as the default handler of the key presses that the minimode will
receive when there is no other keybind defined for the minimode.
All the keys were handled and managed by the default "invisible"
widget that processes the keys for the minimode. And there is
room for custom widgets that are explained next.
All the keys were handled and managed by the default "invisible" widget
that processes the keys for the minimode. And there is room for custom
widgets.
[]($section.id("custom_widgets"))
## A custom widget
@ -119,5 +113,4 @@ example(look for it in the command palette `:`).
* Head to [architecture](/docs/architecture)
* Review [commands](/docs/architecture/command)
* Deep in the [editor](/docs/architecture/editor)
* Review [keybindings](/docs/architecture/keybind)

View file

@ -10,22 +10,24 @@
},
---
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 anything(a.k.a. cancel), filter the elements, and having
special elements that trigger different actions.
Palettes are overlay menus with auto complete 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 anything(a.k.a. cancel), filter
the elements, and having special elements that trigger different
actions, for example, the task palette.
Examples of palettes are command_palette, clipboard_palette, they all
are based on palette.zig that does all the heavy lifting and sets the
framework to create new palettes as simple as possible.
Examples of palettes are `command_palette`, `clipboard_palette`, they
all are based on `src/tui/mode/overlay/palette.zig that does all the
heavy lifting and sets the framework to create new palettes as simple
as possible.
Palettes are an special case of minimode and for instance a mode, they
receive inputs from keyboards and execute the beforehand mentioned
Palettes are an special case of [minimode] and for instance a mode, they
receive inputs from the keyboard and execute the beforehand mentioned
actions in response.
To get the most of this section, it's recommended to have read about
[commands](/docs/architecture/command), and optionally
[commands](/docs/architecture/command), and optionally,
[minimodes](/docs/architecture/minimode).
[]($section.id("anatomy"))
@ -69,8 +71,7 @@ The index will identify the action to be taken.
When populating with each entry, there must be a relation that links the
option chosen with the required action, and this happens in
`add_menu_entry` used when the user writes in the input to filter out
options.
`add_menu_entry`.
```zig
pub fn add_menu_entry(palette: *Type, entry: *Entry, matches: ?[]const usize) !void {
@ -80,14 +81,17 @@ The common line that will be used when registering the event to a
selected item is
```zig
try palette.menu.add_item_with_handler(value.written(), select);
try palette.menu.add_item_with_handler(value, select);
```
Which will apply the `select` function when the value is selected.
[]($section.id("select"))
### Acting on selection
When the selection happens, it is time to invoke the command with the
selection and the palette needs to be closed. Those actions will be
selection making sure to close the palette. Those actions will be
handled inside `select`, whose signature is:
```zig
@ -96,7 +100,7 @@ fn select(menu: **Type.MenuType, button: *Type.ButtonType, pos: Type.Pos) void {
Other common operations in the palettes can be inspected looking at the
source code of the palettes, all of them import `palette.zig`. Once the
are ready, it's time to make the palette available as a command.
palette is ready, it's time to make the palette available as a command.
[]($section.id("register"))
## Registering the palette
@ -113,6 +117,5 @@ To view a complete implementation of a palette, take a look at
## Next steps
* [Minimodes](/docs/architecture/minimode)
* [Editor topics](/docs/architecture/editor)
* [On commands](/docs/architecture/command)
* [Architecture](/docs/architecture)

View file

@ -12,6 +12,7 @@
This document describes implementation of Helix Mode.
[]($section.id('what'))
## What and what not
The first and biggest difference is that Flow has a mode that emulates
@ -26,12 +27,13 @@ make sure to review
[other issues](https://github.com/neurocyte/flow/issues?q=is%3Aissue%20state%3Aopen%20label%3Ahelix-mode)
to avoid repeating or see if there is anyone interested in porting on
[Discord](https://discord.gg/kzJC9fA7) to ask if or there is a
workaoround, remember that it's possible to bounce back to Flow mode
workaround, remember that it's possible to bounce back to Flow mode
if needed.
[]($section.id('enhancing'))
## Enhancing hx mode
This is a programmer editor, you are more than welcome to enhance to
This is a programmer's editor, you are more than welcome to enhance to
suit your needs that maybe coincide with others.
Please take a look at [architecture](/docs/architecture) and
@ -43,6 +45,7 @@ particular work to make it real is in `src/tui/mode/helix.zig`, adding
a `command` and the corresponding `meta` is what is required.
[More on commands](/docs/architecture/command).
[]($section.id('pickers'))
### Pickers
Flow hx mode offers most of the picker types equivalents with `panels`
@ -53,9 +56,12 @@ files). Examples of `palettes` are `space` `b` to pick a buffer or
editor while palettes open overlapping the working area.
One medium sized project is to create a widget that has one input
widget, two panels, on the left, the list of options and, on the right,
the preview of the selected option and offer various keybindings to
manipulate the objects inside both panels with filtering.
widget with two panels, on the left, the list of options and, on the
right, the preview of the selected option and offer various keybindings
to manipulate the objects inside both panels with filtering.
[]($section.id('next'))
## Next steps
Said all of this, it's possible to start contributing via pull
requesting [keybinds](/docs/architecture/keybind),
@ -64,4 +70,7 @@ requesting [keybinds](/docs/architecture/keybind),
mentioned previously.
More about the [architecture](/docs/architecture) or jump to
[contribution guidelines](/docs/contributing).
[contribution guidelines](/docs/contributing).
Join the [#helix-mode channel](https://discord.gg/sxdejrAA) and get in
touch with other hx users.

View file

@ -9,8 +9,9 @@
.codepath ="test",
},
---
Currently flow tests are aimed to work as unit tests, it always is a good
idea to review the
Currently flow tests are aimed to work as unit tests.
If new to zig, it always is a good idea to review the
[zig tests documentation](https://ziglang.org/documentation/master/#Zig-Test)
and also an
[introduction to testing](https://pedropark99.github.io/zig-book/Chapters/03-unittests.html).
@ -26,7 +27,7 @@ Flow tests are placed in the directory `test`.
[]($section.id("running_tests"))
## Running the tests
To run the full set of tests, inside flow, use `F5`, which runs a task that
To run the full set of tests, inside flow, use `f5`, which runs a task that
invokes:
```
@ -56,8 +57,8 @@ nature, for example, when there are a lot of branching
* You find something that could be changed in the future affecting the
current behavior
* A bug is fixed
* A defined behavior could be thought different, for example when in a mode,
it was defined that something might diverge from other programs.
* A defined behavior could be thought different, for example when in a
mode, it was defined that something might diverge from other programs.
Tests are placed under `test` directory. Add your test in the file that
exercises the functionality and makes proof of it behaving as expected.
@ -77,8 +78,8 @@ In such cases the module that has the logic should provide a pub
`test_internal`, by convention, exposing the target functionalities to
be tested.
For example in `src/tui/mode/helix.zig`, `test_internal` exposes the private
function
For example in `src/tui/mode/helix.zig`, `test_internal` exposes the
private function
```zig
fn move_cursor_long_word_right_end(root: Buffer.Root, cursor: *Cursor, metrics: Buffer.Metrics) error{Stop}!void
@ -156,7 +157,8 @@ of adding a new test file for project manager.
## FAQ on tests
[]($section.id("import_editor"))
### I need to test something that requires importing the editor ¿What do I do?
### I need to test something that requires importing the editor ¿What
do I do?
There are two paths from here:
@ -171,7 +173,26 @@ Refactor the functions involved in the functionality to make them
not rely directly with editor and other higher level components, and
test the lower level ones.
An example of this can be seen in commands
For example, in `vim NORMAL` mode, the key `F` looks for a character to
the left in the same line, if the character is not found it goes to the
beginning of the line. In the case of `hx NOR` mode, the `F` key looks
for a character to the beginning of the file, if found, makes a
selection from the initial cursor position to the character found, if
not, no selection is made and the cursor is not moved at all.
Given that Helix has that movement and selection functionality, finding
the character was the first action and hence the search function is
the one tested in `test/tests_helix.zig`, given that positioning the
selection is rather simple compared to looking for the character. It
was decided to test the search functionality making it not depend
on editor, but only on the cursor, buffer, metrics and context, all
of them do not require graphic elements at all.
The group of functions `beyond_eol` can be seen in
[this commit](https://github.com/neurocyte/flow/pull/330/commits/baac14b3ae5243cef6461df42dae6fcf5ea15201)
and whose tests are
[here](https://github.com/neurocyte/flow/pull/330/commits/38a08aed49f4fbba18aab9ccbd3c8b9758414221).
[]($section.id("end_to_end"))
### Use additional tools to test a running flow session
@ -187,5 +208,6 @@ If in doubt about how to do something,
## Next steps
* [How to contribute](/docs/contributing)
* [User Documentation](/docs)
* [Personalizing keybindings](/docs/architecture/keybind)
* [Enhance flow with commands](/docs/architecture/command)
* [Other Flow topics](/docs/architecture)