commit a4c7cc6187134c6d916b72d02c2f21b65a31aece
parent 10e1cf68bc6d451ef957c3008d9879655f4e1c63
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 10 Dec 2017 00:24:56 -0500
Implement lists
Diffstat:
A | scdoc.1.scd | | | 101 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | scdoc.5.scd | | | 80 | ------------------------------------------------------------------------------- |
M | src/main.c | | | 76 | +++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
3 files changed, 154 insertions(+), 103 deletions(-)
diff --git a/scdoc.1.scd b/scdoc.1.scd
@@ -0,0 +1,101 @@
+scdoc(1)
+
+# NAME
+
+scdoc - tool for generating *roff*(7) manual pages
+
+# SYNOPSIS
+
+*scdoc* < _input_ > _output_
+
+# DESCRIPTION
+
+scdoc is a tool designed to make the process of writing man pages more
+friendly. It reads scdoc syntax from stdin and writes roff to stdout, suitable
+for reading with *man*(1).
+
+# SYNTAX
+
+Input files must use the UTF-8 encoding.
+
+## PREAMBLE
+
+Each scdoc file must begin with the following preamble:
+
+ *name*(_section_)
+
+The *name* is the name of the man page you are writing, and _section_ is the
+section you're writing for (see *man*(1) for information on manual sections).
+
+## SECTION HEADERS
+
+Each section of your man page should begin with something similar to the
+following:
+
+ # HEADER NAME
+
+Subsection headers are also understood - use two hashes. Each header must have
+an empty line on either side.
+
+## PARAGRAPHS
+
+Begin a new paragraph with an empty line.
+
+## FORMATTING
+
+Text can be made *bold* or _underlined_ with asterisks and underscores: \*bold\*
+or \_underlined\_.
+
+## INDENTATION
+
+You may indent lines with tab characters (*\\t*) to indent them by 4 spaces in
+the output. Indented lines may not contain headers.
+
+ The result looks something like this.
+
+ You may use multiple lines and most _formatting_.
+
+Deindent to return to normal.
+
+## LISTS
+
+You may start bulleted lists with dashes, like so:
+
+```
+- Item 1
+- Item 2
+ - Subitem 1
+ - Subitem 2
+- Item 3
+```
+
+The result looks like this:
+
+- Item 1
+- Item 2
+ - Subitem 1
+ - Subitem 2
+- Item 3
+
+## LITERAL TEXT
+
+You may turn off scdoc formatting and output literal text with escape codes and
+literal blocks. Inserting a \\ into your source will cause the subsequent symbol
+to be treated as a literal and copied directly to the output. You may also make
+blocks of literal syntax like so:
+
+```
+\`\`\`
+_This formatting_ will *not* be interpreted by scdoc.
+\`\`\`
+```
+
+These blocks will be indented one level. Note that literal text is shown
+literally in the man viewer - that is, it's not a means for inserting your own
+roff macros into the output.
+
+# AUTHORS
+
+Maintained by Drew DeVault <sir@cmpwn.com>. Up-to-date sources can be found at
+https://git.sr.ht/~sircmpwn/scdoc and bugs/patches can be submitted by email to
+sir@cmpwn.com.
diff --git a/scdoc.5.scd b/scdoc.5.scd
@@ -1,80 +0,0 @@
-scdoc(5)
-
-# NAME
-
-scdoc - syntax description for scdoc markup language
-
-# DESCRIPTION
-
-scdoc is a tool designed to make the process of writing man pages more
-friendly. It converts scdoc files into roff macros, which can then be converted
-to man pages or a number of other formats. The syntax is inspired by, but not
-directly taken from, markdown. Input files *must* use the UTF-8 encoding.
-
-# PREAMBLE
-
-Each scdoc file must begin with the following preamble:
-
- *name*(_section_)
-
-The *name* is the name of the man page you are writing, and _section_ is the
-section you're writing for (see *man*(1) for information on manual sections).
-
-# SECTION HEADERS
-
-Each section of your man page should begin with something similar to the
-following:
-
- # HEADER NAME
-
-Subsection headers are also understood - use two hashes. Each header must have
-an empty line on either side.
-
-# PARAGRAPHS
-
-Begin a new paragraph with an empty line.
-
-# FORMATTING
-
-Text can be made *bold* or _underlined_ with asterisks and underscores: \*bold\*
-or \_underlined\_.
-
-# INDENTATION
-
-You may indent lines with tab characters (*\\t*) to indent them by 4 spaces in
-the output. Indented lines may not contain headers.
-
-# LISTS
-
-You may start bulleted lists with dashes, like so:
-
-```
-- Item 1
-- Item 2
-- Item 3
-```
-
-You may also use numbered lists like so:
-
-```
-1. Item 1
-2. Item 2
-3. Item 3
-```
-
-# LITERAL TEXT
-
-You may turn off scdoc formatting and output literal text with escape codes and
-literal blocks. Inserting a \\ into your source will cause the subsequent symbol
-to be treated as a literal and copied directly to the output. You may also make
-blocks of literal syntax like so:
-
-```
-\`\`\`
-_This formatting_ will *not* be interpreted by scdoc.
-\`\`\`
-```
-
-These blocks will be indented one level. Note that literal text is shown
-literally in the man viewer - that is, it's not a means for inserting your own
-roff macros into the output.
diff --git a/src/main.c b/src/main.c
@@ -1,5 +1,6 @@
#include <assert.h>
#include <ctype.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
@@ -97,6 +98,9 @@ static void parse_text(struct parser *p) {
case '_':
parse_format(p, FORMAT_UNDERLINE);
break;
+ case '\n':
+ utf8_fputch(p->output, ch);
+ return;
case '.':
if (!i) {
// Escape . if it's the first character
@@ -108,9 +112,6 @@ static void parse_text(struct parser *p) {
utf8_fputch(p->output, ch);
break;
}
- if (ch == '\n') {
- break;
- }
++i;
}
}
@@ -146,46 +147,75 @@ static void parse_heading(struct parser *p) {
}
}
-static int parse_indent(struct parser *p) {
+static int parse_indent(struct parser *p, int *indent) {
int i = 0;
uint32_t ch;
while ((ch = parser_getch(p)) == '\t') {
++i;
}
parser_pushch(p, ch);
+ if (i == *indent - 1) {
+ roff_macro(p, "RE", NULL);
+ } else if (i == *indent + 1) {
+ roff_macro(p, "RS", "4", NULL);
+ } else if (i != *indent && ch == '\t') {
+ parser_fatal(p, "(De)indented by an amount greater than 1");
+ }
+ *indent = i;
return i;
}
-static void parse_document(struct parser *p) {
+static void parse_list(struct parser *p, int *indent) {
uint32_t ch;
- int indent = 0;
+ if ((ch = parser_getch(p)) != ' ') {
+ parser_fatal(p, "Expected space before start of list entry");
+ }
+ roff_macro(p, "IP", "\\(bu", "4", NULL);
+ parse_text(p);
do {
- int i = parse_indent(p);
- if (i == indent - 1) {
- roff_macro(p, "RE", NULL);
- } else if (i == indent + 1) {
- roff_macro(p, "RS", "4", NULL);
- } else if (i != indent && ch == '\t') {
- parser_fatal(p, "(De)indented by an amount greater than 1");
- }
- indent = i;
-
- ch = parser_getch(p);
- if (ch == UTF8_INVALID) {
+ parse_indent(p, indent);
+ if ((ch = parser_getch(p)) == UTF8_INVALID) {
break;
}
-
- if (indent != 0) {
- // Only text is allowed at this point
- parser_pushch(p, ch);
+ switch (ch) {
+ case ' ':
+ break;
+ case '-':
+ if ((ch = parser_getch(p)) != ' ') {
+ parser_fatal(p, "Expected space before start of list entry");
+ }
+ fprintf(p->output, ".sp -1\n");
+ roff_macro(p, "IP", "\\(bu", "4", NULL);
parse_text(p);
- continue;
+ break;
+ default:
+ fprintf(p->output, "\n");
+ parser_pushch(p, ch);
+ return;
}
+ } while (ch != UTF8_INVALID);
+}
+static void parse_document(struct parser *p) {
+ uint32_t ch;
+ int indent = 0;
+ do {
+ parse_indent(p, &indent);
+ if ((ch = parser_getch(p)) == UTF8_INVALID) {
+ break;
+ }
switch (ch) {
case '#':
+ if (indent != 0) {
+ parser_pushch(p, ch);
+ parse_text(p);
+ break;
+ }
parse_heading(p);
break;
+ case '-':
+ parse_list(p, &indent);
+ break;
case ' ':
parser_fatal(p, "Tabs are required for indentation");
break;