From 32553f6b70a955e3718442cc9538fe3024c2beee Mon Sep 17 00:00:00 2001 From: GB609 <39741460+GB609@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:02:05 +0000 Subject: [PATCH 1/6] Handle md-style code fences --- shdoc | 52 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/shdoc b/shdoc index 3eb6d09..2970b51 100755 --- a/shdoc +++ b/shdoc @@ -724,20 +724,46 @@ function debug(msg) { } in_description { - if (/^[^[[:space:]]*#]|^[[:space:]]*# @[^d]|^[[:space:]]*[^#]|^[[:space:]]*$/) { - debug("→ → in_description: leave") - - in_description = 0 - - handle_description() - } else { - sub(/^[[:space:]]*# @description[[:space:]]*/, "") - sub(/^[[:space:]]*#[[:space:]]*/, "") - sub(/^[[:space:]]*#$/, "") - debug("→ → in_description: concat [" $0 "]") + switch($0) { + case /^[^[[:space:]]*#]|^[[:space:]]*# @[^d]|^[[:space:]]*[^#]|^[[:space:]]*$/: + debug("→ → in_description: leave") + in_description = 0 + handle_description() + break + + case /^[[:space:]]*#[[:space:]]+[~~~+|```+].*$/: + debug("→ → in_description: fenced block [" $0 "]") + match($0, /~~~+|```+/) + cur_fence = substr($0, RSTART, RLENGTH) + sub(/^[[:space:]]*# /, "") + description = concat(description, $0) + if (fenced_block == "") { + debug("→ → → start") + fenced_block = cur_fence + } else if (fenced_block == cur_fence) { + debug("→ → → end") + fenced_block = "" + } else { + debug("→ → → inner fence - ignore") + } + cur_fence = "" + next + break + + default: + sub(/^[[:space:]]*# @description[[:space:]]*/, "") + # only remove surplus spaces when not in a fenced block + if (fenced_block == "") { + sub(/^[[:space:]]*#[[:space:]]*/, "") + sub(/^[[:space:]]*#$/, "") + } else { + sub(/^[[:space:]]*# /, "") + } + debug("→ → in_description: concat [" $0 "]") - description = concat(description, $0) - next + description = concat(description, $0) + next + break } } From 3cad75111c23cb52f759bafe5856f917e284d450 Mon Sep 17 00:00:00 2001 From: GB609 <39741460+GB609@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:46:08 +0000 Subject: [PATCH 2/6] introduce literal blocks (no space trimming) --- shdoc | 62 ++++++++++++++++++++++------------------------------------- 1 file changed, 23 insertions(+), 39 deletions(-) diff --git a/shdoc b/shdoc index 2970b51..3f0e332 100755 --- a/shdoc +++ b/shdoc @@ -724,51 +724,35 @@ function debug(msg) { } in_description { - switch($0) { - case /^[^[[:space:]]*#]|^[[:space:]]*# @[^d]|^[[:space:]]*[^#]|^[[:space:]]*$/: - debug("→ → in_description: leave") - in_description = 0 - handle_description() - break - - case /^[[:space:]]*#[[:space:]]+[~~~+|```+].*$/: - debug("→ → in_description: fenced block [" $0 "]") - match($0, /~~~+|```+/) - cur_fence = substr($0, RSTART, RLENGTH) - sub(/^[[:space:]]*# /, "") - description = concat(description, $0) - if (fenced_block == "") { - debug("→ → → start") - fenced_block = cur_fence - } else if (fenced_block == cur_fence) { - debug("→ → → end") - fenced_block = "" - } else { - debug("→ → → inner fence - ignore") - } - cur_fence = "" - next - break - - default: - sub(/^[[:space:]]*# @description[[:space:]]*/, "") - # only remove surplus spaces when not in a fenced block - if (fenced_block == "") { - sub(/^[[:space:]]*#[[:space:]]*/, "") - sub(/^[[:space:]]*#$/, "") - } else { - sub(/^[[:space:]]*# /, "") - } - debug("→ → in_description: concat [" $0 "]") + if (/^[^[[:space:]]*#]|^[[:space:]]*# @[^d]|^[[:space:]]*[^#]|^[[:space:]]*$/) { + debug("→ → in_description: leave") + + in_description = 0 - description = concat(description, $0) - next - break + handle_description() + } else if (match($0, /^[[:space:]]*#\|/)) { + sub(/^[[:space:]]*#/, "") + if (match($0, /^\|.*\|[[:space:]]*$/)){ + debug("→ → in_description: table row [" $0 "] (ignore |)") + } else { + sub(/^\|/, "") + debug("→ → in_description: literal [" $0 "] (keep spaces)") + } + description = concat(description, $0) + next + } else { + sub(/^[[:space:]]*# @description[[:space:]]*/, "") + sub(/^[[:space:]]*#[[:space:]]*/, "") + sub(/^[[:space:]]*#$/, "") + debug("→ → in_description: concat [" $0 "]") + description = concat(description, $0) + next } } /^[[:space:]]*# @endsection/ { debug("→ @endsection") + process_section() section = "" section_description = "" section_active = 0 From 32200422c6a778e703b01c9436fc5c0bc657d4f1 Mon Sep 17 00:00:00 2001 From: GB609 <39741460+GB609@users.noreply.github.com> Date: Tue, 9 Dec 2025 13:49:34 +0000 Subject: [PATCH 3/6] Create md-literal-lines.test.sh --- tests/testcases/md-literal-lines.test.sh | 115 +++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 tests/testcases/md-literal-lines.test.sh diff --git a/tests/testcases/md-literal-lines.test.sh b/tests/testcases/md-literal-lines.test.sh new file mode 100644 index 0000000..a4246a7 --- /dev/null +++ b/tests/testcases/md-literal-lines.test.sh @@ -0,0 +1,115 @@ +#!/bin/bash + +tests:put input < Date: Tue, 9 Dec 2025 15:02:52 +0000 Subject: [PATCH 4/6] Update README.md --- README.md | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/README.md b/README.md index e136eee..b46cbda 100644 --- a/README.md +++ b/README.md @@ -477,6 +477,93 @@ show-msg() { ## Advanced features +### Literal md source + +By default, `shdoc` performs whitespace trimming at the start of a comment line while it builds description blocks. +This behavior disables the possibility to use formatting options like code blocks by indentation (4 spaces), or use +pre-formatted (and indented) text within fenced code blocks (`~~~` or ` ``` `). + +It is possible to disable the trimming behavior by using `#|` as comment prefix, instead of just `# ` (as for annotations). +`shdoc` will only consume the beginning of the line matching the regex `[ ]*#|` and leave the rest untouched. +**Exception:** There is a simple detection if the line contains a table row definition (when it also ends with `|[ ]*`). +In that case, only `[ ]*#` at the beginning will be consumed and the pipe will be left untouched. + +**Examples** + +- Simple + + + + + + + + + +
InputResult
+ +```bash +# @description Simple +#| This is kept literally... +#| ... this too +# me too... not. +``` + + + +```md +Simple + This is kept literally... + ... this too +me too... not. +``` + +
+ +- Tables +**Note:** In MD itself, there is little reason to indenting a table. Instead, indenting it too far would convert the table into a code block instead, +where the table source code is not processed as MD. +The literal md marker does not perform any extra checks to find out wether the pipe contained in `#|` is part of the table or not. The pipe character +connected to the comment hash will be stripped. As a consequence, writing tables requires a space between `#` and the left beginning `|` for regular +tables. Alternatively, if the table code should really be indented, 2 pipes must be used, with spaces in between. + + + + + + + + + + +
InputResult
+ +```bash +# @description Table +#| co1 | co2 | +# | abc | def | +#| | 123 | 456 | +#| | 123 | 456 | +``` + + + +```md +Table + co1 | co2 | +| abc | def | + | 123 | 456 | + | 123 | 456 | +``` + +
+ + +Takeaway: +1. If (for optical reasons only) you want to indent a table, don't use `#|`. +2. For regular tables, keep at least one space between `#` and `|` at the beginning of the line +3. Indenting table source requires `#|`, followed by the desired amount of spaces, then `|` to start the table row. + ### Parameter support **fork-specific** From 02631759dd44d961d1583ece52887dc748db3d42 Mon Sep 17 00:00:00 2001 From: GB609 <39741460+GB609@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:03:38 +0000 Subject: [PATCH 5/6] Update shdoc --- shdoc | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/shdoc b/shdoc index 3f0e332..762e63d 100755 --- a/shdoc +++ b/shdoc @@ -731,13 +731,8 @@ in_description { handle_description() } else if (match($0, /^[[:space:]]*#\|/)) { - sub(/^[[:space:]]*#/, "") - if (match($0, /^\|.*\|[[:space:]]*$/)){ - debug("→ → in_description: table row [" $0 "] (ignore |)") - } else { - sub(/^\|/, "") - debug("→ → in_description: literal [" $0 "] (keep spaces)") - } + debug("→ → in_description: literal [" $0 "] (keep spaces)") + sub(/^[[:space:]]*#\|/, "") description = concat(description, $0) next } else { From a10bcadc8a1099ad54adc4fbcb3162025558c47e Mon Sep 17 00:00:00 2001 From: GB609 <39741460+GB609@users.noreply.github.com> Date: Tue, 9 Dec 2025 15:05:11 +0000 Subject: [PATCH 6/6] Update md-literal-lines.test.sh --- tests/testcases/md-literal-lines.test.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/testcases/md-literal-lines.test.sh b/tests/testcases/md-literal-lines.test.sh index a4246a7..5bcf3b5 100644 --- a/tests/testcases/md-literal-lines.test.sh +++ b/tests/testcases/md-literal-lines.test.sh @@ -91,9 +91,9 @@ The literal marker '#|' has rudimentary detection for tables. the pipe from the literal marker `#|` will not be stripped. Table with slight indention -| | literal | table | -| | :---: | :---: | -| | keep? | yes | + | literal | table | + | :---: | :---: | + | keep? | yes | Indented, but not in literal mode | literal | table | @@ -101,15 +101,15 @@ Indented, but not in literal mode | keep? | yes | Directly at line start -|| literal | table | -|| :---: | :---: | -|| keep? | yes | - -Without duplicate left pipes | literal | table | | :---: | :---: | | keep? | yes | +Without duplicate left pipes + literal | table | + :---: | :---: | + keep? | yes | + EOF assert