To weave a portion of the code into a tree of rendering instructions.


§1. The Master Weaver.Here's what has happened so far, on a weave. The web was read completely into memory and fully parsed. A request was then made either to swarm a mass of individual weaves, or to make just a single weave, with the target in each case being identified by its range. A further decoding layer then translated each range into rather more basic details of what to weave and where to put the result: and so we arrive at the front door of the routine Weaver::weave below.

The basic idea is to build a new tree of rendering instructions, and then to hand it over for rendering. A fair critique of this approach would be that, because LP source is now stored in a semantically detailed tree already, there's no real need to manufacture another slightly different one. This came about for historical reasons, i.e., because LP source used to be stored less comprehensibly. But it turns out to be convenient, and it's well-understood code which works well enough in practice.

void Weaver::weave(weave_order *wv) {
    WeavingFormats::render(wv, Weaver::weave_tree(wv));
}

§2. The tree is independent of format except that, to save passing arguments endlessly around, it contains a marker in the root of its head node which has a pointer to wv. In particular, this means that the tree records what format (HTML, etc.) it will be woven to.

heterogeneous_tree *Weaver::weave_tree(weave_order *wv) {
    heterogeneous_tree *tree = WeaveTree::new_tree(wv);
    TEMPORARY_TEXT(banner)
    WRITE_TO(banner, "Weave of '%S' generated by %s", wv->booklet_title, PROGRAM_NAME);
    tree_node *head = WeaveTree::head(tree, banner);
    DISCARD_TEXT(banner)
    tree_node *body = WeaveTree::body(tree);
    tree_node *tail = WeaveTree::tail(tree, I"End of weave");
    Trees::make_child(head, tree->root);
    Trees::make_child(body, tree->root);
    Trees::make_child(tail, tree->root);
    Weaver::weave_inner(wv, tree, body);
    WeaveTree::prune(tree);
    return tree;
}

void Weaver::weave_inner(weave_order *wv, heterogeneous_tree *tree, tree_node *body) {
    ls_web *W = wv->weave_web;
    weaver_state state_at; weaver_state *state = &state_at;
    Start the weaver with a clean slate2.5;
    ls_chapter *C, *last_heading = NULL;
    ls_section *S;
    LOOP_OVER_LINKED_LIST(C, ls_chapter, W->chapters)
        if (C->imported == FALSE) {
            LOOP_OVER_LINKED_LIST(S, ls_section, C->sections)
                if (WebRanges::is_within(WebRanges::of(S), wv->weave_range)) {
                    Weave any necessary chapter header2.1;
                    Weave any necessary section header2.3;
                    LanguageMethods::begin_weave(S, wv);
                    Weave this section2.6;
                    Weave any necessary section footer2.4;
                }
        }
    Weave any necessary chapter footer2.2;
}

§2.1. Weave any necessary chapter header2.1 =

    if (last_heading != C) {
        Weave any necessary chapter footer2.2;
        tree_node *CH = WeaveTree::chapter(tree, C);
        Trees::make_child(CH, state->body_node);
        state->chapter_node = CH;
        state->ap = CH;
        last_heading = C;
        if (wv->theme_match == NULL) {
            tree_node *H = WeaveTree::chapter_header(tree, C);
            Trees::make_child(H, state->chapter_node);
        }
    }

§2.2. Weave any necessary chapter footer2.2 =

    if (wv->theme_match == NULL) {
        if (last_heading != NULL) {
            tree_node *F = WeaveTree::chapter_footer(tree, last_heading);
            Trees::make_child(F, state->chapter_node);
        }
    }

§2.3. Weave any necessary section header2.3 =

    tree_node *SH = WeaveTree::section(tree, S);
    Trees::make_child(SH, state->chapter_node);
    state->section_node = SH;
    state->ap = SH;
    if (Str::len(wv->theme_match) == 0) {
        tree_node *H = WeaveTree::section_header(tree, S);
        Trees::make_child(H, state->section_node);
    }

§2.4. Weave any necessary section footer2.4 =

    if (Str::len(wv->theme_match) == 0) {
        tree_node *F = WeaveTree::section_footer(tree, S);
        Trees::make_child(F, state->section_node);
    }

§3. The state.We can now begin on a clean page, by initialising the state of the weaver:

enum COMMENTARY_MATERIAL from 1
enum MACRO_MATERIAL           when a macro is being defined...
enum DEFINITION_MATERIAL      ...versus when an @d definition is being made
enum CODE_MATERIAL            verbatim code
enum ENDNOTES_MATERIAL        endnotes at the foot of a paragraph
enum FOOTNOTES_MATERIAL      footnote texts for a paragraph
typedef struct weaver_state {
    int kind_of_material;  one of the enumerated *_MATERIAL constants above
    int line_break_pending;  insert a line break before the next woven line?
    int next_heading_without_vertical_skip;
    struct ls_section *last_extract_from;
    struct tree_node *body_node;
    struct tree_node *chapter_node;
    struct tree_node *section_node;
    struct tree_node *para_node;
    struct tree_node *carousel_node;
    struct tree_node *material_node;
    struct tree_node *ap;
} weaver_state;

