From a4c7cc6187134c6d916b72d02c2f21b65a31aece Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Sun, 10 Dec 2017 00:24:56 -0500 Subject: [PATCH] Implement lists --- scdoc.5.scd => scdoc.1.scd | 57 +++++++++++++++++++--------- src/main.c | 76 ++++++++++++++++++++++++++------------ 2 files changed, 92 insertions(+), 41 deletions(-) rename scdoc.5.scd => scdoc.1.scd (65%) diff --git a/scdoc.5.scd b/scdoc.1.scd similarity index 65% rename from scdoc.5.scd rename to scdoc.1.scd index db5cf1d..556c326 100644 --- a/scdoc.5.scd +++ b/scdoc.1.scd @@ -1,17 +1,24 @@ -scdoc(5) +scdoc(1) # NAME -scdoc - syntax description for scdoc markup language +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 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. +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 +## PREAMBLE Each scdoc file must begin with the following preamble: @@ -20,7 +27,7 @@ Each scdoc file must begin with the following preamble: 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 +## SECTION HEADERS Each section of your man page should begin with something similar to the following: @@ -30,39 +37,47 @@ following: Subsection headers are also understood - use two hashes. Each header must have an empty line on either side. -# PARAGRAPHS +## PARAGRAPHS Begin a new paragraph with an empty line. -# FORMATTING +## FORMATTING Text can be made *bold* or _underlined_ with asterisks and underscores: \*bold\* or \_underlined\_. -# INDENTATION +## 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 + 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 ``` -You may also use numbered lists like so: +The result looks like this: -``` -1. Item 1 -2. Item 2 -3. Item 3 -``` +- Item 1 +- Item 2 + - Subitem 1 + - Subitem 2 +- Item 3 -# LITERAL TEXT +## 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 @@ -78,3 +93,9 @@ _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 . 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/src/main.c b/src/main.c index 35352cd..6df52a7 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -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;