To manage the weaving of commentary or source code text.
§1. Commentary text. 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->md, (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->md, 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->md, I"TeX Mathematics Notation"); if (Str::ne(tex_notation, I"Off")) Recognise mathematics1.3; text_stream *xref_notation = Bibliographic::get_datum(wv->weave_web->md, 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; } }
- This code is used in §1.
§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) } }
- This code is used in §1.
§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++; } } }
- This code is used in §1 (twice).
§1.4. Detect use of footnotes1.4 =
TEMPORARY_TEXT(before) TEMPORARY_TEXT(cue) TEMPORARY_TEXT(after) int allow = FALSE; if (Parser::detect_footnote(wv->weave_web, matter, before, cue, after)) { footnote *F = Parser::find_footnote_in_para( wv->current_weave_line->owning_paragraph, 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 { Main::error_in_web(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;
- This code is used in §1.
§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++; } } }
- This code is used in §1.
§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->md, 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)
- This code is used in §1.5.
§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; }
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); }
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->md, 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) && (wv->current_weave_line->category != TEXT_EXTRACT_LCAT)) { TEMPORARY_TEXT(fname) int j = i; while (Str::get_at(colouring, j) == FUNCTION_COLOUR) PUT_TO(fname, Str::get_at(matter, j++)); if (Analyser::is_reserved_word_for_section( wv->current_weave_line->owning_section, 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) }
- This code is used in §4.
§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++; } }
- This code is used in §4.
§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->md, 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)
- This code is used in §4.2.
language_function *fn = Analyser::get_function( wv->current_weave_line->owning_section, fname, FUNCTION_COLOUR); if (fn) { source_line *defn_line = fn->function_header_at; if (wv->current_weave_line == defn_line) { 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, defn_line->owning_paragraph, 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, defn_line->owning_paragraph, 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; } }
- This code is used in §4.
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) } }