# Operations reference

> Every operation a stetdoc batch can hold, with its fields, whether Word tracks it, and an example in block text.

Source: https://stetdoc.clauseo.chat/docs/reference/operations · stetdoc 0.9.1

There are 19 operations. A batch names the base token it was written against and lists operations, which apply completely or not at all. Every operation is a JSON object with an `op` field, and an unknown field is refused. A range inside a paragraph is `find` (which must match once, or `occurrence` says which match) or `start` and `end` (offsets in the paragraph's Final text, in Unicode scalar values unless the edit asks for UTF-16 units), or nothing for the whole paragraph.

## Block text

Block text is the same batch without JSON escaping. The grammar is provisional until the format experiments settle it.

```text
base: 3f9a0c11d2b4e577:7:51ac09f2e8b34d11
---
@replace
ref: p42
find: the Supplier shall
with: the Supplier must
---
@insert
ref: p42
place: after
paragraphs: <<END
A first new paragraph.
A second one.
END
```

A stanza starts with `@name`. A field is `key: value` on one line, or `key: <<TAG` and the lines up to a line that is exactly `TAG`. A key that is not a field of the operation is refused. What a newline means depends on the kind of the field:

| Kind | One line | Heredoc | A newline inside the value |
|---|---|---|---|
| text | everything after the first `: ` | the lines, joined by a newline | only in a heredoc |
| list | one entry | one entry for each line | never inside an entry |
| ref, choice, number, bool | the value | not allowed | never |

## Summary

| Operation | What it does | Tracked | Reversible |
|---|---|---|---|
| [`replace`](#replace) | Replaces a text range, or the whole paragraph, with new text. The difference is made word by word. | yes | yes |
| [`insert`](#insert) | Inserts new paragraphs before or after a paragraph or a table, in order. | yes | yes |
| [`delete`](#delete) | Deletes a whole paragraph or table, a text range, or the blocks from one paragraph through another. | yes | yes |
| [`split`](#split) | Cuts a paragraph in two, at an offset or before or after some text. | yes | yes |
| [`merge`](#merge) | Joins a paragraph and the one after it. | yes | yes |
| [`format`](#format) | Changes the formatting of the runs in a range, or of the whole paragraph. | yes | yes |
| [`paragraph`](#paragraph) | Changes the formatting of a paragraph. Values take units such as 0.5in, 6pt and 1.5cm. | yes | yes |
| [`style`](#style) | Sets the paragraph style. | yes | yes |
| [`list`](#list) | Changes the level of a list item, restarts its numbering at a number, or takes it out of the list. | yes | yes |
| [`set`](#set) | Sets any schema property of a paragraph, run, paragraph mark, section, table, row or cell. | yes | yes |
| [`row`](#row) | Inserts a table row, or deletes one. | yes | yes |
| [`comment`](#comment) | Adds a comment anchored to a range, or to the whole paragraph. | no | no |
| [`reply`](#reply) | Replies to a comment thread. | no | no |
| [`resolve`](#resolve) | Resolves a comment thread, or reopens it. | no | no |
| [`edit-comment`](#edit-comment) | Replaces the text of one of the author's own comments. | no | no |
| [`delete-comment`](#delete-comment) | Deletes one of the author's own comments, with its replies. | no | no |
| [`delete-note`](#delete-note) | Deletes a footnote or endnote, with its reference. | yes | yes |
| [`accept`](#accept) | Accepts revisions: applies them. | no | no |
| [`reject`](#reject) | Rejects revisions: undoes them. | no | no |

## `replace`

Replaces a text range, or the whole paragraph, with new text. The difference is made word by word.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph. |
| `with` | text | yes | The new text. A newline is a line break inside the paragraph, and a tab is written as a tab. |
| `find` | text | no | The text to find in the paragraph's Final text. It must match once, or `occurrence` says which match. A newline matches a line break of the paragraph. |
| `occurrence` | number | no | Which match of `find` to use, counted from 1. |
| `start` | number | no | The first character of the range, as an offset in the Final text. Not with `find`. |
| `end` | number | no | One past the last character of the range, as an offset in the Final text. Not with `find`. |

```json
{"op":"replace","ref":"p42","find":"shall","with":"must"}
```

## `insert`

Inserts new paragraphs before or after a paragraph or a table, in order.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph or table the new paragraphs go next to. |
| `place` | choice | yes | Whether they go before or after it. One of `before`, `after`. |
| `paragraphs` | list | yes | The paragraphs, in order. Each is one paragraph of text, and a newline inside one is a line break of that paragraph. In JSON an entry may be an object with a text and a style, and in block text one style applies to all. |

```json
{"op":"insert","ref":"p42","place":"after","paragraphs":["A new paragraph."]}
```

## `delete`

Deletes a whole paragraph or table, a text range, or the blocks from one paragraph through another.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph, table or first paragraph of the range. |
| `to` | ref | no | The last paragraph of a range that spans paragraphs. Then `start` is an offset in `ref` and `end` an offset in `to`. |
| `find` | text | no | The text to find in the paragraph's Final text. It must match once, or `occurrence` says which match. A newline matches a line break of the paragraph. |
| `occurrence` | number | no | Which match of `find` to use, counted from 1. |
| `start` | number | no | The first character of the range, as an offset in the Final text. Not with `find`. |
| `end` | number | no | One past the last character of the range, as an offset in the Final text. Not with `find`. |

```json
{"op":"delete","ref":"p42"}
```

## `split`

Cuts a paragraph in two, at an offset or before or after some text.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes. Give exactly one of `at`, `before`, `after`.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph. |
| `at` | number | no | The offset of the cut in the Final text. |
| `before` | text | no | Cut just before this text, which must match once. A newline matches a line break. |
| `after` | text | no | Cut just after this text, which must match once. A newline matches a line break. |

```json
{"op":"split","ref":"p42","before":"Notwithstanding"}
```

## `merge`

Joins a paragraph and the one after it.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph that stays. |
| `second` | ref | no | The paragraph that is joined into it. By default the next paragraph that is not a deleted block. |

```json
{"op":"merge","ref":"p42"}
```

## `format`

Changes the formatting of the runs in a range, or of the whole paragraph.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph. |
| `bold` | bool | no | Bold on or off. |
| `italic` | bool | no | Italic on or off. |
| `underline` | text | no | The underline style: `single`, `double`, `none` and the others Word has. |
| `strike` | bool | no | Strike through on or off. |
| `color` | text | no | The text colour, `RRGGBB` or `auto`. |
| `highlight` | text | no | The highlight colour, by Word's name. |
| `size` | text | no | The font size with a unit, such as `12pt`. |
| `font` | text | no | The font name. |
| `char_style` | text | no | The id or name of a character style. |
| `clear` | list | no | The names of formatting to remove, one for each entry. |
| `find` | text | no | The text to find in the paragraph's Final text. It must match once, or `occurrence` says which match. A newline matches a line break of the paragraph. |
| `occurrence` | number | no | Which match of `find` to use, counted from 1. |
| `start` | number | no | The first character of the range, as an offset in the Final text. Not with `find`. |
| `end` | number | no | One past the last character of the range, as an offset in the Final text. Not with `find`. |

```json
{"op":"format","ref":"p42","find":"Losses","bold":true}
```

## `paragraph`

Changes the formatting of a paragraph. Values take units such as 0.5in, 6pt and 1.5cm.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph. |
| `align` | choice | no | The alignment. One of `left`, `center`, `right`, `justify`. |
| `indent_left` | text | no | The left indent. |
| `indent_right` | text | no | The right indent. |
| `first_line` | text | no | The indent of the first line. |
| `hanging` | text | no | The hanging indent. |
| `space_before` | text | no | The space before the paragraph. |
| `space_after` | text | no | The space after the paragraph. |
| `line_spacing` | text | no | The line spacing. |
| `keep_next` | bool | no | Keep with the next paragraph. |
| `keep_lines` | bool | no | Keep the lines together. |
| `page_break_before` | bool | no | Start a new page before the paragraph. |
| `clear` | list | no | The names of properties to remove, one for each entry. |

```json
{"op":"paragraph","ref":"p42","align":"center","space_after":"6pt"}
```

## `style`

Sets the paragraph style.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph. |
| `style` | text | yes | The style, by id or by name as the view shows it. One line. |

```json
{"op":"style","ref":"p42","style":"Heading 2"}
```

## `list`

Changes the level of a list item, restarts its numbering at a number, or takes it out of the list.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes. Give exactly one of `level`, `restart`, `remove`.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph. |
| `level` | number | no | The new level, from 0. |
| `restart` | number | no | Restart the numbering at this number. |
| `remove` | bool | no | Take the paragraph out of its list. |

```json
{"op":"list","ref":"p42","level":1}
```

## `set`

Sets any schema property of a paragraph, run, paragraph mark, section, table, row or cell.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `props` | properties | yes | The properties to set. In block text each line is a name, an optional value and `attribute=value` pairs, with no spaces inside a value. A property with children is JSON only. |
| `target` | choice | no | What to set it on. By default from the kind of `ref`. One of `paragraph`, `run`, `mark`, `section`, `table`, `row`, `cell`. |
| `ref` | ref | no | The paragraph, table or row. A section is named by `section` instead. |
| `section` | number | no | The number of the section, as `inspect sections` shows it, from 1. |
| `cell` | number | no | The cell of a row, from 1. |
| `clear` | list | no | The names of properties to remove, one for each entry. |
| `find` | text | no | The text to find in the paragraph's Final text. It must match once, or `occurrence` says which match. A newline matches a line break of the paragraph. |
| `occurrence` | number | no | Which match of `find` to use, counted from 1. |
| `start` | number | no | The first character of the range, as an offset in the Final text. Not with `find`. |
| `end` | number | no | One past the last character of the range, as an offset in the Final text. Not with `find`. |

```json
{"op":"set","ref":"p42","props":[{"name":"jc","val":"center"}]}
```

## `row`

Inserts a table row, or deletes one.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The row. |
| `action` | choice | yes | Whether to insert a row next to this one or delete it. One of `insert`, `delete`. |
| `place` | choice | no | For an insert, whether the new row goes before or after. After by default. One of `before`, `after`. |
| `cells` | list | no | For an insert, the text of each cell, in order. A newline inside one is a line break of the cell. |

```json
{"op":"row","ref":"r17","action":"delete"}
```

## `comment`

Adds a comment anchored to a range, or to the whole paragraph.

Tracked as revisions: no. Reversible by rejecting what it wrote: no.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `ref` | ref | yes | The paragraph. |
| `text` | text | yes | The text of the comment. A newline is a paragraph break of the comment, which has no line break inside a paragraph. |
| `initials` | text | no | The initials shown with the comment. By default the first letters of the author's words. |
| `find` | text | no | The text to find in the paragraph's Final text. It must match once, or `occurrence` says which match. A newline matches a line break of the paragraph. |
| `occurrence` | number | no | Which match of `find` to use, counted from 1. |
| `start` | number | no | The first character of the range, as an offset in the Final text. Not with `find`. |
| `end` | number | no | One past the last character of the range, as an offset in the Final text. Not with `find`. |

```json
{"op":"comment","ref":"p42","find":"Losses","text":"Check this against schedule 2."}
```

## `reply`

Replies to a comment thread.

Tracked as revisions: no. Reversible by rejecting what it wrote: no.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `comment` | ref | yes | Any comment of the thread, such as `c3`. |
| `text` | text | yes | The text of the reply. A newline is a paragraph break. |

```json
{"op":"reply","comment":"c3","text":"Agreed."}
```

## `resolve`

Resolves a comment thread, or reopens it.

Tracked as revisions: no. Reversible by rejecting what it wrote: no.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `comment` | ref | yes | Any comment of the thread. |
| `reopen` | bool | no | Reopen the thread instead of resolving it. |

```json
{"op":"resolve","comment":"c3"}
```

## `edit-comment`

Replaces the text of one of the author's own comments.

Tracked as revisions: no. Reversible by rejecting what it wrote: no.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `comment` | ref | yes | The comment. |
| `text` | text | yes | The new text. A newline is a paragraph break. |

```json
{"op":"edit-comment","comment":"c3","text":"Checked."}
```

## `delete-comment`

Deletes one of the author's own comments, with its replies.

Tracked as revisions: no. Reversible by rejecting what it wrote: no.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `comment` | ref | yes | The comment. |

```json
{"op":"delete-comment","comment":"c3"}
```

## `delete-note`

Deletes a footnote or endnote, with its reference.

Tracked as revisions: yes. Reversible by rejecting what it wrote: yes.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `note` | ref | yes | The note, such as `fn3` or `en2`: its kind and its ordinal. |

```json
{"op":"delete-note","note":"fn3"}
```

## `accept`

Accepts revisions: applies them.

Tracked as revisions: no. Reversible by rejecting what it wrote: no. Give exactly one of `all`, `author`, `ids`.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `all` | bool | no | Every revision. |
| `author` | text | no | Every revision of this author, by name or by the short code the view shows. |
| `ids` | number list | no | The revisions with these ids, the numbers after `#` in the view. A change is resolved whole. |

```json
{"op":"accept","author":"JD"}
```

## `reject`

Rejects revisions: undoes them.

Tracked as revisions: no. Reversible by rejecting what it wrote: no. Give exactly one of `all`, `author`, `ids`.

| Field | Kind | Required | Meaning |
|---|---|---|---|
| `all` | bool | no | Every revision. |
| `author` | text | no | Every revision of this author, by name or by the short code the view shows. |
| `ids` | number list | no | The revisions with these ids, the numbers after `#` in the view. A change is resolved whole. |

```json
{"op":"reject","ids":[7,8]}
```
