diff --git a/docs/book.toml b/docs/book.toml index 5029b73d..0f9409f1 100644 --- a/docs/book.toml +++ b/docs/book.toml @@ -7,8 +7,8 @@ description = "A next-generation terminal multiplexer that records everything yo authors = ["Caleb Foust"] [output.html] -default-theme = "light" -preferred-dark-theme = "ayu" +default-theme = "navy" +preferred-dark-theme = "navy" site-url = "/cy/" git-repository-url = "https://github.com/cfoust/cy" additional-css = ["./theme/asciinema-player.css"] diff --git a/docs/gendoc.py b/docs/gendoc.py index 2c07bc99..a48b869d 100644 --- a/docs/gendoc.py +++ b/docs/gendoc.py @@ -13,6 +13,7 @@ GENDOC_REGEX = re.compile("{{gendoc (.+)}}") KEYS_REGEX = re.compile(r"{{keys (.+)}}") +API_REGEX = re.compile(r"{{api ([a-z0-9/]+)}}") class Symbol(NamedTuple): @@ -186,10 +187,17 @@ def render_keys(bindings: List[Binding], args: List[str]) -> str: binding['Function'] = symbol_lookup[func] bindings.append(Binding(**binding)) + errors: int = 0 + def report_error(chapter, start, end, msg): + global errors + errors += 1 + print(f"{chapter['name']}:{start}{end}: {msg}", file=sys.stderr) + def transform_chapter(chapter) -> None: replace = [] content = chapter['content'] + for ref in GENDOC_REGEX.finditer(content): command = ref.group(1) if len(command) == 0: @@ -227,6 +235,30 @@ def transform_chapter(chapter) -> None: ) ) + for ref in API_REGEX.finditer(content): + name = ref.group(1) + if len(name) == 0: + continue + + if not name in symbol_lookup: + report_error( + chapter, + ref.start(0), + ref.end(0), + f"missing symbol: {name}", + ) + continue + + symbol = symbol_lookup[name] + + replace.append( + ( + ref.start(0), + ref.end(0), + render_symbol_link(symbol), + ) + ) + for start, end, text in reversed(replace): content = content[:start] + text + content[end:] @@ -244,4 +276,8 @@ def transform_chapter(chapter) -> None: transform_chapter(section['Chapter']) + if errors > 0: + print(f"{errors} error(s) while preprocessing") + exit(1) + print(json.dumps(book)) diff --git a/docs/src/api.md b/docs/src/api.md index fe792a8a..c47d95f4 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -11,7 +11,7 @@ Janet code executed with `cy` can also access everything from [Janet's standard Several API functions related to binding keys return a `Binding`. A `Binding` table represents a single key sequence and its associated function. Each table has the following properties: - `:node`: the [NodeID](api.md#nodeid) where the binding is defined. -- `:sequence`: a list of strings representing the key sequence that will execute this action. If the original call to [`(key/bind)`](api.md#keybind) used a [regex](keybindings.md#regexes), it will be returned as a string with a `re:` prefix. +- `:sequence`: a list of strings representing the key sequence that will execute this action. If the original call to {{api key/bind}} used a [regex](keybindings.md#regexes), it will be returned as a string with a `re:` prefix. - `:function`: the Janet function that will be called when this sequence is executed. For example: @@ -29,6 +29,6 @@ For example: Many API functions have a parameter of type `NodeID`, which can be one of two values: - `:root` which is a short way of referring to `cy`'s top-level group. -- An integer that refers to a node in `cy`'s [node tree](groups-and-panes.md#the-node-tree). You cannot infer these yourself, but they are returned from API functions like [`(pane/current)`](api.md#panecurrent) and [`(group/children)`](api.md#groupchildren). +- An integer that refers to a node in `cy`'s [node tree](groups-and-panes.md#the-node-tree). You cannot infer these yourself, but they are returned from API functions like {{api pane/current}} and {{api group/children}}. {{gendoc api}} diff --git a/docs/src/default-keys.md b/docs/src/default-keys.md index 15dd63e6..de23dd0d 100644 --- a/docs/src/default-keys.md +++ b/docs/src/default-keys.md @@ -12,7 +12,7 @@ These bindings apply everywhere and can always be invoked. ### Prefixed -All of the bindings in this table are prefixed by ctrl+a by default. You can change the prefix for cy's bindings using [`(key/remap)`](api.md#keyremap). +All of the bindings in this table are prefixed by ctrl+a by default. You can change the prefix for cy's bindings using {{api key/remap}}. #### General @@ -34,7 +34,7 @@ These bindings are not prefixed by ctrl+a. ## Fuzzy finding -[`(input/find)`](api.md#inputfind) has several key bindings that are not yet configurable, but are worth documenting. +{{api input/find}} has several key bindings that are not yet configurable, but are worth documenting. | Sequence | Description | | ------------------------------------ | ----------------------------------- | @@ -45,7 +45,7 @@ These bindings are not prefixed by ctrl+a. ## Replay mode -The actions found in the tables below are only valid in a pane that is in replay mode. Replay mode uses two isolated binding scopes that can be accessed by providing `:time` (for time mode) or `:copy` (for copy mode) to a [`(key/bind)`](api.md#keybind) call: +The actions found in the tables below are only valid in a pane that is in replay mode. Replay mode uses two isolated binding scopes that can be accessed by providing `:time` (for time mode) or `:copy` (for copy mode) to a {{api key/bind}} call: ```janet (key/bind :time ["ctrl+b"] (fn [&] (do-something))) diff --git a/docs/src/fuzzy-finding.md b/docs/src/fuzzy-finding.md index 28849283..64dbbcc1 100644 --- a/docs/src/fuzzy-finding.md +++ b/docs/src/fuzzy-finding.md @@ -2,11 +2,11 @@ {{story cast input/find/full-bottom}} -Simple, fast, and configurable fuzzy finding is one of `cy`'s most important features. `cy` provides a purpose-built fuzzy finder (similar to [fzf](https://github.com/junegunn/fzf)) in the form of [`(input/find)`](./api.md#inputfind), which is a function available in [the API](./api.md#inputfind). +Simple, fast, and configurable fuzzy finding is one of `cy`'s most important features. `cy` provides a purpose-built fuzzy finder (similar to [fzf](https://github.com/junegunn/fzf)) in the form of {{api input/find}}, which is a function available in [the API](./api.md#inputfind). ## Choosing a string from a list -In its simplest form, [`(input/find)`](api.md#inputfind) takes a single parameter: a [Janet array](https://janet-lang.org/docs/data_structures/arrays.html) of strings that it will present to the user and from which they can choose a single option: +In its simplest form, {{api input/find}} takes a single parameter: a [Janet array](https://janet-lang.org/docs/data_structures/arrays.html) of strings that it will present to the user and from which they can choose a single option: ```janet (input/find @["one" "two" "three"]) @@ -16,7 +16,7 @@ By default, the background will be animated with one of `cy`'s [animations](./an ## Choosing an arbitrary value from a list -[`(input/find)`](api.md#inputfind) also allows you to ask the user to choose from a list of items, each of which has an underlying Janet value that is returned instead of the string value that the user filters. +{{api input/find}} also allows you to ask the user to choose from a list of items, each of which has an underlying Janet value that is returned instead of the string value that the user filters. You do this by providing a Janet array of tuples, each of which has two elements: @@ -30,13 +30,13 @@ You do this by providing a Janet array of tuples, each of which has two elements ["three" 3]]) ``` -If the user chooses `"one"`, [`(input/find)`](api.md#inputfind) will return `1`. +If the user chooses `"one"`, {{api input/find}} will return `1`. ## Filtering tabular data {{story cast input/find/table/full-bottom}} -It is sometimes handy to be able to have the user choose from a row in a table rather than a single line of text. [`(input/find)`](api.md#inputfind) allows you to provide tabular data in addition to titles for each column in the form of tuples. +It is sometimes handy to be able to have the user choose from a row in a table rather than a single line of text. {{api input/find}} allows you to provide tabular data in addition to titles for each column in the form of tuples. ```janet (input/find @@ -51,13 +51,13 @@ It is sometimes handy to be able to have the user choose from a row in a table r ## Choosing with previews -Where [`(input/find)`](api.md#inputfind) really shines, however, is in its ability to show a preview window for each option, which is conceptually similar to `fzf`'s `--preview` command line flag. [`(input/find)`](api.md#inputfind) can preview three different types of content: +Where {{api input/find}} really shines, however, is in its ability to show a preview window for each option, which is conceptually similar to `fzf`'s `--preview` command line flag. {{api input/find}} can preview three different types of content: - **Panes:** Show the current state of a pane in `cy`'s [node tree](./groups-and-panes.md#the-node-tree). This is the live view of a pane, regardless of how many other clients are interacting with it or what is happening on the screen. - **`.borg` files:** Show a moment in time in a `.borg` file. - **Text** Render some text. -Options with previews are passed to [`(input/find)`](api.md#inputfind) as Janet tuples with three elements: +Options with previews are passed to {{api input/find}} as Janet tuples with three elements: 1. The text (or columns) that the user will filter against 1. A Janet [table](https://janet-lang.org/docs/data_structures/tables.html) describing how this option should be previewed @@ -76,4 +76,4 @@ Here are some examples: ]) ``` -[`(input/find)`](api.md#inputfind) is used extensively in `cy`'s [default startup script](https://github.com/cfoust/cy/blob/main/pkg/cy/cy-boot.janet). You can find several idiomatic examples of its usage there. +{{api input/find}} is used extensively in `cy`'s [default startup script](https://github.com/cfoust/cy/blob/main/pkg/cy/cy-boot.janet). You can find several idiomatic examples of its usage there. diff --git a/docs/src/groups-and-panes.md b/docs/src/groups-and-panes.md index 77823fb5..5d1fbdce 100644 --- a/docs/src/groups-and-panes.md +++ b/docs/src/groups-and-panes.md @@ -13,7 +13,7 @@ Every pane `cy` belongs to a **group**. A group has a name and children, which c Groups also have two unique features: - **Key bindings:** You may define key bindings that will only activate when you type that sequence while attached to any descendant of that group. -- **Parameters:** A key-value store that can be interacted with using `(cy/get)` and `(cy/set)`. Parameters are used both [to configure aspects of `cy`](./parameters.md) and also to create any functionality you desire by storing state in `cy`'s tree. +- **Parameters:** A key-value store that can be interacted with using {{api cy/get}} and {{api cy/set}}. Parameters are used both [to configure aspects of `cy`](./parameters.md) and also to create any functionality you desire by storing state in `cy`'s tree. ## The node tree @@ -38,7 +38,7 @@ Instead, each node is permanently assigned a unique identifier (which is just an `cy`'s flexibility comes from the way key bindings and parameters interact: - **Key bindings** are inherited down the tree, but can be overridden by descendant groups. -- **Parameters** work the same way: [`(cy/get)`](api.md#cyget) will get the value of a parameter from the closest parent group that defines it. +- **Parameters** work the same way: {{api cy/get}} will get the value of a parameter from the closest parent group that defines it. Imagine that you are attached to `/my-project/group-2/pane-3` in the example above: diff --git a/docs/src/keybindings.md b/docs/src/keybindings.md index 9112f6b4..e1ea63ec 100644 --- a/docs/src/keybindings.md +++ b/docs/src/keybindings.md @@ -1,6 +1,6 @@ # Keybindings -In `cy`, keybindings consist of a sequence of one or more keys that execute Janet code when you type them. You define new key sequences with the [`(key/bind)`](api.md#keybind) function. +In `cy`, keybindings consist of a sequence of one or more keys that execute Janet code when you type them. You define new key sequences with the {{api key/bind}} function. For example: @@ -10,7 +10,7 @@ For example: This tells `cy` that whenever you type `ctrl+l` it should show a toast with the text "you hit ctrl+l". -The [`(key/bind)`](api.md#keybind) function takes three parameters: +The {{api key/bind}} function takes three parameters: 1. **A scope**: The circumstances in which this binding should apply, such as a [group](./groups-and-panes.md) or mode (e.g. `:time`). In this case we use the `:root` [keyword](https://janet-lang.org/docs/strings.html), which is a handy way of saying this binding should apply everywhere. 1. **A key sequence**: A Janet [tuple](https://janet-lang.org/docs/data_structures/tuples.html) that indicates the keys that must be typed for the callback to execute. @@ -18,7 +18,7 @@ The [`(key/bind)`](api.md#keybind) function takes three parameters: Scopes will be covered in a later chapter: here we will cover key sequences and functions at length. -You can avoid calling [`(key/bind)`](api.md#keybind) over and over by using the [`(key/bind-many)`](./api.md#keybind-many) macro. Here is an example: +You can avoid calling {{api key/bind}} over and over by using the {{api key/bind-many}} macro. Here is an example: ```janet (key/bind-many :root @@ -26,7 +26,7 @@ You can avoid calling [`(key/bind)`](api.md#keybind) over and over by using the ["ctrl+b" "2"] do-something-else) ``` -You can also clear previously bound key bindings with [`(key/unbind)`](./api.md#keyunbind) or rebind them with [`(key/remap)`](./api.md#keyremap). +You can also clear previously bound key bindings with {{api key/unbind}} or rebind them with {{api key/remap}}. ## Key sequences @@ -79,17 +79,17 @@ Accessing individual match groups is not supported; functions always receive the ## Functions -Any Janet function can be passed as a callback to [`(key/bind)`](api.md#keybind). The arity of that function should match the output of the provided sequence; for key sequences that do not include any regex patterns, this means that the function should not take any arguments. +Any Janet function can be passed as a callback to {{api key/bind}}. The arity of that function should match the output of the provided sequence; for key sequences that do not include any regex patterns, this means that the function should not take any arguments. -Like `tmux`, many users at once can connect to the same `cy` server. The function provided to [`(key/bind)`](api.md#keybind) **is executed in the context of the user that invoked it**. Certain functions in `cy`'s API, such as [`(pane/current)`](api.md#panecurrent), return information about the state of the current user, rather than the server as a whole. This means that if two users type the same sequence, they will get different results. +Like `tmux`, many users at once can connect to the same `cy` server. The function provided to {{api key/bind}} **is executed in the context of the user that invoked it**. Certain functions in `cy`'s API, such as {{api pane/current}}, return information about the state of the current user, rather than the server as a whole. This means that if two users type the same sequence, they will get different results. ### Actions -In some cases it is inconvenient to have to provide functions directly to [`(key/bind)`](api.md#keybind). For example, if you are writing a plugin, you might want to be able to provide new actions that a user can take without forcing them to use your key bindings. The user also may not want to assign all of your plugin's functionality to arcane bindings they won't remember. +In some cases it is inconvenient to have to provide functions directly to {{api key/bind}}. For example, if you are writing a plugin, you might want to be able to provide new actions that a user can take without forcing them to use your key bindings. The user also may not want to assign all of your plugin's functionality to arcane bindings they won't remember. To assist with this, `cy` has a system for **actions**, which are similar in nature to commands [in VSCode](https://code.visualstudio.com/api/extension-guides/command) or [in Sublime Text](https://docs.sublimetext.io/reference/commands.html). An action consists of a short description and a function. When the user opens the command palette (which is bound by default to `"ctrl+a" "ctrl+p"`), they can search for and execute an action based on that description. -You define new actions using the [`(key/action)`](api.md#keyaction) macro. Here is an example from `cy`'s source code: +You define new actions using the {{api key/action}} macro. Here is an example from `cy`'s source code: ```janet (key/action @@ -106,7 +106,7 @@ You define new actions using the [`(key/action)`](api.md#keyaction) macro. Here (key/bind :root ["ctrl+b" "b"] cy/kill-current-pane) ``` -[`(key/action)`](api.md#keyaction) actually just invokes Janet's `(defn)` macro under the hood. This means that actions are just ordinary Janet functions that happen to be registered with `cy`. [`(key/action)`](api.md#keyaction) exists so that you can clearly identify to the user the functionality your plugin provides. +{{api key/action}} actually just invokes Janet's `(defn)` macro under the hood. This means that actions are just ordinary Janet functions that happen to be registered with `cy`. {{api key/action}} exists so that you can clearly identify to the user the functionality your plugin provides. You can also just use actions to avoid memorizing a key binding you rarely use: @@ -119,7 +119,7 @@ You can also just use actions to avoid memorizing a key binding you rarely use: ## Changing and deleting existing keybindings -`cy` provides two API functions for manipulating existing keybindings, [`(key/remap)`](api.md#keyremap) and [`(key/unbind)`](api.md#keyunbind). +`cy` provides two API functions for manipulating existing keybindings, {{api key/remap}} and {{api key/unbind}}. It is sometimes convenient to change the activation sequence for many bindings at once. For example, you may want to change the prefix used for most of cy's bindings, ctrl+a, into ctrl+v: @@ -127,4 +127,4 @@ It is sometimes convenient to change the activation sequence for many bindings a (key/remap :root ["ctrl+a"] ["ctrl+v"]) ``` -Similarly, you may also delete keybindings with [`(key/unbind)`](api.md#keyunbind). +Similarly, you may also delete keybindings with {{api key/unbind}}. diff --git a/docs/src/parameters.md b/docs/src/parameters.md index 80103d9d..ece539bc 100644 --- a/docs/src/parameters.md +++ b/docs/src/parameters.md @@ -2,7 +2,7 @@ `cy` contains a primitive key-value store it refers to as parameters. In addition to being available for use from Janet for arbitrary purposes, parameters are also the primary means of configuring `cy`'s behavior. -Parameters are set with [`(cy/set)`](api.md#cyset) and retrieved with [`(cy/get)`](api.md#cyget): +Parameters are set with {{api cy/set}} and retrieved with {{api cy/get}}: ```janet (cy/set :some-parameter true) @@ -19,4 +19,4 @@ Some parameters are used by `cy` to change how it performs certain operations. | ---------------- | ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | | `:data-dir` | [inferred on startup](replay-mode.md#recording-terminal-sessions-to-disk) | the directory in which `.borg` files are saved; if empty, recording to file is disabled | | `:animate` | `true` | whether animations are enabled (disabled over SSH connections by default) | -| `:default-shell` | inferred from `$SHELL` on startup | the default command used for [`(cmd/new)`](api.md#cmdnew) | +| `:default-shell` | inferred from `$SHELL` on startup | the default command used for {{api cmd/new}} | diff --git a/docs/src/replay-mode.md b/docs/src/replay-mode.md index 1be69a9e..cbf3051c 100644 --- a/docs/src/replay-mode.md +++ b/docs/src/replay-mode.md @@ -62,4 +62,4 @@ The directory will be created if it does not exist. You can access previous sessions through the `cy/open-log` action, which by default can be invoked by searching for `open an existing log file` in the command palette (`ctrl+a` `ctrl+p`). -You are also free to use the API call [`(replay/open)`](api.md#replayopen) to open `.borg` files anywhere on your filesystem. +You are also free to use the API call {{api replay/open}} to open `.borg` files anywhere on your filesystem.