§2.5. Start the weaver with a clean slate2.5 =

    state->kind_of_material = COMMENTARY_MATERIAL;
    state->line_break_pending = FALSE;
    state->next_heading_without_vertical_skip = FALSE;
    state->last_extract_from = NULL;
    state->body_node = body;
    state->chapter_node = NULL;
    state->section_node = NULL;
    state->para_node = NULL;
    state->carousel_node = NULL;
    state->material_node = NULL;
    state->ap = body;

§2.6. Weaving a section.Weave this section2.6 =

    int toc_made = FALSE;
    for (ls_paragraph *par = S->literate_source->first_par; par; par = par->next_par) {
        if (toc_made == FALSE) {
            if (LiterateSource::unit_has_purpose(S->literate_source)) {
                text_stream *purp = Str::duplicate(LiterateSource::unit_purpose(S->literate_source));
                tree_node *F = WeaveTree::purpose(tree, purp);
                Trees::make_child(F, state->ap);
            }
            Weaver::weave_table_of_contents(tree, state->ap, S);
            toc_made = TRUE;
        }
        if (LiterateSource::is_tagged_with(par, wv->theme_match)) Weave this paragraph2.6.1;
    }

§2.6.1. Weave this paragraph2.6.1 =

    Deal with the marker for the start of a new paragraph, section or chapter2.6.1.3;

    for (ls_chunk *chunk = par->first_chunk; chunk; chunk = chunk->next_chunk) {
        if (chunk->chunk_type == EXTRACT_LSCT) {
            state->line_break_pending = FALSE;
            LanguageMethods::reset_syntax_colouring(S->sect_language);
        }
        if ((chunk->chunk_type == COMMENTARY_LSCT) && (chunk->as_markdown))
            Deal with a Markdown commentary chunk2.6.1.1
        else
            Deal with some other sort of chunk2.6.1.2;
        if (chunk->chunk_type == EXTRACT_LSCT)
            Weaver::change_material(tree, state, COMMENTARY_MATERIAL, FALSE, NULL, NULL);
    }
    Weaver::change_material(tree, state, ENDNOTES_MATERIAL, FALSE, NULL, NULL);
    Weaver::show_endnotes_on_previous_paragraph(tree, wv, state->ap, par);

§2.6.1.1. Markdown commentary bypasses the need to make elaborate subtrees here: we won't parse it further, but simply encapsulate it as a blob of Markdown content.

Deal with a Markdown commentary chunk2.6.1.1 =

    tree_node *C = WeaveTree::markdown_chunk(tree, chunk->as_markdown);
    Trees::make_child(C, state->para_node);

§2.6.1.2. Otherwise, though, we have to attack line by line.

Deal with some other sort of chunk2.6.1.2 =

    for (ls_line *lst = chunk->first_line; lst; lst = lst->next_line) {
        wv->current_weave_line = lst;
        ls_line_analysis *L = (ls_line_analysis *) lst->analysis_ref;
        if (LanguageMethods::skip_in_weaving(S->sect_language, wv, lst) == FALSE) {
            if ((lst == chunk->first_line) && (chunk->holon) && (Str::len(chunk->holon->holon_name) > 0))
                Weave holon name2.6.1.2.1;
            Weave insertions2.6.1.2.3;
            Weave this line2.6.1.2.2;
        }
    }

§2.6.1.3. How paragraphs begin.Deal with the marker for the start of a new paragraph, section or chapter2.6.1.3 =

    LanguageMethods::reset_syntax_colouring(S->sect_language);
    if (Str::len(wv->theme_match) > 0) Apply special rules for thematic extracts2.6.1.3.1;
    state->para_node = WeaveTree::paragraph_heading(tree, par,
        state->next_heading_without_vertical_skip);
    Trees::make_child(state->para_node, state->section_node);

    Weaver::change_material_for_para(tree, state);
    state->kind_of_material = COMMENTARY_MATERIAL;
    state->next_heading_without_vertical_skip = FALSE;

§2.6.1.3.1. If we are weaving a selection of extracted paragraphs, normal conventions about breaking pages at chapters and sections fail to work. So:

Apply special rules for thematic extracts2.6.1.3.1 =

    text_stream *cap = LiterateSource::retrieve_caption_for_tag(par, wv->theme_match);
    if (Str::len(cap) > 0) {
        Weaver::weave_subheading(tree, wv, state->ap, C->ch_title);
    } else if ((W->single_file == NULL) && (state->last_extract_from != S)) {
        TEMPORARY_TEXT(extr)
        WRITE_TO(extr, "From %S: %S", C->ch_title, S->sect_title);
        Weaver::weave_subheading(tree, wv, state->ap, extr);
        DISCARD_TEXT(extr)
    }
    state->last_extract_from = S;

