чување 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:
измењених датотека: 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 <<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<\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<\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);