Appendix 2 to Chapter 4:

Using @root Directives, Tangling and Untangling

This appendix discusses @root trees. @root and @file directives have much in common.  I recommend that you read and understand Chapter 4 before attempting this chapter.  This appendix assumes you are familiar with the terminology used in Chapter 4.

@file vs. @root trees
Sections and section definitions
Tangling @root trees with the Tangle commands
Untangling @root trees with the Untangle commands
@verbose, @terse, @quiet and @silent directives

@file vs. @root trees

Leo outlines may contain both @root and @file trees, and I strongly recommend using @file trees whenever possible.  @file trees are much easier to use than @root trees:

However, @root trees are more flexible than @file trees.

@root trees differ from @file trees as follows:

Sections and section definitions

Just as with @file trees, @root trees may contain kinds of sections: code sections and doc sections. Code sections start with section definition lines (see below) or the @c directive. Doc sections start with an @ directive (an @ followed by whitespace or a newline at the start of a line.) Doc sections continue until the end of body text or until the next @c or @(space) directive.

The term "section" has two related meanings. Sections are syntactic units of text in the body pane. Leo writes the text of section to derived files, so another meaning of "section" is "the text that is written to the derived file." Which meaning is intended should be clear from context.

Body text in @root trees contain zero or more sections in any order.  The @c directive starts a named code section if the node's headline starts with <<section name>>.  Otherwise, the @c directive is invalid.

Section definition lines of the form

<< section name>>= 

(note the equal sign) also start named code sections.  Named code sections in @root trees may be defined in several places.  The definition of a named code section is the concatenation of all code sections with the same name. Body text that defines no code section is ignored.

At least one non-blank line must follow the section definition line. That is, empty sections are not allowed.

As in @file trees, paired << and >> characters on the same line always denote a section name, even within comments are strings.  That is, << and >> characters that do not delimit a section name must be placed on separate lines.  If << and >> are not paired on a line, they are treated as literal << and >> characters. 

Here is a typical example of body text within an @root tree:

@ This method puts an open node sentinel for node v.
<<atFile methods>>=
def putOpenNodeSentinel(self,v):
    if v.isAtFileNode() and v != self.root:
        << issue an error message >>
    else:
        s = self.nodeSentinelText(v)
        self.putSentinel("@+node:" + s)

Provided that the node's headline starts with <<atFile methods>>, the example above is equivalent to:

@ This method puts an open node sentinel for node v.
@c
def putOpenNodeSentinel(self,v):
    if v.isAtFileNode() and v != self.root:
        << issue an error message >>
    else:
        s = self.nodeSentinelText(v)
        self.putSentinel("@+node:" + s)

We may not eliminate @c directives in @root trees.  If we convert the doc part to a comment we are left with:

@c
# This method puts an open node sentinel for node v.
def putOpenNodeSentinel(self,v):
    if v.isAtFileNode() and v != self.root:
        << issue an error message >>
    else:
        s = self.nodeSentinelText(v)
        self.putSentinel("@+node:" + s)

The following escape convention applies only in @root trees.  Within a code parts @@ in the first column (and only in the first column) stands for a single @ sign.  

Tangling @root trees and the Tangle commands

Each @root tree  represents a single derived file.  Tangling is the process of creating derived files from @file or @root trees. Leo tangles @file trees automatically whenever an outline is saved.  The user must tangle @file trees explicitly using one of the Tangle commands.

Leo creates derived files from @root trees by expanding all section references in an @root node. Leo expands a section reference by substituting the code section itself for the section reference. This is a recursive process: the substituted code section may contain other code references which are themselves expanded, and so on.  

It is unusual and bad style for the meaning of an @root tree to depend on the position of nodes within it. The meaning of a section definition in an @root tree usually does not depend on is position, and we may place sections wherever we want.  The outline provides a natural way of organizing an sections as follows:

Place the definition of a section S in a child of the node containing the reference to S.

If a section is referenced in more than one node, I usually place its definition in a node containing all the nodes that refer to it. Using this rule of thumb creates an outline whose structure mirrors the intrinsic organization of a program.

The Tangle command creates derived files from @root node. The @root directive indicates which sections constitute an output file. The text following a @root directive forms the entire content of the file, that is, after section references are expanded. An outline can contain arbitrarily many @root directives: Leo's Tangle commands will create one output file for each.

For example, the following @root section shows a typical way of specifying a header file xx.h.

@root"xx.h"
#ifndef xx_defined
#define xx_defined
<< declarations of public constants of the xx class >>
<< declarations of public types of the xx class >>
<< declarations of public variables of the xx class >>
<< public prototypes of the xx class >>
#endif

The Tangle commands will create the file xx.h from this body text by expanding all the section references. Incidentally, the introductory documentation will be included in the header file: any text preceding the @root directive is treated just like the documentation part of an section definition.

