# Rank PolymoRphic Text editor (RPRT) A compositional, point-free language for text manipulation. # 1. Core Concepts ## 1.1 Two Fundamental Types All functions work with two core types: 1. **Selection** — addresses and regions in buffers Every selection exists within one or more buffers. Selections have a rank: - **Rank 0**: Position — a natural number offset within a single buffer - **Rank 1**: Range — a pair of positions [start,end) with capture groups, within a single buffer - **Rank 2**: Ranges — a list of ranges with capture groups, within a single buffer - **Rank 3**: Multi-buffer selection — a mapping from buffer identifiers to rank 2 selections Ranks 0-2 operate within a single buffer (typically the current buffer). Rank 3 is distinguished by spanning multiple buffers simultaneously. 2. **Text** — string data # 2. Selection Functions Selection functions produce Selection outputs and take zero (nullary functions), one (monadic functions), or two (dyadic functions) inputs of type Selection. ## 2.1 Core Selection Functions There are ten core selection functions in RPRT. All ten have nullary and monadic forms, while the function `-` additionally has dyadic semantics---it is the only selection function that may take two arguments. | Function | Nullary semantics | Output rank | |------------|------------------------------------------------------------|-------------| | `e` | Empty selection | 2 | | `$` | End of buffer | 0 | | `#n` (n∈ℕ) | Character n in buffer | 0 | | `n` (n∈ℕ) | Line n in buffer | 1 | | `/re/` | First match forward in buffer from start | 1 | | `x/re/` | All matches within buffer | 2 | | `+n` | Line n in buffer | 1 | | `B/re/` | All buffers whose name match re, mapping to their contents | 3 | | `-` | Entire buffer (0-$) | 2 | In the monadic case, all defined functions are rank preserving. Their action on ranks > 1 are given by broadcasting, that is, `α F` where `α` has rank 2 is computed by applying `F` to each rank 1 range in `α` and collecting the results into a list of ranges, mutatis mutandis for rank 3. | Function | Semantics for rank 0 `α` | Semantics for rank 1 `α` | |-----------|----------------------------------|------------------------------------------| | `α e` | Empty selection (rank 2) | Empty selection (rank 2) | | `α $` | `α` | End position of `α` | | `α #n` | `α` | Char n within `α` | | `α n` | `α` | Line n within `α` | | `α /re/` | `α` | First re within `α` | | `α x/re/` | `α` | All re within `α` | | `α +n` | `α` | Line n within `α` | | `α B/re/` | Buffer matches `re`? `α` : empty | buffer matches `re`? `α` : empty | | `α -` | Range from `α` to end of buffer | Range from start of `α` to end of buffer | The span function `-` is the only selection function with dyadic semantics. It creates ranges by spanning from one selection to another. | Rank of `α` | Rank of `ω` | Rank of `α-ω` | Semantics | |-------------|-------------|---------------|-------------------------------------------------------| | 0 | 0 | 1 | Range from `α` to `ω` | | 0 | 1 | 1 | Range from `α` to end of `ω` | | 1 | 0 | 1 | Range from start of `α` to `ω` | | 1 | 1 | 1 | Range from start of `α` to end of `ω` | | 0/1 | 2 | 2 | `α` to each range in `ω` (broadcast) | | 2 | 0/1 | 2 | Each range in `α` to `ω` (broadcast) | | 2 | 2 | 2 | Pairwise ranges (zip shortest) | | 0 | 3 | 3 | `α` to each range in `ω` (broadcast) | | 3 | 0 | 3 | Each range in `α` to `ω` (broadcast) | | 3 | 1/2 | - | Erroneous (TODO: maybe makes sense if indices align?) | | 1/2 | 3 | - | Erroneous (TODO: maybe makes sense if indices align?) | ## 2.2 Selection Function Operators Operators take functions as arguments and return new functions. ### 2.2.1 The Reverse Operator `'` The reverse operator `'` takes a selection function and reverses its direction. **Note:** `'F` is not defined when `F` is one of the functions `B-` . | Function | Nullary | Rank | |----------|--------------------------------|------| | `'e` | synonymous with `e` | 2 | | `'$` | Start of buffer (position 0) | 0 | | `'#n` | Character n from end of buffer | 0 | | `'n` | Line n from end of buffer | 1 | | `'/re/` | First match backward from end | 1 | | `'x/re/` | All matches, right-to-left | 2 | | `'+n` | Line -n in buffer | 1 | In the monadic case, all functions are rank preserving, and all of the above functions are the identity on rank 0 inputs. Their action on ranks > 1 is by broadcasting. | Function | Semantics for rank 0 `α` | Semantics for rank 1 `α` | |------------|--------------------------|----------------------------------| | `α 'e` | Empty selection (rank 2) | Empty selection (rank 2) | | `α '$` | `α` | Start position of `α` | | `α '#n` | `α` | Char n from end of `α` | | `α 'n` | `α` | Line n from end of `α` | | `α '/re/` | `α` | First match backward within `α` | | `α 'x/re/` | `α` | All matches right-to-left in `α` | | `α '+n` | `α` | Line -n within `α` | ### 2.2.2 The Sequential Operator `;` The sequential operator `;` transforms a selection function from operating "within" a selection to operating "starting from the end" of that selection. **Note:** It is erroneous to use `;F` in the nullary case. TODO: or are there interesting semantics? **Note:** `;F` is not defined when `F` is one of `B-` . | Function | Semantics for rank 0 `α` | Semantics for rank 1 `α` | |------------|------------------------------|-------------------------------------| | `α ;e` | Empty selection (rank 2) | Empty selection (rank 2) | | `α ;$` | End of buffer | End of buffer (ignores `α`) | | `α ;#n` | Character n after `α` | Character n after end of `α` | | `α ;n` | Line n after `α` | Line n after end of `α` | | `α ;/re/` | First match forward from `α` | First match forward from end of `α` | | `α ;x/re/` | All matches forward from `α` | All matches forward from end of `α` | | `α ;+n` | Line n after `α` | Line n after end of `α` | ### 2.2.3 The Complement Operator `~` The complement operator `~` takes a selection function and produces a new selection function which returns the complement. Naturally this changes rank somewhat, as explained in the below table. | Rank of output of `F` | Rank of output of `~F` | Semantics | |-----------------------|------------------------|------------------------------------------------------------------| | 0 | 2 | The complement of the position its buffer as a selection | | 1 | 2 | The complement of the range in its buffer as a selection | | 2 | 2 | The selection corresponding to the ranges between the selections | | 3 | 3 | The broadcast of `~` to each buffer | # 3. Text Functions and Editor State ## 3.1 The Editor State Monad All RPRT expressions evaluate within an implicit `EditorState` monad containing: - Buffer contents (for all open buffers) - Current buffer - Current selection - File/buffer mappings Selection and Text functions have signatures `EditorState Selection` and `EditorState Text` respectively. ## 3.2 Type Coercion When a Text argument is required, a Selection is implicitly coerced to Text by extracting its contents. This coercion has no side effects. | Input rank | Coerced Text | |------------|------------------------------------------------------------------| | 0 | Empty string (position has no extent) | | 1 | Contents of the range | | 2 | Contents of each range (text function broadcasts per range) | | 3 | Contents per buffer per range (broadcasts per buffer then range) | For ranks 2 and 3, the selection provides multiple text values. Text operations broadcast accordingly: if `α F β` where β is rank 2, the operation applies once per range in β, using the contents of each range as the text argument. ## 3.3 Text Operations Text operations have signature `Selection × Text → Selection`. They modify the editor state (buffer contents) and return the affected Selection. TODO: unfortunately `.` and `d` ignore opposite arguments so we're stuck with not being able to give monadic text funcions? | Function | Semantics | |----------|------------------------------------------------------------------------| | `α . τ` | Current selection in buffer(s) named by `τ` (`α` ignored) | | `α c τ` | Change (replace) `α` with text `τ` | | `α i τ` | Insert text `τ` before `α` | | `α a τ` | Append text `τ` after `α` | | `α d τ` | Delete `α` (`τ` ignored) | | `α w τ` | Write buffers associated with `α` (`τ` ignored) | | `α \| τ` | Pipe `α` through command `τ`, return rank 3 selection of output buffer | **Note:** The text argument `τ` may be a string literal or a Selection (which coerces to Text). **Note:** The `.` function unifies multiple use cases: - `.` (nullary) — current selection in current buffer - `e . "name"` — current selection in buffer "name" - `e . β` where β is rank 2 or 3 — current selections in buffers named by β's contents (returns rank 3) ## 3.4 Evaluation Contexts **Top-level Selection:** Sets the editor's current selection. ``` α # Finds pattern AND sets editor selection to it ``` **All text operations:** Modify editor content. Note that `F` returns a selection, so at the top level this also changes the current selection. ``` α F τ # F modifies contents, sets selection to changed region. α F (β G τ) # Inner G modifies contents but doesn't set selection. F modifies contents and sets the new selection. ``` **Buffer switching statement:** The `b` statement changes the current buffer in the EditorState. ``` b "name" # Switch current buffer to "name" /pattern/ # Searches in "name" ``` The `b` statement is not a function and cannot be composed. It only appears as a top-level statement. ## 3.5 The Grouping Operator `{}` The grouping operator `{}` provides transactional semantics: all operations within see the same input editor state, and their modifications are merged with position tracking where possible. Any error aborts the entire evaluation. **Syntax:** `{ op₁ , op₂ , ... , opₙ }` **Semantics:** - Captures editor state on entry - All operations execute with the original positions - Returns the union of all resulting Selections **Example:** Where `α` and `β` are selections ``` α {swap i , d} β ``` Evaluates in parallel * `α (swap i) β` which is `β i α` which means "insert at (the start of) β the content from α" * `α d β` which means "delete α" The net result of this is to _move_ the content of α to (the start of) the selection given by β. ## 3.6 Shell Integration The `|` text function pipes selections through shell commands, returning rank 3 selections for ephemeral buffers containing command output. Use the empty selection `e` to run commands with no stdin. **Examples:** TODO: throw some combinators in to make this example nicer. ``` e | "date" # Run date with no input, returns selection to output /pattern/ c (e | "date") # Replace pattern with date command output selection c (selection | "sort") # Pipe selection through sort, replace with result ``` # 4 Composition and Parsing **Precedence:** Following BQN rules: - Operators bind tighter than functions - Functions and operators apply left-to-right - Dyadic functions are infix