To write rendering instructions for commentary or source code text.


§1. Commentary text.This section deals with commentary which is not written in Markdown format, but in Inweb's older format.

The following takes text, divides it up at stroke-mark boundaries — that is, this is inside, this is outside — and sends contiguous pieces of it either to TextWeaver::inline_code_fragment or TextWeaver::commentary_fragment as appropriate.

void TextWeaver::commentary_text(heterogeneous_tree *tree, tree_node *ap, text_stream *matter) {
    TextWeaver::commentary_r(tree, ap, matter, FALSE, FALSE);
}
void TextWeaver::comment_text_in_code(heterogeneous_tree *tree, tree_node *ap, text_stream *matter) {
    TextWeaver::commentary_r(tree, ap, matter, FALSE, TRUE);
}

void TextWeaver::commentary_r(heterogeneous_tree *tree, tree_node *ap, text_stream *matter,
    int within, int in_code) {
    weave_document_node *C = RETRIEVE_POINTER_weave_document_node(tree->root->content);
    weave_order *wv = C->wv;
    text_stream *code_in_comments_notation =
        Bibliographic::get_datum(wv->weave_web,
        (in_code)?(I"Code In Code Comments Notation"):(I"Code In Commentary Notation"));
    if (Str::ne(code_in_comments_notation, I"Off")) Split text and code extracts1.1;

    int display_flag = TRUE;
    text_stream *tex_notation = Bibliographic::get_datum(wv->weave_web,
        I"TeX Mathematics Displayed Notation");
    if (Str::ne(tex_notation, I"Off")) Recognise mathematics1.3;
    display_flag = FALSE;
    tex_notation = Bibliographic::get_datum(wv->weave_web,
        I"TeX Mathematics Notation");
    if (Str::ne(tex_notation, I"Off")) Recognise mathematics1.3;

    text_stream *xref_notation = Bibliographic::get_datum(wv->weave_web,
        I"Cross-References Notation");
    if (Str::ne(xref_notation, I"Off")) Recognise cross-references1.5;

    if (within) {
        TextWeaver::inline_code_fragment(tree, ap, matter);
    } else {
        Recognise hyperlinks1.2;
        Detect use of footnotes1.4;
        TextWeaver::commentary_fragment(tree, ap, matter, in_code);
    }
}

§1.1. Split text and code extracts1.1 =

    for (int i=0; i < Str::len(matter); i++) {
        if (Str::get_at(matter, i) == '\\') i += Str::len(code_in_comments_notation) - 1;
        else if (Str::includes_at(matter, i, code_in_comments_notation)) {
            TEMPORARY_TEXT(before)
            Str::copy(before, matter); Str::truncate(before, i);
            TEMPORARY_TEXT(after)
            Str::substr(after, Str::at(matter,
                i + Str::len(code_in_comments_notation)), Str::end(matter));
            TextWeaver::commentary_r(tree, ap, before, within, in_code);
            TextWeaver::commentary_r(tree, ap, after, (within)?FALSE:TRUE, in_code);
            DISCARD_TEXT(before)
            DISCARD_TEXT(after)
            return;
        }
    }

§1.2. Recognise hyperlinks1.2 =

    for (int i=0; i < Str::len(matter); i++) {
        if ((Str::includes_at(matter, i, I"http:")) 
                (Str::includes_at(matter, i, I"https:"))) {
            TEMPORARY_TEXT(before)
            Str::copy(before, matter); Str::truncate(before, i);
            TEMPORARY_TEXT(after)
            Str::substr(after, Str::at(matter, i), Str::end(matter));
            match_results mr = Regexp::create_mr();
            if (Regexp::match(&mr, after, U"(https*:%C+)(%c*)")) {
                while (TextWeaver::boundary_character(FALSE, Str::get_last_char(mr.exp[0]))) {
                    inchar32_t c = Str::get_last_char(mr.exp[0]);
                    Str::delete_last_character(mr.exp[0]);
                    TEMPORARY_TEXT(longer)
                    WRITE_TO(longer, "%c%S", c, mr.exp[1]);
                    Str::clear(mr.exp[1]);
                    Str::copy(mr.exp[1], longer);
                    DISCARD_TEXT(longer)
                }
                TextWeaver::commentary_r(tree, ap, before, within, in_code);
                Trees::make_child(WeaveTree::url(tree, mr.exp[0], mr.exp[0], TRUE), ap);
                TextWeaver::commentary_r(tree, ap, mr.exp[1], within, in_code);
                Regexp::dispose_of(&mr);
                return;
            }
            Regexp::dispose_of(&mr);
            DISCARD_TEXT(before)
            DISCARD_TEXT(after)
        }
    }

