<\body> editing model> Routines for editing documents are usually based on one or several of the following ingredients: <\enumerate> Identification of the document fragments which have to be edited. Modification of one or several document fragments. Moving the cursor to a new place. 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 documents or document fragments can be thought of as , as explained in more detail in the chapter about the document format|../../format/basics/basics.en.tm>. For instance, the mathematical formula <\equation> a+\+a corresponds to the tree <\equation> |a||1>|+\+a||n>> Trees which are part of a document which is effectively being edited are said to be , and they are implemented using the type. Besides this representation format, which is preferred when editing document fragments, also allows you to represent document fragments by trees. This alternative representation, which corresponds to the type , is more convenient when writing routines for processing documents (such as conversions to another format). Finally, provides a representation, which corresponds to the type . The type (corresponding to the prefix , for simplicity) is typically used for writing abstract utility routines for trees, which can then be applied indistinctly to objects of type or . One major advantage of active trees (of type ) is that they are aware of their own location in the document. As a consequence, provides editing routines which allow you to modify the document simply by assigning a tree to a different value. For instance, assume that the variable contains the subscript in formula (). Then the instruction <\scm-code> (tree-set! t "2") will simultaneously change the subscript into a and update the variable . Another nicety is that the value of is during changes of other parts of the document. For instance, if we change the 's into 's in the formula (), then keeps its value its location. Of course, the location of may be lost when or one of its parents is modified. Nevertheless, the modification routines are designed in such a way that we try hard to remember locations. For instance, if ``+>'' is inserted in front of the formula () using the routine , then keeps its value its location, even though one of its ancestors was altered. Some further precisions and terminology will be useful. First of all, we have seen a distinction between and trees, according to whether a tree is part of a document or not. Secondly, both supports (of type ), which are implemented in C++, and (of type ), which have a more familiar syntax. Finally, unify native and scheme trees. Formally speaking, a hybrid tree is either a string, a native tree or a list whose first element is a symbol and whose other elements are again hybrid trees. We notice that active trees are necessarily native, but native trees may both be active or passive. Furthermore, certain descendants of an inactive tree may be active, but we never have the contrary. The main way to address positions inside a tree is via a list of positive integers, called a , and corresponding to the type . For instance, assume that corresponds to the expression(). Then the subscript is identified uniquely by the path>. Similarly the cursor position just behind the subscript corresponds to the path>. More generally, if is a path to a string leaf, then the path corresponds to the cursor position just behind the -th character in the string (we notice that is used to append a new element at the end of a list). If is a path to a non-string subtree, then and ) correspond to the cursor positions before and behind this subtree. It should be noticed that paths do not necessarily correspond to subtrees or cursor positions. Clearly, some of the elements in the path may be ``out of range''. However, certain possible cursor positions may correspond to invisible parts of the document (like a cursor position inside a folded argument or an attribute of ). Moreover, two possible cursor positions may actually coincide, like the paths and inside the expression(). In this example, only the second cursor path is valid. Usually, the validity of a cursor path may be quickly detected using DRD (Data Relation Definition) information, which is determined from the style file. In exceptional cases, the validity may only be available after typesetting the document. It should also be noticed that all active trees are a subtree of the global edit tree> or , which can be retrieved using . The routines path> and 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 , by considering the subtrees themselves. The persistent analogue of a cursor path is a , which corresponds to an object of type . One particularity of persitent positions is that, even when a tree into which they point is removed, they keep indicating a valid close position in the remaining document. For instance, assume that stands for the cursor position in the expression(). If we remove +\+>, then the tree corresponding to the remaining expression > is given by <\equation*> |a||n>> and the position associated to becomes . provides the routines , , and to create, delete, set and get persistent cursor positions. Because accessing subtrees using paths may become quite cumbersome, provides some additional functionality to simplify this task. As a general rule, the routines and may be used to select all subtrees of a given tree which match a certain pattern. For instance, if corresponds to the expression(), then <\scm-code> (select x '(rsub :%1)) returns a list with the two subscripts and . In fact, may also be used in order to navigate through a tree. For instance, if corresponds to the subscript in(), then <\scm-code> (select t '(:up :next)) returns the list with one element ``+a>''. The routine is implicitly called by many routines which operate on trees. For instance, with as above, <\scm-code> (tree-ref t :up :next) directly returns the tree ``+a>''. Besides simpler access to subtrees of a tree or other ``close trees'', also provides several other useful mechanisms for writing editing routines. For instance, the routine and the macro 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 and , which allow you to perform some operations at a temporarily distinct cursor position to compute the cursor position after some operations, without actually changing the current cursor position. In order to illustrate the API for editing documents on a simple example, assume that we wish to write a function 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 . Together with the routine for modifying a tree, this yields a first simple implementation: <\scm-code> (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 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: <\scm-code> (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 and , 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: <\scm-code> (define (variant-circulate t forward?) \ \ (:require (tree-is? t 'frac)) \ \ (swap-numerator-denominator)) Notice that this implementation can be incorrect when operating on nested fractions. The implementation can be further improved by letting operate on a specifictree: <\scm-code> (define (swap-numerator-denominator t) \ \ (:require (tree-is? 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))))) The corresponding generic routine could be defined as <\scm-code> (define (swap-numerator-denominator t) \ \ (and-with p (tree-outer t) \ \ \ \ (swap-numerator-denominator p))) This piece of code will perform an outward recursion until a specific handler is found. We may now replace the call by . The new implementation also allows us to toggle the numerator and denominator of aselected fraction using . However, the focus is not necessarily conserved during the operation, thereby disallowing to restore the original state by toggling a second time. We may explicitly conserve the focus as follows: <\scm-code> (define (swap-numerator-denominator t) \ \ (:require (tree-is? 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))) \ \ \ \ (tree-focus t))) This routine will even work when we are inside a nested fraction and operating on the outer fraction.