1
0
Fork 0
mirror of https://github.com/ganelson/inform.git synced 2024-07-03 07:24:58 +03:00
inform7/inter/index-module/Chapter 2/Index Interpreter.w
2021-07-27 00:42:09 +01:00

203 lines
7.3 KiB
OpenEdge ABL

[InterpretIndex::] Index Interpreter.
An index is generated by interpreting an index structure file.
@ The index is generated by a bare-bones structure file. These are identified
by name: in particular |Basic| is the barer version, for Basic Inform projects,
while |Standard| is the index as generated to suit typical IF uses of the Standard
Rules -- so, in other words, that's the index which most Inform users know.
These names have to correspond to |.indext| structure files stored in the
Inform distribution.
The structure file really just shows which index elements to include on which
pages. For example:
= (text)
page Kinds e9cf08
element Ch
element Ar
element Vl
=
declares a new index page with leafname |Kinds.html|, and with the highlight
colour (in CSS hexadecimal style) |e9cf08|; and then declzres that it contains
the three elements |Ch|, |Ar| and |Vl|, in that order. Note that this file does
not contain any user-facing text: all of that comes from //html: Localisation//.
The file also doesn't contain instructions for what goes into those elements.
All of that is hardwired into this module's code: for example, |Ar| is generated
by the function //ArithmeticElement::render// in //Arithmetic Element//.
The method here is basically to read all the declarations, generating a set
of //index_page// and //index_element// objects to represent them, and only to
begin writing some HTML when this scanning is done, i.e., when the whole structure
file has been read.
=
void InterpretIndex::generate(text_stream *structure, index_session *session) {
localisation_dictionary *D = Indexing::get_localisation(session);
Indexing::empty_list_of_pages(session);
filename *index_structure = InstalledFiles::index_structure_file(structure);
@<Read the structure file line by line@>;
@<Actually generate the index files@>;
}
@<Read the structure file line by line@> =
TextFiles::read(index_structure, FALSE, "unable to read index structure file", TRUE,
&InterpretIndex::read_structure, NULL, (void *) session);
@ |contents| is currently implemented identically to |pages|, but it is supposed to
represent the home page of the index. The declaration for it should come
last in the structure file, like so:
= (text)
contents Welcome 111111
=
It has no elements, because its only content will be a menu of links to the other
pages.
=
void InterpretIndex::read_structure(text_stream *text, text_file_position *tfp, void *state) {
index_session *session = (index_session *) state;
localisation_dictionary *D = Indexing::get_localisation(session);
match_results mr = Regexp::create_mr();
if (Regexp::match(&mr, text, L"page (%C+) (%C+)")) {
@<Register a new index page@>;
} else if (Regexp::match(&mr, text, L"contents (%C+) (%C+)")) {
@<Register a new index page@>;
} else if (Regexp::match(&mr, text, L"element (%C+)")) {
@<Register a new index element@>;
}
Regexp::dispose_of(&mr);
}
@ Note that the heading written on |Kinds.html|, say, is drawn from the
localisation file under the key |%Title| in the context |%%Kinds|. In English,
that will be "Kinds", but if the index is being generated with a Dutch localisation
dictionary then perhaps it would be "Soorten". Under the hood, though, the filename
will be |Kinds.html| either way.
@<Register a new index page@> =
text_stream *col = mr.exp[1];
text_stream *key = mr.exp[0];
TEMPORARY_TEXT(path)
WRITE_TO(path, "Index.Pages.%S.Title", key);
text_stream *heading = Localisation::read(D, path);
Str::clear(path);
WRITE_TO(path, "Index.Pages.%S.Caption", key);
text_stream *explanation = Localisation::read(D, path);
DISCARD_TEXT(path)
InterpretIndex::register_page(col, heading, explanation, key, session);
@<Register a new index element@> =
index_page *latest = Indexing::latest_page(session);
if (latest == NULL) internal_error("element without page");
text_stream *elt = mr.exp[0];
TEMPORARY_TEXT(tkey)
TEMPORARY_TEXT(hkey)
WRITE_TO(tkey, "Index.Elements.%S.Title", elt);
WRITE_TO(hkey, "Index.Elements.%S.Heading", elt);
InterpretIndex::register_element(elt, latest, Localisation::read(D, tkey), hkey);
DISCARD_TEXT(tkey)
DISCARD_TEXT(hkey)
@<Actually generate the index files@> =
index_page *page;
linked_list *L = Indexing::get_list_of_pages(session);
LOOP_OVER_LINKED_LIST(page, index_page, L) {
TEMPORARY_TEXT(leafname)
WRITE_TO(leafname, "%S.html", page->page_leafname);
TEMPORARY_TEXT(key)
WRITE_TO(key, "Index.Pages.%S.Title", page->page_leafname);
text_stream index_file_struct; text_stream *OUT = &index_file_struct;
InterpretIndex::open_file(OUT, page, leafname, Localisation::read(D, key),
-1, session);
Elements::periodic_table(OUT, page, leafname, session);
InterpretIndex::close_index_file(OUT);
DISCARD_TEXT(key)
DISCARD_TEXT(leafname)
}
GroupedElement::detail_pages(session);
@h Registering.
So, then, here are the objects representing the index pages and their elements
of content:
=
typedef struct index_page {
int no_elements;
struct text_stream *key_colour;
struct text_stream *page_title;
struct text_stream *page_explanation;
struct text_stream *page_leafname;
struct linked_list *elements; /* of |index_element| */
struct index_session *for_session;
CLASS_DEFINITION
} index_page;
index_page *InterpretIndex::register_page(text_stream *col, text_stream *title,
text_stream *exp, text_stream *leaf, index_session *session) {
index_page *new_page = CREATE(index_page);
new_page->no_elements = 0;
new_page->key_colour = Str::duplicate(col);
new_page->page_title = Str::duplicate(title);
new_page->page_explanation = Str::duplicate(exp);
new_page->page_leafname = Str::duplicate(leaf);
new_page->elements = NEW_LINKED_LIST(index_element);
new_page->for_session = session;
Indexing::add_page(session, new_page);
return new_page;
}
@ =
typedef struct index_element {
int atomic_number; /* 1, 2, 3, ..., within its page */
struct text_stream *chemical_symbol;
struct text_stream *element_name;
struct text_stream *explanation_key;
struct index_page *owning_page;
CLASS_DEFINITION
} index_element;
index_element *InterpretIndex::register_element(text_stream *abb, index_page *owner,
text_stream *title, text_stream *explanation) {
if (owner == NULL)
internal_error("template creates index elements improperly");
if (Str::len(abb) > 2)
internal_error("abbreviation for index element too long");
index_element *ie = CREATE(index_element);
ie->owning_page = owner;
ie->atomic_number = ++(owner->no_elements);
ie->chemical_symbol = Str::duplicate(abb);
ie->element_name = Str::duplicate(title);
ie->explanation_key = Str::duplicate(explanation);
ADD_TO_LINKED_LIST(ie, index_element, owner->elements);
return ie;
}
@h Opening and closing HTML files.
=
text_stream *InterpretIndex::open_file(text_stream *IF,
index_page *page, text_stream *index_leaf,
text_stream *title, int sub, index_session *session) {
filename *F = IndexLocations::filename(index_leaf, sub);
if (STREAM_OPEN_TO_FILE(IF, F, UTF8_ENC) == FALSE) {
#ifdef CORE_MODULE
Problems::fatal_on_file("Can't open index file", F);
#endif
#ifndef CORE_MODULE
Errors::fatal_with_file("can't open index file", F);
#endif
}
HTML::header(IF, title,
InstalledFiles::filename(CSS_FOR_STANDARD_PAGES_IRES),
InstalledFiles::filename(JAVASCRIPT_FOR_STANDARD_PAGES_IRES),
(void *) page);
IndexUtilities::clear_page_data(session);
return IF;
}
@ =
void InterpretIndex::close_index_file(text_stream *ifl) {
HTML::footer(ifl);
STREAM_CLOSE(ifl);
}