As another example, the following shows a typical way of specifying the corresponding xx.c file:

@root"xx.c"
<< public variables of the xx class >>
<< private types of the xx class >>
<< private variables of the xx class >>
<< private function prototypes of the xx class >>
<< methods of the xx class >>

There are three menu commands that tangle an outline: Tangle, Tangle All and Tangle Marked. These commands are identical except for how much of the outline is tangled. The Tangle command tangles only the selected portion of the outline, the Tangle All command tangles the entire outline, and the Tangle Marked command tangles only marked headlines.

The @root directive has three forms. All three forms mean exactly the same thing.

@root filename
@root "filename"
@root <filename>

If filename is an absolute filename the location of the derived file is specified only by the filename. Otherwise, if the @root node contains a relative filename, the location of the derived file is relative to:

  1. the directory specified the applicable @path directive, or
  2. the "Default Tangle Directory" in the Preferences panel if no @path directive is in effect, or
  3. the directory in which the .leo resides if the .leo file has ever been saved.

An error occurs if no absolute path can be computed according to these rules, or if the filename or directory does not exist.

The Tangle commands format derived files so they are easy to read. The .c file in the Examples folder shows how derived files are formatted by the Tangle commands.

There is one complication that we haven't discussed yet: the scope of section definitions. The scope of a definition is the tree in which the definition is known.

By default, Tangle commands look for section definitions only in the suboutline of the @root node being tangled. That is, all sections are assumed to be defined either in the body text of the headline, say h, containing the @root directive, or in the body texts of the descendants of h.

The @unit directive explicitly indicates the scope of section definitions. When a Tangle command encounters the @unit directive it treats the suboutline containing the @unit command as the scope for all enclosed roots. This ensures that the group of roots in the subtree use the same section definitions.

For example, suppose we have a tree organized as follows:

	+ @unit
		+ @root A
		sections in A
		+ @root B
		sections in B

The @unit directive insures that:

  1. only sections defined in the unit can effect files A and B and
  2. all sections definitions in A and B are compatible with each other.

Finally, Tangle commands ignore any tree containing an @ignore directive. This ensures that trees that contain cloned nodes or other subsidiary information do not cause the tangle commands to issue spurious error messages. It also ensures that a tree can never contribute a section definition to another part of the outline by mistake.

Untangling @root trees with the Untangle commands

The Untangle, Untangle All and Untangle Marked commands are the reverse of the corresponding Tangle commands. They update one or more @root nodes based on changes made to the corresponding derived files.

For example, suppose you create a new part of the outline and Tangle it for the first time. When you compile derived files for the first you are likely to get many syntax errors. You could fix those errors in the outline and Tangle the outline again, but there is a much easier way: you fix the errors in the derived files using the compiler's editor, then run the untangle command on the part of the outline that created the derived file. The Untangle command updates the selected outline to match the changes in the derived files. It's as simple as that. By the way, the Untangle command marks all the nodes in the outline that it updates, and you can examine all such nodes with the Go To Next Marked command in the Outline menu.

You cannot use Untangle to update doc parts, or leading comments in code parts or "trivial" whitespace in code parts. This is a limitation of the Untangle command that cannot be fixed; Untangle has no way of knowing whether leading comments came from doc parts or are just leading comments.

Untangle never changes the structure of an outline; it never inserts, deletes or moves nodes. Don't attempt to change the structure of an outline by modifying derived files; it won't work. Also, never delete, move or alter the sentinel lines in derived files written by the Tangle command. Such lines start with /// followed by a section name.

If you change the section name in a sentinel line Untangle will not update the code in the outline (with the old name) that generated the renamed section. Untangle now warns about sections that appear in a derived file but not in the outline. Untangle has no trouble with changed section references in derived files; it is only changed sentinel lines that cause problems.

Cloned nodes that generate code in several files may cause problems for Untangle. If Untangle is run separately on these derived files, Untangle will update all cloned nodes each time it is run, so only the code in the last Untangle run will take effect. Therefore, the safe way to update text in cloned nodes is to make the change in the .leo file rather than the derived files.

The @verbose, @terse, @quiet and @silent directives

The @verbose, @terse, @quiet and @silent directives determine how the Tangle command outputs comments in @root trees. Comments written by the user in code sections are always output: these directives control only: a) the comments containing doc sections and b) sentinel comments that delimit the beginning and end of code sections.

When @verbose is in effect Tangle outputs all comments. When @terse is in effect, Tangle outputs only those comments necessary for Untangle to work. When @silent is in effect Tangle no additional comments. The @quiet directive is like @silent except that it does output leading sentinels as comments. Like @silent, @quiet inhibits untangling.

@verbose is the default.  If more than one of these directives appear in the same body text the "most verbose" of these options will be in effect.