To write the Commands element (Cm) in the index.


§1.

void CommandsElement::render(OUTPUT_STREAM, index_session *session) {
    localisation_dictionary *LD = Indexing::get_localisation(session);
    inter_tree *I = Indexing::get_tree(session);

    linked_list *entries = NEW_LINKED_LIST(command_index_entry);
    Create the entries for the command list1.1;
    linked_list *sorted = CommandsElement::sort(entries);

    inchar32_t head_letter = 0;
    command_index_entry *cie;
    LOOP_OVER_LINKED_LIST(cie, command_index_entry, sorted) {
        if (Str::get_first_char(cie->command_headword) != head_letter) {
            if (head_letter) HTML_TAG("br");
            head_letter = Str::get_first_char(cie->command_headword);
        }
        Render an index entry from the sorted list1.5;
    }
}

§1.1. Create the entries for the command list1.1 =

    inter_package *pack = InterPackage::from_URL(I, I"/main/completion/grammar");
    inter_package *entry;
    LOOP_THROUGH_SUBPACKAGES(entry, pack, I"_command_grammar")
        if ((Metadata::read_optional_numeric(entry, I"^is_command")) &&
            (InterTree::no_subpackages(entry, I"_cg_line") > 0))
            Create entry for this command1.1.1;
    CommandsElement::make_direction_entry(entries);

§1.1.1. Create entry for this command1.1.1 =

    text_stream *main_command = Metadata::optional_textual(entry, I"^command");
    if (Str::len(main_command) == 0) main_command = I"0";
    CommandsElement::make_entry(main_command, entry, NORMAL_COMMAND, entries);
    inter_package *alias;
    LOOP_THROUGH_SUBPACKAGES(alias, entry, I"_cg_alias") {
        text_stream *alias_command = Metadata::required_textual(alias, I"^alias");
        CommandsElement::make_entry(alias_command, entry, ALIAS_COMMAND, entries);
    }

§1.2. Entries in the list correspond to the headwords of commands which can be typed at runtime, like QUIT or INVENTORY. For indexing purposes, we divide these headwords as follows:

define NORMAL_COMMAND 1
define ALIAS_COMMAND 2
define OUT_OF_WORLD_COMMAND 3
define TESTING_COMMAND 4
define BARE_DIRECTION_COMMAND 5
typedef struct command_index_entry {
    int nature;  one of the above values
    struct text_stream *command_headword;  text of command headword, such as "REMOVE"
    struct inter_package *cg_indexed;  ...leading to...
    struct command_index_entry *next_alphabetically;  next in linked list
    CLASS_DEFINITION
} command_index_entry;

command_index_entry *sorted_command_index = NULL;  in alphabetical order of text

§1.3.

void CommandsElement::make_test_entry(text_stream *t, linked_list *entries) {
    command_index_entry *cie;
    cie = CREATE(command_index_entry);
    cie->command_headword = Str::duplicate(t);
    cie->nature = TESTING_COMMAND;
    cie->cg_indexed = NULL;
    cie->next_alphabetically = NULL;
    ADD_TO_LINKED_LIST(cie, command_index_entry, entries);
}

void CommandsElement::make_entry(text_stream *headword, inter_package *cg_pack,
    int nature, linked_list *entries) {
    command_index_entry *cie = CREATE(command_index_entry);
    cie->command_headword = Str::duplicate(headword);
    cie->nature = nature;
    cie->cg_indexed = cg_pack;
    cie->next_alphabetically = NULL;
    ADD_TO_LINKED_LIST(cie, command_index_entry, entries);
}

void CommandsElement::make_direction_entry(linked_list *entries) {
    command_index_entry *cie = CREATE(command_index_entry);
    cie->command_headword = I"0";
    cie->nature = BARE_DIRECTION_COMMAND;
    cie->cg_indexed = NULL;
    cie->next_alphabetically = NULL;
    ADD_TO_LINKED_LIST(cie, command_index_entry, entries);
}

§1.4.

