To refresh the mini-website of available extensions presented in the Inform GUI applications.


§1. The mini-website. The Inform GUI apps present HTML in-app documentation on extensions: in effect, a mini-website showing all the extensions available to the current user, and giving detailed documentation on each one. The code in this chapter of supervisor runs only if and when we want to generate or update that website, and plays no part in Inform compilation or building as such: it lives in supervisor because it's essentially concerned with managing resources (i.e., extensions in nests).

A principle used throughout is that we fail safe and silent: if we can't write the documentation website for any reason (permissions failures, for example) then we make no complaint. It's a convenience for the user, but not an essential. This point of view was encouraged by many Inform users working clandestinely on thumb drives at their places of work, and whose employers had locked their computers down fairly heavily.

§2. The process always involves a "census" of all installed extensions, but can happen for two different reasons:

Reason (a) typically happens because the user installs a new extension from the app, and it calls the inform7 tool in -census mode to force an update of the documentation. But (a) can also happen from the command line using either inbuild or inform7.

The second sort of census is lighter in effect because only incremental changes to documentation are made, but the process of census-taking is the same either way. Here are the functions for (a) and (b) respectively:

void ExtensionWebsite::handle_census_mode(void) {
    HTML::set_link_abbreviation_path(NULL);
    ExtensionWebsite::go(NULL, TRUE);
}

void ExtensionWebsite::index_after_compilation(inform_project *proj) {
    HTML::set_link_abbreviation_path(Projects::path(proj));
    ExtensionWebsite::go(proj, FALSE);
}

void ExtensionWebsite::go(inform_project *proj, int force_update) {
    ExtensionDictionary::read_from_file();

    extension_census *C = ExtensionCensus::perform(proj);
    Time-stamp extensions used in the project as being last used today2.1;
    Write index pages2.2;
    Write individual pages on individual extensions2.3;

    ExtensionDictionary::write_back();
}

§2.1. This simply ensures that dates used are updated to today's date for extensions used in the current run; otherwise they wouldn't show in the documentation as used today until the next run, for obscure timing reasons.

Time-stamp extensions used in the project as being last used today2.1 =

    if (proj) {
        inform_extension *E;
        LOOP_OVER_LINKED_LIST(E, inform_extension, proj->extensions_included) {
            ExtensionDictionary::time_stamp(E);
            E->has_historically_been_used = TRUE;
        }
    }

§2.2. Write index pages2.2 =

    ExtensionIndex::write(ExtensionWebsite::index_URL(I"Extensions.html"), HOME_EXTPAGE, C);
    ExtensionIndex::write(ExtensionWebsite::index_URL(I"ExtIndex.html"), INDEX_EXTPAGE, C);

§2.3. Each extension gets its own page in the external documentation area, but this page can have two forms:

Write individual pages on individual extensions2.3 =

    if (proj) {
        inform_extension *E;
        LOOP_OVER_LINKED_LIST(E, inform_extension, proj->extensions_included)
            ExtensionPages::write_page(NULL, E, FALSE, proj);  deluxe
    }
    extension_census_datum *ecd;
    LOOP_OVER(ecd, extension_census_datum)
        ExtensionPages::write_page(ecd, NULL, force_update, NULL);  ordinaire

§3. Organisation of the website. There is a top level consisting of two home pages: a directory of all installed extensions, and an index to the terms defined in those extensions. A cross-link switches between them. Each of these links down to the bottom level, where there is a page for every installed extension (wherever it is installed). The picture is therefore something like this:

         Extensions -- ExtIndex
             |      \/    |
             |      /\    |
    Nigel Toad/Eggs    Barnabas Dundritch/Neopolitan Iced Cream   ...

These pages would be stored in the transient area at the relative URLs:

    Documentation/Extensions.html
    Documentation/ExtIndex.html
    Documentation/Extensions/Nigel Toad/Eggs.html
    Documentation/Extensions/Barnabas Dundritch/Neopolitan Iced Cream.html

And see also the function ExtensionDictionary::filename, which uses a file in the same area but not as part of the site.

pathname *ExtensionWebsite::home_URL(void) {
    pathname *P = Supervisor::transient();
    if (P == NULL) return NULL;
    if (Pathnames::create_in_file_system(P) == 0) return NULL;
    P = Pathnames::down(P, I"Documentation");
    if (Pathnames::create_in_file_system(P) == 0) return NULL;
    return P;
}

§4. The top-level files Extensions.html and ExtIndex.html go here:

filename *ExtensionWebsite::index_URL(text_stream *leaf) {
    pathname *P = ExtensionWebsite::home_URL();
    if (P == NULL) return NULL;
    return Filenames::in(P, leaf);
}

§5. And individual extension pages here. A complication is that a single extension may also have sidekick pages for any examples in its supplied documentation: so for instance we might actually see —

    Documentation/Extensions/Emily Short/Locksmith.html
    Documentation/Extensions/Emily Short/Locksmith-eg1.html
    Documentation/Extensions/Emily Short/Locksmith-eg2.html
    Documentation/Extensions/Emily Short/Locksmith-eg3.html
    Documentation/Extensions/Emily Short/Locksmith-eg4.html

The following supplies the necessary filenames.

filename *ExtensionWebsite::page_URL(inbuild_work *work, int eg_number) {
    TEMPORARY_TEXT(leaf)
    Str::copy(leaf, work->title);
    if (eg_number > 0) WRITE_TO(leaf, "-eg%d", eg_number);
    WRITE_TO(leaf, ".html");
    pathname *P = ExtensionWebsite::home_URL();
    if (P == NULL) return NULL;
    P = Pathnames::down(P, I"Extensions");
    if (Pathnames::create_in_file_system(P) == 0) return NULL;
    filename *F = Filenames::in(Pathnames::down(P, work->author_name), leaf);
    DISCARD_TEXT(leaf)
    return F;
}