Living in a structural world is nice, but sometimes we need to convert structural content to/from plain text representation, e.g. for file I/O and system clipboard. Neomacs provides some low-level hooks and a table-driven parser framework for converting to/from plain text.
Interface to parsers:
*dom-output*
read-dom
(stream &optional recursive-p)
*syntax-table*
.read-dom
, for example some
function that is bound in *syntax-table*
.*dom-output*
is bound, append the results as children of *dom-output*
. Otherwise, return the results as a list of DOM nodes.read-dom-from-file
(file)
*syntax-table*
.*dom-output*
is bound, append the results as children of *dom-output*
. Otherwise, return the results as a list of DOM nodes.The following hooks implement actual (de)-serialization:
read-dom-aux
(buffer stream)
*dom-output*
. Reading can stop at whatever boundary that makes
sense, i.e. multiple children can be built and appended.write-dom-aux
(buffer node stream)
read-dom-aux
.Note that parsers use append-child
to append children to *dom-output*
directly, i.e. they use low-level DOM edits instead of editing-primitives. It is therefore important to never bind *dom-output*
to live DOM nodes in any buffer, which would result in corrupted state (inconsistency between Lisp-side and renderer-side DOM). Typically, one wants to call the parser to build DOM nodes outside any buffer, then use insert-nodes
to insert them into some buffer if needed.
Neomacs provides a parser framework driven by syntax-tables, which binds characters to functions that consume some (more) characters and builds DOM nodes. The parser reads a character from input stream, looks it up in *syntax-table*
, and calls the function with two arguments: the stream and the character. If the character is not bound to any function, the special value t
is looked up in *syntax-table*
next, and the function (if any) bound to t
is used as default. If t
does not have binding either, an error is signaled.
get-syntax-table
(char table)
set-syntax-range
(table beg end symbol)
make-syntax-table
(&rest bindings)
*syntax-table*
It's quite common to read consecutive characters of the same "category" as a string and process as a whole, possibly building a DOM element or inserting as text. The following functions help with such cases:
read-constituent
(stream symbol escape-chars)
*syntax-table*
is
encountered, with one exception: a character in the list ESCAPE-CHARS
makes the next character accepted unconditionally.append-text
(parent string)
last-child
, concat into the
text node instead.read-newline
(stream c)
*dom-output*
.read-text
(stream c)
*dom-output*
.read-ignore
(stream c)