§2.6.1.2.1. Weave holon name2.6.1.2.1 =

    TEMPORARY_TEXT(matter)
    WRITE_TO(matter, "%S%S@> =", I"@<", chunk->holon->holon_name);
    Weaver::change_material(tree, state, MACRO_MATERIAL, chunk->plainer, S->sect_language, NULL);
    state->line_break_pending = FALSE;
    Weave verbatim matter in code style2.6.1.2.1.1;
    DISCARD_TEXT(matter)

§2.6.1.2.2. Weave this line2.6.1.2.2 =

    TEMPORARY_TEXT(matter)
    Str::copy(matter, LiterateSource::line_weaving_matter(lst));
    if ((lst->classification.major == EXTRACT_MATTER_MAJLC) ||
        (lst->classification.major == DEFINITION_MAJLC) ||
        (lst->classification.major == DEFINITION_CONTINUED_MAJLC)) {
        Change material if necessary2.6.1.2.2.2;
        Weave verbatim matter in code style2.6.1.2.1.1
    } else
        Weave verbatim matter in commentary style2.6.1.2.2.1;
    DISCARD_TEXT(matter)

§2.6.1.2.3. And lastly we ignore commands, or act on them if they happen to be aimed at us; but we don't weave them into the output, that's for sure.

Weave insertions2.6.1.2.3 =

    switch (lst->classification.minor) {
        case AUDIO_MINLC: Weave an audio clip2.6.1.2.3.3; continue;
        case CAROUSEL_SLIDE_MINLC: Weave a carousel2.6.1.2.3.7; continue;
        case CAROUSEL_END_MINLC: Weave a carousel end2.6.1.2.3.8; continue;
        case DOWNLOAD_MINLC: Weave a download2.6.1.2.3.5; continue;
        case EMBEDDED_AV_MINLC: Weave an embed2.6.1.2.3.6; continue;
        case FIGURE_MINLC: Weave a figure2.6.1.2.3.1; continue;
        case HTML_MINLC: Weave a raw HTML extract2.6.1.2.3.2; continue;
        case VIDEO_MINLC: Weave a video clip2.6.1.2.3.4; continue;
    }

§2.6.1.2.3.1. Weave a figure2.6.1.2.3.1 =

    int w, h;
    text_stream *figname = Weaver::parse_dimensions(lst->classification.operand1, &w, &h);
    Trees::make_child(WeaveTree::figure(tree, figname, w, h), state->ap);

§2.6.1.2.3.2. Weave a raw HTML extract2.6.1.2.3.2 =

    Trees::make_child(WeaveTree::raw_extract(tree, lst->classification.operand1),
        state->ap);

§2.6.1.2.3.3. Weave an audio clip2.6.1.2.3.3 =

    int w, h;
    text_stream *figname = Weaver::parse_dimensions(lst->classification.operand1, &w, &h);
    Trees::make_child(WeaveTree::audio(tree, figname, w), state->ap);

§2.6.1.2.3.4. Weave a video clip2.6.1.2.3.4 =

    int w, h;
    text_stream *figname = Weaver::parse_dimensions(lst->classification.operand1, &w, &h);
    Trees::make_child(WeaveTree::video(tree, figname, w, h), state->ap);

§2.6.1.2.3.5. Weave a download2.6.1.2.3.5 =

    Trees::make_child(WeaveTree::download(tree, lst->classification.operand1, lst->classification.operand2),
        state->ap);

§2.6.1.2.3.6. Weave an embed2.6.1.2.3.6 =

    int w, h;
    text_stream *ID = Weaver::parse_dimensions(lst->classification.operand2, &w, &h);
    Trees::make_child(WeaveTree::embed(tree, lst->classification.operand1, ID, w, h), state->ap);

§2.6.1.2.3.7. Weave a carousel2.6.1.2.3.7 =

    tree_node *C = WeaveTree::carousel_slide(tree, chunk->metadata.operand1, chunk->carousel_caption_position);
    Trees::make_child(C, state->para_node);
    state->ap = C;
    state->carousel_node = C;

§2.6.1.2.3.8. Weave a carousel end2.6.1.2.3.8 =

    state->ap = state->para_node;
    state->carousel_node = NULL;

§4. Parsing of dimensions.It's possible, optionally, to specify width and height for some visual matter. This is the syntax used.

