To specify modified versions of the Markdown markup syntax.
- §5. The CommonMark variation
- §6. Github extensions to CommonMark
- §7. Inweb extensions to GFM
- §8. Methods for features
§1. In practice, nobody quite uses pure Markdown, because there are always minor additions or removals people want to make in particular use cases. We'll call modified versions of the Markdown syntax "variations", but will provide only one of these here: the baseline of CommonMark.
define MAX_MARKDOWNFEATURES 256
markdown_feature *markdown_feature_registry[MAX_MARKDOWNFEATURES]; void MarkdownVariations::start(void) { Markdown::create_item_types(); for (int i=0; i<MAX_MARKDOWNFEATURES; i++) markdown_feature_registry[i] = NULL; MarkdownVariations::define_CommonMark(); MarkdownVariations::define_GFM(); MarkdownVariations::define_IWFM(); } markdown_variation *CommonMark_variation = NULL; markdown_variation *GitHub_flavored_Markdown_variation = NULL; markdown_variation *Inweb_flavoured_Markdown_variation = NULL; markdown_variation *simplified_Inweb_flavoured_Markdown_variation = NULL; markdown_variation *TeX_flavoured_Markdown_variation = NULL; markdown_variation *MarkdownVariations::CommonMark(void) { return CommonMark_variation; } markdown_variation *MarkdownVariations::GitHub_flavored_Markdown(void) { return GitHub_flavored_Markdown_variation; } markdown_variation *MarkdownVariations::Inweb_flavoured_Markdown(void) { return Inweb_flavoured_Markdown_variation; } markdown_variation *MarkdownVariations::simplified_Inweb_flavoured_Markdown(void) { return simplified_Inweb_flavoured_Markdown_variation; } markdown_variation *MarkdownVariations::TeX_flavoured_Markdown(void) { return TeX_flavoured_Markdown_variation; }
§2. A variation is essentially a named collection of features, which may affect parsing, or rendering, or both.
All newly-created variations begin with the CommonMark baseline set of features
active, and no others. The caller should use MarkdownVariations::add_feature to
add a home-brew feature, or MarkdownVariations::remove_feature to take away
one of the CommonMark ones.
classdef markdown_variation { struct text_stream *name; int active_built_in_features[NO_DEFINED_MARKDOWNFEATURE_VALUES]; struct method_set *methods; } markdown_variation *MarkdownVariations::new(text_stream *name) { markdown_variation *variation = CREATE(markdown_variation); variation->name = Str::duplicate(name); variation->methods = Methods::new_set(); for (int i=0; i<NO_DEFINED_MARKDOWNFEATURE_VALUES; i++) variation->active_built_in_features[i] = FALSE; MarkdownVariations::make_baseline_features_active(variation); return variation; } void MarkdownVariations::add_feature(markdown_variation *variation, int feature_id) { variation->active_built_in_features[feature_id] = TRUE; } void MarkdownVariations::remove_feature(markdown_variation *variation, int feature_id) { variation->active_built_in_features[feature_id] = FALSE; } void MarkdownVariations::copy_features_of(markdown_variation *to, markdown_variation *from) { for (int i=0; i<NO_DEFINED_MARKDOWNFEATURE_VALUES; i++) to->active_built_in_features[i] = from->active_built_in_features[i]; }
- The structure markdown_variation is accessed in 2/mth, 2/trs, 4/prp, 4/jsn, 5/mrk, 5/im, 7/ld and here.
§3. A "feature" is an aspect of Markdown syntax or behaviour; any given variation can either support it or not.
classdef markdown_feature { struct text_stream *name; int feature_ID; struct method_set *methods; } markdown_feature *MarkdownVariations::new_feature(text_stream *name, int id) { markdown_feature *feature = CREATE(markdown_feature); if (id >= MAX_MARKDOWNFEATURES) internal_error("too many Markdown features"); feature->name = Str::duplicate(name); feature->feature_ID = id; feature->methods = Methods::new_set(); if (markdown_feature_registry[id]) internal_error("Markdown feature ID clash"); markdown_feature_registry[id] = feature; return feature; }
- The structure markdown_feature is accessed in 2/mth, 2/trs, 4/prp, 4/jsn, 5/mrk, 5/im, 7/ld and here.
§4. The point of the cumbersome business of both defining an ID and creating an object to represent the same feature was to make this function quick.
int MarkdownVariations::supports(markdown_variation *variation, int feature_id) { return variation->active_built_in_features[feature_id]; }
enumerate BLOCK_QUOTES_MARKDOWNFEATURE 0
enumerate ORDERED_LISTS_MARKDOWNFEATURE
enumerate UNORDERED_LISTS_MARKDOWNFEATURE
enumerate INDENTED_CODE_BLOCKS_MARKDOWNFEATURE
enumerate FENCED_CODE_BLOCKS_MARKDOWNFEATURE
enumerate HTML_BLOCKS_MARKDOWNFEATURE
enumerate THEMATIC_MARKERS_MARKDOWNFEATURE
enumerate ATX_HEADINGS_MARKDOWNFEATURE
enumerate SETEXT_HEADINGS_MARKDOWNFEATURE
enumerate WEB_AUTOLINKS_MARKDOWNFEATURE
enumerate EMAIL_AUTOLINKS_MARKDOWNFEATURE
enumerate INLINE_HTML_MARKDOWNFEATURE
enumerate BACKTICKED_CODE_MARKDOWNFEATURE
enumerate LINKS_MARKDOWNFEATURE
enumerate IMAGES_MARKDOWNFEATURE
enumerate ASTERISK_EMPHASIS_MARKDOWNFEATURE
enumerate UNDERSCORE_EMPHASIS_MARKDOWNFEATURE
enumerate ENTITIES_MARKDOWNFEATURE
markdown_feature *block_quotes_Markdown_feature = NULL; markdown_feature *ordered_lists_Markdown_feature = NULL; markdown_feature *unordered_lists_Markdown_feature = NULL; markdown_feature *indented_code_blocks_Markdown_feature = NULL; markdown_feature *fenced_code_blocks_Markdown_feature = NULL; markdown_feature *HTML_blocks_Markdown_feature = NULL; markdown_feature *thematic_markers_Markdown_feature = NULL; markdown_feature *ATX_headings_Markdown_feature = NULL; markdown_feature *setext_headings_Markdown_feature = NULL; markdown_feature *web_autolinks_Markdown_feature = NULL; markdown_feature *email_autolinks_Markdown_feature = NULL; markdown_feature *inline_HTML_Markdown_feature = NULL; markdown_feature *backticked_code_Markdown_feature = NULL; markdown_feature *links_Markdown_feature = NULL; markdown_feature *images_Markdown_feature = NULL; markdown_feature *asterisk_emphasis_Markdown_feature = NULL; markdown_feature *underscore_emphasis_Markdown_feature = NULL; markdown_feature *entities_Markdown_feature = NULL; void MarkdownVariations::define_CommonMark(void) { block_quotes_Markdown_feature = MarkdownVariations::new_feature(I"block quotes", BLOCK_QUOTES_MARKDOWNFEATURE); ordered_lists_Markdown_feature = MarkdownVariations::new_feature(I"ordered lists", ORDERED_LISTS_MARKDOWNFEATURE); unordered_lists_Markdown_feature = MarkdownVariations::new_feature(I"unordered lists", UNORDERED_LISTS_MARKDOWNFEATURE); indented_code_blocks_Markdown_feature = MarkdownVariations::new_feature(I"indented code blocks", INDENTED_CODE_BLOCKS_MARKDOWNFEATURE); fenced_code_blocks_Markdown_feature = MarkdownVariations::new_feature(I"fenced code blocks", FENCED_CODE_BLOCKS_MARKDOWNFEATURE); HTML_blocks_Markdown_feature = MarkdownVariations::new_feature(I"HTML blocks", HTML_BLOCKS_MARKDOWNFEATURE); thematic_markers_Markdown_feature = MarkdownVariations::new_feature(I"thematic markers", THEMATIC_MARKERS_MARKDOWNFEATURE); ATX_headings_Markdown_feature = MarkdownVariations::new_feature(I"ATX headings", ATX_HEADINGS_MARKDOWNFEATURE); setext_headings_Markdown_feature = MarkdownVariations::new_feature(I"setext headings", SETEXT_HEADINGS_MARKDOWNFEATURE); web_autolinks_Markdown_feature = MarkdownVariations::new_feature(I"web autolinks", WEB_AUTOLINKS_MARKDOWNFEATURE); email_autolinks_Markdown_feature = MarkdownVariations::new_feature(I"email autolinks", EMAIL_AUTOLINKS_MARKDOWNFEATURE); inline_HTML_Markdown_feature = MarkdownVariations::new_feature(I"inline HTML", INLINE_HTML_MARKDOWNFEATURE); backticked_code_Markdown_feature = MarkdownVariations::new_feature(I"backticked code", BACKTICKED_CODE_MARKDOWNFEATURE); links_Markdown_feature = MarkdownVariations::new_feature(I"links", LINKS_MARKDOWNFEATURE); images_Markdown_feature = MarkdownVariations::new_feature(I"images", IMAGES_MARKDOWNFEATURE); asterisk_emphasis_Markdown_feature = MarkdownVariations::new_feature(I"emphasis", ASTERISK_EMPHASIS_MARKDOWNFEATURE); underscore_emphasis_Markdown_feature = MarkdownVariations::new_feature(I"emphasis", UNDERSCORE_EMPHASIS_MARKDOWNFEATURE); entities_Markdown_feature = MarkdownVariations::new_feature(I"entities", ENTITIES_MARKDOWNFEATURE); CommonMark_variation = MarkdownVariations::new(I"CommonMark 0.30"); } void MarkdownVariations::make_baseline_features_active(markdown_variation *variation) { MarkdownVariations::add_feature(variation, BLOCK_QUOTES_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, ORDERED_LISTS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, UNORDERED_LISTS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, INDENTED_CODE_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, FENCED_CODE_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, HTML_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, THEMATIC_MARKERS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, ATX_HEADINGS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, SETEXT_HEADINGS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, WEB_AUTOLINKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, EMAIL_AUTOLINKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, INLINE_HTML_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, BACKTICKED_CODE_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, LINKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, IMAGES_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, ASTERISK_EMPHASIS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, UNDERSCORE_EMPHASIS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, ENTITIES_MARKDOWNFEATURE); }
§6. Github extensions to CommonMark. See GitHub's specification, which is based on CommonMark, though its description of new features is a little more concise, since these have been added with more prudent syntax.
enumerate STRIKETHROUGH_MARKDOWNFEATURE
enumerate TABLES_MARKDOWNFEATURE
enumerate TASK_LIST_ITEMS_MARKDOWNFEATURE
enumerate EXTENDED_AUTOLINKS_MARKDOWNFEATURE
enumerate DISALLOWED_RAW_HTML_MARKDOWNFEATURE
markdown_feature *strikethrough_Markdown_feature = NULL; markdown_feature *tables_Markdown_feature = NULL; markdown_feature *task_list_items_Markdown_feature = NULL; markdown_feature *extended_autolinks_Markdown_feature = NULL; markdown_feature *disallowed_raw_HTML_Markdown_feature = NULL; void MarkdownVariations::define_GFM(void) { strikethrough_Markdown_feature = MarkdownVariations::new_feature(I"strikethrough", STRIKETHROUGH_MARKDOWNFEATURE); tables_Markdown_feature = MarkdownVariations::new_feature(I"tables", TABLES_MARKDOWNFEATURE); task_list_items_Markdown_feature = MarkdownVariations::new_feature(I"task list items", TASK_LIST_ITEMS_MARKDOWNFEATURE); extended_autolinks_Markdown_feature = MarkdownVariations::new_feature(I"extended autolinks", EXTENDED_AUTOLINKS_MARKDOWNFEATURE); disallowed_raw_HTML_Markdown_feature = MarkdownVariations::new_feature(I"disallowed raw HTML", DISALLOWED_RAW_HTML_MARKDOWNFEATURE); GitHub_flavored_Markdown_variation = MarkdownVariations::new(I"GitHub-flavored Markdown 0.29"); MarkdownVariations::make_GitHub_features_active(GitHub_flavored_Markdown_variation); } void MarkdownVariations::make_GitHub_features_active(markdown_variation *variation) { MarkdownVariations::add_feature(variation, STRIKETHROUGH_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, TABLES_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, TASK_LIST_ITEMS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, EXTENDED_AUTOLINKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, DISALLOWED_RAW_HTML_MARKDOWNFEATURE); }
§7. Inweb extensions to GFM. We provide just a few of these, and they are intended to be used on top of GFM:
enumerate TEX_MARKDOWNFEATURE
enumerate ALT_TEX_MARKDOWNFEATURE
enumerate INWEB_LINKS_MARKDOWNFEATURE
enumerate ALT_INWEB_LINKS_MARKDOWNFEATURE
enumerate INWEB_SYNTAX_COLOURING_MARKDOWNFEATURE
enumerate FOOTNOTES_MARKDOWNFEATURE
enumerate STROKED_CODE_MARKDOWNFEATURE
markdown_feature *TeX_Markdown_feature = NULL; markdown_feature *alt_TeX_Markdown_feature = NULL; markdown_feature *inweb_links_Markdown_feature = NULL; markdown_feature *alt_inweb_links_Markdown_feature = NULL; markdown_feature *inweb_syntax_colouring_Markdown_feature = NULL; markdown_feature *footnotes_Markdown_feature = NULL; markdown_feature *stroked_code_Markdown_feature = NULL; void MarkdownVariations::define_IWFM(void) { TeX_Markdown_feature = MarkdownVariations::new_feature(I"TeX", TEX_MARKDOWNFEATURE); alt_TeX_Markdown_feature = MarkdownVariations::new_feature(I"alt-TeX", ALT_TEX_MARKDOWNFEATURE); inweb_links_Markdown_feature = MarkdownVariations::new_feature(I"inweb links", INWEB_LINKS_MARKDOWNFEATURE); alt_inweb_links_Markdown_feature = MarkdownVariations::new_feature(I"alt-inweb links", ALT_INWEB_LINKS_MARKDOWNFEATURE); inweb_syntax_colouring_Markdown_feature = MarkdownVariations::new_feature(I"inweb syntax-colouring", INWEB_SYNTAX_COLOURING_MARKDOWNFEATURE); footnotes_Markdown_feature = MarkdownVariations::new_feature(I"inweb footnotes", FOOTNOTES_MARKDOWNFEATURE); stroked_code_Markdown_feature = MarkdownVariations::new_feature(I"stroked code", STROKED_CODE_MARKDOWNFEATURE); Inweb_flavoured_Markdown_variation = MarkdownVariations::new(I"Inweb-flavoured Markdown"); MarkdownVariations::make_GitHub_features_active(Inweb_flavoured_Markdown_variation); MarkdownVariations::make_Inweb_features_active(Inweb_flavoured_Markdown_variation); simplified_Inweb_flavoured_Markdown_variation = MarkdownVariations::new(I"Inweb-flavoured Markdown"); MarkdownVariations::make_simplified_Inweb_features_active(simplified_Inweb_flavoured_Markdown_variation); TeX_flavoured_Markdown_variation = MarkdownVariations::new(I"TeX-flavoured Markdown"); MarkdownVariations::make_TeX_flavoured_Markdown_features_active(TeX_flavoured_Markdown_variation); } void MarkdownVariations::make_Inweb_features_active(markdown_variation *variation) { MarkdownVariations::add_feature(variation, TEX_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, INWEB_LINKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, FOOTNOTES_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, INWEB_SYNTAX_COLOURING_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, EXTENDED_AUTOLINKS_MARKDOWNFEATURE); } void MarkdownVariations::make_simplified_Inweb_features_active(markdown_variation *variation) { MarkdownVariations::remove_feature(variation, BLOCK_QUOTES_MARKDOWNFEATURE); //MarkdownVariations::remove_feature(variation, ORDERED_LISTS_MARKDOWNFEATURE);//MarkdownVariations::remove_feature(variation, UNORDERED_LISTS_MARKDOWNFEATURE);MarkdownVariations::remove_feature(variation, INDENTED_CODE_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, FENCED_CODE_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, HTML_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, THEMATIC_MARKERS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, ATX_HEADINGS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, SETEXT_HEADINGS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, WEB_AUTOLINKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, EMAIL_AUTOLINKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, INLINE_HTML_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, BACKTICKED_CODE_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, LINKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, IMAGES_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, TEX_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, INWEB_LINKS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, FOOTNOTES_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, STROKED_CODE_MARKDOWNFEATURE); } void MarkdownVariations::make_TeX_flavoured_Markdown_features_active(markdown_variation *variation) { MarkdownVariations::remove_feature(variation, BLOCK_QUOTES_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, ORDERED_LISTS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, UNORDERED_LISTS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, INDENTED_CODE_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, FENCED_CODE_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, HTML_BLOCKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, THEMATIC_MARKERS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, ATX_HEADINGS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, SETEXT_HEADINGS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, WEB_AUTOLINKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, EMAIL_AUTOLINKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, INLINE_HTML_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, BACKTICKED_CODE_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, LINKS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, IMAGES_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, ASTERISK_EMPHASIS_MARKDOWNFEATURE); MarkdownVariations::remove_feature(variation, UNDERSCORE_EMPHASIS_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, TEX_MARKDOWNFEATURE); MarkdownVariations::add_feature(variation, STROKED_CODE_MARKDOWNFEATURE); //MarkdownVariations::add_feature(variation, INWEB_LINKS_MARKDOWNFEATURE);//MarkdownVariations::add_feature(variation, FOOTNOTES_MARKDOWNFEATURE);}
§8. Methods for features. New features need to be able to intervene in the parsing or rendering algorithms, so for that we provide methods.
RENDER_MARKDOWN_MTID allows a feature to meddle in how a node is rendered.
enumerate RENDER_MARKDOWN_MTID
INT_METHOD_TYPE(RENDER_MARKDOWN_MTID, markdown_feature *feature, text_stream *OUT, markdown_item *md, int mode) int MarkdownVariations::intervene_in_rendering(markdown_variation *variation, text_stream *OUT, markdown_item *md, int mode) { markdown_feature *feature; LOOP_OVER(feature, markdown_feature) { if (MarkdownVariations::supports(variation, feature->feature_ID)) { int rv = FALSE; INT_METHOD_CALL(rv, feature, RENDER_MARKDOWN_MTID, OUT, md, mode); if (rv) return TRUE; } } return FALSE; }
§9. POST_PHASE_I_MARKDOWN_MTID allows a feature to restructure or annotate the
block tree produced by Phase I parsing; similarly POST_PHASE_II_MARKDOWN_MTID.
enumerate POST_PHASE_I_MARKDOWN_MTID
enumerate POST_PHASE_II_MARKDOWN_MTID
VOID_METHOD_TYPE(POST_PHASE_I_MARKDOWN_MTID, markdown_feature *feature, markdown_item *tree, md_links_dictionary *link_references) VOID_METHOD_TYPE(POST_PHASE_II_MARKDOWN_MTID, markdown_feature *feature, markdown_item *tree, md_links_dictionary *link_references) void MarkdownVariations::intervene_after_Phase_I(markdown_variation *variation, markdown_item *tree, md_links_dictionary *link_references) { markdown_feature *feature; LOOP_OVER(feature, markdown_feature) { if (MarkdownVariations::supports(variation, feature->feature_ID)) { VOID_METHOD_CALL(feature, POST_PHASE_I_MARKDOWN_MTID, tree, link_references); } } } void MarkdownVariations::intervene_after_Phase_II(markdown_variation *variation, markdown_item *tree, md_links_dictionary *link_references) { markdown_feature *feature; LOOP_OVER(feature, markdown_feature) { if (MarkdownVariations::supports(variation, feature->feature_ID)) { VOID_METHOD_CALL(feature, POST_PHASE_II_MARKDOWN_MTID, tree, link_references); } } }
§10. MULTIFILE_MARKDOWN_MTID allows a feature to tell the parser that the content
will end up being split across multiple HTML files. If a feature wants to do
this, it should then set a "file point" at any top-level positions of its
choice, and return TRUE.
enumerate MULTIFILE_MARKDOWN_MTID
INT_METHOD_TYPE(MULTIFILE_MARKDOWN_MTID, markdown_feature *feature, markdown_item *tree, md_links_dictionary *link_references) int MarkdownVariations::multifile_mode(markdown_variation *variation, markdown_item *tree, md_links_dictionary *link_references) { if (tree->down) { markdown_feature *feature; LOOP_OVER(feature, markdown_feature) { if (MarkdownVariations::supports(variation, feature->feature_ID)) { int rv = FALSE; INT_METHOD_CALL(rv, feature, MULTIFILE_MARKDOWN_MTID, tree, link_references); if (rv) { MarkdownVariations::assign_URLs_to_headings(tree, link_references); return TRUE; } } } } return FALSE; } void MarkdownVariations::assign_URLs_to_headings(markdown_item *tree, md_links_dictionary *link_references) { if (tree->down->type != VOLUME_MIT) { markdown_item *index = Markdown::new_volume_marker(I"all in one"); index->next = tree->down; tree->down = index; } for (markdown_item *md = tree->down; md; md = md->next) { if (md->type == VOLUME_MIT) { md->down = md->next; md->next = NULL; markdown_item *ch = md->down, *prev_ch = NULL; while ((ch) && (ch->type != VOLUME_MIT)) { prev_ch = ch, ch = ch->next; } if (ch) { prev_ch->next = NULL; md->next = ch; } } } for (markdown_item *vol = tree->down; vol; vol = vol->next) { if (vol->type == VOLUME_MIT) { if ((vol->down) && (vol->down->type != FILE_MIT)) { #ifdef SUPERVISOR_MODULE text_stream *home_URL = DocumentationCompiler::home_URL_at_volume_item(vol); #endif #ifndef SUPERVISOR_MODULE text_stream *home_URL = I"index.html"; #endif markdown_item *index = Markdown::new_file_marker(Filenames::from_text(home_URL)); index->next = vol->down; vol->down = index; } for (markdown_item *md = vol->down; md; md = md->next) { if (md->type == FILE_MIT) { md->down = md->next; md->next = NULL; markdown_item *ch = md->down, *prev_ch = NULL; while ((ch) && (ch->type != FILE_MIT) && (ch->type != VOLUME_MIT)) { prev_ch = ch, ch = ch->next; } if (ch) { prev_ch->next = NULL; md->next = ch; } } } } } markdown_item *headings[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; MarkdownVariations::multifile_r(tree->down, link_references, headings, NULL); }
void MarkdownVariations::multifile_r(markdown_item *md, md_links_dictionary *link_references, markdown_item *headings[7], markdown_item *file_item) { int non_heading_found = FALSE; for (; md; md = md->next) { if (md->type == HEADING_MIT) { int L = Markdown::get_heading_level(md); headings[L] = md; for (int i=L+1; i<=6; i++) headings[i] = NULL; text_stream *URL = Str::new(); if (file_item) { WRITE_TO(URL, "%f", Markdown::get_filename(file_item)); } TEMPORARY_TEXT(xref) TEMPORARY_TEXT(anchor) match_results mr = Regexp::create_mr(); if (Regexp::match(&mr, md->stashed, U"Chapter (%d+): *(%c*)")) { WRITE_TO(xref, "%S", mr.exp[1]); WRITE_TO(anchor, "chapter%S", mr.exp[0]); } else if (Regexp::match(&mr, md->stashed, U"Chapter (%d+)")) { WRITE_TO(xref, "%S", md->stashed); WRITE_TO(anchor, "chapter%S", mr.exp[0]); } else if (Regexp::match(&mr, md->stashed, U"Section (%d+).(%d+): *(%c*)")) { WRITE_TO(xref, "%S", mr.exp[2]); WRITE_TO(anchor, "c%Ss%S", mr.exp[0], mr.exp[1]); } else if (Regexp::match(&mr, md->stashed, U"Section (%d+).(%d+)")) { WRITE_TO(xref, "%S", md->stashed); WRITE_TO(anchor, "c%Ss%S", mr.exp[0], mr.exp[1]); } else if (Regexp::match(&mr, md->stashed, U"Section (%d+): *(%c*)")) { WRITE_TO(xref, "%S", mr.exp[1]); WRITE_TO(anchor, "s%S", mr.exp[0]); } else if (Regexp::match(&mr, md->stashed, U"Section (%d+)")) { WRITE_TO(xref, "%S", md->stashed); WRITE_TO(anchor, "s%S", mr.exp[0]); } else { WRITE_TO(xref, "%S", md->stashed); WRITE_TO(anchor, "heading%d", md->id); } Regexp::dispose_of(&mr); if (non_heading_found) { WRITE_TO(URL, "#%S", anchor); } md->user_state = STORE_POINTER_text_stream(URL); Markdown::create(link_references, xref, URL, md->stashed); DISCARD_TEXT(xref) DISCARD_TEXT(anchor) } else { non_heading_found = TRUE; } MarkdownVariations::multifile_r(md->down, link_references, headings, (md->type == FILE_MIT)?md:NULL); } } text_stream *MarkdownVariations::URL_for_heading(markdown_item *md) { if ((md) && (md->type == HEADING_MIT) && (Markdown::get_heading_level(md) <= 2)) if (GENERAL_POINTER_IS_NULL(md->user_state) == FALSE) return RETRIEVE_POINTER_text_stream(md->user_state); return NULL; }