diff --git a/indoc/Chapter 1/Basics.w b/indoc/Chapter 1/Basics.w index be170391b..0ea1a1abd 100755 --- a/indoc/Chapter 1/Basics.w +++ b/indoc/Chapter 1/Basics.w @@ -30,7 +30,7 @@ void Basics::end(void) { @h Setting up the memory manager. We need to itemise the structures we'll want to allocate: -@e indoc_instructions_MT +@e settings_block_MT @e volume_MT @e chapter_MT @e section_MT @@ -49,7 +49,7 @@ We need to itemise the structures we'll want to allocate: @ And then expand: = -ALLOCATE_INDIVIDUALLY(indoc_instructions) +ALLOCATE_INDIVIDUALLY(settings_block) ALLOCATE_INDIVIDUALLY(volume) ALLOCATE_INDIVIDUALLY(chapter) ALLOCATE_INDIVIDUALLY(section) diff --git a/indoc/Chapter 1/Configuration.w b/indoc/Chapter 1/Configuration.w index 6ef378885..34967e51d 100644 --- a/indoc/Chapter 1/Configuration.w +++ b/indoc/Chapter 1/Configuration.w @@ -14,7 +14,7 @@ void Configuration::add_instructions_file(filename *F) { ADD_TO_LINKED_LIST(F, filename, instructions_files); } -void Configuration::read_instructions(text_stream *target, indoc_instructions *settings) { +void Configuration::read_instructions(text_stream *target, settings_block *settings) { Instructions::read_instructions(target, instructions_files, settings); } @@ -23,18 +23,16 @@ void Configuration::read_instructions(text_stream *target, indoc_instructions *s = typedef struct cl_state { struct text_stream *target_chosen; - struct indoc_instructions *settings; + struct settings_block *settings; } cl_state; -void Configuration::read_command_line(int argc, char **argv, indoc_instructions *settings) { - pathname *IM = Pathnames::from_text(I"indoc"); - IM = Pathnames::subfolder(IM, I"Materials"); - filename *basics = Filenames::in_folder(IM, I"basic-instructions.txt"); - Configuration::add_instructions_file(basics); +void Configuration::read_command_line(int argc, char **argv, settings_block *settings) { cl_state state; state.target_chosen = Str::new(); state.settings = settings; @; + Configuration::add_instructions_file( + Filenames::in_folder(path_to_indoc_materials, I"basic-instructions.txt")); Configuration::add_instructions_file( Filenames::in_folder(settings->book_folder, I"indoc-instructions.txt")); Configuration::read_instructions(state.target_chosen, settings); @@ -73,7 +71,7 @@ void Configuration::read_command_line(int argc, char **argv, indoc_instructions @ = void Configuration::switch(int id, int val, text_stream *arg, void *v_cl_state) { - indoc_instructions *settings = ((cl_state *) v_cl_state)->settings; + settings_block *settings = ((cl_state *) v_cl_state)->settings; switch (id) { case VERBOSE_CLSW: settings->verbose_mode = val; break; case TEST_INDEX_CLSW: settings->test_index_mode = val; break; diff --git a/indoc/Chapter 1/Instructions.w b/indoc/Chapter 1/Instructions.w index f9c81a8c8..b6af94b14 100644 --- a/indoc/Chapter 1/Instructions.w +++ b/indoc/Chapter 1/Instructions.w @@ -3,8 +3,10 @@ Instructions of indoc to different output types. @h Definitions. - -@ A few fundamental options set at the command line. +The command-line and Instructions-file-set values provide a large slate of +what used to be global variables in the Perl version of Indoc. Today they +are herded together into an instance of the |settings_block| structure, +and in particular into a global instance of this called |indoc_settings|. @d LETTER_ALPHABETIZATION 1 @d WORD_ALPHABETIZATION 2 @@ -29,7 +31,7 @@ Instructions of indoc to different output types. @d WRAPPER_zip 3 = -typedef struct indoc_instructions { +typedef struct settings_block { int verbose_mode; int test_index_mode; @@ -85,13 +87,13 @@ typedef struct indoc_instructions { struct navigation_design *navigation; MEMORY_MANAGEMENT -} indoc_instructions; +} settings_block; @ = -indoc_instructions *Instructions::clean_slate(void) { - indoc_instructions *settings = CREATE(indoc_instructions); +settings_block *Instructions::clean_slate(void) { + settings_block *settings = CREATE(settings_block); settings->verbose_mode = FALSE; settings->test_index_mode = FALSE; @@ -145,18 +147,11 @@ indoc_instructions *Instructions::clean_slate(void) { settings->wrapper = WRAPPER_none; settings->ebook = NULL; - settings->navigation = Gadgets::default(); + settings->navigation = Nav::default(); return settings; } -@ = -typedef struct dc_metadatum { - struct text_stream *dc_key; - struct text_stream *dc_val; - MEMORY_MANAGEMENT -} dc_metadatum; - @h Instructions file. Note that |indoc| reports errors in the instructions file, but doesn't halt on them until all have been found. (The user may as well get all of the bad news, @@ -164,13 +159,12 @@ not just the beginning of it.) = void Instructions::read_instructions(text_stream *target_sought, linked_list *L, - indoc_instructions *settings) { + settings_block *settings) { int found_flag = FALSE; /* was a target of this name actually found? */ settings->change_logs_folder = Pathnames::subfolder(settings->book_folder, I"Change Logs"); settings->examples_directory = Pathnames::subfolder(settings->book_folder, I"Examples"); - pathname *Materials = Pathnames::subfolder(Pathnames::from_text(I"indoc"), I"Materials"); - settings->css_source_file = Filenames::in_folder(Materials, I"base.css"); + settings->css_source_file = Filenames::in_folder(path_to_indoc_materials, I"base.css"); settings->definitions_index_leafname = Str::duplicate(I"general_index.html"); filename *F; @@ -181,7 +175,7 @@ void Instructions::read_instructions(text_stream *target_sought, linked_list *L, @; @; - HTMLUtilities::add_image_source(Pathnames::subfolder(Materials, I"images")); + HTMLUtilities::add_image_source(Pathnames::subfolder(path_to_indoc_materials, I"images")); if (found_flag == FALSE) Errors::fatal_with_text("unknown target %S", target_sought); @@ -201,13 +195,13 @@ applies 20 for all targets except |hypercard|, where it applies 40. = typedef struct ins_helper_state { int found_aim; - struct indoc_instructions *settings; + struct settings_block *settings; struct text_stream *desired_target; struct text_stream *scanning_target; } ins_helper_state; int Instructions::read_instructions_from(filename *F, text_stream *desired, - indoc_instructions *settings) { + settings_block *settings) { ins_helper_state ihs; ihs.scanning_target = Str::new(); ihs.desired_target = desired; @@ -222,7 +216,7 @@ int Instructions::read_instructions_from(filename *F, text_stream *desired, void Instructions::read_instructions_helper(text_stream *cl, text_file_position *tfp, void *v_ihs) { ins_helper_state *ihs = (ins_helper_state *) v_ihs; - indoc_instructions *settings = ihs->settings; + settings_block *settings = ihs->settings; match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, cl, L" *#%c*")) { Regexp::dispose_of(&mr); return; } @@ -269,9 +263,7 @@ void Instructions::read_instructions_helper(text_stream *cl, text_file_position settings->book_contains_examples = TRUE; } else if (Regexp::match(&mr, cl, L" *dc:(%C+): *(%c*?) *")) { @; - dc_metadatum *dcm = CREATE(dc_metadatum); - dcm->dc_key = Str::duplicate(mr.exp[0]); - dcm->dc_val = Str::duplicate(mr.exp[1]); + Instructions::create_ebook_metadata(Str::duplicate(mr.exp[0]), Str::duplicate(mr.exp[1])); } else if (Regexp::match(&mr, cl, L" *css: *(%c*?) *")) { @; } else if (Regexp::match(&mr, cl, L" *index: *(%c*?) *")) { @@ -397,15 +389,20 @@ taste). In a multiple-line value, each line is terminated with a newline. @ = if (Str::eq_wide_string(key, L"alphabetization")) { - if (Str::eq_wide_string(val, L"word-by-word")) { settings->index_alphabetisation_algorithm = WORD_ALPHABETIZATION; } - else if (Str::eq_wide_string(val, L"letter-by-letter")) { settings->index_alphabetisation_algorithm = LETTER_ALPHABETIZATION; } + if (Str::eq_wide_string(val, L"word-by-word")) + settings->index_alphabetisation_algorithm = WORD_ALPHABETIZATION; + else if (Str::eq_wide_string(val, L"letter-by-letter")) + settings->index_alphabetisation_algorithm = LETTER_ALPHABETIZATION; else Errors::in_text_file("no such alphabetization", tfp); } - else if (Str::eq_wide_string(key, L"assume_Public_Library")) { - settings->assume_Public_Library = Instructions::set_yn(key, val, tfp); } - else if (Str::eq_wide_string(key, L"change_logs_directory")) { settings->change_logs_folder = Instructions::set_path(val, settings); } - else if (Str::eq_wide_string(key, L"contents_leafname")) { settings->contents_leafname = Str::duplicate(val); } - else if (Str::eq_wide_string(key, L"contents_expandable")) { settings->contents_expandable = Instructions::set_yn(key, val, tfp); } + else if (Str::eq_wide_string(key, L"assume_Public_Library")) + settings->assume_Public_Library = Instructions::set_yn(key, val, tfp); + else if (Str::eq_wide_string(key, L"change_logs_directory")) + settings->change_logs_folder = Instructions::set_path(val, settings); + else if (Str::eq_wide_string(key, L"contents_leafname")) + settings->contents_leafname = Str::duplicate(val); + else if (Str::eq_wide_string(key, L"contents_expandable")) + settings->contents_expandable = Instructions::set_yn(key, val, tfp); else if (Str::eq_wide_string(key, L"css_source_file")) { settings->css_source_file = Instructions::set_file(val, settings); } else if (Str::eq_wide_string(key, L"definitions_filename")) { settings->definitions_filename = Instructions::set_file(val, settings); } else if (Str::eq_wide_string(key, L"definitions_index_filename")) { @@ -452,7 +449,7 @@ taste). In a multiple-line value, each line is terminated with a newline. settings->link_to_extensions_index = Str::duplicate(val); } else if (Str::eq_wide_string(key, L"manifest_leafname")) { settings->manifest_leafname = Str::duplicate(val); } else if (Str::eq_wide_string(key, L"navigation")) { - settings->navigation = Gadgets::parse(val); + settings->navigation = Nav::parse(val); if (settings->navigation == NULL) Errors::in_text_file("no such navigation mode", tfp); } else if (Str::eq_wide_string(key, L"retina_images")) { @@ -487,7 +484,7 @@ taste). In a multiple-line value, each line is terminated with a newline. } settings->contents_expandable = FALSE; settings->images_copy = 1; - settings->navigation = Gadgets::for_ebook(settings->navigation); + settings->navigation = Nav::for_ebook(settings->navigation); settings->format = HTML_FORMAT; settings->XHTML = TRUE; settings->ebook = Epub::new(I"untitled ebook", ""); @@ -511,7 +508,7 @@ taste). In a multiple-line value, each line is terminated with a newline. } if (settings->format == PLAIN_FORMAT) - settings->navigation = Gadgets::for_plain_text(settings->navigation); + settings->navigation = Nav::for_plain_text(settings->navigation); @ = if (settings->wrapper == WRAPPER_epub) Symbols::declare_symbol(I"EPUB"); @@ -526,7 +523,7 @@ Note the Unix-style conveniences for pathnames: an initial |~| means the home folder, |~~| means the book folder. = -pathname *Instructions::set_path(text_stream *val, indoc_instructions *settings) { +pathname *Instructions::set_path(text_stream *val, settings_block *settings) { if (Str::get_at(val, 0) == '~') { if (Str::get_at(val, 1) == '~') { if ((Str::get_at(val, 2) == '/') || (Str::get_at(val, 2) == FOLDER_SEPARATOR)) { @@ -549,7 +546,7 @@ pathname *Instructions::set_path(text_stream *val, indoc_instructions *settings) } @ = -filename *Instructions::set_file(text_stream *val, indoc_instructions *settings) { +filename *Instructions::set_file(text_stream *val, settings_block *settings) { if (Str::get_at(val, 0) == '~') { if (Str::get_at(val, 1) == '~') { if ((Str::get_at(val, 2) == '/') || (Str::get_at(val, 2) == FOLDER_SEPARATOR)) { @@ -605,6 +602,18 @@ int Instructions::set_yn(text_stream *key, text_stream *val, text_file_position @ For ebooks only. = +typedef struct dc_metadatum { + struct text_stream *dc_key; + struct text_stream *dc_val; + MEMORY_MANAGEMENT +} dc_metadatum; + +void Instructions::create_ebook_metadata(text_stream *key, text_stream *value) { + dc_metadatum *dcm = CREATE(dc_metadatum); + dcm->dc_key = Str::duplicate(key); + dcm->dc_val = Str::duplicate(value); +} + void Instructions::apply_ebook_metadata(ebook *E) { dc_metadatum *dcm; LOOP_OVER(dcm, dc_metadatum) { diff --git a/indoc/Chapter 1/Main.w b/indoc/Chapter 1/Main.w index 6840b7e5d..b1890db6b 100644 --- a/indoc/Chapter 1/Main.w +++ b/indoc/Chapter 1/Main.w @@ -2,39 +2,15 @@ The top level of the program. -@h Definitions. - -@ Indoc is one of the earliest Inform tools, and it spent much of its -life as a hacky Perl script: like all too many quick-fix Perl scripts, it -was still in use ten years later. In 2012, I spent some time tidying it up -to generate better HTML, and moved it over to literate code. This took an -exasperatingly long time, not least because the original had produced -typically sloppy turn-of-the-century HTML, with tables for layout and -no CSS, and with many now-deprecated tags and elements. The 2012 edition, -by contrast, needed to produce validatable XHTML 1.1 Strict in order to -make EPUBs which read roughly correctly in today's ebook-readers, and -when they call this Strict they're not kidding. It took something like -four weeks of spare evenings. - -Just as I was finishing up, the programmer and commentator John Siracusa -described an almost identical web-content-and-ebook generation task on his -podcast (Hypercritical 85): "My solution for this is... I was trying to -think of a good analogy for what happens when you're a programmer and you -have this sort of task in front of you. Is it, the cobbler's children have -no shoes? ... You would expect someone who is a programmer to make some -awesome system which would generate these three things. But when you're a -programmer, you have the ability to do whatever you want really, really -quickly in the crappiest possible way... And that's what I did. I wrote a -series of incredibly disgusting Perl scripts." - -This made me feel better. Nevertheless, in 2016, I rewrote in C. - @h Nutshell. We turn the source matter, "rawtext", into a batch of output files using the chosen format, a process we'll call "rendering". We do this in two passes. = -indoc_instructions *indoc_settings = NULL; +pathname *path_to_indoc = NULL; /* where we are installed */ +pathname *path_to_indoc_materials = NULL; /* the materials pathname */ + +settings_block *indoc_settings = NULL; int no_volumes = 0; int no_examples = 0; @@ -61,10 +37,13 @@ int main(int argc, char **argv) { @ = PRINT("indoc [[Version Number]] (Inform Tools Suite)\n"); - Gadgets::start(); + Nav::start(); Symbols::start_up_symbols(); indoc_settings = Instructions::clean_slate(); Configuration::read_command_line(argc, argv, indoc_settings); + path_to_indoc = Pathnames::installation_path("INDOC_PATH", I"indoc"); + if (indoc_settings->verbose_mode) PRINT("Installation path is %p\n", path_to_indoc); + path_to_indoc_materials = Pathnames::subfolder(path_to_indoc, I"Materials"); if (indoc_settings->wrapper == WRAPPER_epub) { HTMLUtilities::image_URL(NULL, Filenames::get_leafname(indoc_settings->book_cover_image)); @@ -97,7 +76,7 @@ section by section. volume *V; text_stream *TO = NULL; LOOP_OVER(V, volume) TO = Rawtext::process_large_rawtext_file(TO, V); - Gadgets::render_navigation_contents_files(); + Nav::render_navigation_contents_files(); @ The following functions here are for use only when compiling documentation to go inside the Inform user interface application. diff --git a/indoc/Chapter 2/CSS.w b/indoc/Chapter 2/CSS.w index 2de5f5562..4f7646d92 100644 --- a/indoc/Chapter 2/CSS.w +++ b/indoc/Chapter 2/CSS.w @@ -213,7 +213,7 @@ all CSS files, but here we know that |base.css| is tidily written. @ = void CSS::expand_IMAGES(text_stream *text) { match_results mr = Regexp::create_mr(); - if (indoc_settings->suppress_fonts == 1) { + if (indoc_settings->suppress_fonts) { while (Regexp::match(&mr, text, L"(%c*?)font-family:(%c*?);(%c*)")) { text_stream *L = mr.exp[0], *M = NULL, *R = mr.exp[2]; if (Regexp::match(NULL, mr.exp[1], L"%c*monospace%c*")) M = I"___MONOSPACE___"; diff --git a/indoc/Chapter 2/Renderer.w b/indoc/Chapter 2/Renderer.w index 6d8234a88..e624b55f9 100644 --- a/indoc/Chapter 2/Renderer.w +++ b/indoc/Chapter 2/Renderer.w @@ -85,11 +85,11 @@ routine which doesn't surround the text with navigational gadgets and headings. text_stream *Renderer::render_block(OUTPUT_STREAM, volume *V, section *S) { OUT = Renderer::formatted_file_must_be(OUT, V, S); - Gadgets::render_navigation_top(OUT, V, S); + Nav::render_navigation_top(OUT, V, S); Renderer::render_text_of_block(OUT, V, S); - Gadgets::render_navigation_middle(OUT, V, S); + Nav::render_navigation_middle(OUT, V, S); @; - Gadgets::render_navigation_bottom(OUT, V, S); + Nav::render_navigation_bottom(OUT, V, S); return OUT; } @@ -102,14 +102,14 @@ text_stream *Renderer::render_block(OUTPUT_STREAM, volume *V, section *S) { if (E->example_displayed_at_section[V->allocation_id] == S) { no_examples_rendered_here++; if (no_examples_rendered_here == 1) - Gadgets::render_navigation_example_top(OUT, V, S); + Nav::render_navigation_example_top(OUT, V, S); @; if (indoc_settings->examples_mode == EXMODE_open_internal) HTMLUtilities::ruled_line(OUT); } } if (no_examples_rendered_here > 0) - Gadgets::render_navigation_example_bottom(OUT, V, S); + Nav::render_navigation_example_bottom(OUT, V, S); @ Examples need to connect with particular sections of documentation, but they do so by title, not by block number, to protect them from renumbering diff --git a/indoc/Chapter 3/Indexing Utilities.w b/indoc/Chapter 3/Indexing Utilities.w index de85e3f2a..2df436806 100644 --- a/indoc/Chapter 3/Indexing Utilities.w +++ b/indoc/Chapter 3/Indexing Utilities.w @@ -35,7 +35,7 @@ text_stream *IndexUtilities::open_page(text_stream *title, text_stream *leafname } DISCARD_TEXT(head); - Gadgets::render_navigation_index_top(OUT, leafname, title); + Nav::render_navigation_index_top(OUT, leafname, title); return OUT; } diff --git a/indoc/Chapter 4/Codename Architect.w b/indoc/Chapter 4/Codename Architect.w index 8ea368253..c980cfda7 100644 --- a/indoc/Chapter 4/Codename Architect.w +++ b/indoc/Chapter 4/Codename Architect.w @@ -8,7 +8,7 @@ heading includes these anyway. = navigation_design *Architect::create(void) { - navigation_design *ND = Gadgets::new(I"architect", FALSE, FALSE); + navigation_design *ND = Nav::new(I"architect", FALSE, FALSE); ND->columnar = TRUE; ND->contents_body_class = I"paper architectpapertint"; METHOD_ADD(ND, RENDER_SECTION_TITLE_MTID, Architect::architect_section_title); diff --git a/indoc/Chapter 4/Codename Lacuna.w b/indoc/Chapter 4/Codename Lacuna.w index 5587fe071..35023734a 100644 --- a/indoc/Chapter 4/Codename Lacuna.w +++ b/indoc/Chapter 4/Codename Lacuna.w @@ -7,7 +7,7 @@ no navigational features at all. = navigation_design *Lacuna::create(void) { - navigation_design *ND = Gadgets::new(I"lacuna", FALSE, TRUE); + navigation_design *ND = Nav::new(I"lacuna", FALSE, TRUE); METHOD_ADD(ND, RENDER_CHAPTER_TITLE_MTID, Lacuna::lacuna_chapter_title); METHOD_ADD(ND, RENDER_SECTION_TITLE_MTID, Lacuna::lacuna_section_title); return ND; diff --git a/indoc/Chapter 4/Codename Midnight.w b/indoc/Chapter 4/Codename Midnight.w index c60225dd6..a99623631 100644 --- a/indoc/Chapter 4/Codename Midnight.w +++ b/indoc/Chapter 4/Codename Midnight.w @@ -6,7 +6,7 @@ The "midnight" style of navigational gadgets. = navigation_design *Midnight::create(void) { - navigation_design *ND = Gadgets::new(I"midnight", FALSE, FALSE); + navigation_design *ND = Nav::new(I"midnight", FALSE, FALSE); ND->columnar = TRUE; METHOD_ADD(ND, RENDER_SECTION_TITLE_MTID, Midnight::midnight_section_title); METHOD_ADD(ND, RENDER_INDEX_TOP_MTID, Midnight::midnight_navigation_index_top); @@ -197,7 +197,7 @@ void Midnight::write_contents_page(navigation_design *self, volume *V) { TEMPORARY_TEXT(title); WRITE_TO(title, "Contents"); @; - Gadgets::navigation_contents_heading(OUT, V); + Nav::navigation_contents_heading(OUT, V); for (int column = 0; column < no_volumes; column++) if ((column == V->allocation_id) || (self->columnar)) diff --git a/indoc/Chapter 4/Codename Roadsign.w b/indoc/Chapter 4/Codename Roadsign.w index 30bb9682c..b3b6e9a78 100644 --- a/indoc/Chapter 4/Codename Roadsign.w +++ b/indoc/Chapter 4/Codename Roadsign.w @@ -6,7 +6,7 @@ The "roadsign" style of navigational gadgets. = navigation_design *Roadsign::create(void) { - navigation_design *ND = Gadgets::new(I"roadsign", TRUE, FALSE); + navigation_design *ND = Nav::new(I"roadsign", TRUE, FALSE); METHOD_ADD(ND, RENDER_VOLUME_TITLE_MTID, Roadsign::roadsign_volume_title); METHOD_ADD(ND, RENDER_CHAPTER_TITLE_MTID, Roadsign::roadsign_chapter_title); METHOD_ADD(ND, RENDER_SECTION_TITLE_MTID, Roadsign::roadsign_section_title); diff --git a/indoc/Chapter 4/Codename Twilight.w b/indoc/Chapter 4/Codename Twilight.w index 5e36854da..6a8c8e202 100644 --- a/indoc/Chapter 4/Codename Twilight.w +++ b/indoc/Chapter 4/Codename Twilight.w @@ -7,7 +7,7 @@ of "midnight". = navigation_design *Twilight::create(void) { - navigation_design *ND = Gadgets::new(I"twilight", FALSE, FALSE); + navigation_design *ND = Nav::new(I"twilight", FALSE, FALSE); ND->simplified_examples = TRUE; ND->simplified_letter_rows = TRUE; METHOD_ADD(ND, RENDER_CHAPTER_TITLE_MTID, Twilight::twilight_chapter_title); diff --git a/indoc/Chapter 4/Codename Unsigned.w b/indoc/Chapter 4/Codename Unsigned.w index b5e318fa0..9bcfaafcb 100644 --- a/indoc/Chapter 4/Codename Unsigned.w +++ b/indoc/Chapter 4/Codename Unsigned.w @@ -6,7 +6,7 @@ The "unsigned" style of navigational gadgets. = navigation_design *Unsigned::create(void) { - navigation_design *ND = Gadgets::new(I"unsigned", TRUE, FALSE); + navigation_design *ND = Nav::new(I"unsigned", TRUE, FALSE); METHOD_ADD(ND, RENDER_VOLUME_TITLE_MTID, Unsigned::unsigned_volume_title); METHOD_ADD(ND, RENDER_CHAPTER_TITLE_MTID, Unsigned::unsigned_chapter_title); METHOD_ADD(ND, RENDER_SECTION_TITLE_MTID, Unsigned::unsigned_section_title); diff --git a/indoc/Chapter 4/Navigational Gadgets.w b/indoc/Chapter 4/Navigational Gadgets.w deleted file mode 100644 index 29a275601..000000000 --- a/indoc/Chapter 4/Navigational Gadgets.w +++ /dev/null @@ -1,221 +0,0 @@ -[Gadgets::] Navigational Gadgets. - -To render linking gadgets in HTML forms of documentation, so that -the reader can navigate from section to section. - -@h - -= -typedef struct navigation_design { - struct text_stream *codename; - int ebook_friendly; - int plain_friendly; - int columnar; - int simplified_examples; - int simplified_letter_rows; - struct text_stream *contents_body_class; - METHOD_CALLS - MEMORY_MANAGEMENT -} navigation_design; - -navigation_design *Gadgets::new(text_stream *code, int e, int p) { - navigation_design *ND = CREATE(navigation_design); - ND->codename = Str::duplicate(code); - ND->ebook_friendly = e; - ND->plain_friendly = p; - ND->columnar = FALSE; - ND->simplified_examples = FALSE; - ND->simplified_letter_rows = FALSE; - ND->contents_body_class = I"paper midnightpapertint"; - ND->methods = Methods::new_set(); - return ND; -} - -void Gadgets::start(void) { - Midnight::create(); /* needs to be created first */ - Twilight::create(); - Architect::create(); - Roadsign::create(); /* needs to be created before unsigned */ - Unsigned::create(); - Lacuna::create(); -} - -navigation_design *Gadgets::default(void) { - return FIRST_OBJECT(navigation_design); -} - -navigation_design *Gadgets::for_ebook(navigation_design *current) { - if (current->ebook_friendly) return current; - navigation_design *ND; - LOOP_OVER(ND, navigation_design) - if (ND->ebook_friendly) - return ND; - return NULL; -} - -navigation_design *Gadgets::for_plain_text(navigation_design *current) { - if (current->plain_friendly) return current; - navigation_design *ND; - LOOP_OVER(ND, navigation_design) - if (ND->plain_friendly) - return ND; - return NULL; -} - -navigation_design *Gadgets::parse(text_stream *val) { - navigation_design *ND; - LOOP_OVER(ND, navigation_design) - if (Str::eq(val, ND->codename)) - return ND; - return NULL; -} - -@h Top. -At the front end of a section, before any of its text. - -@e RENDER_VOLUME_TITLE_MTID -@e RENDER_CHAPTER_TITLE_MTID -@e RENDER_SECTION_TITLE_MTID - -= -VMETHOD_TYPE(RENDER_VOLUME_TITLE_MTID, navigation_design *ND, text_stream *OUT, volume *V) -VMETHOD_TYPE(RENDER_CHAPTER_TITLE_MTID, navigation_design *ND, text_stream *OUT, volume *V, chapter *C) -VMETHOD_TYPE(RENDER_SECTION_TITLE_MTID, navigation_design *ND, text_stream *OUT, volume *V, chapter *C, section *S) - -void Gadgets::render_navigation_top(OUTPUT_STREAM, volume *V, section *S) { - if (V->sections[0] == S) VMETHOD_CALL(indoc_settings->navigation, RENDER_VOLUME_TITLE_MTID, OUT, V); - - chapter *C = S->begins_which_chapter; - if (C) VMETHOD_CALL(indoc_settings->navigation, RENDER_CHAPTER_TITLE_MTID, OUT, V, C); - - if (indoc_settings->html_for_Inform_application) - @; - - VMETHOD_CALL(indoc_settings->navigation, RENDER_SECTION_TITLE_MTID, OUT, V, C, S); -} - -@ = - WRITE("\n"); - TEMPORARY_TEXT(comment); - WRITE_TO(comment, "SEARCH TITLE \"%S\"", S->unlabelled_title); - HTML::comment(OUT, comment); - Str::clear(comment); - WRITE_TO(comment, "SEARCH SECTION \"%S\"", S->label); - HTML::comment(OUT, comment); - Str::clear(comment); - WRITE_TO(comment, "SEARCH SORT \"%S\"", S->sort_code); - HTML::comment(OUT, comment); - DISCARD_TEXT(comment); - -@h Index top. -And this is a variant for index pages, such as the index of examples. - -@e RENDER_INDEX_TOP_MTID - -= -VMETHOD_TYPE(RENDER_INDEX_TOP_MTID, navigation_design *ND, text_stream *OUT, text_stream *filename, text_stream *title) - -void Gadgets::render_navigation_index_top(OUTPUT_STREAM, text_stream *filename, text_stream *title) { - VMETHOD_CALL(indoc_settings->navigation, RENDER_INDEX_TOP_MTID, OUT, filename, title); -} - -@h Middle. -At the middle part, when the text is over, but before any example cues. - -@e RENDER_NAV_MIDDLE_MTID - -= -VMETHOD_TYPE(RENDER_NAV_MIDDLE_MTID, navigation_design *ND, text_stream *OUT, volume *V, section *S) - -void Gadgets::render_navigation_middle(OUTPUT_STREAM, volume *V, section *S) { - VMETHOD_CALL(indoc_settings->navigation, RENDER_NAV_MIDDLE_MTID, OUT, V, S); -} - -@h Example top. -This is reached before the first example is rendered, provided at least -one example will be: - -@e RENDER_EXAMPLE_TOP_MTID - -= -VMETHOD_TYPE(RENDER_EXAMPLE_TOP_MTID, navigation_design *ND, text_stream *OUT, volume *V, section *S) - -void Gadgets::render_navigation_example_top(OUTPUT_STREAM, volume *V, section *S) { - - if (indoc_settings->format == HTML_FORMAT) { - HTML::begin_div_with_class_S(OUT, I"bookexamples"); - HTML_OPEN_WITH("p", "class=\"chapterheading\""); - } - - if (indoc_settings->examples_granularity == CHAPTER_GRANULARITY) { - chapter *C = S->in_which_chapter; - WRITE("Examples from %S", C->chapter_full_title); - } else if (indoc_settings->examples_granularity == BOOK_GRANULARITY) { - WRITE("Examples"); - } - - if (indoc_settings->format == HTML_FORMAT) { - HTML_CLOSE("p"); - } else { WRITE("\n\n"); } - - VMETHOD_CALL(indoc_settings->navigation, RENDER_EXAMPLE_TOP_MTID, OUT, V, S); -} - -@h Example bottom. -Any closing ornament at the end of examples? This is reached after the -last example is rendered, provided at least one example has been. - -@e RENDER_EXAMPLE_BOTTOM_MTID - -= -VMETHOD_TYPE(RENDER_EXAMPLE_BOTTOM_MTID, navigation_design *ND, text_stream *OUT, volume *V, section *S) - -void Gadgets::render_navigation_example_bottom(OUTPUT_STREAM, volume *V, section *S) { - if (indoc_settings->format == PLAIN_FORMAT) { - WRITE("\n\n"); - } - - if (indoc_settings->format == HTML_FORMAT) { - if (indoc_settings->examples_mode != EXMODE_open_internal) { HTMLUtilities::ruled_line(OUT); } - HTML::end_div(OUT); - } - - VMETHOD_CALL(indoc_settings->navigation, RENDER_EXAMPLE_BOTTOM_MTID, OUT, V, S); -} - -@h Bottom. -At the end of the section, after any example cues and perhaps also example -bodied. (In a section with no examples, this immediately follows the middle.) - -@e RENDER_NAV_BOTTOM_MTID - -= -VMETHOD_TYPE(RENDER_NAV_BOTTOM_MTID, navigation_design *ND, text_stream *OUT, volume *V, section *S) - -void Gadgets::render_navigation_bottom(OUTPUT_STREAM, volume *V, section *S) { - if (indoc_settings->format == HTML_FORMAT) { - HTML::comment(OUT, I"START IGNORE"); - } - VMETHOD_CALL(indoc_settings->navigation, RENDER_NAV_BOTTOM_MTID, OUT, V, S); - if (indoc_settings->format == HTML_FORMAT) { - HTML::comment(OUT, I"END IGNORE"); - } -} - -@h Contents page. -Midnight provides a contents page of its very own. - -@e RENDER_CONTENTS_MTID -@e RENDER_CONTENTS_HEADING_MTID - -= -VMETHOD_TYPE(RENDER_CONTENTS_MTID, navigation_design *ND) -VMETHOD_TYPE(RENDER_CONTENTS_HEADING_MTID, navigation_design *ND, text_stream *OUT, volume *V) - -void Gadgets::render_navigation_contents_files(void) { - VMETHOD_CALLV(indoc_settings->navigation, RENDER_CONTENTS_MTID); -} - -void Gadgets::navigation_contents_heading(OUTPUT_STREAM, volume *V) { - VMETHOD_CALL(indoc_settings->navigation, RENDER_CONTENTS_HEADING_MTID, OUT, V); -} diff --git a/indoc/Contents.w b/indoc/Contents.w index 7083c12c6..a07b6c6a6 100644 --- a/indoc/Contents.w +++ b/indoc/Contents.w @@ -12,11 +12,16 @@ Build Date: 16 February 2019 Import: foundation +Preliminaries + Introduction to Indoc + Volumes and Instructions + Documentation Markup + Chapter 1: Setting Up Basics - Instructions - Configuration Main + Configuration + Instructions Context Symbols Chapter 2: Processing @@ -34,7 +39,7 @@ Chapter 3: Indexing Examples Index Chapter 4: Navigation Styles - Navigational Gadgets + Navigational Designs Codename Lacuna Codename Midnight Codename Architect diff --git a/indoc/Preliminaries/Documentation Markup.w b/indoc/Preliminaries/Documentation Markup.w new file mode 100644 index 000000000..64b6711e8 --- /dev/null +++ b/indoc/Preliminaries/Documentation Markup.w @@ -0,0 +1,5 @@ +Documentation Markup. + +How to mark up the plain-text source for Inform documentation. + +@h Stuff. diff --git a/indoc/Preliminaries/Introduction to Indoc.w b/indoc/Preliminaries/Introduction to Indoc.w new file mode 100644 index 000000000..f72375845 --- /dev/null +++ b/indoc/Preliminaries/Introduction to Indoc.w @@ -0,0 +1,93 @@ +Introduction to Indoc. + +What Indoc is, and its limited but complicated uses. + +@ Intest is a command line tool for generating (mainly) HTML or EPUB format +documentation. A million of those have been written, and Indoc has no +ambition to replace them. It is needed because Inform 7's documentation +source consists of many small text files with idiosyncratic markup, while +its formatted HTML version needs to be indexed in elaborate ways. + +Indoc is a purely command-line tool, used in building Inform but not in +running it: it's not present in the Inform UI apps. + +If you have compiled the standard distribution of the command-line tools +for Inform then the Indoc executable will be at |indoc/Tangled/indoc/|. +Usage is very simple: + + |$ indoc/Tangled/indoc [OPTIONS] TARGET| + +By default, Indoc reads its source documentation from a direction called +|Documentation| (with respect to the current working directory); the +option |-from X| changes this path to |X|, but in this manual we'll call +it |Documentation|. + +In addition to documentation files, which will be described later, Indoc +also reads instruction files. At minimum it will read + + |Documentation/indoc-instructions.txt| + +but the option |-instructions X| causes it to read |X| as well. Instructions +files mainly specify indexing notations, or CSS styles, or miscellaneous +settings, but they group these under named "targets". For example: + + |windows_app {| + | ...| + |}| + +declares a target called |windows_app|. (This is the form of HTML needed for +use inside the Windows UI application for Inform.) The idea here is that +there is probably no single form of HTML needed -- it will be needed in +subtly different versions for different platforms: inside the app, as a +stand-alone website, inside an Epub ebook. These different forms are +called "targets". On any given run, Indoc generates a single target -- +the one named on the command line. + +The HTML produced is placed, by default, in the directory: + + |Documentation/Output| + +This can be changed with the option |-to X|. + +@ When it runs, Indoc needs to know where it is installed in the file +system. There is no completely foolproof, cross-platform way to know this +(on some Unixes, a program cannot determine its own location), so Indoc +decides by the following set of rules: + +(a) If the user, at the command line, specified |-at P|, for some path +|P|, then we use that. +(b) Otherwise, if the host operating system can indeed tell us where the +executable is, we use that. This is currently implemented only on MacOS, +Windows and Linux. +(c) Otherwise, if the environment variable |$INDOC_PATH| exists and is +non-empty, we use that. +(d) And if all else fails, we assume that the location is |indoc|, with +respect to the current working directory. + +If you're not sure what Indoc has decided and suspect it may be wrong, +running Indoc with the |-verbose| switch will cause it to print its belief +about its location as it starts up. + +@ As a program, Indoc began as a rat's nest of Perl in 2002, and you can still +see where the rats used to live. Like all too many quick-fix Perl scripts, it +was still in use ten years later. In 2012, I spent some time tidying it up to +generate better HTML, and made it a web (that is, a literate program). The +original had produced typically sloppy turn-of-the-century HTML, with tables +for layout and no CSS, and with many now-deprecated tags and elements. The +2012 edition, by contrast, needed to produce validatable XHTML 1.1 Strict in +order to make EPUBs which read roughly correctly in today's ebook-readers, and +when they call this Strict they're not kidding. It took something like four +weeks of spare evenings. + +Just as I was finishing up, the programmer and commentator John Siracusa +described a not dissimilar web-content-and-ebook generation task on his +podcast (Hypercritical 85): "I was trying to think of a good analogy for what +happens when you're a programmer and you have this sort of task in front of +you. Is it, the cobbler's children have no shoes? ... You would expect someone +who is a programmer to make some awesome system which would generate these +three things. But when you're a programmer, you have the ability to do +whatever you want really, really quickly in the crappiest possible way... And +that's what I did. I wrote a series of incredibly disgusting Perl scripts." + +This made me feel better. Nevertheless, in 2016, indoc was rewritten in C, +and it received a further revision in 2019. diff --git a/indoc/Preliminaries/Volumes and Instructions.w b/indoc/Preliminaries/Volumes and Instructions.w new file mode 100644 index 000000000..878d1cdbb --- /dev/null +++ b/indoc/Preliminaries/Volumes and Instructions.w @@ -0,0 +1,321 @@ +Volumes and Instructions. + +Dual- versus single-volume mode, and how to write instructions files. + +@h Model. +Conceptually, an Indoc project has either one or two volumes. The source for +each volume is a single UTF-8 encoded plain text file. In the core Inform +repository, there are two volumes, with the files being + + |Documentation/Writing with Inform.txt| + |Documentation/The Recipe Book.txt| + +These are independent books, with individual titles. It would seem simpler +just to make them two different Indoc projects, but in dual-volume mode, +Indoc can generate joint contents pages, and provide crosswise HTML links +between the two volumes. + +The project can also include a number of "Examples", each being a single +text file such as: + + |Documentation/Examples/Prague.txt| + +which is the source for an Inform example called "The Prague Job". +(These same text files are also used by Intest to test that all of the code +samples included in the Inform documentation actually work as claimed.) +There can be any number of examples, including none; Inform currently has 468. + +Each volume is divided into a series of chapters, and each chapter into a +series of sections. Examples are always placed at the ends of sections; +note that in dual-volume mode, examples are (mostly) present in both volumes, +giving them two different locations. Thus, "The Prague Job" appears in section +"More general linkages" of chapter "Scenes" of volume "Writing with Inform", +and also in section "Scripted Scenes" of chapter "Time and Plot" of volume +"The Recipe Book". + +@h Project instructions. +The main instructions file for an Indoc project is, as noted earlier, at: + + |Documentation/indoc-instructions.txt| + +An instruction file is a UTF-8 encoded plain text file. Single instructions +occupy single lines (i.e., line breaks are significant). A white-space line, +or a line whose first non-white-space character is a |#|, are ignored. + +The file should begin by specifying one or two volumes, and then, if they +will contain Examples in the above sense, by giving the special |examples| +instruction. Inform opens thus: + + |volume: Writing with Inform| + |volume: The Inform Recipe Book (RB) = The Recipe Book.txt| + |examples| + +But a simpler, single-volume project might have just: + + |volume: Pandemonium 2.0 for Fun and Profit| + +Each volume has a title, and Indoc automatically generates an abbreviation +for it: by default, it takes the capital letters from the title, so that it +abbreviates "Writing with Inform" to WI. That same method would have made +turned "The Inform Recipe Book" into TIRB, but because we didn't want that, +we supplied our own abbreviation RB instead. + +The third, also optional, part of a |volume| instruction specifies the +leafname of the documentation source file for it. By default, this will be +the title plus |.txt|: for example, |Writing with Inform.txt|. But we can +use |= X| to specify that it should be |X| instead. + +Two other project instructions exist: + +If the project will contain images, then they will be looked for in a list +of places. Top of the list is a directory internal to Indoc which includes +some navigation icons such as |arrow-up.png|. The instruction |images: X| +adds the directory |X| to this source list. + +Lastly, the cover image for the project can be specified with an instruction +such as: + + |cover: combined_cover.png| + +This specifies a leafname which must exist in one of the image sources +mentioned above. + +@h Durham Core metadata. +If the project needs to generate Epub books, then these will need to have +some basic DC ("Durham Core") metadata supplied. For example: + + |dc:title: Inform - A Design System for Interactive Fiction| + |dc:creator: Graham Nelson and Emily Short| + |dc:subject: Interactive Fiction| + |dc:identifier: wwi-rb-combined| + +The instruction |dc:KEY: VALUE| supplies a DC key-value pair. + +@h Targets. +The instructions file typically begins as above, but then goes into a +block of general settings or instructions (for which see below); and +eventually gets around to describing one or more targets. A target +looks like so: + + |IDENTIFIER {| + | ...| + |}| + +where |IDENTIFIER| is its name. Targets, as noted in the introduction, +are different forms of the documentation we might need to produce: Inform, +for example, has targets called |plain|, |website|, |linux_app| and so on. +What's important here is not that these are written to different locations +on disc (though they are) but that they have finicky little differences +in settings. The |...| stretch of lines can specify these. For example: + + |ebook {| + | granularity = 2| + | examples_mode = open| + | follow: epub-css-tweaks.txt| + |}| + +makes two specific settings and one instruction, all applying only for the +target |ebook|. + +@h Symbols. +The instruction |declare: SYMBOL| creates the symbol |SYMBOL|. These exist +so that we can mark certain paragraphs of documentation as being present in +only some of the targets. + +For example, we might want Linux installation instructions to appear only +in the Linux version of a manual. To do that, we'll need the symbol: + + |linux_app {| + | ...| + | declare: Linux| + | ...| + |}| + +In the documentation, we could then mark up a paragraph like so: + + |{Linux:}To install, first...| + +The symbol |indoc| is always declared, but by default no other symbols are. +Lastly, |undeclare: SYMBOL| removes a symbol. + +@h Other instructions. +|follow: I| tells Indoc to follow the instructions file |I|. This works +rather like |#include| in C, or similar languages. If the |follow:| is +included inside a target block, then it affects only that target. On +other targets, the file |I| won't even be opened, and need never exist. + +|css:| specifies additional CSS (Cascading Style Sheet) styling. This +will be needed only if, for example, unusual indexing features are used, +in which different categories of index entry need different visual styling. +For example, + + |css: span.indextitle ++ {| + | font-style: italic;| + |}| + +Here the material between the braces is pure CSS, not Indoc syntax. The +notation |++| here tells Indoc that an entirely new CSS style is being +created; |+| would supply new lines to an existing style. + +|index: NOTATION = CATEGORY OPTION| defines a new indexing markup notation; +for example, + + |index: ^{@headword} = name (invert)| + +says that markup notations like |^{@Andrew Plotkin}| put a name into the index, +which should be an index entry of category |name|, and should be inverted, +in that it will be alphabetised under "Plotkin, Andrew". The text |headword| +in the prototype is where the entry text should appear in the notation. + +@h Miscellaneous settings. +There are a great many of these, but most are set to sensible defaults, +and it is not compulsory to set any of them. Lines such as + + |SETTING = VALUE| + +change the default settings if need be. Here is an A-Z list; they're really +too miscellaneous to be grouped usefully by subject matter. + +|alphabetization| sets the index sorting algorithm. The default is +|letter-by-letter|; the alternative is |word-by-word|. The difference is +that letter-by-letter would ignore word divisions and sort in the order +"peach", "peachpit", "peach tree"; whereas word-by-word would go for +"peach", "peach tree", "peachpit". + +|assume_Public_Library| can be |yes| or |no|. The default is |no|. This +specifies whether special HTML links to the Public Library will be valid; +outside of Inform UI apps, the answer is definitely no. + +|change_logs_directory| is the path to a directory holding Inform release +change log files. By default, this will be |Documentation/Change Logs|. + +|contents_leafname| is the (unextended) leafname to give the HTML contents +page. The default is |index|. + +|contents_expandable| can be |yes| or |no|. The default is |no|. This sets +whether Javascript-powered "expand" buttons are to be used in the contents +page, and has effect only on the Midnight navigation design. + +|css_source_file| is the filename of the CSS style sheet to use. The default +is the |base.css| file included in the Indoc distribution. + +|definitions_filename| is the filename to use if you would like Indoc to +output a special file of Inform phrase definitions, for use by Inform itself +when it generates indexes. The default for this is |definitions.html|. This +has nothing to do with the |definitions_index_filename|. + +|definitions_index_filename| is the leafname to use for the General Index +in the documentation. The default is |general_index.html|. This +has nothing to do with the |definitions_filename|. + +|destination| is the directory into which output is generated. The default +is |Documentation/Output|. Note that specifying |-to X| at the command line +overrides this setting: if |-to| is used, |destination| is ignored. + +|examples_directory| is the directory holding the Example files. The default +is |Documentation/Examples|. + +|examples_alphabetical_leafname| is the leafname to use for the alphabetical +index of examples in the documentation. The default is |examples_alphabetical.html|. + +|examples_granularity| is 1, 2, or 3. It can never be less than |granularity|, +and by default is equal to it. It specifies where examples should appear: +at the end of the relevant volume (1), chapter (2), or section (3). + +|examples_mode| is |open| or |openable|, and is by default |open|. Open means +that an example has its full contents visible by default; openable means that +the contents are hidden behind a Javascript-powered button which causes them +to be revealed. + +|examples_numerical_leafname| is the leafname to use for the numerical +index of examples in the documentation. The default is |examples_numerical.html|. + +|examples_thematic_leafname| is the leafname to use for the thematic +index of examples in the documentation. The default is |examples_thematic.html|. + +|format| is the most important of all the settings, and is |HTML| or |text|, +but by default |HTML| unless the target name is |plain|, in which case |text|. + +|granularity| is 1, 2, or 3. The default is 3 unless the target is called +|webpage| or |plain|, in which case it is 1. This specifies how much the +documentation is broken down into pieces. 1 means "each volume in a single +HTML file"; 2 means "each chapter", 3 means "each section". Low granularity +means fewer but larger files, high granularity more but smaller files. + +|html_for_Inform_application| can be |yes| or |no|. The default is |no|. This +specifies whether the HTML is for use inside the Inform UI application, and +can therefore use links with the special HTTP transports only available there. + +|images_copy| can be |yes| or |no|. The default is |yes|. In this mode, +any needed image files are copied into place into the |images_path|. (The +alternative assumes they are already there, and should be used if |images_path| +is some URL external to the HTML being generated.) + +|images_path| is where the generated HTML expects to find its image files. +The default is |~~/Images/|, where |~~| means the destination directory: +that is, the default is a subdirectory called |Images| of the destination. + +|inform_definitions_mode| can be |yes| or |no|. The default is |no|. This +is cosmetic, and provides extra styling on lines of documentation giving the +syntax for Inform phrases. + +|javascript| can be |yes| or |no|. The default is |yes|. This indicates +whetber Indoc is allowed to compile Javascript, or has to stick to inactive +HTML. + +|javascript_paste_method| can be |none|, |Andrew| or |David|. The default +is |none|. The difference relates to how "paste Inform source" links are +implemented inside the Inform application: |Andrew| mode is suitable for +most platforms, but |David| is needed for Windows. + +|link_to_extensions_index| is meaningful only if |html_for_Inform_application| +is set, and specifies the URL of the Extensions index inside the app. + +|manifest_leafname| is meaningful only if |html_for_Inform_application| +is set, and is by default |manifest.txt|. This provides a cross-reference +list of files generated by Indoc. + +|navigation| is the design used for navigation links in the HTML produced. +There are currently six designs, called |architect|, |lacuna|, |midnight|, +|roadsign|, |twilight|, and |unsigned|; the default is |roadsign|, though +inside the Inform applications, the design chosen is usually |architect|. +If the format is |text| not |HTML|, then the design is always |lacuna|. + +|retina_images| can be |yes| or |no|. The default is |no|. This indicates +whether MacOS/iOS "retina" versions of the paste and create icons are +available: |paste@2x.png| and |create@2x.png| respectively. + +|support_creation| can be |yes| or |no|. The default is |no|. This indicates +whether the Examples have a "create" button which creates a new Inform +project demonstrating them in action; this can only be done in the UI apps, +so it should always be |no| unless |html_for_Inform_application| is |yes|. + +|suppress_fonts| can be |yes| or |no|. The default is |no|. If |yes|, this +strips out lists of fonts to use in CSS, leaving only whether they are +|monospace| or not. + +|toc_granularity| is 1, 2, or 3. It can never be less than |granularity|, +and by default is 3. It shows the level of detail in the table of contents: 1 +means volumes, 2 means volumes and chapters, 3 goes down to sections. + +|top_and_tail| specifies a prototype HTML file to follow for the more +important HTML pages generated by Indoc. The default is not to. If +this exists, it can provide a surround for the HTML we generate -- for +example, it can contain website-specific navigation, or a banner across +the top. The prototype should somewhere include the text |[TEXT]|, and +this will be replaced with whatever Indoc generates. + +|top_and_tail_sections| is the same as |top_and_tail|, but for individual +section files. + +|treat_code_as_verbatim| can be |yes| or |no|. The default is |yes|. This +affects the styling of marked-up code material in documentation. Without +it, code markup is largely unavailable. + +|wrapper| can be |EPUB|, |zip| or |none|. The default is |none|. The wrapper +is put around the whole mass of generated HTML; |EPUB| makes the result an +Epub-format ebook. + +|XHTML| can be |yes| or |no|. The default is |no|. This forces the HTML we +produce to conform to XHTML 1.1 Strict. If the |wrapper| is |EPUB|, then +this is automatically set to |yes|.