An index is generated by interpreting an index structure file.
§1. 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:
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 declares 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 Localisation (in html).
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 line1.1; Actually generate the index files1.2; }
§1.1. Read the structure file line by line1.1 =
TextFiles::read(index_structure, FALSE, "unable to read index structure file", TRUE, &InterpretIndex::read_structure, NULL, (void *) session);
- This code is used in §1.
§2. 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:
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, U"page (%C+) (%C+)")) { Register a new index page2.1; } else if (Regexp::match(&mr, text, U"contents (%C+) (%C+)")) { Register a new index page2.1; } else if (Regexp::match(&mr, text, U"element (%C+)")) { Register a new index element2.2; } Regexp::dispose_of(&mr); }
§2.1. 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 page2.1 =
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);
- This code is used in §2 (twice).
§2.2. Register a new index element2.2 =
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)
- This code is used in §2.
§1.2. Actually generate the index files1.2 =
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);
- This code is used in §1.
§3. 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; }
- The structure index_page is accessed in 2/sas, 3/tpt, 4/sm and here.
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; }
- The structure index_element is accessed in 2/sas, 3/tpt and here.
§5. 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 } InformPages::header(IF, title, JAVASCRIPT_FOR_STANDARD_PAGES_IRES, (void *) page); IndexUtilities::clear_page_data(session); return IF; }
void InterpretIndex::close_index_file(text_stream *ifl) { InformPages::footer(ifl); STREAM_CLOSE(ifl); }