define POINTS_PER_CM 72
text_stream *Weaver::parse_dimensions(text_stream *item, int *w, int *h) {
    *w = -1; *h = -1;
    text_stream *use = item;
    match_results mr = Regexp::create_mr();
    if (Regexp::match(&mr, item, U"(%c+) at (%d+) by (%d+)")) {
        *w = Str::atoi(mr.exp[1], 0);
        *h = Str::atoi(mr.exp[2], 0);
        use = Str::duplicate(mr.exp[0]);
    } else if (Regexp::match(&mr, item, U"(%c+) at height (%d+)")) {
        *h = Str::atoi(mr.exp[1], 0);
        use = Str::duplicate(mr.exp[0]);
    } else if (Regexp::match(&mr, item, U"(%c+) at width (%d+)")) {
        *w = Str::atoi(mr.exp[1], 0);
        use = Str::duplicate(mr.exp[0]);
    } else if (Regexp::match(&mr, item, U"(%c+) at (%d+)cm by (%d+)cm")) {
        *w = POINTS_PER_CM*Str::atoi(mr.exp[1], 0);
        *h = POINTS_PER_CM*Str::atoi(mr.exp[2], 0);
        use = Str::duplicate(mr.exp[0]);
    } else if (Regexp::match(&mr, item, U"(%c+) at height (%d+)cm")) {
        *h = POINTS_PER_CM*Str::atoi(mr.exp[1], 0);
        use = Str::duplicate(mr.exp[0]);
    } else if (Regexp::match(&mr, item, U"(%c+) at width (%d+)cm")) {
        *w = POINTS_PER_CM*Str::atoi(mr.exp[1], 0);
        use = Str::duplicate(mr.exp[0]);
    }
    Regexp::dispose_of(&mr);
    return use;
}

§2.6.1.2.2.1. Commentary matter.Typographically this is a fairly simple business: it's almost the case that we only have to transcribe it. But not quite!

Weave verbatim matter in commentary style2.6.1.2.2.1 =

    Weave displayed source in its own special style2.6.1.2.2.1.1;
    Weave a blank line as a thin vertical skip and paragraph break2.6.1.2.2.1.2;
    Weave bracketed list indications at start of line into items2.6.1.2.2.1.3;
    Weave tabbed code material as a new indented paragraph2.6.1.2.2.1.4;
    Weave footnotes2.6.1.2.2.1.5;
    WRITE_TO(matter, "\n");
    Weaver::commentary_text(tree, wv, state->ap, matter);
    continue;

§2.6.1.2.2.1.1. Displayed source is the material marked with >> arrows in column 1.

Weave displayed source in its own special style2.6.1.2.2.1.1 =

    if (chunk->chunk_type == QUOTATION_LSCT) {
        Trees::make_child(WeaveTree::display_line(tree, lst->classification.operand1), state->ap);
        continue;
    }

§2.6.1.2.2.1.2. Our style is to use paragraphs without initial-line indentation, so we add a vertical skip between them to show the division more clearly.

Weave a blank line as a thin vertical skip and paragraph break2.6.1.2.2.1.2 =

    if (Regexp::string_is_white_space(matter)) {
        if (lst->next_line) {
            match_results mr = Regexp::create_mr();
            if ((state->kind_of_material != CODE_MATERIAL) ||
                (Regexp::match(&mr, matter, U"\t|(%c*)|(%c*?)")))
                Trees::make_child(WeaveTree::vskip(tree, TRUE), state->ap);
            Regexp::dispose_of(&mr);
        }
        continue;
    }

§2.6.1.2.2.1.3. Here our extension is simply to provide a tidier way to use TeX's standard \item and \itemitem macros for indented list items.

Weave bracketed list indications at start of line into items2.6.1.2.2.1.3 =

    match_results mr = Regexp::create_mr();
    if (Regexp::match(&mr, matter, U"%(-...%) (%c*)")) {  continue double
        Weaver::change_material(tree, state, COMMENTARY_MATERIAL, FALSE, NULL, NULL);
        Trees::make_child(WeaveTree::weave_item_node(tree, 2, I""), state->ap);
        Str::copy(matter, mr.exp[0]);
    } else if (Regexp::match(&mr, matter, U"%(...%) (%c*)")) {  continue single
        Weaver::change_material(tree, state, COMMENTARY_MATERIAL, FALSE, NULL, NULL);
        Trees::make_child(WeaveTree::weave_item_node(tree, 1, I""), state->ap);
        Str::copy(matter, mr.exp[0]);
    } else if (Regexp::match(&mr, matter, U"%(-([a-zA-Z0-9*]+)%) (%c*)")) {  begin double
        Weaver::change_material(tree, state, COMMENTARY_MATERIAL, FALSE, NULL, NULL);
        Trees::make_child(WeaveTree::weave_item_node(tree, 2, mr.exp[0]), state->ap);
        Str::copy(matter, mr.exp[1]);
    } else if (Regexp::match(&mr, matter, U"%(([a-zA-Z0-9*]+)%) (%c*)")) {  begin single
        Weaver::change_material(tree, state, COMMENTARY_MATERIAL, FALSE, NULL, NULL);
        Trees::make_child(WeaveTree::weave_item_node(tree, 1, mr.exp[0]), state->ap);
        Str::copy(matter, mr.exp[1]);
    }
    Regexp::dispose_of(&mr);

§2.6.1.2.2.1.4. Finally, matter encased in vertical strokes one tab stop in from column 1 in the source is set indented in code style.

