const EDITING: &str = "\
patch_page_content takes ops {op, path, from, through, value, position, to_page, label, at_text}.
- add: value is a block or a list of blocks; position before/after a block path or start/end of a children list (\"\" or /<id>/innerBlocks).
- replace /<id>: a block, keeping its id; fields you leave out keep their values; a container's replacement needs innerBlocks (use {\"clientId\":\"…\"} stubs to keep children).
- replace /<id>/attributes/<name>: sets one attribute at any depth; a missing key is added. remove on it deletes the attribute.
- replace on a children list or \"\": array rules: a stub keeps a block, a block with clientId replaces it, a block without one is new; leaving out an existing block or naming an unknown id is an error. Use this to reorder.
- move/copy: from (+through) to path+position; to_page moves or copies to another page. move keeps ids, copy assigns new ones (a copied exercise becomes a new exercise without submissions).
- remove: a block or a range (path + through).
- wrap (path, through, value: the container), unwrap (path), split (path, at_text: the second block starts there), merge (from into path; from must be the next sibling).
- Exercise blocks can be moved, copied and removed, not replaced or edited; patch_exercise edits an exercise's name, own deadline and instructions.
- dry_run: true stages nothing and returns the diff; read_back reads the result in the same call.";