§1.3. Recognise mathematics1.3 =

    int N = Str::len(tex_notation);
    for (int i=0; i < Str::len(matter); i++) {
        if ((within == FALSE) && (Str::includes_at(matter, i, tex_notation))) {
            int j = i + N;
            while (j < Str::len(matter)) {
                if (Str::includes_at(matter, j, tex_notation)) {
                    int allow = FALSE;
                    TEMPORARY_TEXT(before)
                    TEMPORARY_TEXT(maths)
                    TEMPORARY_TEXT(after)
                    Str::substr(before, Str::start(matter), Str::at(matter, i));
                    Str::substr(maths, Str::at(matter, i + N), Str::at(matter, j));
                    Str::substr(after, Str::at(matter, j + N), Str::end(matter));
                    TextWeaver::commentary_r(tree, ap, before, within, in_code);
                    Trees::make_child(WeaveTree::mathematics(tree, maths, display_flag), ap);
                    TextWeaver::commentary_r(tree, ap, after, within, in_code);
                    allow = TRUE;
                    DISCARD_TEXT(before)
                    DISCARD_TEXT(maths)
                    DISCARD_TEXT(after)
                    if (allow) return;
                }
                j++;
            }
        }
    }

§1.4. Detect use of footnotes1.4 =

    TEMPORARY_TEXT(before)
    TEMPORARY_TEXT(cue)
    TEMPORARY_TEXT(after)
    int allow = FALSE;
    if (LiterateSource::detect_footnote(wv->weave_web->web_syntax,
            matter, before, cue, after)) {
        ls_footnote *F = LiterateSource::find_footnote_in_para(
            LiterateSource::par_of_line(wv->current_weave_line), cue);
        if (F) {
            F->cued_already = TRUE;
            allow = TRUE;
            TextWeaver::commentary_r(tree, ap, before, within, in_code);
            Trees::make_child(WeaveTree::footnote_cue(tree, F->cue_text), ap);
            TextWeaver::commentary_r(tree, ap, after, within, in_code);
        } else {
            WebErrors::issue_at(I"this is a cue for a missing note", wv->current_weave_line);
        }
    }
    DISCARD_TEXT(before)
    DISCARD_TEXT(cue)
    DISCARD_TEXT(after)
    if (allow) return;

§1.5. Recognise cross-references1.5 =

    int N = Str::len(xref_notation);
    for (int i=0; i < Str::len(matter); i++) {
        if ((within == FALSE) && (Str::includes_at(matter, i, xref_notation)) &&
            ((i == 0) || (TextWeaver::boundary_character(TRUE,
                Str::get_at(matter, i-1))))) {
            int j = i + N+1;
            while (j < Str::len(matter)) {
                if ((Str::includes_at(matter, j, xref_notation)) &&
                    (TextWeaver::boundary_character(FALSE,
                        Str::get_at(matter, j+Str::len(xref_notation))))) {
                    int allow = FALSE;
                    TEMPORARY_TEXT(before)
                    TEMPORARY_TEXT(reference)
                    TEMPORARY_TEXT(after)
                    Str::substr(before, Str::start(matter), Str::at(matter, i));
                    Str::substr(reference, Str::at(matter, i + N), Str::at(matter, j));
                    Str::substr(after, Str::at(matter, j + N), Str::end(matter));
                    Attempt to resolve the cross-reference1.5.1;
                    DISCARD_TEXT(before)
                    DISCARD_TEXT(reference)
                    DISCARD_TEXT(after)
                    if (allow) return;
                }
                j++;
            }
        }
    }

