From 5c782cda95427e7170bab7a9d7eef19c7c2d12d0 Mon Sep 17 00:00:00 2001
From: Zandr Martin <git@zandr.me>
Date: Tue, 13 Aug 2019 07:49:18 -0400
Subject: [PATCH] fix bug preventing indented literal blocks

This commit fixes a bug in parsing indented literal blocks. For example:

test(8)

	```
	This is a block
	```

Prior to this commit, this would fail, but with an unexpected error
message: "Error at 4:3: Cannot deindent in literal block". The
indentation was being parsed at every character, so the parser saw the
`T`, then parsed indentation again. The indentation was 0 (since there
were no tab characters between the `T` and the `h`), but the block
started with an indentation level of 1. 0 < 1, so this would be
considered a dedent, which is not allowed.

This commit introduces a new local variable, `check_indent`, which
controls whether the parser tries to parse indentation or not; now
indentation is only parsed when the last character was a newline. From
my testing this seems to fix the issue - indented literal blocks are now
allowed.

---
 src/main.c  | 23 +++++++++++++++--------
 test/indent | 21 +++++++++++++++++++++

diff --git a/src/main.c b/src/main.c
index 72b7eaff0eb5dc5fd67847745627e1d7cb3c506a..cf142880ec779524557e74b5053d51cdcea7d07a 100644
--- a/src/main.c
+++ b/src/main.c
@@ -374,15 +374,19 @@ 	}
 	int stops = 0;
 	roff_macro(p, "nf", NULL);
 	fprintf(p->output, ".RS 4\n");
+	bool check_indent = true;
 	do {
-		int _indent = *indent;
-		parse_indent(p, &_indent, false);
-		if (_indent < *indent) {
-			parser_fatal(p, "Cannot deindent in literal block");
-		}
-		while (_indent > *indent) {
-			--_indent;
-			fprintf(p->output, "\t");
+		if (check_indent) {
+			int _indent = *indent;
+			parse_indent(p, &_indent, false);
+			if (_indent < *indent) {
+				parser_fatal(p, "Cannot deindent in literal block");
+			}
+			while (_indent > *indent) {
+				--_indent;
+				fprintf(p->output, "\t");
+			}
+			check_indent = false;
 		}
 		if ((ch = parser_getch(p)) == UTF8_INVALID) {
 			break;
@@ -415,6 +419,9 @@ 				} else {
 					utf8_fputch(p->output, ch);
 				}
 				break;
+			case '\n':
+				check_indent = true;
+				/* fallthrough */
 			default:
 				utf8_fputch(p->output, ch);
 				break;
diff --git a/test/indent b/test/indent
index 9ea38e1168d9bd001fcb5231863ca7639981331d..6ce4892537155e547669cf5bf019ecc5f5d143c3 100755
--- a/test/indent
+++ b/test/indent
@@ -54,3 +54,24 @@ 		Indented two levels
 Not indented
 EOF
 end 0
+
+begin "Allows indented literal blocks"
+scdoc <<EOF >/dev/null
+test(8)
+
+	\`\`\`
+	This block is indented.
+	\`\`\`
+EOF
+end 0
+
+begin "Disallows dedenting in literal blocks"
+scdoc <<EOF >/dev/null
+test(8)
+
+		\`\`\`
+		This block is indented.
+	This line is dedented past the start of the block.
+		\`\`\`
+EOF
+end 1

-- 
2.48.1