Weave tabbed code material as a new indented paragraph2.6.1.2.2.1.4 =

    match_results mr = Regexp::create_mr();
    if (Regexp::match(&mr, matter, U"\t|(%c*)|(%c*?)")) {
        TEMPORARY_TEXT(original)
        Weaver::change_material(tree, state, CODE_MATERIAL, FALSE, NULL, NULL);
        Str::copy(original, mr.exp[0]);
        Str::copy(matter, mr.exp[1]);
        TEMPORARY_TEXT(colouring)
        for (int i=0; i<Str::len(original); i++) PUT_TO(colouring, PLAIN_COLOUR);
        tree_node *CL = WeaveTree::code_line(tree);
        Trees::make_child(CL, state->ap);
        TextWeaver::source_code(tree, CL, original, colouring, chunk->hyperlinked);
        DISCARD_TEXT(colouring)
        DISCARD_TEXT(original)
        Weaver::commentary_text(tree, wv, state->ap, matter);
        Regexp::dispose_of(&mr);
        continue;
    }
    Regexp::dispose_of(&mr);

§2.6.1.2.2.1.5. Weave footnotes2.6.1.2.2.1.5 =

    if (lst->footnote_text) {
        Weaver::change_material(tree, state, FOOTNOTES_MATERIAL, FALSE, NULL, NULL);
        ls_footnote *F = lst->footnote_text;
        tree_node *FN = WeaveTree::footnote(tree, F->cue_text);
        Trees::make_child(FN, state->material_node);
        if (F->cued_already == FALSE) WebErrors::issue_at(I"footnote never cued", lst);
        state->ap = FN;
    }

§2.6.1.2.1.1. Code-like matter.Even though our approach, unlike CWEB's, is to respect the layout of the original, this is still quite typographically complex: commentary and macro usage is rendered differently.

Weave verbatim matter in code style2.6.1.2.1.1 =

    int suppress = FALSE;
    Weave a blank line as a thin vertical skip2.6.1.2.1.1.1;

    if (suppress == FALSE) {
        Str::rectify_indentation(matter, 4);

        TEMPORARY_TEXT(prefatory)
        TEMPORARY_TEXT(concluding_comment)
        Extract any comment matter ending the line to be set in italic2.6.1.2.1.1.2;
        Give constant definition lines slightly fancier openings2.6.1.2.1.1.3;

        tree_node *CL = WeaveTree::code_line(tree);
        Trees::make_child(CL, state->ap);
        if (Str::len(prefatory) > 0)
            Trees::make_child(WeaveTree::weave_defn_node(tree, prefatory), CL);
        Str::clear(prefatory);

        Offer the line to the language to weave2.6.1.2.1.1.4;

        if (suppress == FALSE) {
            Find macro usages and adjust syntax colouring accordingly2.6.1.2.1.1.5;
            TEMPORARY_TEXT(colouring)
            LanguageMethods::syntax_colour(S->sect_language, wv, lst, matter, colouring,
                Pathnames::path_to_inweb());
            TextWeaver::source_code(tree, CL, matter, colouring, chunk->hyperlinked);
            DISCARD_TEXT(colouring)

            if (Str::len(concluding_comment) > 0)
                TextWeaver::comment_text_in_code(tree, CL, concluding_comment);
        }
        DISCARD_TEXT(concluding_comment)
        DISCARD_TEXT(prefatory)
    }

§2.6.1.2.2.2. We're not in Kansas any more, so:

Change material if necessary2.6.1.2.2.2 =

    if (state->kind_of_material != CODE_MATERIAL) {
        int will_be = CODE_MATERIAL;
        if (lst->classification.major == HOLON_DECLARATION_MAJLC)
            will_be = MACRO_MATERIAL;
        else if (chunk->chunk_type == DEFINITION_LSCT)
            will_be = DEFINITION_MATERIAL;
        programming_language *pl = chunk->extract_language;
        if (pl == NULL) pl = S->sect_language;
        if (will_be != CODE_MATERIAL) pl = NULL;
        if (LiterateSource::is_tagged_with(LiterateSource::par_of_line(lst), I"Preform")) {
            programming_language *prepl =
                TangleTargets::find_language(I"Preform", wv->weave_web, FALSE);
            if (prepl) pl = prepl;
        }
        text_stream *note = NULL;
        if (Str::len(chunk->extract_to) > 0) {
            note = Str::new();
            WRITE_TO(note, "This is part of the extract file %S.", chunk->extract_to);
        }
        Weaver::change_material(tree, state, will_be, chunk->plainer, pl, note);
        state->line_break_pending = FALSE;
    }

§2.6.1.2.1.1.1. A blank line is implemented differently in different formats, so it gets a node of its own, a vskip:

Weave a blank line as a thin vertical skip2.6.1.2.1.1.1 =

    if (state->line_break_pending) {
        Trees::make_child(WeaveTree::vskip(tree, FALSE), state->ap);
        state->line_break_pending = FALSE;
    }
    if (Regexp::string_is_white_space(matter)) {
        state->line_break_pending = TRUE;
        suppress = TRUE;
    }

§2.6.1.2.1.1.2. Comments which run to the end of a line can be set in italic type, for example, or flush left.