§1.5.1. Attempt to resolve the cross-reference1.5.1 =

    TEMPORARY_TEXT(url)
    TEMPORARY_TEXT(title)
    int ext = FALSE;
    if (Colonies::resolve_reference_in_weave(url, title, wv->weave_to, reference,
        wv->weave_web, wv->current_weave_line, &ext)) {
        TextWeaver::commentary_r(tree, ap, before, within, in_code);
        Trees::make_child(WeaveTree::url(tree, url, title, ext), ap);
        TextWeaver::commentary_r(tree, ap, after, within, in_code);
        allow = TRUE;
    }
    DISCARD_TEXT(url)
    DISCARD_TEXT(title)

§2. This tests whether a cross-reference is allowed to begin or end: it must begin after and finish before a "boundary character".

Note the one-sided treatment of :, which is a boundary after but not before, so that http:// won't trigger a cross-reference with the standard // xref notation.

int TextWeaver::boundary_character(int before, inchar32_t c) {
    if (c == 0) return TRUE;
    if (Characters::is_whitespace(c)) return TRUE;
    if ((c == '.') || (c == ',') || (c == '!') || (c == '?') || (c == ';') ||
        (c == '(')|| (c == ')')) return TRUE;
    if ((before == FALSE) && (c == ':')) return TRUE;
    return FALSE;
}

§3.

void TextWeaver::commentary_fragment(heterogeneous_tree *tree, tree_node *ap,
    text_stream *fragment, int in_code) {
    if (Str::len(fragment) > 0)
        Trees::make_child(WeaveTree::commentary(tree, fragment, in_code), ap);
}

void TextWeaver::inline_code_fragment(heterogeneous_tree *tree, tree_node *ap, text_stream *fragment) {
    tree_node *I = WeaveTree::inline(tree);
    Trees::make_child(I, ap);
    TEMPORARY_TEXT(colouring)
    for (int i=0; i< Str::len(fragment); i++) PUT_TO(colouring, EXTRACT_COLOUR);
    tree_node *SC = WeaveTree::source_code(tree, fragment, colouring);
    DISCARD_TEXT(colouring)
    Trees::make_child(SC, I);
}

§4. Code text.

void TextWeaver::source_code(heterogeneous_tree *tree, tree_node *ap,
    text_stream *matter, text_stream *colouring, int linked) {
    weave_document_node *C = RETRIEVE_POINTER_weave_document_node(tree->root->content);
    weave_order *wv = C->wv;
    Str::truncate(colouring, Str::len(matter));
    int from = 0;
    for (int i=0; i < Str::len(matter); i++) {
        if (linked) {
            Pick up hyperlinking at the eleventh hour4.1;
            text_stream *xref_notation = Bibliographic::get_datum(wv->weave_web,
                I"Cross-References Notation");
            if (Str::ne(xref_notation, I"Off"))
                Pick up cross-references at the eleventh hour4.2;
        }
        if ((Str::get_at(colouring, i) == FUNCTION_COLOUR) &&
            (LiterateSource::is_text_extract_chunk(wv->current_weave_line->owning_chunk) == FALSE)) {
            TEMPORARY_TEXT(fname)
            int j = i;
            while (Str::get_at(colouring, j) == FUNCTION_COLOUR)
                PUT_TO(fname, Str::get_at(matter, j++));
            if (CodeAnalysis::is_reserved_word_for_section(
                LiterateSource::section_of_line(wv->current_weave_line), fname, FUNCTION_COLOUR))
                Spot the function4.3;
            DISCARD_TEXT(fname)
        }

    }
    if (from < Str::len(matter))
        TextWeaver::source_code_piece(tree, ap, matter, colouring, from, Str::len(matter));
}

