From 0494574c363d968e14c3bababf24b8176c63e2df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Thu, 30 Oct 2025 23:35:53 -0500 Subject: [PATCH] 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. --- content/docs/architecture.smd | 2 +- content/docs/architecture/command.smd | 119 ++++++++++-------- content/docs/architecture/editor.smd | 2 +- .../docs/architecture/inner_data_exchange.smd | 66 +++++----- content/docs/architecture/keybind.smd | 42 ++++--- content/docs/architecture/minimode.smd | 91 +++++++------- content/docs/architecture/palette.smd | 37 +++--- content/docs/mode/helix.smd | 21 +++- content/docs/testing.smd | 42 +++++-- 9 files changed, 234 insertions(+), 188 deletions(-) diff --git a/content/docs/architecture.smd b/content/docs/architecture.smd index d1c5ff6..0b5ce3f 100644 --- a/content/docs/architecture.smd +++ b/content/docs/architecture.smd @@ -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 diff --git a/content/docs/architecture/command.smd b/content/docs/architecture/command.smd index e454ec7..081ba83 100644 --- a/content/docs/architecture/command.smd +++ b/content/docs/architecture/command.smd @@ -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) \ No newline at end of file diff --git a/content/docs/architecture/editor.smd b/content/docs/architecture/editor.smd index 48bfd74..2ec1887 100644 --- a/content/docs/architecture/editor.smd +++ b/content/docs/architecture/editor.smd @@ -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", diff --git a/content/docs/architecture/inner_data_exchange.smd b/content/docs/architecture/inner_data_exchange.smd index c5e66e6..45a94f8 100644 --- a/content/docs/architecture/inner_data_exchange.smd +++ b/content/docs/architecture/inner_data_exchange.smd @@ -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) diff --git a/content/docs/architecture/keybind.smd b/content/docs/architecture/keybind.smd index 164b57d..b39c856 100644 --- a/content/docs/architecture/keybind.smd +++ b/content/docs/architecture/keybind.smd @@ -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) diff --git a/content/docs/architecture/minimode.smd b/content/docs/architecture/minimode.smd index ab3753c..3a173e2 100644 --- a/content/docs/architecture/minimode.smd +++ b/content/docs/architecture/minimode.smd @@ -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) diff --git a/content/docs/architecture/palette.smd b/content/docs/architecture/palette.smd index a99aa85..41dfecf 100644 --- a/content/docs/architecture/palette.smd +++ b/content/docs/architecture/palette.smd @@ -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) \ No newline at end of file diff --git a/content/docs/mode/helix.smd b/content/docs/mode/helix.smd index e31114c..3b983f4 100644 --- a/content/docs/mode/helix.smd +++ b/content/docs/mode/helix.smd @@ -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). \ No newline at end of file +[contribution guidelines](/docs/contributing). + +Join the [#helix-mode channel](https://discord.gg/sxdejrAA) and get in +touch with other hx users. \ No newline at end of file diff --git a/content/docs/testing.smd b/content/docs/testing.smd index 5ee58b3..8684dd2 100644 --- a/content/docs/testing.smd +++ b/content/docs/testing.smd @@ -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) \ No newline at end of file