The TeXmacs editing model |
Routines for editing documents are usually based on one or several of the following ingredients:
Before going into the precise API which allows you to carry out these tasks, let us first describe the fundamental underlying data types, and go through an example.
All TeXmacs documents or document fragments can be thought of as trees, as explained in more detail in the chapter about the TeXmacs document format. For instance, the mathematical formula
a1 + ⋯ + an | (1) |
corresponds to the tree
(2) |
Trees which are part of a document which is effectively being edited
are said to be active, and they are implemented using the
Besides this representation format, which is preferred when editing
document fragments, TeXmacs also allows you to represent passive
document fragments by
One major advantage of active trees (of type tree) is
that they are aware of their own location in the document. As a
consequence, TeXmacs provides editing routines which allow you to
modify the document simply by assigning a tree to a different value.
For instance, assume that the
(tree-set! t "2")
will simultaneously change the subscript into a 2 and update the
Some further precisions and terminology will be useful. First of all,
we have seen a distinction between active and
passive trees, according to whether a tree is part of a
document or not. Secondly, TeXmacs both supports native trees
(of type tree), which are implemented in C++, and
scheme trees (of type stree), which have a
more familiar
The main way to address positions inside a tree is via a list of
positive integers, called a path, and corresponding to the
It should be noticed that paths do not necessarily correspond to
valid subtrees or cursor positions. Clearly, some of the
elements in the path may be “out of range”. However,
certain a priori possible cursor positions may correspond to
invisible parts of the document (like a cursor position inside a
folded argument or an attribute of
It should also be noticed that all active trees are a subtree of the global TeXmacs edit tree or root tree, which can be retrieved using (root-tree). The routines tree->path and path->tree can be used in order to get the location of an active tree and the active tree at a given location.
A simple way to address subtrees of a tree in a more persistent way is
using object of type tree, i.e. by
considering the subtrees themselves. The persistent analogue of a
cursor path is a persistent position, which corresponds to an
object of
and the position associated to pos becomes (0 0). TeXmacs provides the routines position-new, position-delete, position-set and position-get to create, delete, set and get persistent cursor positions.
Because accessing subtrees using paths may become quite cumbersome, TeXmacs provides some additional functionality to simplify this task. As a general rule, the routines select and match? may be used to select all subtrees of a given tree which match a certain pattern. For instance, if x corresponds to the expression (?), then
(select x '(rsub :%1))
returns a list with the two subscripts 1 and n. In fact, select may also be used in order to navigate through a tree. For instance, if t corresponds to the subscript 1 in (?), then
(select t '(:up :next))
returns the list with one element “ + ⋯ + a”. The routine select is implicitly called by many routines which operate on trees. For instance, with t as above,
(tree-ref t :up :next)
directly returns the tree “ + ⋯ + a”.
Besides simpler access to subtrees of a tree or other “close trees”, TeXmacs also provides several other useful mechanisms for writing editing routines. For instance, the routine tree-innermost and the macro with-innermost may be used to retrieve the innermost supertree of a certain type at the current cursor position. Since many editing routines operate at the current cursor position, two other useful macros are with-cursor and cursor-after, which allow you to perform some operations at a temporarily distinct cursor position resp. to compute the cursor position after some operations, without actually changing the current cursor position.
In order to illustrate the TeXmacs API for editing documents on a simple example, assume that we wish to write a function swap-numerator-denominator which allows us to swap the numerator and the denominator of the innermost fraction at the current cursor position.
The innermost fraction may simply be retrieved using the macro with-innermost. Together with the routine tree-set! for modifying a tree, this yields a first simple implementation:
(define (swap-numerator-denominator)
(with-innermost t 'frac
(tree-set! t ‘(frac ,(tree-ref t 1)
,(tree-ref t 0)))))
It should be noticed that the macro with-innermost ignores its body whenever no innermost fraction is found.
The above implementation has the disadvantage that we loose the current cursor position inside the numerator or denominator (whereever we were). The following refined implementation allows us to remain at the “same position” modulo the exchange numerator/denominator:
(define (swap-numerator-denominator)
(with-innermost t 'frac
(with p (tree-cursor-path t)
(tree-set! t ‘(frac ,(tree-ref t 1)
,(tree-ref t 0)))
(tree-go-to t (cons (- 1 (car p)) (cdr p))))))
Here we used the routines tree-cursor-path and tree-go-to, which allow us to manipulate the cursor position relative to a given tree. As the icing on the cake, we may make our routine available through the mechanism of structured variants:
(define (variant-circulate forward?)
(:inside frac)
(swap-numerator-denominator))