From c87d310f7af5a37b65d450c97e1574bde9fe11fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Fri, 17 Oct 2025 23:34:17 -0500 Subject: [PATCH 01/10] docs: Starting point for minimode and helix mode --- content/docs/architecture/minimode.smd | 110 +++++++++++++++++++++++++ content/docs/mode/helix.smd | 67 +++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 content/docs/architecture/minimode.smd create mode 100644 content/docs/mode/helix.smd diff --git a/content/docs/architecture/minimode.smd b/content/docs/architecture/minimode.smd new file mode 100644 index 0000000..834ec16 --- /dev/null +++ b/content/docs/architecture/minimode.smd @@ -0,0 +1,110 @@ +--- +.title = "Minimodes", +.date = @date("2025-10-15T00:00:00"), +.author = "Igor Támara", +.layout = "index.shtml", +.draft = false, +--- + +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. + +## Anatomy of minimodes + +To create a minimode it's needed: + +* A Keybinding +* An Action mapping +* A Minimode definition + +### 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. + +### 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 them 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. + +### Minimode definition + +Possibly the simplest minimode that will be found that does +not require defining a particular widget is the `replace` +minimode, used in helix mode 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 pressed key. +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 + +```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 + +- The `deinit` function whose type is + +```zig +pub fn deinit(*Self) +``` + +- 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`. + +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 defined. + +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. + +## A custom widget + +When there is a need for an specialized widget, it's possible to +define one, for example, the `file_browser` is used to load and +save files, and `numeric_input` is used to set the tab width for +example(look for it in the command palette `:`). + + +* Head to [architecture](/docs/architecture) +* Learn about [commands](/docs/architecture/command) +* Review [keybindings](/docs/architecture/keybind) diff --git a/content/docs/mode/helix.smd b/content/docs/mode/helix.smd new file mode 100644 index 0000000..62b5606 --- /dev/null +++ b/content/docs/mode/helix.smd @@ -0,0 +1,67 @@ +--- +.title = "Helix Mode", +.date = @date("2025-10-10T00:00:00"), +.author = "Igor Támara", +.layout = "index.shtml", +.draft = false, +--- + +This document describes implementation of Helix Mode. + +## What and what not + +The first and biggest difference is that Flow has a mode that +emulates Helix, or at least has equivalent of the worthiest +actions that can be done in Helix. The conversely is not true. + +`:` opens up Flow's rich command palette that might have +functionalities Helix users are used to have, if you find +something missing, it's possible to +[open a Feature Request](https://github.com/neurocyte/flow/issues) +to see if there is anyone interested in porting it. Or maybe +someone is already creating or interested in the one you are +missing. [Join Discord](https://discord.gg/kzJC9fA7) to ask +if anyone is working on something similar or there is a +workaoround. + +## Enhancing hx mode + +This is a programmer 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 +[contributing](/docs/contributing) for an overview and the +mechanics of getting your changes into Flow. + +hx mode is modal kind, the same as vim mode, and the file +that has the 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). + +### Pickers + +Flow hx mode offers most of the picker types equivalents +with `panels` and `palettes`. Example of panels are +the `g` `r` (go to reference from lsp) and `space` `/` +(a.k.a find in files). Examples of `palettes` are +`space` `b` to pick a buffer or `space` `f` to open a +file in your project. Panels open below the 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. + +Given this, it's possible to start contributing via +pull requesting [keybinds](/docs/architecture/keybind), +[commands](/docs/architecture/command), +[palettes](/docs/architecture/palette), or the +special widget mentioned previously. + + +More about the [architecture](/docs/architecture) or jump to +[contribution guidelines](/docs/contributing). \ No newline at end of file From 1964cb7fd68b0d4cc61a4ff1aa934bd127570a70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Sat, 18 Oct 2025 22:13:59 -0500 Subject: [PATCH 02/10] Add footer for edition --- content/docs/architecture/minimode.smd | 24 +++++++++++++----------- content/docs/mode/helix.smd | 15 ++++++++------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/content/docs/architecture/minimode.smd b/content/docs/architecture/minimode.smd index 834ec16..28a8eae 100644 --- a/content/docs/architecture/minimode.smd +++ b/content/docs/architecture/minimode.smd @@ -2,8 +2,9 @@ .title = "Minimodes", .date = @date("2025-10-15T00:00:00"), .author = "Igor Támara", -.layout = "index.shtml", +.layout = "tutorial.shtml", .draft = false, +.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/minimode.md"}, --- Minimodes can be used by other modes adding functionality @@ -38,7 +39,8 @@ minimode. 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 them dynamically when needed. +`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 @@ -46,14 +48,14 @@ does its own task. ### Minimode definition -Possibly the simplest minimode that will be found that does -not require defining a particular widget is the `replace` -minimode, used in helix mode and vim mode. To enter the +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 pressed key. -If there are multiple selections, all the characters are -replaced by the one typed after **r**. +**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 @@ -83,7 +85,7 @@ pub fn receive(*Self, tp.pid_ref, tp.message) error{Exit}!bool - A `commands` field that will expose the minimode `Collection` of `Commands`. -An special command `mini_mode_insert_code_point` as an element +- An special command `mini_mode_insert_code_point` as an element of the commands collection with type: ```zig @@ -91,7 +93,7 @@ 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 defined. +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 diff --git a/content/docs/mode/helix.smd b/content/docs/mode/helix.smd index 62b5606..8bd5def 100644 --- a/content/docs/mode/helix.smd +++ b/content/docs/mode/helix.smd @@ -2,8 +2,9 @@ .title = "Helix Mode", .date = @date("2025-10-10T00:00:00"), .author = "Igor Támara", -.layout = "index.shtml", +.layout = "tutorial.shtml", .draft = false, +.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/mode/helix.md"}, --- This document describes implementation of Helix Mode. @@ -17,12 +18,12 @@ actions that can be done in Helix. The conversely is not true. `:` opens up Flow's rich command palette that might have functionalities Helix users are used to have, if you find something missing, it's possible to -[open a Feature Request](https://github.com/neurocyte/flow/issues) -to see if there is anyone interested in porting it. Or maybe -someone is already creating or interested in the one you are -missing. [Join Discord](https://discord.gg/kzJC9fA7) to ask -if anyone is working on something similar or there is a -workaoround. +[open a Feature Request](https://github.com/neurocyte/flow/issues), +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 if needed. ## Enhancing hx mode From ca131d21352b0fbfe9106f8ce904f8ea3b0ce246 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Sun, 19 Oct 2025 01:05:57 -0500 Subject: [PATCH 03/10] Add initial docs for command, editor, keybind, palette --- content/docs/architecture/command.smd | 121 +++++++++++++++++++++ content/docs/architecture/editor.smd | 76 ++++++++++++++ content/docs/architecture/keybind.smd | 145 ++++++++++++++++++++++++++ content/docs/architecture/palette.smd | 24 +++++ 4 files changed, 366 insertions(+) create mode 100644 content/docs/architecture/command.smd create mode 100644 content/docs/architecture/editor.smd create mode 100644 content/docs/architecture/keybind.smd create mode 100644 content/docs/architecture/palette.smd diff --git a/content/docs/architecture/command.smd b/content/docs/architecture/command.smd new file mode 100644 index 0000000..ce4f15d --- /dev/null +++ b/content/docs/architecture/command.smd @@ -0,0 +1,121 @@ +--- +.title = "Commands", +.date = @date("2025-10-15T00:00:00"), +.author = "Igor Támara", +.layout = "tutorial.shtml", +.draft = false, +.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/command.md"}, +--- + +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. + +## 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. + +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. + +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 developing +flow itself. + +## Understanding and creating commands + +A command is a function with a type like + +```zig +pub fn copy(self: *Self, _: Context) Result +``` + +and a `Meta` definition with the same name and suffix `_meta`. + +```zig +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. + +`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. + +## 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. + +```zig +pub fn q(_: *void, _: Ctx) Result { + try cmd("quit", .{}); +} +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. + +## 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`. + +```zig +pub fn wq(_: *void, _: Ctx) Result { + try cmd("save_file", command.fmt(.{ "then", .{ "quit", .{} } })); +} +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. + +# More in depth commands + +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. + +```zig +pub fn select_to_char_left_helix(_: *void, ctx: Ctx) Result { + try helix_with_selections_const_arg(ctx, &select_cursel_to_char_left_helix); +} +``` + +## Sending parameters to commands + +`cmd` is in charge of finding a command given its name, and parameters sent +to commands are vary for each command, for example, when interacting with +the clipboard, the messages sent are multiple chunks of information, for +now an example of such usage can be seen in a function that fetches contents +from the clipboard. + + + +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). diff --git a/content/docs/architecture/editor.smd b/content/docs/architecture/editor.smd new file mode 100644 index 0000000..f96ec87 --- /dev/null +++ b/content/docs/architecture/editor.smd @@ -0,0 +1,76 @@ +--- +.title = "Editor", +.date = @date("2025-10-19T00:00:00"), +.author = "Igor Támara", +.layout = "tutorial.shtml", +.draft = false, +.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/editor.md"}, +--- + +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 +[commands](/docs/architecture/command) and +[keybinds](/docs/architecture/keybind). + +## 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. + +Other cursors can be in the `View` or in regions outside the +current view, depending on the size of both the buffer and +the editor view. + +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` has a cursor and optionally a Selection. + +Most of editor operations act on the set of CurSels, the Primary +Cursor is in fact a CurSel, as opposed to what we previously +mentioned. + +To complete the editor scenario, `Marks` have the potential +to become selections, and behind the scenes CurSels and are +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. + +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, the +beginning has been reached when interacting with a Cursor. + +## Editor Commands + +We mentioned earlier that most of the operations work on all +the cursors and selections, there are various commands that +will use functions that iterate over 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 `` to +get the root of it to find and position the cursors. While +we will use `` when the buffer is to be modified. + +## Moving + + + +## Selections + +## Modifying the buffer + + +[Discord](https://discord.com/invite/4wvteUPphx) and +[Github issues](https://github.com/neurocyte/flow/issues) are the +main channels to do so. + diff --git a/content/docs/architecture/keybind.smd b/content/docs/architecture/keybind.smd new file mode 100644 index 0000000..82d950d --- /dev/null +++ b/content/docs/architecture/keybind.smd @@ -0,0 +1,145 @@ +--- +.title = "Keybinding", +.date = @date("2025-10-19T00:00:00"), +.author = "Igor Támara", +.layout = "tutorial.shtml", +.draft = false, +.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/keybind.md"}, +--- + +If you are here, it's possible that you already have edited your +own keybinds to suit your needs and are looking for some advanced +topics to extend your use cases and make everything easier and +fluid when in Flow. If you have not, take a peek to learning how +to do it. + +Using the command palette `Ctrl+Shift+p` and typing **Edit key bindings**, +takes you to the json file to extend Flow configuring +keybindings to suit your needs. + +[]($section.id('tldr')) +## ;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, where the first element is the combination to map to the +commands that will happen, the array accepts strings like in + +```js +["ctrl+alt+shift+p", "open_command_palette"] +``` + +To avoid screwing up the combinations, and putting Flow in an unusable +state derived from a wrong mapping of key combinations, read on. + +## Resetting keys to factory defaults + +User configured keybindings are stored in Flow's configuration +directory under `keys/mode.json` where mode can be `flow`, +`emacs`, `vim`, `helix` or customized ones. Removing the keys +directory or the particular mode file can take you out from a +broken state. + +## Keybinds for each mode + +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. + +[introducing keybindings](/devlog/2024#2024-12-05T20:55:00) showcases +how to get to edit keybindings. + +## Keybindings hierarchy + +Some terminology + +* **Mode**: Stored in a json file, like flow mode declared in `flow.json`. +* **Imode**: under the json file. +* **Major Imode**: `project` or descendant from `project`. +* **Minimodes**: To be used momentarily and do not inherit from `project`. + +In general a keybinding json shows this hierarchy: + +``` +Mode > Imode > press > Key and commands +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`, 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. + +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 hierarchy and it's common for major imodes to be +descendants from `project`. + +## Adding a Keybinding + +The most basic case to map a keybind to a command was covered in +[TLDR](#tldr) which used the combination of three keys pressed +simultaneously `ctrl`, `shift` and `p`, all of them where combined +with `+` to execute the command `open_command_palette`. + +A common use case is to add a keybinding to invoke an already +existing command and chain it to another, making Flow more suited to your +own needs. + +[]($section.id('shell')) +## Running shell commands + +For example, `f5` by default is used to run `zig build test` +outputting its results to a *scratch buffer* called `test`. + +```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. + +``` +[ + "f5", + [ + "create_scratch_buffer", + "*test*" + ], + [ + "shell_execute_insert", + "zig", + "build", + "test" + ] +] +``` + +Observe [tasks running](/devlog/2025#2025-01-26T22:11:00) and maybe +consider using more keybindings or running tasks for your projects. + +Probably binding commands is good, but maybe there is a feature in +other texts 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. + diff --git a/content/docs/architecture/palette.smd b/content/docs/architecture/palette.smd new file mode 100644 index 0000000..c5b8597 --- /dev/null +++ b/content/docs/architecture/palette.smd @@ -0,0 +1,24 @@ +--- +.title = "Palettes", +.date = @date("2025-10-20T00:00:00"), +.author = "Igor Támara", +.layout = "tutorial.shtml", +.draft = false, +.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/palette.md"}, +--- + +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(cancel), filter the elements, and +having special elements that trigger different actions. + +To get the most of this section, it's recommended to have +read about [commands](/docs/architecture/command), and optionally +[minimodes](/docs/architecture/minimode). + +See +[clipboard history palette](https://github.com/neurocyte/flow/commit/634a18cb5685a3c3fcfc08301306e628d33c3256) + + + From a7bcd6dd9ea4fc56211f529b88cd9d1678809a3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Tue, 21 Oct 2025 20:12:25 -0500 Subject: [PATCH 04/10] Add some more information to palettes --- content/docs/architecture/palette.smd | 90 +++++++++++++++++++++++++-- 1 file changed, 85 insertions(+), 5 deletions(-) diff --git a/content/docs/architecture/palette.smd b/content/docs/architecture/palette.smd index c5b8597..a388206 100644 --- a/content/docs/architecture/palette.smd +++ b/content/docs/architecture/palette.smd @@ -4,21 +4,101 @@ .author = "Igor Támara", .layout = "tutorial.shtml", .draft = false, -.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/palette.md"}, +.custom = { + .githubedit = "/docs/architecture/palette.md" +}, --- 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(cancel), filter the elements, and -having special elements that trigger different actions. +the palette without selecting anything(a.k.a. cancel), filter +the elements, and having special elements that trigger different +actions. + +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. + +Palettes are an special case of minimode and for instance a +mode, they receive inputs from keyboards 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 [minimodes](/docs/architecture/minimode). -See -[clipboard history palette](https://github.com/neurocyte/flow/commit/634a18cb5685a3c3fcfc08301306e628d33c3256) +## Defining the palette +Palettes are under `tui/overlay` and use the facilities offered by +`palette.zig` to perform all the operations. +1. Defining the list of elements +2. Filtering the elements +3. Perform an action with the selected element +Note: Palettes are meant to show options and allowing to select +the options to execute an action on the given selection. To +maintain as readable as possible the code and thus extensible, +the data to be used should be prepared previously. + +### Fields + +Basic fields that give hints to the user and need to be set are: + +```zig +pub const label = "Clipboard history"; +pub const name = " clipboard"; +pub const description = "clipboard"; +pub const icon = " "; +``` + +### Defining the list of elements in the palette + +`load_entries` is in charge of populating the visible entries, +each one with an index. + +```zig +pub fn load_entries(palette: *Type) !usize +``` + +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. + +```zig +pub fn add_menu_entry(palette: *Type, entry: *Entry, matches: ?[]const usize) !void { +``` + +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); +``` + +### 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 handled inside `select`, whose signature is: + +```zig +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 functions are +ready, it's time to make the palette available as a command. + +## Registering the palette + +Commands that open the palette are defined in `tui.zig` in a similar way as it +is done with [minimodes](/docs/architecture/minimode). + +To view a complete implementation of a palette, take a look at +[clipboard history palette commit](https://github.com/neurocyte/flow/commit/634a18cb5685a3c3fcfc08301306e628d33c3256) From d14b44ed1cfab4622d15342e55a625ac7dc14c5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Tue, 21 Oct 2025 22:31:48 -0500 Subject: [PATCH 05/10] Added more documentation to editor --- content/docs/architecture/editor.smd | 111 +++++++++++++++++++++++---- 1 file changed, 94 insertions(+), 17 deletions(-) diff --git a/content/docs/architecture/editor.smd b/content/docs/architecture/editor.smd index f96ec87..da50512 100644 --- a/content/docs/architecture/editor.smd +++ b/content/docs/architecture/editor.smd @@ -4,7 +4,16 @@ .author = "Igor Támara", .layout = "tutorial.shtml", .draft = false, -.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/editor.md"}, +.custom = { + .githubedit = "docs/architecture/editor.md", + .prevurl = "docs/command", + .prevtext = "Commands", + .topurl = "docs/architecture", + .toptext = "Architecture", + .nexturl = "docs/architecture/minimode", + .nexttext = "Mini modes", + .codepath ="src/tui/editor.zig", +}, --- The `editor` coordinates visualization and modification of @@ -24,51 +33,119 @@ portion of the buffer. Other cursors can be in the `View` or in regions outside the current view, depending on the size of both the buffer and -the editor view. +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` has a cursor and optionally a Selection. +`Cursel` is composed by a cursor and optionally a Selection. -Most of editor operations act on the set of CurSels, the Primary -Cursor is in fact a CurSel, as opposed to what we previously -mentioned. +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. To complete the editor scenario, `Marks` have the potential -to become selections, and behind the scenes CurSels and are -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. +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. 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, the -beginning has been reached when interacting with a Cursor. +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". ## Editor Commands We mentioned earlier that most of the operations work on all -the cursors and selections, there are various commands that -will use functions that iterate over cursors, selections, cursels +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 `` to -get the root of it to find and position the cursors. While -we will use `` 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. ## 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`. +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. ## 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. + +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 +``` + ## 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. [Discord](https://discord.com/invite/4wvteUPphx) and [Github issues](https://github.com/neurocyte/flow/issues) are the From 34ec8be3559aa2c526d52f7baab3d5105b80e2e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Tue, 21 Oct 2025 22:32:01 -0500 Subject: [PATCH 06/10] Added more documentation to palette --- content/docs/architecture/palette.smd | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/content/docs/architecture/palette.smd b/content/docs/architecture/palette.smd index a388206..c3da6be 100644 --- a/content/docs/architecture/palette.smd +++ b/content/docs/architecture/palette.smd @@ -5,7 +5,12 @@ .layout = "tutorial.shtml", .draft = false, .custom = { - .githubedit = "/docs/architecture/palette.md" + .githubedit = "docs/architecture/palette.md", + .prevurl = "docs/minimode", + .prevtext = "Mini modes", + .topurl = "docs/architecture", + .toptext = "Architecture", + .codepath ="src/tui/mode/overlay/clipboard_palette.zig", }, --- @@ -98,7 +103,8 @@ ready, it's time to make the palette available as a command. ## Registering the palette Commands that open the palette are defined in `tui.zig` in a similar way as it -is done with [minimodes](/docs/architecture/minimode). +is done with [minimodes](/docs/architecture/minimode). We have got +you covered if in doubt about [how to create a command](/docs/architecture/command). To view a complete implementation of a palette, take a look at [clipboard history palette commit](https://github.com/neurocyte/flow/commit/634a18cb5685a3c3fcfc08301306e628d33c3256) From 5eedc1754230698f0e9a06b5d9b2cdb264cca20c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Mon, 27 Oct 2025 08:41:17 -0500 Subject: [PATCH 07/10] Add explanation of exchanging data --- .../docs/architecture/inner_data_exchange.smd | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 content/docs/architecture/inner_data_exchange.smd diff --git a/content/docs/architecture/inner_data_exchange.smd b/content/docs/architecture/inner_data_exchange.smd new file mode 100644 index 0000000..6df5c43 --- /dev/null +++ b/content/docs/architecture/inner_data_exchange.smd @@ -0,0 +1,125 @@ +--- +.title = "Command arguments and message passing", +.date = @date("2025-10-27T00:00:00"), +.author = "CJ van den Berg", +.layout = "tutorial.shtml", +.draft = false, +.custom = { + .githubedit = "docs/architecture/inner_data_exchange.smd", + .prevurl = "docs/architecture/editor.zig", + .prevtext = "Editor", + .topurl = "docs/architecture", + .toptext = "Architecture", + .codepath ="src/tui/editor.zig", +}, +--- + +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). + +This chapter describes the mechanisms that flow has to pass arguments +between components. + +## Library usage + +* The Thespian library sends and receives `thespian.message` values, which +are strongly typed, but schema free CBOR encoded structures. It supports +spawning, linking, killing, etc., of lightweight processes (aka the "Actor +Model" with "Green Threads") and provides async file and network IO and +child process management. +* The CBOR library encodes decodes CBOR structured data to/from Zig +variables + * Encoding happens via the `cbor.write*` functions. These are wrapped by + `command.fmt` and `thespian.message.fmt` which provide fast allocation + free encoding to a thread local buffer. Note that the CBOR data encoded + via the `*.fmt` functions will only survive until another 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` 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. + +### Example of command argument usage + +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) +via its meta is declared as: + +```zig +pub const goto_line_meta: Meta = .{ .arguments = &.{.integer} }; +``` + +To actually receiving the integer parameter: + +```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; +``` + +Cbor features en/decoding arrays and compounds of basic types and the only +requirement is to decode in the same order as encoding the data, more +samples of usage can be seen in +[cbor tests](https://github.com/neurocyte/cbor/blob/master/test/tests.zig). + +## 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. + +* Received messages are read directly from the thespian process (actor) +receive buffer and remain in scope only for the duration of an actor's +receive method call +* `thespian.message.fmt` encoded messages are stored in the thread local +`thespian.message_buffer` and remain in scope only until the next +`thespian.message.fmt` call on the same thread +* `thespian.exit_message` encoded message are stored in the thread local +`thespian.error_message_buffer` and remain in scope only until the next +`thespian.exit_message` call on the same thread +* `command.fmt` encoded messages are stored in the thread local +`command.context_buffer` and remain in scope only until the next +`command.fmt` call on the same thread + +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. +* 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. + +## More information + +* [Deepwiki on cbor](https://deepwiki.com/neurocyte/cbor) +* [Samples of cbor usage](https://github.com/neurocyte/cbor/blob/master/test/tests.zig) +* [Deepwiki on thespian](https://deepwiki.com/neurocyte/thespian) \ No newline at end of file From e837a66b9795abdeea8bd7f18f1a8c2fb7827a4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Wed, 29 Oct 2025 16:43:37 -0500 Subject: [PATCH 08/10] Links between developer docs --- README.md | 2 +- content/docs/architecture.smd | 68 +++++----- content/docs/architecture/command.smd | 84 ++++++++---- content/docs/architecture/editor.smd | 20 ++- .../docs/architecture/inner_data_exchange.smd | 87 ++++++------ content/docs/architecture/keybind.smd | 128 ++++++++++-------- content/docs/architecture/minimode.smd | 15 +- content/docs/architecture/palette.smd | 82 ++++++----- content/docs/mode/helix.smd | 73 +++++----- content/docs/testing.smd | 2 +- 10 files changed, 318 insertions(+), 243 deletions(-) diff --git a/README.md b/README.md index 156377e..a0ab542 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Some [custom frontmatter](https://zine-ssg.io/docs/supermd/#frontmatter) fields Directs to contribute editing this documentation. Used by `layout/tutorial.shtml`. ```ziggy - .githubedit** = "/docs/testing.md", + .githubedit** = "/docs/testing.smd", ``` ### codepath (Optional) diff --git a/content/docs/architecture.smd b/content/docs/architecture.smd index 51a6924..d1c5ff6 100644 --- a/content/docs/architecture.smd +++ b/content/docs/architecture.smd @@ -44,27 +44,32 @@ offers services around the set of projects. []($section.id("commands")) ## Editor commands and modes -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 higher level, the selections, -cursors, cursor selections `CurSel` and the `View`. The commands are -used by `Modes` with `Keybindings`. The main mode is Flow and the -keybindings can be used to map to a mode built up entirely on solely -calling already created commands. An example of a mode created by -command composition is `Emacs` mode, for instance, it's possible to -create a nano mode with just keybindings. In the other hand, `Vim` and -`Helix` modes have particular definitions for commands that interact -with the buffers, being modal editors. +When a buffer is active, it has an [Editor](/docs/architecture/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 +higher level, the selections, cursors, cursor selections `CurSel` and +the `View`. [Commands](/docs/architecture/command) are used by `Modes` +with [Keybindings](/docs/architecture/keybind). The main mode is Flow +and the keybindings can be used to map to a mode built up entirely on +solely calling already created commands. An example of a mode +created by command composition is `Emacs` mode, for instance, it's +possible to create a nano mode with just keybindings. In the other hand, +`Vim` and [Helix](/docs/mode/helix) modes have particular definitions +for commands that interact with the buffers, being modal editors. []($section.id("tui")) ## Text user interface -`Tui` governs it all offering support for `Palettes` that are known -in other environments as pickers, as well as offering information -through a set of `_views` (i.e. `logview`, `inputview`, -`inspector_view`) and `status` (i.e. `tabs`, `clock`, `branch`, -`linenum`). +`Tui` governs it all offering support for +[palettes](/docs/architecture/palette) that are known in other +environments as pickers, as well as offering information through a +set of `_views` (i.e. `logview`, `inputview`, `inspector_view`) and +`status` (i.e. `tabs`, `clock`, `branch`, `linenum`), in the statusbar +[minimodes](/docs/architecture/minimode) will be present too, those +that receive more keypresses to offer additional functionality, such +as finding in files, finding in the current buffer, open files +and replacing a character. []($section.id("oses")) ## Operating systems and UI @@ -77,16 +82,16 @@ and Android via Termux, while in Windows there is an special GUI. ## Communication between components [Thespian](https://github.com/neurocyte/thespian) is in charge of -processes synchronization and allows sending messages between -different flow components, for example, when a widget needs -updating information from changing states of internal data and -when components or external processes take time and need to return -an answer, all this without blocking the user interface. Tree-sitter -queries to highlight the current file of a particular -language and LSPs usually take time by the nature of operations they -perform, integration with git and running a `shell` command via a -`task` all are coordinated thanks to the infrastructure that -Thespian provides. +processes synchronization and allows sending +[messages between different flow components](/docs/architecture/inner_data_exchange), +for example, when a widget needs updating information from changing +states of internal data and when components or external processes take +time and need to return an answer, all this without blocking the user +interface. Tree-sitter queries to highlight the current file of a +particular language and LSPs usually take time by the nature of +operations they perform, integration with git and running a `shell` +command via a `task` all are coordinated thanks to the infrastructure +that Thespian provides. []($section.id("languages")) ## Programming languages support @@ -111,7 +116,7 @@ feedback via `logview`. To view logs use `f11` to toggle the previous messages, or alternatively, open flow with the option `--show-logs`. -To log something import +To log something, first import ```zig const log = @import("log"); @@ -135,13 +140,14 @@ logger.print("{} unsaved buffer(s) remaining", .{remaining}); ### View key presses There are situations when you press some keys without the expected -behavior happening, to review if flow is getting the keys, or your desktop -environment or something else are capturing them, you will want to -invoke flow with the option `--show-input`. +behavior happening, to review if flow is getting the keys, or your +desktop environment or something else are capturing them, you will want +to invoke flow with the option `--show-input`. []($section.id("next")) ## Next steps * [Guidelines for contributions](/docs/contributing) * [Take a peek on testing](/docs/testing) +* [Configure some keybinds](/docs/architecture/keybind) * [Back to docs](/docs) \ No newline at end of file diff --git a/content/docs/architecture/command.smd b/content/docs/architecture/command.smd index ce4f15d..e454ec7 100644 --- a/content/docs/architecture/command.smd +++ b/content/docs/architecture/command.smd @@ -4,32 +4,36 @@ .author = "Igor Támara", .layout = "tutorial.shtml", .draft = false, -.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/command.md"}, +.custom = { + .githubedit = "/docs/architecture/command.smd", + .codepath = "src/tui/editor.zig", +}, --- -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. +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. +[]($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 +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. 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. -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 developing -flow itself. +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 +developing flow itself. +[]($section.id('creating')) ## Understanding and creating commands A command is a function with a type like @@ -45,8 +49,8 @@ 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 @@ -54,6 +58,7 @@ 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 @@ -71,6 +76,7 @@ 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 @@ -87,10 +93,12 @@ 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. -# More in depth commands +[]($section.id('deepen')) +## More in depth commands -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 @@ -102,20 +110,40 @@ pub fn select_to_char_left_helix(_: *void, ctx: Ctx) Result { } ``` -## Sending parameters to commands +[]($section.id('command_arguments')) +### Sending parameters to commands `cmd` is in charge of finding a command given its name, and parameters sent -to commands are vary for each command, for example, when interacting with -the clipboard, the messages sent are multiple chunks of information, for -now an example of such usage can be seen in a function that fetches contents -from the clipboard. +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: +```zig +pub const goto_line_meta: Meta = .{ .arguments = &.{.integer} }; +``` -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 +and to actually receiving the integer parameter: + +```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; +``` + +[]($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 +* [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 da50512..48bfd74 100644 --- a/content/docs/architecture/editor.smd +++ b/content/docs/architecture/editor.smd @@ -5,13 +5,7 @@ .layout = "tutorial.shtml", .draft = false, .custom = { - .githubedit = "docs/architecture/editor.md", - .prevurl = "docs/command", - .prevtext = "Commands", - .topurl = "docs/architecture", - .toptext = "Architecture", - .nexturl = "docs/architecture/minimode", - .nexttext = "Mini modes", + .githubedit = "docs/architecture/editor.smd", .codepath ="src/tui/editor.zig", }, --- @@ -24,6 +18,7 @@ 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`, @@ -63,6 +58,7 @@ 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 @@ -85,6 +81,7 @@ 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 @@ -103,6 +100,7 @@ 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 @@ -138,6 +136,7 @@ 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` @@ -151,3 +150,10 @@ place and then applying the modification. [Github issues](https://github.com/neurocyte/flow/issues) are the main channels to do so. +[]($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. diff --git a/content/docs/architecture/inner_data_exchange.smd b/content/docs/architecture/inner_data_exchange.smd index 6df5c43..c5e66e6 100644 --- a/content/docs/architecture/inner_data_exchange.smd +++ b/content/docs/architecture/inner_data_exchange.smd @@ -6,42 +6,40 @@ .draft = false, .custom = { .githubedit = "docs/architecture/inner_data_exchange.smd", - .prevurl = "docs/architecture/editor.zig", - .prevtext = "Editor", - .topurl = "docs/architecture", - .toptext = "Architecture", .codepath ="src/tui/editor.zig", }, --- 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). +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). This chapter describes the mechanisms that flow has to pass arguments between components. +[]($section.id('libraries')) ## Library usage -* The Thespian library sends and receives `thespian.message` values, which -are strongly typed, but schema free CBOR encoded structures. It supports -spawning, linking, killing, etc., of lightweight processes (aka the "Actor -Model" with "Green Threads") and provides async file and network IO and -child process management. +* The Thespian library sends and receives `thespian.message` values, +which are strongly typed, but schema free CBOR encoded structures. +It supports spawning, linking, killing, etc., of lightweight processes +(aka the "Actor Model" with "Green Threads") and provides async file +and network IO and child process management. * The CBOR library encodes decodes CBOR structured data to/from Zig variables - * Encoding happens via the `cbor.write*` functions. These are wrapped by - `command.fmt` and `thespian.message.fmt` which provide fast allocation - free encoding to a thread local buffer. Note that the CBOR data encoded - via the `*.fmt` functions will only survive until another message is - encoded and must be copied somewhere for more permanent storage, or - possibly sent somewhere via thespian. + * Encoding happens via the `cbor.write*` functions. These are wrapped + by `command.fmt` and `thespian.message.fmt` which provide fast + allocation free encoding to a thread local buffer. Note that the CBOR + data encoded via the `*.fmt` functions will only survive until another + 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. @@ -51,31 +49,19 @@ variables data buffer. `thespian.message.match` and `thespian.extract` functions are fairly simple wrappers. -### Example of command argument usage +The most basic example on deserialization of an integer value can is shown +in [commands](/docs/architecture/command#command_arguments). -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) -via its meta is declared as: - -```zig -pub const goto_line_meta: Meta = .{ .arguments = &.{.integer} }; -``` - -To actually receiving the integer parameter: - -```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; -``` - -Cbor features en/decoding arrays and compounds of basic types and the only -requirement is to decode in the same order as encoding the data, more -samples of usage 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 +multiple chunks of information, + + +[]($section.id('scoping')) ## Buffer scoping CBOR structures are mostly stored in a way that avoids allocation entirely. @@ -118,6 +104,17 @@ from. 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) + +[]($section.id('more')) ## More information * [Deepwiki on cbor](https://deepwiki.com/neurocyte/cbor) diff --git a/content/docs/architecture/keybind.smd b/content/docs/architecture/keybind.smd index 82d950d..164b57d 100644 --- a/content/docs/architecture/keybind.smd +++ b/content/docs/architecture/keybind.smd @@ -4,26 +4,31 @@ .author = "Igor Támara", .layout = "tutorial.shtml", .draft = false, -.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/keybind.md"}, +.custom = { + .githubedit = "/docs/architecture/keybind.smd", + .codepath ="src/keybind/builtin/", +}, --- -If you are here, it's possible that you already have edited your +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 extend your use cases and make everything easier and -fluid when in Flow. If you have not, take a peek to learning how -to do it. +topics to cope your use cases and make everything easier 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 -keybindings to suit your needs. +Using the command palette `Ctrl+Shift+p` and typing **Edit key +bindings**, takes you to the 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. []($section.id('tldr')) ## ;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, where the first element is the combination to map to the -commands that will happen, the array accepts strings like in +(internal mode) that will accept the key or keys/combo 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 ```js ["ctrl+alt+shift+p", "open_command_palette"] @@ -32,33 +37,37 @@ commands that will happen, the array accepts strings like in To avoid screwing up the combinations, and putting Flow in an unusable state derived from a wrong mapping of key combinations, read on. +[]($section.id('defaults')) ## Resetting keys to factory defaults -User configured keybindings are stored in Flow's configuration -directory under `keys/mode.json` where mode can be `flow`, -`emacs`, `vim`, `helix` or customized ones. Removing the keys -directory or the particular mode file can take you out from a -broken state. +User configured keybindings are stored in Flow's configuration directory +under `keys/mode.json` where mode can be `flow`, `emacs`, `vim`, `helix` +or customized ones. Removing the keys directory or the particular mode +file can take you out from a broken state. +[]($section.id('modes')) ## Keybinds for each mode -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 +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. [introducing keybindings](/devlog/2024#2024-12-05T20:55:00) showcases how to get to edit keybindings. +[]($section.id('hierarchy')) ## Keybindings hierarchy Some terminology -* **Mode**: Stored in a json file, like flow mode declared in `flow.json`. +* **Mode**: Stored in a json file, like flow mode declared in +`flow.json`. * **Imode**: under the json file. * **Major Imode**: `project` or descendant from `project`. -* **Minimodes**: To be used momentarily and do not inherit from `project`. +* **Minimodes**: To be used momentarily and do not inherit from +`project`. In general a keybinding json shows this hierarchy: @@ -67,41 +76,40 @@ Mode > Imode > press > Key and commands 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. +`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`, usually one will be using -only `press` inside `normal` imode or the specific mode -if inside `vim`, `helix` or `emacs` modes. +`project` is the main imode in `flow.json` and it can be noticed that +`normal` imode `inherit`s 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 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 hierarchy and it's common for major imodes to be -descendants from `project`. +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 +hierarchy and it's common for major imodes to be descendants from +`project`. +[]($section.id('adding')) ## Adding a Keybinding The most basic case to map a keybind to a command was covered in [TLDR](#tldr) which used the combination of three keys pressed -simultaneously `ctrl`, `shift` and `p`, all of them where combined -with `+` to execute the command `open_command_palette`. +simultaneously `ctrl`, `shift` and `p`, all of them where combined with +`+` to execute the command `open_command_palette`. -A common use case is to add a keybinding to invoke an already -existing command and chain it to another, making Flow more suited to your -own needs. +A common use case is to add a keybinding to invoke an already existing +command and chain it to another, making Flow more suited to your own +needs. []($section.id('shell')) ## Running shell commands -For example, `f5` by default is used to run `zig build test` -outputting its results to a *scratch buffer* called `test`. +For example, `f5` by default is used to run `zig build test` outputting +its results to a *scratch buffer* called `test`. ```js ["f5", ["create_scratch_buffer", "*test*"], ["shell_execute_insert", "zig", "build", "test"]], @@ -110,14 +118,13 @@ outputting its results to a *scratch buffer* called `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. +`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. ``` [ @@ -138,8 +145,21 @@ command. Observe [tasks running](/devlog/2025#2025-01-26T22:11:00) and maybe consider using more keybindings or running tasks for your projects. -Probably binding commands is good, but maybe there is a feature in -other texts editors that you miss and would love to have it at -your fingertips. Then it's Zig time: +[]($section.id('next')) +## Next steps + +If you realized that there is a handy combination that others can +benefit from or that a mode lacks the combination and it might be +included in flow, look at the [contribution guidelines](/docs/contributing) +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. + +* Making flow even better with [tests](/docs/testing) +* [How to contribute](/docs/contributing) +* [Get in touch](https://discord.com/invite/4wvteUPphx) to share your +combos diff --git a/content/docs/architecture/minimode.smd b/content/docs/architecture/minimode.smd index 28a8eae..ab3753c 100644 --- a/content/docs/architecture/minimode.smd +++ b/content/docs/architecture/minimode.smd @@ -4,7 +4,10 @@ .author = "Igor Támara", .layout = "tutorial.shtml", .draft = false, -.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/architecture/minimode.md"}, +.custom = { + .githubedit = "/docs/architecture/minimode.smd", + .codepath ="src/tui/mode/mini/", +}, --- Minimodes can be used by other modes adding functionality @@ -15,6 +18,7 @@ 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. +[]($section.id("anatomy")) ## Anatomy of minimodes To create a minimode it's needed: @@ -23,6 +27,7 @@ To create a minimode it's needed: * An Action mapping * A Minimode definition +[]($section.id("keybind")) ### Keybinding When a key or a keystroke(set of keys) are pressed, the @@ -34,6 +39,7 @@ and look for `mini_find`, where you will know which specific actions are triggered by the keybindings of the minimode. +[]($section.id("mapping")) ### Action mapping Actions executed by each minimode are stored one per @@ -46,6 +52,7 @@ 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 @@ -99,6 +106,7 @@ 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. +[]($section.id("custom_widgets")) ## A custom widget When there is a need for an specialized widget, it's possible to @@ -106,7 +114,10 @@ define one, for example, the `file_browser` is used to load and save files, and `numeric_input` is used to set the tab width for example(look for it in the command palette `:`). +[]($section.id("next")) +## Next steps * Head to [architecture](/docs/architecture) -* Learn about [commands](/docs/architecture/command) +* 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 c3da6be..a99aa85 100644 --- a/content/docs/architecture/palette.smd +++ b/content/docs/architecture/palette.smd @@ -5,35 +5,30 @@ .layout = "tutorial.shtml", .draft = false, .custom = { - .githubedit = "docs/architecture/palette.md", - .prevurl = "docs/minimode", - .prevtext = "Mini modes", - .topurl = "docs/architecture", - .toptext = "Architecture", + .githubedit = "docs/architecture/palette.smd", .codepath ="src/tui/mode/overlay/clipboard_palette.zig", }, --- 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. +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. -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 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 actions in response. +Palettes are an special case of minimode and for instance a mode, they +receive inputs from keyboards 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 +To get the most of this section, it's recommended to have read about +[commands](/docs/architecture/command), and optionally [minimodes](/docs/architecture/minimode). +[]($section.id("anatomy")) ## Defining the palette Palettes are under `tui/overlay` and use the facilities offered by @@ -43,11 +38,12 @@ Palettes are under `tui/overlay` and use the facilities offered by 2. Filtering the elements 3. Perform an action with the selected element -Note: Palettes are meant to show options and allowing to select -the options to execute an action on the given selection. To -maintain as readable as possible the code and thus extensible, -the data to be used should be prepared previously. +Note: Palettes are meant to show options and allowing to select the +options to execute an action on the given selection. To maintain as +readable as possible the code and thus extensible, the data to be used +should be prepared previously. +[]($section.id("basic")) ### Fields Basic fields that give hints to the user and need to be set are: @@ -59,10 +55,11 @@ pub const description = "clipboard"; pub const icon = " "; ``` +[]($section.id("entries")) ### Defining the list of elements in the palette -`load_entries` is in charge of populating the visible entries, -each one with an index. +`load_entries` is in charge of populating the visible entries, each one +with an index. ```zig pub fn load_entries(palette: *Type) !usize @@ -70,10 +67,10 @@ pub fn load_entries(palette: *Type) !usize 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. +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. ```zig pub fn add_menu_entry(palette: *Type, entry: *Entry, matches: ?[]const usize) !void { @@ -86,25 +83,36 @@ selected item is try palette.menu.add_item_with_handler(value.written(), select); ``` +[]($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 handled inside `select`, whose signature is: +selection and the palette needs to be closed. Those actions will be +handled inside `select`, whose signature is: ```zig 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 functions are -ready, it's time to make the palette available as a command. +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. +[]($section.id("register")) ## Registering the palette -Commands that open the palette are defined in `tui.zig` in a similar way as it -is done with [minimodes](/docs/architecture/minimode). We have got -you covered if in doubt about [how to create a command](/docs/architecture/command). +Commands that open the palette are defined in `tui.zig` in a similar way +it is done with [minimodes](/docs/architecture/minimode). We have got +you covered if in doubt about +[how to create a command](/docs/architecture/command). To view a complete implementation of a palette, take a look at [clipboard history palette commit](https://github.com/neurocyte/flow/commit/634a18cb5685a3c3fcfc08301306e628d33c3256) + +[]($section.id("next")) +## 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 8bd5def..e31114c 100644 --- a/content/docs/mode/helix.smd +++ b/content/docs/mode/helix.smd @@ -4,65 +4,64 @@ .author = "Igor Támara", .layout = "tutorial.shtml", .draft = false, -.custom = { .githubedit = "https://github.com/neurocyte/flow-website/tree/master/content/docs/mode/helix.md"}, +.custom = { + .githubedit = "/docs/mode/helix.smd", + .codepath = "src/tui/mode/helix.zig", +}, --- This document describes implementation of Helix Mode. ## What and what not -The first and biggest difference is that Flow has a mode that -emulates Helix, or at least has equivalent of the worthiest -actions that can be done in Helix. The conversely is not true. +The first and biggest difference is that Flow has a mode that emulates +Helix, or at least has equivalent of the worthiest actions that can be +done with Helix. The conversely is not true. `:` opens up Flow's rich command palette that might have -functionalities Helix users are used to have, if you find -something missing, it's possible to +functionalities Helix users are used to have, if you find something +missing, it's possible to [open a Feature Request](https://github.com/neurocyte/flow/issues), -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 if needed. +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 +if needed. ## Enhancing hx mode -This is a programmer editor, you are more than welcome to -enhance to suit your needs that maybe coincide with others. +This is a programmer 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 -[contributing](/docs/contributing) for an overview and the -mechanics of getting your changes into Flow. +[contributing](/docs/contributing) for an overview and the mechanics +of getting your changes into Flow. -hx mode is modal kind, the same as vim mode, and the file -that has the particular work to make it real is in -`src/tui/mode/helix.zig`, adding a `command` and the -corresponding `meta` is what is required. +hx mode is modal kind, the same as vim mode, and the file that has the +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). ### Pickers -Flow hx mode offers most of the picker types equivalents -with `panels` and `palettes`. Example of panels are -the `g` `r` (go to reference from lsp) and `space` `/` -(a.k.a find in files). Examples of `palettes` are -`space` `b` to pick a buffer or `space` `f` to open a -file in your project. Panels open below the editor -while palettes open overlapping the working area. +Flow hx mode offers most of the picker types equivalents with `panels` +and [palettes](/docs/architecture/palette). Example of panels are +the `g` `r` (go to reference from lsp) and `space` `/` (a.k.a find in +files). Examples of `palettes` are `space` `b` to pick a buffer or +`space` `f` to open a file in your project. Panels open below the +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. +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. -Given this, it's possible to start contributing via -pull requesting [keybinds](/docs/architecture/keybind), +Said all of this, it's possible to start contributing via pull +requesting [keybinds](/docs/architecture/keybind), [commands](/docs/architecture/command), -[palettes](/docs/architecture/palette), or the -special widget mentioned previously. - +[palettes](/docs/architecture/palette), or the special widget +mentioned previously. More about the [architecture](/docs/architecture) or jump to [contribution guidelines](/docs/contributing). \ No newline at end of file diff --git a/content/docs/testing.smd b/content/docs/testing.smd index 31c48d7..5ee58b3 100644 --- a/content/docs/testing.smd +++ b/content/docs/testing.smd @@ -5,7 +5,7 @@ .layout = "tutorial.shtml", .draft = false, .custom = { - .githubedit = "/docs/testing.md", + .githubedit = "/docs/testing.smd", .codepath ="test", }, --- 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 09/10] 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 From b01dfdb992103a6321269bfdadf132a948772f82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20T=C3=A1mara?= Date: Fri, 31 Oct 2025 08:53:12 -0500 Subject: [PATCH 10/10] Add more internal links and precisions on command arguments --- content/docs/architecture.smd | 13 +++++---- content/docs/architecture/command.smd | 26 +++++++++++------ content/docs/architecture/keybind.smd | 40 +++++++++++++++++---------- content/docs/index.smd | 4 +-- 4 files changed, 53 insertions(+), 30 deletions(-) diff --git a/content/docs/architecture.smd b/content/docs/architecture.smd index 0b5ce3f..5e8dbd4 100644 --- a/content/docs/architecture.smd +++ b/content/docs/architecture.smd @@ -140,14 +140,17 @@ logger.print("{} unsaved buffer(s) remaining", .{remaining}); ### View key presses There are situations when you press some keys without the expected -behavior happening, to review if flow is getting the keys, or your -desktop environment or something else are capturing them, you will want -to invoke flow with the option `--show-input`. +behavior happening, to review if flow is getting the keys, the +[keybindings are associated](/docs/architecture/keybind), and are +executing the [desired command](/docs/architecture/command), or maybe +your desktop environment or something else is capturing them, you will +want to invoke flow with the option `--show-input`. []($section.id("next")) ## Next steps -* [Guidelines for contributions](/docs/contributing) -* [Take a peek on testing](/docs/testing) * [Configure some keybinds](/docs/architecture/keybind) +* [Guidelines for contributions](/docs/contributing) +* [Create your own commands](/docs/architecture/command) +* [Take a peek on testing](/docs/testing) * [Back to docs](/docs) \ No newline at end of file diff --git a/content/docs/architecture/command.smd b/content/docs/architecture/command.smd index 081ba83..8d251cf 100644 --- a/content/docs/architecture/command.smd +++ b/content/docs/architecture/command.smd @@ -69,7 +69,7 @@ in Vim Mode `vim.zig`, `q` corresponds to (quit), the most famous one. ```zig pub fn q(_: *void, _: Ctx) Result { - try cmd("quit", .{}); + try command.cmd("quit", .{}); } pub const q_meta: Meta = .{ .description = "q (quit)" }; ``` @@ -122,14 +122,14 @@ pub fn select_to_char_left_helix(_: *void, ctx: Ctx) Result { `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: +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, `goto_line` will -extract it like this: +extract from the context like this: ```zig pub fn goto_line(self: *Self, ctx: Context) Result { @@ -140,9 +140,17 @@ pub fn goto_line(self: *Self, ctx: Context) Result { ``` 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 +the same when retrieving it. We will refer as encode and decode when +packing parameters in the context. To pack the `command.fmt` we will +encode it like this, when invoking `goto_line`. + +```zig +var the_line: usize = 43; +try command.cmd("goto_line", command.fmt(.{the_line - 1})); +``` + +Or calling the command directly, if we have a reference to the object +that holds the command. ```zig var the_line: usize = 43; @@ -150,10 +158,12 @@ 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. +and json, packing all of them in Command.Context. A deeper explanation of the rules about parameter passing is exposed in -[inner data exchange](/docs/architecture/inner_data_exchange). +[inner data exchange](/docs/architecture/inner_data_exchange), given +that parameters can be sent not only to commands, but other broather +use cases. []($section.id('next')) ## Next steps diff --git a/content/docs/architecture/keybind.smd b/content/docs/architecture/keybind.smd index b39c856..2ef1b31 100644 --- a/content/docs/architecture/keybind.smd +++ b/content/docs/architecture/keybind.smd @@ -12,29 +12,38 @@ 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, faster and -fluid when in Flow. +own keybinds to suit your use cases and make everything easier, faster +and more fluid when in flow. + +First make sure you are aware of the +[existence of ctrl+f2 palette](/docs#key_controls) which +exposes a list of commands available for you to use, and when you select +a command, it's pasted in your current cursor position. Using the command palette `Ctrl+Shift+p` and typing **Edit key -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. +bindings**, takes you to a json file to extend flow, configuring +keybindings to suit your needs. According to the mode you are in, your +personal mode's file configuration will be opened. Explore the +the file to discover how commands are bound to some combos, key presses +and the different [imodes](#hierarchy) present. + +Command palette can also be reached left clicking on the current +mode in the status bar. []($section.id('tldr')) ## ;TLDR; -Once you open the corresponding json file, locate inside the imode -(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 be invoked, the array accepts strings like in +Once you open the corresponding json file, locate inside the +[imode](#hierarchy)(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 be invoked, the array accepts strings +like in ```js ["ctrl+alt+shift+p", "open_command_palette"] ``` -To avoid screwing up the combinations, and putting Flow in an unusable +To avoid screwing up the combinations, and putting flow in an unusable state derived from a wrong mapping of key combinations, read on. []($section.id('defaults')) @@ -154,11 +163,12 @@ consider using more keybindings or running tasks for your projects. If you realized that there is a handy combination that others can benefit from or that a mode lacks the combination and it might be -included in flow, look at the [contribution guidelines](/docs/contributing) -to submit your findings and solution. +included in flow, look at the +[contribution guidelines](/docs/contributing) to submit your findings +and solutions. 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. +text editors that you miss and would love to have at your fingertips. Then it's Zig time: [Adding commands](/docs/architecture/command) to flow. diff --git a/content/docs/index.smd b/content/docs/index.smd index 5ed7ab1..641f3f7 100644 --- a/content/docs/index.smd +++ b/content/docs/index.smd @@ -15,7 +15,7 @@ command. The manual is included here for convenience. * [Flow Control online help](/docs/help) - +[]($section.id("basic_usage")) ## Basic Usage ```bash flow file.zig:42 # Open at line 42 @@ -24,7 +24,7 @@ flow --list-languages # Show all supported languages flow --help # List of command line options ``` - +[]($section.id("key_controls")) ## Key Controls | Command | Action | |---------------------------|----------------------|