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
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
|
# 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
### Function Types
A **Selection function** is something of signature `Selection × Selection → Selection`.
A **Text function** is something of signature `Selection × Text → Selection`.
Following APL conventions, functions may have nullary, monadic, and dyadic forms. In these cases the number of arguments that they take varies (though not their types).
### [Leading axis theory](https://aplwiki.com/wiki/Leading_axis_theory) and broadcasting
The leading axis is the buffer selection, followed by the range _index_, followed by the character position in each range. When broadcasting occurs axes are aligned.
TODO `α F ω` explain
### Trains
TODO
## 1.2 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.
## 1.3 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.
## 1.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.
## 1.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
# 1.6 Composition and Parsing
**Precedence:** Following BQN rules:
- Operators bind tighter than functions
- Functions and operators apply left-to-right
- Dyadic functions are infix
# 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
## 3.1 Text Operations
Text operations have signature `Selection × Text → Selection`. They modify the editor state (buffer contents) and return the affected Selection.
Text operations use [leading axis theory](https://aplwiki.com/wiki/Leading_axis_theory) where buffer names are the leading axis: TODO TODO TODO if `α F β` where `β` is rank 2 but `α` is rank 1, then operation applies once per range in `β`, using the contents of each range as the text argument.
| Function | Effect | Return selection |
|----------|--------------------------------------------------------------|----------------------|
| `.` | No-op | Current selection |
| `c` | No-op | Current selection |
| `i` | No-op | Current selection |
| `a` | No-op | Current selection |
| `d` | Delete current selection in | Empty selection |
| `w` | Write the current buffer to its associated file. | Current selection |
| `\|` | Run current selection as shell commands, replace with output | Selection of outputs |
**Note:** `\|` is undefined when the rank of the current selection is 0.
| Function | Effect | Return selection |
|----------|--------------------------------------------------|---------------------------------------------|
| `. τ` | No-op | Current selection in buffers named by `τ` |
| `c τ` | No-op | Replace the current selection by `τ` |
| `i τ` | No-op | Insert `τ` into the current selection |
| `a τ` | No-op | Append `τ` to the current selection |
| `d τ` | Delete current selection in buffers named by `τ` | Empty selection in buffers named by `τ` |
| `w τ` | Write the buffers named by `τ`. | Current selection in buffers named by `τ` |
| `\| τ` | Run `τ` | Return selection of ephemeral buffer output |
**Note:** The text argument `τ` may be a string literal or a Selection (which coerces to Text).
**Note:** `\|` and `d` are undefined when the rank of `τ` is 0.
| Function | Effect | Semantics |
|----------|------------------------------------------------------|-----------------------------------------------------------|
| `α . τ` | No-op | Current selection in buffer(s) named by `τ` (`α` ignored) |
| `α c τ` | No-op | Change (replace) `α` with text `τ` |
| `α i τ` | No-op | Insert text `τ` before `α` |
| `α a τ` | No-op | Append text `τ` after `α` |
| `α d τ` | Delete `α` in buffers named by `τ` | Empty selection in buffers nameb by `τ` |
| `α w τ` | Write (concatenation of) `α` in buffers named by `τ` | `α` |
| `α \| τ` | Pipe `α` through command `τ` | Return selection of ephemeral output buffer |
**Examples:**
TODO: throw some combinators in to make this example nicer.
```
| "date" # Run date with no input, returns selection to output
/pattern/ c (| "date") # Replace pattern with date command output
selection c (selection | "sort") # Pipe selection through sort, replace with result
```
An idiom
```
α {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 β.
|