-
Notifications
You must be signed in to change notification settings - Fork 65
/
Individual Pages.w
176 lines (155 loc) · 7.14 KB
/
Individual Pages.w
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
[ExtensionPages::] Individual Pages.
To generate the individual pages on extensions in the extension mini-website.
@ //ExtensionWebsite::go// calls the following function to make either a
detailed or a sketchy documentation page on an extension, supplying either
a non-null |E| for details, or a non-null |ecd| for a sketch.
The outer shell function calls the inner one first to generate the main
page of the documentation (where |eg_number| is |-1|), then uses its return
value (the number of examples provided, which may be 0) to generate
associated files for each example.w
=
void ExtensionPages::write_page(extension_census_datum *ecd,
inform_extension *E, int force_update, inform_project *proj) {
if ((E) && (E->as_copy) &&
(LinkedLists::len(E->as_copy->errors_reading_source_text) > 0)) {
LOG("Not writing documentation on %f because errors occurred scanning it\n",
E->as_copy->location_if_file);
} else {
int c, eg_count;
eg_count = ExtensionPages::write_page_inner(ecd, E, -1, force_update, proj);
for (c=1; c<=eg_count; c++)
ExtensionPages::write_page_inner(ecd, E, c, force_update, proj);
}
}
@ Here then is the nub of it. An ECD is not really enough information to go on.
We are not always obliged to make a sketchy page from an ECD: we decide against
in a normal run where a page exists for it already, as otherwise a user with
many extensions installed would detect an annoying slight delay on every run
of Inform -- whereas a slight delay on each census-mode run is acceptable, since
census-mode runs are made only when extensions are installed or uninstalled.
If we do decide to make a page from an ECD, we in fact read the extension into
the lexer so as to make an E of it. Of course, it won't be a very interesting
E -- since it wasn't used in compilation there will be no definitions arising
from it, so the top half of its documentation page will be vacant -- but it
will at least provide the extension author's supplied documentation, if there
is any, as well as the correct identifying headings and requirements.
=
int ExtensionPages::write_page_inner(extension_census_datum *ecd,
inform_extension *E, int eg_number, int force_update, inform_project *proj) {
inbuild_work *work = NULL;
if (ecd) work = ecd->found_as->copy->edition->work;
else if (E) work = E->as_copy->edition->work;
else internal_error("write_page incorrectly called");
filename *F = ExtensionWebsite::page_URL(work, eg_number);
if (F == NULL) return 0;
int page_exists_already = TextFiles::exists(F);
LOGIF(EXTENSIONS_CENSUS, "Write %s (%X)/%d %s: %f\n",
(ecd)?"ecd":" ef", work, eg_number,
(page_exists_already)?"exists":"does not exist", F);
if (ecd) @<Convert ECD to a text-only E@>;
if (Pathnames::create_in_file_system(Filenames::up(F)) == 0) return 0;
text_stream DOCF_struct;
text_stream *OUT = &DOCF_struct;
if (STREAM_OPEN_TO_FILE(OUT, F, UTF8_ENC) == FALSE)
return 0; /* if we lack permissions, e.g., then write no documentation */
int no_egs = 0;
@<Write the actual extension documentation page@>;
STREAM_CLOSE(OUT);
return no_egs;
}
@ The reader may wonder why we perform the conversion in this slightly recursive
way, by calling our parent function again. Wouldn't it be simpler just to set
|ecd| to null and let events take their course? The answer is that this would
fail if there were examples, because we would return (say) 3 for the number
of examples, and then the function would be called 3 more times -- but with
the original ECD as argument each time: that would mean reading the file
thrice more, reconverting to E each time. So we restart the process from
our E, and return 0 in response to the ECD call to prevent further ECD calls.
@<Convert ECD to a text-only E@> =
if ((page_exists_already == FALSE) || (force_update)) {
Feeds::feed_C_string(L"This sentence provides a firebreak, no more. ");
E = ExtensionManager::from_copy(ecd->found_as->copy);
if (E == NULL) return 0; /* but shouldn't happen: it was there only moments ago */
Copies::get_source_text(E->as_copy);
ExtensionPages::write_page(NULL, E, force_update, proj);
}
return 0;
@<Write the actual extension documentation page@> =
InformPages::header(OUT, I"Extension", JAVASCRIPT_FOR_ONE_EXTENSION_IRES, NULL);
HTML::incorporate_HTML(OUT,
InstalledFiles::filename(EXTENSION_DOCUMENTATION_MODEL_IRES));
@<Write documentation for a specific extension into the page@>;
InformPages::footer(OUT);
@<Write documentation for a specific extension into the page@> =
HTML_OPEN("p");
if (Works::is_standard_rules(work) == FALSE)
@<Write Javascript paste icon for source text to include this extension@>;
WRITE("<b>");
Works::write_to_HTML_file(OUT, work, TRUE);
WRITE("</b>");
HTML_CLOSE("p");
HTML_OPEN("p");
HTML_OPEN_WITH("span", "class=\"smaller\"");
@<Write up any restrictions on VM usage@>;
if (E) @<Write up the version number, if any, and location@>;
HTML_CLOSE("span");
HTML_CLOSE("p");
if (E) {
filename *B = ExtensionWebsite::page_URL(work, -1);
TEMPORARY_TEXT(leaf)
Filenames::write_unextended_leafname(leaf, B);
@<Write up the rubric, if any@>;
@<Write up the table of contents for the supplied documentation, if any@>;
#ifdef CORE_MODULE
IndexExtensions::document_in_detail(OUT, E);
#endif
@<Write up the supplied documentation, if any@>;
DISCARD_TEXT(leaf)
} else {
HTML_TAG("hr");
}
@<Write Javascript paste icon for source text to include this extension@> =
TEMPORARY_TEXT(inclusion_text)
WRITE_TO(inclusion_text, "Include %X.\n\n\n", work);
PasteButtons::paste_text(OUT, inclusion_text);
DISCARD_TEXT(inclusion_text)
WRITE(" ");
@<Write up any restrictions on VM usage@> =
compatibility_specification *C = E->as_copy->edition->compatibility;
if (Str::len(C->parsed_from) > 0) {
WRITE("%S ", C->parsed_from);
ExtensionIndex::write_icons(OUT, C);
}
@<Write up the version number, if any, and location@> =
semantic_version_number V = E->as_copy->edition->version;
if (VersionNumbers::is_null(V) == FALSE) WRITE("Version %v", &V);
if (E->loaded_from_built_in_area) {
if (VersionNumbers::is_null(V)) { WRITE("Extension"); }
WRITE(" built in to Inform");
}
@<Write up the rubric, if any@> =
if (Str::len(E->rubric_as_lexed) > 0) {
HTML_OPEN("p"); WRITE("%S", E->rubric_as_lexed); HTML_CLOSE("p");
}
if (Str::len(E->extra_credit_as_lexed) > 0) {
HTML_OPEN("p"); WRITE("<i>%S</i>", E->extra_credit_as_lexed); HTML_CLOSE("p");
}
@ This appears above the definition paragraphs because it tends to be only
large extensions which provide TOCs: and they, ipso facto, make many definitions.
If the TOC were directly at the top of the supplied documentation, it might
easily be scrolled down off screen when the user first visits the page.
@<Write up the table of contents for the supplied documentation, if any@> =
if (Wordings::nonempty(E->documentation_text)) {
HTML_OPEN("p");
DocumentationRenderer::table_of_contents(E->documentation_text, OUT, leaf);
HTML_CLOSE("p");
}
@<Write up the supplied documentation, if any@> =
if (Wordings::nonempty(E->documentation_text))
no_egs = DocumentationRenderer::set_body_text(E->documentation_text, OUT,
eg_number, leaf);
else {
HTML_OPEN("p");
WRITE("The extension provides no documentation.");
HTML_CLOSE("p");
}