Editing

Editing primitives

Lisp programs are expected to use the following primitives to edit the Neomacs DOM. These primitives provides positions-based interface and handles text-node splitting and merging automatically. These primitives also maintain undo history, update renderer-side DOM, manage setup and destruction of observers and computed attributes, and allocate neomacs-identifier's.

Function: delete-nodes (beg end)
Delete nodes between BEG and END and returns nil.
BEG and END must be sibling positions. If END is nil, delete children starting from BEG till the end of its parent.
Function: extract-nodes (beg end)
Like delete-nodes, but clone and return the deleted contents.
Function: insert-nodes (marker-or-pos &rest things)
Insert THINGS at MARKER-OR-POS.
THINGS can be DOM nodes or strings, which are converted to text nodes.
Function: move-nodes (beg end to)
Move nodes between BEG and END to TO and returns nil.
BEG and END must be sibling positions. If END is nil, move children starting from BEG till the end of its parent.

Editing hooks

More often than not the structured data in a buffer only makes sense if they follow certain constraints or invariants. Neomacs provides a number of facilities to help enforcing invariants, including computed attributes, pre/post command hooks and the following facilities.

Catch all nodes entering and leaving a buffer's DOM:

Progn generic function: on-node-setup (buffer node)
Run some action when NODE is inserted into BUFFER.
NODE can be either an element or a text-node.
Progn generic function: on-node-cleanup (buffer node)
Run some action when NODE is removed from BUFFER.
NODE can be either an element or a text-node.

Schedule some action to run after current command invocation if a node is edited:

Macro: with-post-command ((node &rest slots) &body body)
Run BODY at the end of current command, if any SLOTS of NODE is changed.

Typically, on-node-setup is used to register some computed attributes and post command actions depending on type of node being inserted. with-post-command should be used to restore invariants instead of adding observers (via lwcells's add-observer) that directly edits the DOM, because observers can run in the middle of compound editing operations and commands which might cause unpredictable behavior.

Compound editing operations

Functions implemented using editing primitives, provided for convenience:

Function: splice-node (node)
Splice children of NODE in place of NODE itself.
Function: join-nodes (dst src)
Join DST and SRC nodes.
This moves all children of SRC into DST and deletes SRC.
Function: raise-node (node)
Replace NODE's parent with NODE.
Function: split-node (&optional (pos (focus)))
Split node containing POS at POS.
Let parent be the node containing POS. This involves inserting a clone of parent after parent, and moving children after POS into the clone. Returns the cloned node (i.e. the node after the split point).
Function: wrap-node (node new-node)
Insert NEW-NODE around NODE.
NODE becomes the last child of NEW-NODE.
Function: delete-node (node)
Delete a single NODE.
Function: replace-node (node new-node)
Replace NODE with NEW-NODE.

Editing commands

The following generic editing commands are avaliable in any Neomacs buffer:

Command (enter): new-line (&optional (marker (focus)))
Insert a new line node (br element) at MARKER.
Command (backspace): backward-delete (&optional (marker (focus)))
Command (C-d): forward-delete (&optional (marker (focus)))
Command (M-backspace): backward-delete-word (&optional (marker (focus)))
Command (space, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, @, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, [, \, ], ^, _, `, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z, {, |, }, ~,  , ¡, ¢, £, ¤, ¥, ¦, §, ¨, ©, ª, «, ¬, ­, ®, ¯, °, ±, ², ³, ´, µ, ¶, ·, ¸, ¹, º, », ¼, ½, ¾, ¿, À, Á, Â, Ã, Ä, Å, Æ, Ç, È, É, Ê, Ë, Ì, Í, Î, Ï, Ð, Ñ, Ò, Ó, Ô, Õ, Ö, ×, Ø, Ù, Ú, Û, Ü, Ý, Þ, ß, à, á, â, ã, ä, å, æ, ç, è, é, ê, ë, ì, í, î, ï, ð, ñ, ò, ó, ô, õ, ö, ÷, ø, ù, ú, û, ü, ý, þ): self-insert-command ()
Insert the last typed character into current buffer.

The clipboard

Variable: *clipboard-ring*
Variable: *clipboard-ring-index*

Clipboard commands

Command (C-w): cut-element ()
Cut element under focus and save into clipboard.
If selection is active, cut selected contents instead.
Command (M-w): copy-element ()
Copy element under focus into clipboard.
If selection is active, copy selected contents instead.
Command (C-y): paste ()
Paste the first item in clipboard.
Command (M-y): paste-pop ()
cycle pasted contents, or prompt for a clipboard item to paste.
Command (C-k): forward-cut (&optional (pos (focus)))
Cut until end of line and save into clipboard.