slweb

Једноставни генератор статичких веб страна
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 5a2340fc7629557897a0883c6c06edffdd133eab
родитељ d6e80166edfe4369b9a92140ea3ac8cc46717ed2
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Fri, 22 Jan 2021 22:53:54 +0100

Fixed footnotes, added documentation for footnotes

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MTODO | 2+-
Mexamples/all.do | 2+-
Aexamples/basic/all.do | 2++
Aexamples/blockquote/all.do | 2++
Aexamples/footnotes/all.do | 2++
Aexamples/footnotes/index.slw | 17+++++++++++++++++
Aexamples/footnotes/inline.slw | 11+++++++++++
Aexamples/footnotes/warning.slw | 15+++++++++++++++
Aexamples/includes/all.do | 2++
Aexamples/links/all.do | 2++
Aexamples/macros/all.do | 2++
Aexamples/tags/all.do | 2++
Mindex.html | 2+-
Mslweb.1.in | 153++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Mslweb.c | 136++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
измењених датотека: 15, додавања: 287(+), брисања: 65(-)

diff --git a/TODO b/TODO @@ -7,7 +7,7 @@ [~] Add footnote support [x] Add initial support [ ] Test - [ ] Add documentation + [x] Add documentation [ ] Add horizontal rule support diff --git a/examples/all.do b/examples/all.do @@ -1,4 +1,4 @@ for d in *; do - [ -d $d ] && echo $d/index.html + [ -d $d ] && echo $d/all done | xargs redo-ifchange diff --git a/examples/basic/all.do b/examples/basic/all.do @@ -0,0 +1,2 @@ +redo-ifchange index.html + diff --git a/examples/blockquote/all.do b/examples/blockquote/all.do @@ -0,0 +1,2 @@ +redo-ifchange index.html + diff --git a/examples/footnotes/all.do b/examples/footnotes/all.do @@ -0,0 +1,2 @@ +echo "index.html inline.html" | xargs redo-ifchange + diff --git a/examples/footnotes/index.slw b/examples/footnotes/index.slw @@ -0,0 +1,17 @@ +--- +site-name: Footnotes test +--- + +# Footnotes + +Footnotes can be added by using the syntax `[^id]` and later `[^id]: Footnote +text`[^justlike]. + +You can thus minimize the amount of extra markup present in the text +itself[^links]. + +[^justlike]: Just like this! +[^links]: Similar to links. Footnotes themselves + can contain **some** `markup`, and can be broken up into + multiple lines. + diff --git a/examples/footnotes/inline.slw b/examples/footnotes/inline.slw @@ -0,0 +1,11 @@ +--- +site-name: Inline footnotes test +--- + +# Inline footnotes + +Footnotes can also be inline +^[Note that with inline footnotes, the _entire_ footnote needs to fit on a single line!]. + +Here's another paragraph^[With a footnote.]. + diff --git a/examples/footnotes/warning.slw b/examples/footnotes/warning.slw @@ -0,0 +1,15 @@ +--- +site-name: Footnote warning demo +--- + +# Parse warning + +If the input contains both inline and regular footnotes, **slweb** will issue a +warning to `stderr`^[So this warning won't appear in the output.]. + +The numbering of the footnotes will most likely overlap[^A] (hence the warning), +but the anchors will be unique, having `inline-` prepended to the _id_ for +inline footnotes. + +[^A]: As evident in this example. + diff --git a/examples/includes/all.do b/examples/includes/all.do @@ -0,0 +1,2 @@ +redo-ifchange index.html + diff --git a/examples/links/all.do b/examples/links/all.do @@ -0,0 +1,2 @@ +redo-ifchange index.html + diff --git a/examples/macros/all.do b/examples/macros/all.do @@ -0,0 +1,2 @@ +redo-ifchange index.html + diff --git a/examples/tags/all.do b/examples/tags/all.do @@ -0,0 +1,2 @@ +redo-ifchange index.html + diff --git a/index.html b/index.html @@ -134,7 +134,7 @@ this program. If not, see &lt;<a href="https://www.gnu.org/licenses">https://www <div id="git-log"> Previous commit: -index.slw d116a67 2021-01-20 21:47:06 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD) +index.slw d6e8016 2021-01-21 22:49:28 +0100 (Страхиња Радић) (HEAD -> master, origin/master, origin/HEAD) </div><!--git-log--> diff --git a/slweb.1.in b/slweb.1.in @@ -91,11 +91,14 @@ are using a minimal subset of Markdown with added directives. . .SS Supported Markdown features . -.IP \[bu] +.IP \[bu] 4 .BR Backticks . Text inside \fC`backticks`\fP will be put inside \fC<code></code>\fP. Text -inside triple backticks (\fC```\fP) will be put inside \fC<pre></pre>\fP. Any -\[lq]less-than\[rq] character will be converted to \fC&lt;\fP. +surrounded by triple backticks (\fC```\fP) on the lines by themselves will be +put inside \fC<pre></pre>\fP. Any \[lq]less-than\[rq] character inside backticks +will be converted to \fC&lt;\fP. Any text following the first triple backticks +until the end of the line will be ignored. This is to account for language +highlighting specification, which isn't yet supported. . .IP \[bu] .BR Blockquotes . @@ -110,6 +113,90 @@ underlines__\fP will be put inside \fC<strong></strong>\fP. \fC***More than two*** of the ___same symbol___\fP should be avoided. . .IP \[bu] +.BR "Footnotes (regular and inline)" . +Two-part regular footnotes can be added in a manner similar to links (see +.BR Links ). +Inline footnotes are also supported. +. +.RS +.IP \- 4 +.B Regular footnotes +have two mandatory parts: first, the footnote mark is represented by +\fC[^\f[CI]footnoteid\f[CR]]\fR, where +.I footnoteid +is the footnote identifier. Second, the text of the footnote is represented by +\fC[^\f[CI]footnoteid\f[CR]]: \f[CI]sometext\fR, with +.I sometext +being the text of the footnote. Footnote text construct needs to begin at the +start of a line, and it is the most practical to have it placed near the bottom +of the file, similar to normal links. +. +.IP "" +Combined, the input: +.CDS 8 +This is a text[^first]. + +[^first]: With a footnote! +.CDE +. +.IP "" 4 +gives (some lines are wrapped for this manual): +. +.CDS 8 +This is a text<a href="#footnote-1" id="footnote-text-1"> +<sup>1</sup></a>. + +</p> +<hr /> +<p id="footnote-1"><a href="#footnote-text-1">1.</a> +With a footnote! +</p> +.CDE +. +.IP \- 4 +.B Inline footnotes +can be added by using the construct \fC^[footnotetext]\fP. For example, input +. +.CDS 8 +Inline footnote^[Footnote text needs to fit on a line!] in a +paragraph. +.CDE +. +.IP "" +will produce +. +.CDS 8 +Inline footnote<a href="#inline-footnote-1" +id="inline-footnote-text-1"><sup>1</sup></a> in a +paragraph. +<hr /> +<p id="inline-footnote-1"><a href="#inline-footnote-text-1"> +1.</a> Footnote text needs to fit on a line!</p> +.CDE +.RE +. +.IP +The horizontal rule and the list of footnotes is printed only once, before the +end of +.SM HTML +document body. Rule and the list of footnotes can be surrounded by a div with +the \[lq]\fCfootnotes\fP\[rq] id by setting the +.SM YAML +variable +.I add-footnote-div +to \[lq]1\[rq] (see +.BR add-footnote-div ). +. +.IP +Inline and regular footnotes can be used at the same time, but they don't share +the numbering. This doesn't affect footnote link functionality, but it does +affect footnote presentation, as some footnote numbers will overlap. As a +result, whenever +.B slweb +encounters both footnote types in the same document, a warning will be issued to +.IR stderr . +. +.IP \[bu] .BR Headings . A line starting with \fC#\fP followed by space will be put inside \fC<h?></h?>\fP, where \fC?\fP stands for 1-4, depending on the number of @@ -135,6 +222,11 @@ Which will produce: .CDE . .IP +As with links, a form similar to the \[lq]regular form\[rq] of links can also be +used, using the image id instead of the direct +.SM URL. +. +.IP If the additional link is not desirable, it can be turned off by setting .B add-image-links to \[lq]0\[rq]. @@ -151,10 +243,14 @@ Two spaces followed by a newline will become \fC<br />\fP. . .IP \[bu] .BR Links . +. +.RS +.IP \- 4 +.BR "Inline links" . The construct \fC[A link](https://example.com)\fP will be converted into \fC<a href="https://example.com">A link</a>\fP. . -.IP +.IP "" Special case is the form \fC[=somemacro Link title](https://anything)\fP which prepends the body of a macro .I somemacro @@ -166,13 +262,13 @@ into the \fC<a></a>\fP tag (here broken into multiple lines for clarity): Link title</a> .CDE . -.IP +.IP "" 4 This can, for example, be used to add .SM SVG icons to links. See .BR Macros . . -.IP +.IP "" 4 Also, the form \fC[(Link title)](http://asite.com)\fP will surround the link title (text between \fC<a></a>\fP tags) with \fC<span></span>\fP, like so: . @@ -199,7 +295,39 @@ outside of the \fC<span></span>\fP: <span>Link title</span></a> .CDE . -.IP \[bu] +.IP \- +.BR "Regular links" . +Everything said about the inline links applies to regular links, with the +exception that instead of the parenthesized +.SM URL, +link text inside brackets will be followed by link id (different than the +\[lq]\fCid\fP\[rq] +.IR attribute! ) +inside brackets, and a +separate definition of that link id is needed, usually near the end of input. +. +.IP +For example: +. +.CDS 8 +Here's a link to [my website][mysite]. + +[mysite]: https://mysite.com +.CDE +. +.IP +will produce: +. +.CDS 8 +<p>Here's a link to <a href="https://mysite.com">my +website</a>.</p> +.CDE +. +.IP +This can help reduce the amount of code in the text of the page. +.RE +. +.IP \[bu] 4 .BR Lists . Lines starting with a dash (\fC\-\fP) will start an unordered list (if used for the first time) and start a list item. Input: @@ -257,7 +385,8 @@ will produce: . .IP \[bu] 4 .BR Paragraphs . -Text surrounded by newlines will be put inside \fC<p></p>\fP tags. +Text surrounded by newlines will be put inside \fC<p></p>\fP tags. See +.SM "KNOWN LIMITATIONS." . .SS Directives . @@ -445,6 +574,12 @@ about the current commit would be impossible). .SS Special YAML variables . .IP \[bu] 4 +.BR add-footnote-div . +If set to \[lq]1\[rq], list of footnotes preceded by a horizontal rule will be +surrounded with a div having the id \[lq]\fCfootnotes\fP\[rq] (see +.BR Footnotes ). +. +.IP \[bu] .BR add-image-links . If set to \[lq]0\[rq], links around images will not be added (otherwise they will by default, see @@ -527,7 +662,7 @@ tags. The contents of this variable will be treated as a .SM CSS file name to be included using the \fC<link rel="stylesheet" />\fP tag. You can -have more than one +add more than one .I stylesheet declaration per .I .slw diff --git a/slweb.c b/slweb.c @@ -1497,11 +1497,14 @@ end_head_start_body(FILE* output) } int -end_footnotes(FILE* output) +end_footnotes(FILE* output, BOOL add_footnote_div) { size_t footnote = 0; - print_output(output, "<div class=\"footnotes\">\n<hr />\n"); + if (add_footnote_div) + print_output(output, "<div class=\"footnotes\">\n"); + + print_output(output, "<hr />\n"); for (footnote = 0; footnote < inline_footnote_count; footnote++) print_output(output, "<p id=\"inline-footnote-%d\">" @@ -1521,7 +1524,9 @@ end_footnotes(FILE* output) footnote++; } - print_output(output, "</div><!--footnotes-->\n"); + if (add_footnote_div) + print_output(output, "</div><!--footnotes-->\n"); + return 0; } @@ -1541,7 +1546,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, uint8_t* date = NULL; uint8_t* permalink_url = NULL; uint8_t* ext_in_permalink = NULL; - uint8_t* add_image_links = NULL; + uint8_t* var_add_image_links = NULL; + uint8_t* var_add_footnote_div = NULL; uint8_t* pbuffer = NULL; uint8_t* line = NULL; uint8_t* pline = NULL; @@ -1558,7 +1564,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, BOOL skip_eol = FALSE; BOOL previous_line_blank = FALSE; BOOL processed_start_of_line = FALSE; - BOOL add_links = TRUE; + BOOL add_image_links = TRUE; + BOOL add_footnote_div = FALSE; BOOL list_para = FALSE; size_t pline_len = 0; @@ -1580,8 +1587,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, date = get_value(vars, vars_count, (uint8_t*)"date", NULL); permalink_url = get_value(vars, vars_count, (uint8_t*)"permalink-url", NULL); ext_in_permalink = get_value(vars, vars_count, (uint8_t*)"ext-in-permalink", NULL); - add_image_links = get_value(vars, vars_count, (uint8_t*)"add-image-links", NULL); - add_links = !(add_image_links && *add_image_links == '0'); + var_add_image_links = get_value(vars, vars_count, (uint8_t*)"add-image-links", NULL); + add_image_links = !(var_add_image_links && *var_add_image_links == '0'); + var_add_footnote_div = get_value(vars, vars_count, (uint8_t*)"add-footnote-div", NULL); + add_footnote_div = var_add_footnote_div && *var_add_footnote_div == '1'; CALLOC(line, uint8_t, BUFSIZE) CALLOC(token, uint8_t, BUFSIZE) @@ -1773,8 +1782,9 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, } else if (!(state & (ST_PRE | ST_TAG | ST_YAML))) { - /* Handle ` within headings and link text specially */ - if (state & (ST_HEADING | ST_LINK)) + /* Handle ` within footnotes, headings and link text specially */ + if (state & (ST_INLINE_FOOTNOTE | ST_HEADING + | ST_FOOTNOTE_TEXT | ST_LINK)) { uint8_t* tag = state & ST_CODE ? (uint8_t*)"</code>" @@ -1842,8 +1852,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; case '_': - if (read_yaml_macros_and_links - || state & (ST_CODE | ST_HTML_TAG + if (state & (ST_CODE | ST_HTML_TAG | ST_MACRO_BODY | ST_PRE | ST_TAG | ST_YAML)) { *ptoken++ = *pline++; @@ -1853,8 +1862,9 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, if (u8_strlen(pline) > 1 && *(pline+1) == '_') { - /* Handle __ within headings and link text specially */ - if (state & (ST_HEADING | ST_LINK)) + /* Handle __ within footnotes, headings and link text specially */ + if (state & (ST_INLINE_FOOTNOTE | ST_HEADING + | ST_FOOTNOTE_TEXT | ST_LINK)) { uint8_t* tag = state & ST_BOLD ? (uint8_t*)"</strong>" @@ -1892,8 +1902,9 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, } else { - /* Handle _ within headings and link text specially */ - if (state & (ST_HEADING | ST_LINK)) + /* Handle _ within footnotes, headings and link text specially */ + if (state & (ST_INLINE_FOOTNOTE | ST_HEADING + | ST_FOOTNOTE_TEXT | ST_LINK)) { uint8_t* tag = state & ST_ITALIC ? (uint8_t*)"</em>" @@ -1932,8 +1943,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; case '*': - if (read_yaml_macros_and_links - || state & (ST_CODE | ST_HTML_TAG + if (state & (ST_CODE | ST_HTML_TAG | ST_MACRO_BODY | ST_PRE | ST_YAML)) { *ptoken++ = *pline++; @@ -1950,8 +1960,9 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, } else if (pline_len > 1 && *(pline+1) == '*') { - /* Handle ** within headings and link text specially */ - if (state & (ST_HEADING | ST_LINK)) + /* Handle ** within footnotes, headings and link text specially */ + if (state & (ST_INLINE_FOOTNOTE | ST_HEADING + | ST_FOOTNOTE_TEXT | ST_LINK)) { uint8_t* tag = state & ST_BOLD ? (uint8_t*)"</strong>" @@ -1989,8 +2000,10 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, } else { - /* Handle * within headings and link text specially */ - if (state & (ST_HEADING | ST_LINK)) + /* Handle * within footnotes, headings and link text specially */ + if (state & (ST_INLINE_FOOTNOTE | ST_HEADING + | ST_FOOTNOTE_TEXT | ST_LINK)) + { uint8_t* tag = state & ST_ITALIC ? (uint8_t*)"</em>" @@ -2185,9 +2198,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; case '|': - if (read_yaml_macros_and_links - || (state & (ST_CODE | ST_HTML_TAG - | ST_PRE | ST_TAG | ST_YAML))) + if (state & (ST_CODE | ST_HTML_TAG + | ST_PRE | ST_TAG | ST_YAML)) { *ptoken++ = *pline++; colno++; @@ -2196,8 +2208,9 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, if (u8_strlen(pline) > 1 && *(pline+1) == '|') { - /* Handle || within headings and link text specially */ - if (state & (ST_HEADING | ST_LINK)) + /* Handle || within footnotes, headings and link text specially */ + if (state & (ST_INLINE_FOOTNOTE | ST_HEADING + | ST_FOOTNOTE_TEXT | ST_LINK)) { uint8_t* tag = state & ST_KBD ? (uint8_t*)"</kbd>" @@ -2301,7 +2314,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; case '!': - if (state & (ST_CODE | ST_HEADING | ST_LINK | ST_MACRO_BODY + if (state & (ST_CODE | ST_FOOTNOTE_TEXT | ST_HEADING + | ST_INLINE_FOOTNOTE | ST_LINK | ST_MACRO_BODY | ST_PRE)) { *ptoken++ = *pline++; @@ -2309,15 +2323,19 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; } - /* Output existing text up to ! */ - *ptoken = 0; - if (!read_yaml_macros_and_links) - print_output(output, "%s", token); - *token = 0; - ptoken = token; - if (u8_strlen(pline) > 1 && *(pline+1) == '[') { + /* Output existing text up to ! */ + *ptoken = 0; + process_text_token(line, first_line_in_doc, + previous_line_blank, processed_start_of_line, + read_yaml_macros_and_links, list_para, output, + &token, &ptoken, FALSE); + processed_start_of_line = TRUE; + + *token = 0; + ptoken = token; + state |= ST_IMAGE; pline += 2; colno += 2; @@ -2354,8 +2372,16 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, case '[': pline_len = u8_strlen(pline); + if (state & (ST_CODE | ST_HEADING | ST_MACRO_BODY | ST_PRE)) + { + *ptoken++ = *pline++; + colno++; + break; + } + if (pline_len > 1 && *(pline+1) == '^') { + /* Output existing text up to [^ */ *ptoken = 0; process_text_token(line, first_line_in_doc, previous_line_blank, processed_start_of_line, @@ -2371,13 +2397,6 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; } - if (state & (ST_CODE | ST_HEADING | ST_MACRO_BODY | ST_PRE)) - { - *ptoken++ = *pline++; - colno++; - break; - } - if (*token) /* Output existing text up to [ */ process_text_token(line, first_line_in_doc, @@ -2398,7 +2417,8 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; case '(': - if (state & (ST_CODE | ST_HEADING | ST_MACRO_BODY | ST_PRE)) + if (state & (ST_CODE | ST_FOOTNOTE_TEXT | ST_HEADING + | ST_INLINE_FOOTNOTE | ST_MACRO_BODY | ST_PRE)) *ptoken++ = *pline; else if (state & ST_LINK) { @@ -2456,7 +2476,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, token, output); else process_inline_image(link_text, token, output, - add_links); + add_image_links); } *token = 0; ptoken = token; @@ -2527,7 +2547,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, else if (state & ST_IMAGE_SECOND_ARG) { if (!read_yaml_macros_and_links) - process_image(link_text, token, output, add_links); + process_image(link_text, token, output, add_image_links); *token = 0; ptoken = token; state &= ~(ST_IMAGE | ST_IMAGE_SECOND_ARG); @@ -2600,19 +2620,29 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, break; case '^': - if (u8_strlen(pline) > 1 && *(pline+1) == '[') + if (state & (ST_CODE | ST_FOOTNOTE_TEXT | ST_INLINE_FOOTNOTE + | ST_PRE | ST_YAML)) { - state |= ST_INLINE_FOOTNOTE; - pline += 2; - colno += 2; + *ptoken++ = *pline++; + colno++; break; } - if (read_yaml_macros_and_links - || state & (ST_CODE | ST_PRE | ST_YAML)) + if (u8_strlen(pline) > 1 && *(pline+1) == '[') { - *ptoken++ = *pline++; - colno++; + /* Output existing text up to ^[ */ + *ptoken = 0; + process_text_token(line, first_line_in_doc, + previous_line_blank, processed_start_of_line, + read_yaml_macros_and_links, list_para, output, + &token, &ptoken, FALSE); + processed_start_of_line = TRUE; + + *token = 0; + ptoken = token; + state |= ST_INLINE_FOOTNOTE; + pline += 2; + colno += 2; break; } @@ -2834,7 +2864,7 @@ slweb_parse(uint8_t* buffer, FILE* output, BOOL body_only, if (!read_yaml_macros_and_links && (footnote_count > 0 || inline_footnote_count > 0)) - end_footnotes(output); + end_footnotes(output, add_footnote_div); if (!read_yaml_macros_and_links && !body_only) end_body_and_html(output);