§4.1. Pick up hyperlinking at the eleventh hour4.1 =

    if ((Str::includes_at(matter, i, I"http:")) 
        (Str::includes_at(matter, i, I"https:"))) {
        TEMPORARY_TEXT(after)
        Str::substr(after, Str::at(matter, i), Str::end(matter));
        match_results mr = Regexp::create_mr();
        if (Regexp::match(&mr, after, U"(https*:%C+)(%c*)")) {
            tree_node *U = WeaveTree::url(tree, mr.exp[0], mr.exp[0], TRUE);
            TextWeaver::source_code_piece(tree, ap, matter, colouring, from, i);
            Trees::make_child(U, ap);
            i += Str::len(mr.exp[0]);
            from = i;
        }
        DISCARD_TEXT(after)
    }

§4.2. Pick up cross-references at the eleventh hour4.2 =

    int N = Str::len(xref_notation);
    if ((Str::includes_at(matter, i, xref_notation))) {
        int j = i + N+1;
        while (j < Str::len(matter)) {
            if (Str::includes_at(matter, j, xref_notation)) {
                TEMPORARY_TEXT(reference)
                Str::substr(reference, Str::at(matter, i + N), Str::at(matter, j));
                Attempt to resolve the cross-reference at the eleventh hour4.2.1;
                DISCARD_TEXT(reference)
                break;
            }
            j++;
        }
    }

§4.2.1. Attempt to resolve the cross-reference at the eleventh hour4.2.1 =

    TEMPORARY_TEXT(url)
    TEMPORARY_TEXT(title)
    int ext = FALSE;
    if (Colonies::resolve_reference_in_weave(url, title, wv->weave_to, reference,
        wv->weave_web, wv->current_weave_line, &ext)) {
        tree_node *U = WeaveTree::url(tree, url, title, ext);
        TextWeaver::source_code_piece(tree, ap, matter, colouring, from, i);
        Trees::make_child(U, ap);
        i = j + N;
        from = i;
    }
    DISCARD_TEXT(url)
    DISCARD_TEXT(title)

§4.3. Spot the function4.3 =

    language_function *fn = CodeAnalysis::get_function(
        LiterateSource::section_of_line(wv->current_weave_line), fname, FUNCTION_COLOUR);
    if (fn) {
        ls_paragraph *par = Functions::declaration_lsparagraph(fn);
        if (wv->current_weave_line == fn->function_header_at) {
            if (fn->usage_described == FALSE) {
                TextWeaver::source_code_piece(tree, ap, matter, colouring, from, i);
                tree_node *FD = WeaveTree::function_defn(tree, fn);
                Trees::make_child(FD, ap);
                Weaver::show_function_usage(tree, wv, FD, par, fn, TRUE);
                i += Str::len(fname) - 1;
                from = i+1;
            }
        } else {
            TextWeaver::source_code_piece(tree, ap, matter, colouring, from, i);
            TEMPORARY_TEXT(url)
            Colonies::paragraph_URL(url, par, wv->weave_to);
            tree_node *U = WeaveTree::function_usage(tree, url, fn);
            Trees::make_child(U, ap);
            i += Str::len(fname) - 1;
            from = i+1;
        }
    }

§5.

void TextWeaver::source_code_piece(heterogeneous_tree *tree, tree_node *ap,
    text_stream *matter, text_stream *colouring, int from, int to) {
    if (to > from) {
        TEMPORARY_TEXT(m)
        TEMPORARY_TEXT(c)
        Str::substr(m, Str::at(matter, from), Str::at(matter, to));
        Str::substr(c, Str::at(colouring, from), Str::at(colouring, to));
        tree_node *SC = WeaveTree::source_code(tree, m, c);
        Trees::make_child(SC, ap);
        DISCARD_TEXT(m)
        DISCARD_TEXT(c)
    }
}