Extract any comment matter ending the line to be set in italic2.6.1.2.1.1.2 =

    TEMPORARY_TEXT(part_before_comment)
    TEMPORARY_TEXT(part_within_comment)
    programming_language *pl = chunk->extract_language;
    if (pl == NULL) pl = S->sect_language;
    if ((pl) && (LanguageMethods::parse_comment(pl,
        matter, part_before_comment, part_within_comment))) {
        Str::copy(matter, part_before_comment);
        Str::copy(concluding_comment, part_within_comment);
    }
    DISCARD_TEXT(part_before_comment)
    DISCARD_TEXT(part_within_comment)

§2.6.1.2.1.1.3. Set the @d definition escape very slightly more fancily:

Give constant definition lines slightly fancier openings2.6.1.2.1.1.3 =

    if ((chunk->chunk_type == DEFINITION_LSCT) && (lst == chunk->first_line)) {
        match_results mr = Regexp::create_mr();
        if ((Regexp::match(&mr, matter, U"@d (%c*)")) ||
            (Regexp::match(&mr, matter, U"@define (%c*)"))) {
            Str::copy(prefatory, I"define");
            Str::copy(matter, mr.exp[0]);
        } else if (Regexp::match(&mr, matter, U"@default (%c*)")) {
            Str::copy(prefatory, I"default");
            Str::copy(matter, mr.exp[0]);
        } else if ((Regexp::match(&mr, matter, U"@e (%c*)")) ||
            (Regexp::match(&mr, matter, U"@enum (%c*)"))) {
            Str::copy(prefatory, I"enum");
            Str::copy(matter, mr.exp[0]);
        }
        Regexp::dispose_of(&mr);
    }

§2.6.1.2.1.1.4. Offer the line to the language to weave2.6.1.2.1.1.4 =

    TEMPORARY_TEXT(OUT)
    int taken = LanguageMethods::weave_code_line(OUT, S->sect_language, wv,
        W, C, S, L, matter, concluding_comment);
    if (taken) {
        tree_node *V = WeaveTree::verbatim(tree, OUT);
        Trees::make_child(V, CL);
    }
    DISCARD_TEXT(OUT)
    if (taken) suppress = TRUE;

§2.6.1.2.1.1.5. Find macro usages and adjust syntax colouring accordingly2.6.1.2.1.1.5 =

    match_results mr = Regexp::create_mr();
    while (Regexp::match(&mr, matter, U"(%c*?)%@%<(%c*?)%@%>(%c*)")) {
        ls_paragraph *defn_par = Holons::find_holon(mr.exp[1], S->literate_source);
        if (defn_par) {
            TEMPORARY_TEXT(front_colouring)
            LanguageMethods::syntax_colour(S->sect_language, wv, lst, mr.exp[0], front_colouring, Pathnames::path_to_inweb());
            TextWeaver::source_code(tree, CL, mr.exp[0], front_colouring, chunk->hyperlinked);
            DISCARD_TEXT(front_colouring)
            Str::copy(matter, mr.exp[2]);
            int defn = (LiterateSource::par_of_line(lst) == defn_par)?TRUE:FALSE;
            if (defn) Str::clear(matter);
            Trees::make_child(WeaveTree::pmac(tree, defn_par, defn), CL);
        } else break;
    }
    Regexp::dispose_of(&mr);

§5. Endnotes.The endnotes describe function calls from far away, or unexpected structure usage, or how CWEB-style code substitutions were made.

void Weaver::show_endnotes_on_previous_paragraph(heterogeneous_tree *tree,
    weave_order *wv, tree_node *ap, ls_paragraph *par) {
    tree_node *body = ap;
    if (LiterateSource::is_tagged_with(par, I"Preform"))
        Show endnote on use of Preform5.1;
    IfdefTags::show_endnote_on_ifdefs(tree, ap, par);
    if (LiterateSource::par_contains_named_holon(par))
        Show endnote on where paragraph macro is used5.2;
    language_function *fn;
    ls_paragraph_analysis *P = (ls_paragraph_analysis *) par->analysis_ref;
    LOOP_OVER_LINKED_LIST(fn, language_function, P->functions)
        Show endnote on where this function is used5.3;
    language_type *st;
    LOOP_OVER_LINKED_LIST(st, language_type, P->structures)
        Show endnote on where this language type is accessed5.4;
}

§5.1. Show endnote on use of Preform5.1 =

    tree_node *E = WeaveTree::endnote(tree);
    Trees::make_child(E, body); ap = E;
    TextWeaver::commentary_text(tree, ap, I"This is ");
    TEMPORARY_TEXT(url)
    int ext = FALSE;
    if (Colonies::resolve_reference_in_weave(url, NULL, wv->weave_to,
        I"words: About Preform", wv->weave_web, NULL, &ext))
        Trees::make_child(WeaveTree::url(tree, url, I"Preform grammar", ext), ap);
    else
        TextWeaver::commentary_text(tree, ap, I"Preform grammar");
    DISCARD_TEXT(url)
    TextWeaver::commentary_text(tree, ap, I", not regular C code.");

