Implement lists

master
Drew DeVault 7 years ago
parent 10e1cf68bc
commit a4c7cc6187
  1. 57
      scdoc.1.scd
  2. 76
      src/main.c

@ -1,17 +1,24 @@
scdoc(5) scdoc(1)
# NAME # NAME
scdoc - syntax description for scdoc markup language scdoc - tool for generating *roff*(7) manual pages
# SYNOPSIS
*scdoc* < _input_ > _output_
# DESCRIPTION # DESCRIPTION
scdoc is a tool designed to make the process of writing man pages more 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 friendly. It reads scdoc syntax from stdin and writes roff to stdout, suitable
to man pages or a number of other formats. The syntax is inspired by, but not for reading with *man*(1).
directly taken from, markdown. Input files *must* use the UTF-8 encoding.
# SYNTAX
Input files must use the UTF-8 encoding.
# PREAMBLE ## PREAMBLE
Each scdoc file must begin with the following 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 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 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 Each section of your man page should begin with something similar to the
following: following:
@ -30,39 +37,47 @@ following:
Subsection headers are also understood - use two hashes. Each header must have Subsection headers are also understood - use two hashes. Each header must have
an empty line on either side. an empty line on either side.
# PARAGRAPHS ## PARAGRAPHS
Begin a new paragraph with an empty line. Begin a new paragraph with an empty line.
# FORMATTING ## FORMATTING
Text can be made *bold* or _underlined_ with asterisks and underscores: \*bold\* Text can be made *bold* or _underlined_ with asterisks and underscores: \*bold\*
or \_underlined\_. or \_underlined\_.
# INDENTATION ## INDENTATION
You may indent lines with tab characters (*\\t*) to indent them by 4 spaces in You may indent lines with tab characters (*\\t*) to indent them by 4 spaces in
the output. Indented lines may not contain headers. 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: You may start bulleted lists with dashes, like so:
``` ```
- Item 1 - Item 1
- Item 2 - Item 2
- Subitem 1
- Subitem 2
- Item 3 - Item 3
``` ```
You may also use numbered lists like so: The result looks like this:
``` - Item 1
1. Item 1 - Item 2
2. Item 2 - Subitem 1
3. Item 3 - Subitem 2
``` - Item 3
# LITERAL TEXT ## LITERAL TEXT
You may turn off scdoc formatting and output literal text with escape codes and 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 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 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 literally in the man viewer - that is, it's not a means for inserting your own
roff macros into the output. 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.

@ -1,5 +1,6 @@
#include <assert.h> #include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <time.h> #include <time.h>
@ -97,6 +98,9 @@ static void parse_text(struct parser *p) {
case '_': case '_':
parse_format(p, FORMAT_UNDERLINE); parse_format(p, FORMAT_UNDERLINE);
break; break;
case '\n':
utf8_fputch(p->output, ch);
return;
case '.': case '.':
if (!i) { if (!i) {
// Escape . if it's the first character // Escape . if it's the first character
@ -108,9 +112,6 @@ static void parse_text(struct parser *p) {
utf8_fputch(p->output, ch); utf8_fputch(p->output, ch);
break; break;
} }
if (ch == '\n') {
break;
}
++i; ++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; int i = 0;
uint32_t ch; uint32_t ch;
while ((ch = parser_getch(p)) == '\t') { while ((ch = parser_getch(p)) == '\t') {
++i; ++i;
} }
parser_pushch(p, ch); 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; return i;
} }
static void parse_document(struct parser *p) { static void parse_list(struct parser *p, int *indent) {
uint32_t ch; 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 { do {
int i = parse_indent(p); parse_indent(p, indent);
if (i == indent - 1) { if ((ch = parser_getch(p)) == UTF8_INVALID) {
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) {
break; break;
} }
switch (ch) {
if (indent != 0) { case ' ':
// Only text is allowed at this point break;
parser_pushch(p, ch); 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); 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) { switch (ch) {
case '#': case '#':
if (indent != 0) {
parser_pushch(p, ch);
parse_text(p);
break;
}
parse_heading(p); parse_heading(p);
break; break;
case '-':
parse_list(p, &indent);
break;
case ' ': case ' ':
parser_fatal(p, "Tabs are required for indentation"); parser_fatal(p, "Tabs are required for indentation");
break; break;

Loading…
Cancel
Save