commit 1195ac84d2ddf64b9e43823f77d490ce5ff1fee2
parent c2c7d3b78ae84014787012a6ca78ff722de4c8e0
Author: Umar Getagazov <umar@handlerug.me>
Date: Fri, 25 Mar 2022 22:30:47 +0700
haredoc: multi-line lists, references in lists
This commit adds the following:
- Support for rendering multi-line list items in HTML. To make a
multi-line list item, write it just like this one.
- You can also write multi-line lists without spaces in the beginning,
like you'd wrap a normal paragraph. All references inside list items
are now parsed too.
- If you're wrapping a paragraph that has a hyphen at the wrapping point
- prefix it with whitespace.
Signed-off-by: Umar Getagazov <umar@handlerug.me>
Diffstat:
2 files changed, 51 insertions(+), 25 deletions(-)
diff --git a/cmd/haredoc/docstr.ha b/cmd/haredoc/docstr.ha
@@ -3,6 +3,7 @@
// (c) 2021 Drew DeVault <sir@cmpwn.com>
// (c) 2021 Eyal Sawady <ecs@d2evs.net>
// (c) 2021 Thomas Bracht Laumann Jespersen <t@laumann.xyz>
+// (c) 2022 Umar Getagazov <umar@handlerug.me>
use ascii;
use bufio;
use encoding::utf8;
@@ -17,12 +18,13 @@ type paragraph = void;
type text = str;
type reference = ast::ident;
type sample = str;
-type list = []str;
-type token = (paragraph | text | reference | sample | list);
+type listitem = void;
+type token = (paragraph | text | reference | sample | listitem);
type docstate = enum {
PARAGRAPH,
TEXT,
+ LIST,
};
type parser = struct {
@@ -55,6 +57,15 @@ fn scandoc(par: *parser) (token | void) = {
case =>
return scantext(par);
};
+ case docstate::LIST =>
+ switch (rn) {
+ case '[' =>
+ return scanref(par);
+ case '-' =>
+ return scanlist(par);
+ case =>
+ return scantext(par);
+ };
case docstate::PARAGRAPH =>
switch (rn) {
case ' ', '\t' =>
@@ -98,6 +109,9 @@ fn scantext(par: *parser) (token | void) = {
break;
};
bufio::unreadrune(&par.src, rn);
+ if (par.state == docstate::LIST) {
+ break;
+ };
case =>
strio::appendrune(&buf, rn)!;
};
@@ -219,21 +233,22 @@ fn scansample(par: *parser) (token | void) = {
};
fn scanlist(par: *parser) (token | void) = {
- let items: list = [];
- for (true) {
- match (bufio::scanrune(&par.src)!) {
- case io::EOF => break;
- case let rn: rune =>
- if (rn != '-') {
- break;
- };
+ match (bufio::scanrune(&par.src)!) {
+ case io::EOF => return void;
+ case let rn: rune =>
+ if (rn != '-') {
+ abort();
};
- // XXX: multi-line list items
- append(items, match (bufio::scanline(&par.src)!) {
- case io::EOF => break;
- case let u: []u8 =>
- yield strings::fromutf8(u);
- });
};
- return items;
+ const rn = match (bufio::scanrune(&par.src)!) {
+ case io::EOF => return void;
+ case let rn: rune =>
+ yield rn;
+ };
+ if (rn != ' ') {
+ bufio::unreadrune(&par.src, rn);
+ return strings::dup("-"): text;
+ };
+ par.state = docstate::LIST;
+ return listitem;
};
diff --git a/cmd/haredoc/html.ha b/cmd/haredoc/html.ha
@@ -345,14 +345,23 @@ fn htmlref(ctx: *context, ref: ast::ident) (void | io::error) = {
fn markup_html(ctx: *context, in: io::handle) (void | io::error) = {
let parser = parsedoc(in);
+ let waslist = false;
for (true) {
const tok = match (scandoc(&parser)) {
- case void => break;
+ case void =>
+ if (waslist) {
+ fmt::fprintln(ctx.out, "</ul>")?;
+ };
+ break;
case let tok: token =>
yield tok;
};
match (tok) {
case paragraph =>
+ if (waslist) {
+ fmt::fprintln(ctx.out, "</ul>")?;
+ waslist = false;
+ };
fmt::fprintln(ctx.out)?;
fmt::fprint(ctx.out, "<p>")?;
case let tx: text =>
@@ -371,18 +380,20 @@ fn markup_html(ctx: *context, in: io::handle) (void | io::error) = {
case let re: reference =>
htmlref(ctx, re)?;
case let sa: sample =>
+ if (waslist) {
+ fmt::fprintln(ctx.out, "</ul>")?;
+ waslist = false;
+ };
fmt::fprint(ctx.out, "<pre class='sample'>")?;
html_escape(ctx.out, sa)?;
fmt::fprint(ctx.out, "</pre>")?;
free(sa);
- case let li: list =>
- fmt::fprintln(ctx.out, "<ul>")?;
- for (let i = 0z; i < len(li); i += 1) {
- fmt::fprintln(ctx.out, "<li>")?;
- html_escape(ctx.out, li[i])?;
- fmt::fprintln(ctx.out, "</li>")?;
+ case listitem =>
+ if (!waslist) {
+ fmt::fprintln(ctx.out, "<ul>")?;
+ waslist = true;
};
- fmt::fprintln(ctx.out, "</ul>")?;
+ fmt::fprint(ctx.out, "<li>")?;
};
};
fmt::fprintln(ctx.out)?;