# @example
# echo "test: $(say-hello World)"
#
+#
+# @option -h | --help Display help.
+# @option -v | --value= Set a value.
+#
# @arg $1 string A value to print
#
+# @stdout Output 'Hello $1'.
+# It hopes you say Hello back.
+# @stderr Output 'Oups !' on error.
+# It did it again.
+#
# @exitcode 0 If successful.
# @exitcode 1 If an empty string passed.
#
# @see validate()
+# @see [shdoc](https://github.com/reconquest/shdoc).
say-hello() {
if [[ ! "$1" ]]; then
+ echo "Oups !" >&2
return 1;
fi
@@ -92,6 +103,16 @@ Not thread-safe.
echo "test: $(say-hello World)"
```
+#### Options
+
+* **-h** | **--help**
+
+ Display help.
+
+* **-v\** | **--value=\**
+
+ Set a value.
+
#### Arguments
* **$1** (string): A value to print
@@ -101,9 +122,21 @@ echo "test: $(say-hello World)"
* **0**: If successful.
* **1**: If an empty string passed.
+#### Output on stdout
+
+* Output 'Hello $1'.
+ It hopes you say Hello back.
+
+#### Output on stderr
+
+* Output 'Oups !' on error.
+ It did it again.
+
#### See also
* [validate()](#validate)
+* [shdoc](https://github.com/reconquest/shdoc).
+
~~~
@@ -181,12 +214,31 @@ say-hello() {
}
```
+### `@option`
+
+A description of an option expected to be passed while calling the function.
+Can be specified multiple times to describe any number of arguments.
+If an option argument is expected, it must be specified between `<` and `>`
+
+**Example**
+
+```bash
+# @description Says hi to a given person.
+# @option -h A short option.
+# @arg --value= A long option with argument.
+# @arg -v | --value A long option with short option alternative.
+say-hello() {
+ ...
+}
+```
+
### `@arg`
A description of an argument expected to be passed while calling the function.
Can be specified multiple times to describe any number of arguments.
**Example**
+
```bash
# @description Says hi to a given person.
# @arg $1 string A person's name.
@@ -201,6 +253,7 @@ say-hello() {
A note that the function does not expect any arguments to be passed.
**Example**
+
```bash
# @description Says 'hello world'.
# @noargs
@@ -215,6 +268,7 @@ A description of a global variable that is set while calling the function.
Can be specified multiple times to describe any number of variables
**Example**
+
```bash
# @description Sets hello to the variable REPLY
# @set REPLY string Greeting message.
@@ -229,6 +283,7 @@ Describes an expected exitcode of the function.
Can be specified multiple times to describe all possible exitcodes and their conditions.
**Example**
+
```bash
# @description Says 'hello world'.
# @exitcode 0 If successful.
@@ -243,6 +298,7 @@ say-hello-world() {
The expected input to the function call from `stdin` (usually the terminal or command line)
**Example**
+
```bash
# @description Asks name.
# @stdin The users name from the terminal/command line.
@@ -256,6 +312,7 @@ say-hello-world() {
An expected output of the function call.
**Example**
+
```bash
# @description Says 'hello world'.
# @stdout A path to a temporary file with the message.
@@ -269,6 +326,7 @@ say-hello-world() {
An expected output of the function call on `/dev/stderr`.
**Example**
+
```bash
# @description Says 'hello world'.
# @stderr A error message when world is not available.
@@ -282,6 +340,7 @@ say-hello-world() {
Create a link on the given function in the "See Also" section.
**Example**
+
```bash
# @see say-hello
# @see text with [markdown link](./other-file#other-function)
@@ -298,6 +357,7 @@ It allows you to have the same style of doc comments across the script and keep
functions hidden from users.
**Example**
+
```bash
# @internal
show-msg() {
diff --git a/examples/readme-example.md b/examples/readme-example.md
index 397f015..3f41e0a 100644
--- a/examples/readme-example.md
+++ b/examples/readme-example.md
@@ -25,6 +25,16 @@ Not thread-safe.
echo "test: $(say-hello World)"
```
+#### Options
+
+* **-h** | **--help**
+
+ Display help.
+
+* **-v\** | **--value=\**
+
+ Set a value.
+
#### Arguments
* **$1** (string): A value to print
@@ -47,4 +57,5 @@ echo "test: $(say-hello World)"
#### See also
* [validate()](#validate)
-* Documentation generated using [shdoc](https://github.com/reconquest/shdoc).
\ No newline at end of file
+* [shdoc](https://github.com/reconquest/shdoc).
+
diff --git a/examples/readme-example.sh b/examples/readme-example.sh
index b6bd512..f5a3bab 100644
--- a/examples/readme-example.sh
+++ b/examples/readme-example.sh
@@ -14,6 +14,10 @@
# @example
# echo "test: $(say-hello World)"
#
+#
+# @option -h | --help Display help.
+# @option -v | --value= Set a value.
+#
# @arg $1 string A value to print
#
# @stdout Output 'Hello $1'.
@@ -25,7 +29,7 @@
# @exitcode 1 If an empty string passed.
#
# @see validate()
-# @see Documentation generated using [shdoc](https://github.com/reconquest/shdoc).
+# @see [shdoc](https://github.com/reconquest/shdoc).
say-hello() {
if [[ ! "$1" ]]; then
echo "Oups !" >&2
diff --git a/shdoc b/shdoc
index 13ae5b9..3300061 100755
--- a/shdoc
+++ b/shdoc
@@ -7,16 +7,19 @@ BEGIN {
}
styles["github", "h1", "from"] = ".*"
- styles["github", "h1", "to"] = "# &"
+ styles["github", "h1", "to"] = "# &\n"
styles["github", "h2", "from"] = ".*"
- styles["github", "h2", "to"] = "## &"
+ styles["github", "h2", "to"] = "## &\n"
styles["github", "h3", "from"] = ".*"
- styles["github", "h3", "to"] = "### &"
+ styles["github", "h3", "to"] = "### &\n"
styles["github", "h4", "from"] = ".*"
- styles["github", "h4", "to"] = "#### &"
+ styles["github", "h4", "to"] = "#### &\n"
+
+ styles["github", "strong", "from"] = ".*"
+ styles["github", "strong", "to"] = "**&**"
styles["github", "code", "from"] = ".*"
styles["github", "code", "to"] = "```&"
@@ -35,6 +38,12 @@ BEGIN {
styles["github", "li", "from"] = ".*"
styles["github", "li", "to"] = "* &"
+ styles["github", "dt", "from"] = ".*"
+ styles["github", "dt", "to"] = "* &\n"
+
+ styles["github", "dd", "from"] = "^.*$"
+ styles["github", "dd", "to"] = " &"
+
styles["github", "i", "from"] = ".*"
styles["github", "i", "to"] = "_&_"
@@ -175,19 +184,25 @@ function reset() {
function handle_description() {
debug("→ handle_description")
+
+ # Remove empty lines at the start of description.
+ sub(/^[[:space:]\n]*\n/, "", description)
+ # Remove empty lines at the end of description.
+ sub(/[[:space:]\n]*$/, "", description)
+
if (description == "") {
debug("→ → description: empty")
return;
}
if (section != "" && section_description == "") {
- debug("→ → description: added")
+ debug("→ → section description: added")
section_description = description
return;
}
if (file_description == "") {
- debug("→ → description: added")
+ debug("→ → file description: added")
file_description = description
return;
}
@@ -204,7 +219,7 @@ function concat(x, text) {
}
function push(arr, value) {
- arr[length(arr)+1] = value
+ arr[length(arr)] = value
}
function join(arr) {
@@ -220,7 +235,7 @@ function join(arr) {
}
# @description Remove leading and trailing space from line(s) of text.
-# @arg text A text.
+# @param text A text.
# @return The trimmed text.
function trim(text) {
gsub(/(^[[:blank:]]+|[[:blank:]]+$)/, "", text)
@@ -239,11 +254,33 @@ function docblock_concat(key, value) {
}
}
+# @description Add a value as the new last item of a docblock.
+#
+# @param docblock_name Name of the modified docblock.
+# @param value Added item value.
+#
+# @set docblock[docblock_name] docblock with value added as its last item.
function docblock_push(key, value) {
- docblock[key][length(docblock[key])+1] = value
+ new_item_index = length(docblock[key])
+ # Reinitialize docblock key value if it is empty to allow for array storage.
+ if(new_item_index == 0)
+ {
+ delete docblock[key]
+ }
+ if(isarray(value))
+ {
+
+ # Value is an array. Add its contents key by key to the docblock.
+ # Note that is only allow for single dimension value array.
+ for (i in value) {
+ docblock[key][new_item_index][i] = value[i]
+ }
+ }
+ else {
+ docblock[key][new_item_index] = value
+ }
}
-
# @description Append a text to the last item of a docblock.
#
# @param docblock_name Name of the modified docblock.
@@ -252,7 +289,13 @@ function docblock_push(key, value) {
# @set docblock[docblock_name] docblock with text appended to last item.
function docblock_append(docblock_name, text) {
# Detect last docblock item index.
- last_item_index = length(docblock[docblock_name])
+ last_item_index = length(docblock[docblock_name]) - 1
+
+ # Ensure there is no issue if docblock[docblock_name] is empty.
+ if(last_item_index < 0) {
+ last_item_index = 0
+ }
+
# Append text to last docblock item.
docblock[docblock_name][last_item_index] = docblock[docblock_name][last_item_index] text
}
@@ -265,11 +308,12 @@ function docblock_append(docblock_name, text) {
#
# @stdout A unordered list of the dockblock entries.
function render_docblock_list(docblock, docblock_name, title) {
- push(lines, render("h4", title) "\n")
+ push(lines, render("h4", title))
# Initialize list item.
item = ""
# For each dockblock line.
for (i in docblock[docblock_name]) {
+ docblock[docblock_name][i]
# Ident additionnal lines to add them to the markdown list item.
gsub(/\n/, "\n ", docblock[docblock_name][i])
item = render("li", docblock[docblock_name][i])
@@ -280,38 +324,148 @@ function render_docblock_list(docblock, docblock_name, title) {
push(lines, "")
}
+# @description Process a text as an @option tag content.
+# The @option accept the folling format:
+#
+# # @option