linked_list *CommandsElement::sort(linked_list *entries) {
    command_index_entry *cie, *list_start = NULL;
    LOOP_OVER_LINKED_LIST(cie, command_index_entry, entries) {
        if (list_start == NULL) { list_start = cie; continue; }
        command_index_entry *cie2 = list_start, *last_cie2 = NULL;
        while (cie2 && (Str::cmp(cie->command_headword, cie2->command_headword) > 0)) {
            last_cie2 = cie2;
            cie2 = cie2->next_alphabetically;
        }
        if (last_cie2 == NULL) {
            cie->next_alphabetically = list_start; list_start = cie;
        } else {
            last_cie2->next_alphabetically = cie; cie->next_alphabetically = cie2;
        }
    }
    linked_list *sorted = NEW_LINKED_LIST(command_index_entry);
    for (command_index_entry *cie = list_start; cie; cie = cie->next_alphabetically)
        ADD_TO_LINKED_LIST(cie, command_index_entry, sorted);
    return sorted;
}

§1.5. With those lengthy digressions done, back to the actual indexing:

Render an index entry from the sorted list1.5 =

    inter_package *cg_pack = cie->cg_indexed;
    switch (cie->nature) {
        case NORMAL_COMMAND:
            CommandsElement::index_normal(OUT, I, cg_pack, cie->command_headword, LD);
            break;
        case ALIAS_COMMAND:
            CommandsElement::index_alias(OUT, I, cg_pack, cie->command_headword, LD);
            break;
        case OUT_OF_WORLD_COMMAND:
            HTML::begin_span(OUT, I"indexdullred");
            WRITE(""%S", ", cie->command_headword);
            Localisation::italic(OUT, LD, I"Index.Elements.Cm.Command");
            HTML::end_span(OUT);
            HTML_TAG("br");
            break;
        case TESTING_COMMAND:
            HTML::begin_span(OUT, I"indexdullred");
            WRITE(""%S", ", cie->command_headword);
            Localisation::italic(OUT, LD, I"Index.Elements.Cm.TestingCommand");
            HTML::end_span(OUT);
            HTML_TAG("br");
            break;
        case BARE_DIRECTION_COMMAND:
            WRITE(""[direction]" - ");
            Localisation::italic(OUT, LD, I"Index.Elements.Cm.DirectionCommand");
            HTML_TAG("br");
            break;
    }

§2. Indexing grammar lines.

void CommandsElement::index_normal(OUTPUT_STREAM, inter_tree *I, inter_package *cg_pack,
    text_stream *headword, localisation_dictionary *LD) {
    inter_package *entry;
    LOOP_THROUGH_SUBPACKAGES(entry, cg_pack, I"_cg_line")
        CommandsElement::index_grammar_line(OUT, entry, headword, LD);
}

void CommandsElement::index_alias(OUTPUT_STREAM, inter_tree *I, inter_package *cg_pack,
    text_stream *headword, localisation_dictionary *LD) {
    WRITE(""%S", ", headword);
    Localisation::italic(OUT, LD, I"Index.Elements.Cm.Alias");
    WRITE(" "%S"", Metadata::required_textual(cg_pack, I"^command"));
    IndexUtilities::link_package(OUT, cg_pack);
    HTML_TAG("br");
}

void CommandsElement::index_grammar_line(OUTPUT_STREAM, inter_package *cgl,
    text_stream *headword, localisation_dictionary *LD) {
    inter_symbol *an_s = Metadata::optional_symbol(cgl, I"^action");
    if (an_s == NULL) return;
    inter_package *an = InterPackage::container(an_s->definition);
    int oow = (int) Metadata::read_optional_numeric(an, I"^out_of_world");
    if (Str::len(headword) > 0) IndexUtilities::anchor(OUT, headword);
    if (oow) HTML::begin_span(OUT, I"indexdullred");
    WRITE(""");
    TokensElement::verb_definition(OUT, Metadata::optional_textual(cgl, I"^text"),
        headword, EMPTY_WORDING);
    WRITE(""");
    IndexUtilities::link_package(OUT, cgl);

    WRITE(" - <i>%S</i>", Metadata::required_textual(an, I"^name"));
    IndexUtilities::detail_link(OUT, "A",
        (int) Metadata::read_numeric(an, I"action_id"), TRUE);
    if (Metadata::read_optional_numeric(cgl, I"^reversed")) {
        WRITE(" ");
        Localisation::italic(OUT, LD, I"Index.Elements.Cm.Reversed");
    }
    if (oow) HTML::end_span(OUT);
    HTML_TAG("br");
}