§5.2. Show endnote on where paragraph macro is used5.2 =

    tree_node *E = WeaveTree::endnote(tree);
    Trees::make_child(E, body); ap = E;
    TextWeaver::commentary_text(tree, ap, I"This code is ");
    int ct = 0;
    if (par->holon) {
        holon_usage *mu;
        LOOP_OVER_LINKED_LIST(mu, holon_usage, par->holon->holon_usages)
            ct++;
    }
    if (ct == 0) TextWeaver::commentary_text(tree, ap, I"never used");
    else if (par->holon) {
        int k = 0, used_flag = FALSE;
        holon_usage *mu;
        LOOP_OVER_LINKED_LIST(mu, holon_usage, par->holon->holon_usages)
            if (par != mu->used_in_paragraph) {
                if (used_flag) {
                    if (k < ct-1) TextWeaver::commentary_text(tree, ap, I", ");
                    else TextWeaver::commentary_text(tree, ap, I" and ");
                } else {
                    TextWeaver::commentary_text(tree, ap, I"used in ");
                }
                Trees::make_child(WeaveTree::locale(tree, mu->used_in_paragraph, NULL), ap);
                used_flag = TRUE; k++;
                switch (mu->multiplicity) {
                    case 1: break;
                    case 2: TextWeaver::commentary_text(tree, ap, I" (twice)"); break;
                    case 3: TextWeaver::commentary_text(tree, ap, I" (three times)"); break;
                    case 4: TextWeaver::commentary_text(tree, ap, I" (four times)"); break;
                    case 5: TextWeaver::commentary_text(tree, ap, I" (five times)"); break;
                    default: {
                        TEMPORARY_TEXT(mt)
                        WRITE_TO(mt, " (%d times)", mu->multiplicity);
                        TextWeaver::commentary_text(tree, ap, mt);
                        DISCARD_TEXT(mt)
                        break;
                    }
                }
            }
    }
    TextWeaver::commentary_text(tree, ap, I".");

§5.3. Show endnote on where this function is used5.3 =

    if (fn->usage_described == FALSE)
        Weaver::show_function_usage(tree, wv, ap, par, fn, FALSE);

§5.4. Show endnote on where this language type is accessed5.4 =

    tree_node *E = WeaveTree::endnote(tree);
    Trees::make_child(E, body); ap = E;
    TextWeaver::commentary_text(tree, ap, I"The structure ");
    TextWeaver::commentary_text(tree, ap, st->structure_name);

    ls_section *S;
    LOOP_OVER(S, ls_section) S->scratch_flag = FALSE;
    structure_element *elt;
    LOOP_OVER_LINKED_LIST(elt, structure_element, st->elements) {
        hash_table_entry *hte =
            CodeAnalysis::find_hash_entry_for_section(elt->element_created_at,
                elt->element_name, FALSE);
        if (hte) {
            hash_table_entry_usage *hteu;
            LOOP_OVER_LINKED_LIST(hteu, hash_table_entry_usage, hte->usages)
                if (hteu->form_of_usage & ELEMENT_ACCESS_USAGE)
                    LiterateSource::section_of_par(hteu->usage_recorded_at)->scratch_flag = TRUE;
        }
    }

    int usage_count = 0, external = 0;
    LOOP_OVER(S, ls_section)
        if (S->scratch_flag) {
            usage_count++;
            if (S != LiterateSource::section_of_par(par)) external++;
        }
    if (external == 0) TextWeaver::commentary_text(tree, ap, I" is private to this section");
    else {
        TextWeaver::commentary_text(tree, ap, I" is accessed in ");
        int c = 0;
        LOOP_OVER(S, ls_section)
            if ((S->scratch_flag) && (S != LiterateSource::section_of_par(par))) {
                if (c++ > 0) TextWeaver::commentary_text(tree, ap, I", ");
                TextWeaver::commentary_text(tree, ap, WebRanges::of(S));
            }
        if (LiterateSource::section_of_par(par)->scratch_flag) TextWeaver::commentary_text(tree, ap, I" and here");
    }
    TextWeaver::commentary_text(tree, ap, I".");

§6.

void Weaver::show_function_usage(heterogeneous_tree *tree, weave_order *wv,
    tree_node *ap, ls_paragraph *par, language_function *fn, int as_list) {
    tree_node *body = ap;
    fn->usage_described = TRUE;
    hash_table_entry *hte =
        CodeAnalysis::find_hash_entry_for_section(fn->function_section,
            fn->function_name, FALSE);
    if (as_list == FALSE) {
        tree_node *E = WeaveTree::endnote(tree);
        Trees::make_child(E, body); ap = E;
        TextWeaver::commentary_text(tree, ap, I"The function ");
        TextWeaver::commentary_text(tree, ap, fn->function_name);
    }
    int used_flag = FALSE;
    hash_table_entry_usage *hteu = NULL;
    ls_section *last_cited_in = NULL;
    int count_under = 0;
    LOOP_OVER_LINKED_LIST(hteu, hash_table_entry_usage, hte->usages)
        if ((par != hteu->usage_recorded_at) &&
            (LiterateSource::section_of_par(par) == LiterateSource::section_of_par(hteu->usage_recorded_at)))
            Cite usage of function here6.1;
    LOOP_OVER_LINKED_LIST(hteu, hash_table_entry_usage, hte->usages)
        if (LiterateSource::section_of_par(par) != LiterateSource::section_of_par(hteu->usage_recorded_at))
            Cite usage of function here6.1;
    if (used_flag == FALSE) {
        if (as_list == FALSE) {
            TextWeaver::commentary_text(tree, ap, I" appears nowhere else");
        } else {
            TextWeaver::commentary_text(tree, ap, I"none");
        }
    }
    if (as_list == FALSE) {
        if ((last_cited_in != LiterateSource::section_of_par(par)) && (last_cited_in))
            TextWeaver::commentary_text(tree, ap, I")");
        TextWeaver::commentary_text(tree, ap, I".");
    }
}

