inweb-bootstrap/Chapter_3/The_Weaver_of_Text.nw

347 lines
12 KiB
Text
Raw Normal View History

2020-04-20 22:26:08 +00:00
[TextWeaver::] The Weaver of Text.
To manage the weaving of commentary or source code text.
2024-03-09 06:17:52 +00:00
@ \section{Commentary text.}
2020-04-20 22:26:08 +00:00
The following takes text, divides it up at stroke-mark boundaries --
2024-03-09 06:17:52 +00:00
that is, [[this is inside]], this is outside -- and sends contiguous pieces
of it either to [[TextWeaver::inline_code_fragment]] or [[TextWeaver::commentary_fragment]]
2020-04-20 22:26:08 +00:00
as appropriate.
2024-03-09 06:17:52 +00:00
<<*>>=
2020-04-20 22:26:08 +00:00
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"));
2024-03-09 06:17:52 +00:00
if (Str::ne(code_in_comments_notation, I"Off")) <<Split text and code extracts>>;
2020-04-20 22:26:08 +00:00
int display_flag = TRUE;
text_stream *tex_notation = Bibliographic::get_datum(wv->weave_web->md,
I"TeX Mathematics Displayed Notation");
2024-03-09 06:17:52 +00:00
if (Str::ne(tex_notation, I"Off")) <<Recognise mathematics>>;
2020-04-20 22:26:08 +00:00
display_flag = FALSE;
tex_notation = Bibliographic::get_datum(wv->weave_web->md,
I"TeX Mathematics Notation");
2024-03-09 06:17:52 +00:00
if (Str::ne(tex_notation, I"Off")) <<Recognise mathematics>>;
2020-04-20 22:26:08 +00:00
text_stream *xref_notation = Bibliographic::get_datum(wv->weave_web->md,
I"Cross-References Notation");
2024-03-09 06:17:52 +00:00
if (Str::ne(xref_notation, I"Off")) <<Recognise cross-references>>;
2020-04-20 22:26:08 +00:00
if (within) {
TextWeaver::inline_code_fragment(tree, ap, matter);
} else {
2024-03-09 06:17:52 +00:00
<<Recognise hyperlinks>>;
<<Detect use of footnotes>>;
2020-04-20 22:26:08 +00:00
TextWeaver::commentary_fragment(tree, ap, matter, in_code);
}
}
2024-03-09 06:17:52 +00:00
<<Split text and code extracts>>=
2020-04-20 22:26:08 +00:00
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)) {
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(before)
2020-04-20 22:26:08 +00:00
Str::copy(before, matter); Str::truncate(before, i);
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(after)
2020-04-20 22:26:08 +00:00
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);
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(before)
DISCARD_TEXT(after)
2020-04-20 22:26:08 +00:00
return;
}
}
2024-03-09 06:17:52 +00:00
<<Recognise hyperlinks>>=
2020-04-20 22:26:08 +00:00
for (int i=0; i < Str::len(matter); i++) {
if ((Str::includes_at(matter, i, I"http://")) ||
(Str::includes_at(matter, i, I"https://"))) {
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(before)
2020-04-20 22:26:08 +00:00
Str::copy(before, matter); Str::truncate(before, i);
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(after)
2020-04-20 22:26:08 +00:00
Str::substr(after, Str::at(matter, i), Str::end(matter));
match_results mr = Regexp::create_mr();
if (Regexp::match(&mr, after, L"(https*://%C+)(%c*)")) {
while (TextWeaver::boundary_character(FALSE, Str::get_last_char(mr.exp[0]))) {
wchar_t c = Str::get_last_char(mr.exp[0]);
Str::delete_last_character(mr.exp[0]);
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(longer)
WRITE_TO(longer, "%c%S", c, mr.exp[1]);
Str::clear(mr.exp[1]);
Str::copy(mr.exp[1], longer);
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(longer)
}
2020-04-20 22:26:08 +00:00
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);
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(before)
DISCARD_TEXT(after)
2020-04-20 22:26:08 +00:00
}
}
2024-03-09 06:17:52 +00:00
<<Recognise mathematics>>=
2020-04-20 22:26:08 +00:00
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;
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(before)
TEMPORARY_TEXT(maths)
TEMPORARY_TEXT(after)
2020-04-20 22:26:08 +00:00
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;
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(before)
DISCARD_TEXT(maths)
DISCARD_TEXT(after)
2020-04-20 22:26:08 +00:00
if (allow) return;
}
j++;
}
}
}
2024-03-09 06:17:52 +00:00
<<Detect use of footnotes>>=
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(before)
TEMPORARY_TEXT(cue)
TEMPORARY_TEXT(after)
2020-04-20 22:26:08 +00:00
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);
}
}
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(before)
DISCARD_TEXT(cue)
DISCARD_TEXT(after)
2020-04-20 22:26:08 +00:00
if (allow) return;
2024-03-09 06:17:52 +00:00
<<Recognise cross-references>>=
2020-04-20 22:26:08 +00:00
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))))) {
2020-04-20 22:26:08 +00:00
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))))) {
2020-04-20 22:26:08 +00:00
int allow = FALSE;
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(before)
TEMPORARY_TEXT(reference)
TEMPORARY_TEXT(after)
2020-04-20 22:26:08 +00:00
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));
2024-03-09 06:17:52 +00:00
<<Attempt to resolve the cross-reference>>;
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(before)
DISCARD_TEXT(reference)
DISCARD_TEXT(after)
2020-04-20 22:26:08 +00:00
if (allow) return;
}
j++;
}
}
}
2024-03-09 06:17:52 +00:00
<<Attempt to resolve the cross-reference>>=
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(url)
TEMPORARY_TEXT(title)
int ext = FALSE;
2020-04-20 22:26:08 +00:00
if (Colonies::resolve_reference_in_weave(url, title, wv->weave_to, reference,
wv->weave_web->md, wv->current_weave_line, &ext)) {
2020-04-20 22:26:08 +00:00
TextWeaver::commentary_r(tree, ap, before, within, in_code);
Trees::make_child(WeaveTree::url(tree, url, title, ext), ap);
2020-04-20 22:26:08 +00:00
TextWeaver::commentary_r(tree, ap, after, within, in_code);
allow = TRUE;
}
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(url)
DISCARD_TEXT(title)
2020-04-20 22:26:08 +00:00
@ This tests whether a cross-reference is allowed to begin or end: it must
begin after and finish before a "boundary character".
2024-03-09 06:17:52 +00:00
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.
2020-04-20 22:26:08 +00:00
2024-03-09 06:17:52 +00:00
<<*>>=
int TextWeaver::boundary_character(int before, wchar_t c) {
if (c == 0) return TRUE;
if (Characters::is_whitespace(c)) return TRUE;
2024-03-09 06:17:52 +00:00
if ((c == '.') [[| (c == ',') || (c == '!') || (c == '?') || (c == ';') |]]
(c == '(')|| (c == ')')) return TRUE;
if ((before == FALSE) && (c == ':')) return TRUE;
return FALSE;
}
2024-03-09 06:17:52 +00:00
<<*>>=
2020-04-20 22:26:08 +00:00
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);
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(colouring)
2020-04-20 22:26:08 +00:00
for (int i=0; i< Str::len(fragment); i++) PUT_TO(colouring, EXTRACT_COLOUR);
tree_node *SC = WeaveTree::source_code(tree, fragment, colouring);
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(colouring)
2020-04-20 22:26:08 +00:00
Trees::make_child(SC, I);
}
2024-03-09 06:17:52 +00:00
@ \section{Code text.}
2020-04-20 22:26:08 +00:00
2024-03-09 06:17:52 +00:00
<<*>>=
2020-04-20 22:26:08 +00:00
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) {
2024-03-09 06:17:52 +00:00
<<Pick up hyperlinking at the eleventh hour>>;
2020-04-20 22:26:08 +00:00
text_stream *xref_notation = Bibliographic::get_datum(wv->weave_web->md,
I"Cross-References Notation");
if (Str::ne(xref_notation, I"Off"))
2024-03-09 06:17:52 +00:00
<<Pick up cross-references at the eleventh hour>>;
2020-04-20 22:26:08 +00:00
}
if ((Str::get_at(colouring, i) == FUNCTION_COLOUR) &&
(wv->current_weave_line->category != TEXT_EXTRACT_LCAT)) {
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(fname)
2020-04-20 22:26:08 +00:00
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))
2024-03-09 06:17:52 +00:00
<<Spot the function>>;
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(fname)
2020-04-20 22:26:08 +00:00
}
}
if (from < Str::len(matter))
TextWeaver::source_code_piece(tree, ap, matter, colouring, from, Str::len(matter));
}
2024-03-09 06:17:52 +00:00
<<Pick up hyperlinking at the eleventh hour>>=
2020-04-20 22:26:08 +00:00
if ((Str::includes_at(matter, i, I"http://")) ||
(Str::includes_at(matter, i, I"https://"))) {
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(after)
2020-04-20 22:26:08 +00:00
Str::substr(after, Str::at(matter, i), Str::end(matter));
match_results mr = Regexp::create_mr();
if (Regexp::match(&mr, after, L"(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;
}
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(after)
2020-04-20 22:26:08 +00:00
}
2024-03-09 06:17:52 +00:00
<<Pick up cross-references at the eleventh hour>>=
2020-04-20 22:26:08 +00:00
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)) {
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(reference)
2020-04-20 22:26:08 +00:00
Str::substr(reference, Str::at(matter, i + N), Str::at(matter, j));
2024-03-09 06:17:52 +00:00
<<Attempt to resolve the cross-reference at the eleventh hour>>;
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(reference)
2020-04-20 22:26:08 +00:00
break;
}
j++;
}
}
2024-03-09 06:17:52 +00:00
<<Attempt to resolve the cross-reference at the eleventh hour>>=
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(url)
TEMPORARY_TEXT(title)
int ext = FALSE;
2020-04-20 22:26:08 +00:00
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);
2020-04-20 22:26:08 +00:00
TextWeaver::source_code_piece(tree, ap, matter, colouring, from, i);
Trees::make_child(U, ap);
i = j + N;
from = i;
}
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(url)
DISCARD_TEXT(title)
2020-04-20 22:26:08 +00:00
2024-03-09 06:17:52 +00:00
<<Spot the function>>=
2020-04-20 22:26:08 +00:00
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;
}
}
2024-03-09 06:17:52 +00:00
<<*>>=
2020-04-20 22:26:08 +00:00
void TextWeaver::source_code_piece(heterogeneous_tree *tree, tree_node *ap,
text_stream *matter, text_stream *colouring, int from, int to) {
if (to > from) {
2020-06-27 22:03:14 +00:00
TEMPORARY_TEXT(m)
TEMPORARY_TEXT(c)
2020-04-20 22:26:08 +00:00
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);
2020-06-27 22:03:14 +00:00
DISCARD_TEXT(m)
DISCARD_TEXT(c)
2020-04-20 22:26:08 +00:00
}
}