aboutsummaryrefslogtreecommitdiff
path: root/rprt.md
blob: e34e9cf6c2e4e2c2c5d6e05c82628ced56800d71 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
# 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. Seven have nullary and monadic forms. Two (`e`, `B`) have nullary form only. 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.

**Note:** The functions `eB` have no monadic or dyadic forms. To use them as such is an error condition.

**Note:** When the input has rank 0 (position), all defined monadic functions are the identity since positions have no internal structure within which to search or operate.

| Function  | Semantics for rank 1 `α` |
|-----------|--------------------------|
| `α /re/`  | First re within `α`      |
| `α x/re/` | All re within`α`         |
| `α $`     | End position of`α`       |
| `α #n`    | Char n within`α`         |
| `α n`     | Line n within`α`         |
| `α +n`    | Line n within`α`         |
| `α -`     | Identity                 |

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 `e-B` .

| Function | Nullary                        | Rank |
|----------|--------------------------------|------|
| `'$`     | 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 1 `α`         |
|------------|----------------------------------|
| `α '$`     | 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 `α`               |

**Note:** When the input has rank 0 (position), all defined reversed monadic functions are the identity since positions have no internal structure within which to search or operate.

### 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 `e-B` .

| Function   | Semantics for rank 0 `α`     | Semantics for rank 1 `α`            |
|------------|------------------------------|-------------------------------------|
| `α ;$`     | 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