§6.1. Cite usage of function here6.1 =

    if (as_list == FALSE) {
        if (used_flag == FALSE) TextWeaver::commentary_text(tree, ap, I" is used in ");
    }
    used_flag = TRUE;
    ls_section *S = LiterateSource::section_of_par(hteu->usage_recorded_at);
    if ((S != last_cited_in) && (S != LiterateSource::section_of_par(par))) {
        count_under = 0;
        if (last_cited_in) {
            if (as_list == FALSE) {
                if (last_cited_in != LiterateSource::section_of_par(par)) TextWeaver::commentary_text(tree, ap, I"), ");
                else TextWeaver::commentary_text(tree, ap, I", ");
            } else {
                Trees::make_child(WeaveTree::linebreak(tree), ap);
            }
        }
        TextWeaver::commentary_text(tree, ap, LiterateSource::section_of_par(hteu->usage_recorded_at)->sect_title);
        if (as_list == FALSE) TextWeaver::commentary_text(tree, ap, I" (");
        else TextWeaver::commentary_text(tree, ap, I" - ");
    }
    if (count_under++ > 0) TextWeaver::commentary_text(tree, ap, I", ");
    Trees::make_child(WeaveTree::locale(tree, hteu->usage_recorded_at, NULL), ap);
    last_cited_in = LiterateSource::section_of_par(hteu->usage_recorded_at);

§7. Non-paragraph subheadings.

void Weaver::weave_subheading(heterogeneous_tree *tree, weave_order *wv,
    tree_node *ap, text_stream *text) {
    tree_node *D = WeaveTree::subheading(tree, text);
    Trees::make_child(D, ap);
}

void Weaver::change_material(heterogeneous_tree *tree,
    weaver_state *state, int new_material, int plainly, programming_language *pl,
    text_stream *note) {
    if (state->kind_of_material != new_material) {
        tree_node *D = WeaveTree::material(tree, new_material, plainly, pl, note);
        if (state->carousel_node) Trees::make_child(D, state->carousel_node);
        else Trees::make_child(D, state->para_node);
        state->material_node = D;
        state->ap = D;
        state->kind_of_material = new_material;
    }
}

void Weaver::change_material_for_para(heterogeneous_tree *tree, weaver_state *state) {
    tree_node *D = WeaveTree::material(tree, COMMENTARY_MATERIAL, FALSE, NULL, NULL);
    Trees::make_child(D, state->para_node);
    state->material_node = D;
    state->ap = D;
    state->kind_of_material = COMMENTARY_MATERIAL;
}

void Weaver::figure(heterogeneous_tree *tree, weave_order *wv,
    tree_node *ap, text_stream *figname, int w, int h) {
    tree_node *F = WeaveTree::figure(tree, figname, w, h);
    Trees::make_child(F, ap);
}

void Weaver::commentary_text(heterogeneous_tree *tree, weave_order *wv,
    tree_node *ap, text_stream *matter) {
    TextWeaver::commentary_text(tree, ap, matter);
}

§8. Section tables of contents.These appear at the top of each woven section, and give links to the paragraphs marked as @h headings.

int Weaver::weave_table_of_contents(heterogeneous_tree *tree,
    tree_node *ap, ls_section *S) {
    int noteworthy = 0;
    for (ls_paragraph *par = S->literate_source->first_par; par; par = par->next_par)
        if (Str::len(LiterateSource::par_title(par)) > 0)
            noteworthy++;
    if (noteworthy == 0) return FALSE;

    tree_node *TOC = WeaveTree::table_of_contents(tree, WebRanges::of(S));
    Trees::make_child(TOC, ap);
    for (ls_paragraph *par = S->literate_source->first_par; par; par = par->next_par)
        if (Str::len(LiterateSource::par_title(par)) > 0) {
            TEMPORARY_TEXT(loc)
            WRITE_TO(loc, "%S%S", LiterateSource::par_ornament(par), par->paragraph_number);
            Trees::make_child(
                WeaveTree::contents_line(tree, loc,
                    par->titling.operand1, par), TOC);
            DISCARD_TEXT(loc)
        }
    return TRUE;
}