diff --git a/shdoc b/shdoc
index 5613dbe..70f9a81 100755
--- a/shdoc
+++ b/shdoc
@@ -23,11 +23,11 @@ BEGIN {
 
     styles["github", "/code", "to"] = "```"
 
-    styles["github", "argN", "from"] = "^(\\$[0-9]) (\\S+)"
-    styles["github", "argN", "to"] = "**\\1** (\\2):"
+    styles["github", "argN", "from"] = "^(\\$[0-9]+)[[:blank:]]+(\\S+)[[:blank:]]+"
+    styles["github", "argN", "to"] = "**\\1** (\\2): "
 
-    styles["github", "arg@", "from"] = "^\\$@ (\\S+)"
-    styles["github", "arg@", "to"] = "**...** (\\1):"
+    styles["github", "arg@", "from"] = "^\\$@[[:blank:]]+(\\S+)[[:blank:]]+"
+    styles["github", "arg@", "to"] = "**...** (\\1): "
 
     styles["github", "set", "from"] = "^(\\S+) (\\S+)"
     styles["github", "set", "to"] = "**\\1** (\\2):"
@@ -52,6 +52,27 @@ BEGIN {
     debug_file = "/dev/fd/" debug_fd
 }
 
+# @description Display the given error message with its line number on stderr.
+#              and exit with error.
+# @arg $message string A error message.
+# @exitcode 1
+function error(message) {
+    error_message_color="\033[1;31m"
+    color_clear="\033[1;0m"
+    printf("%sline %4s, error : %s%s\n",\
+        error_message_color, NR, message, color_clear) > "/dev/stderr"
+    exit 1
+}
+
+# @description Display the given warning message with its line number on stderr.
+# @arg $message string A warning message.
+function warn(message) {
+    warn_message_color="\033[1;34m"
+    color_clear="\033[1;0m"
+    printf("%sline %4s, warning : %s%s\n", \
+        warn_message_color, NR, message, color_clear) > "/dev/stderr"
+}
+
 function render(type, text) {
     return gensub( \
         styles[style, type, "from"],
@@ -170,6 +191,14 @@ function join(arr) {
     return result
 }
 
+# @description Remove leading and trailing space from line(s) of text.
+# @arg text A text.
+# @return The trimmed text.
+function trim(text) {
+    gsub(/(^[[:blank:]]+|[[:blank:]]+$)/, "", text)
+    return text
+}
+
 function docblock_set(key, value) {
     docblock[key] = value
 }
@@ -218,16 +247,21 @@ function render_docblock(func_name, description, docblock) {
 
     if ("arg" in docblock) {
         push(lines, render("h4", "Arguments") "\n")
-        for (i in docblock["arg"]) {
-            item = docblock["arg"][i]
+
+        # Sort args by indexes (i.e. by argument number.)
+        asorti(docblock["arg"], sorted_indexes)
+        for (i in sorted_indexes) {
+            item = docblock["arg"][sorted_indexes[i]]
+            # Render numbered arguments ($[0-9]+).
             item = render("argN", item)
+            # Render catch-all argument ($@).
             item = render("arg@", item)
             item = render("li", item)
-            if (i == length(docblock["arg"])) {
-                item = item "\n"
-            }
             push(lines, item)
         }
+
+        # Add empty line to signal end of list in markdown.
+        push(lines, "")
     }
 
     if ("noargs" in docblock) {
@@ -392,19 +426,48 @@ in_example {
 
 }
 
-/^[[:space:]]*# @arg/ {
+# Select @arg lines with content.
+/^[[:blank:]]*#[[:blank:]]+@arg[[:blank:]]+[^[:blank:]]/ {
     debug("→ @arg")
-    sub(/^[[:space:]]*# @arg /, "")
+    
+    arg_text = $0
 
-    docblock_push("arg", $0)
+    # Remove '# @arg ' tag.
+    sub(/^[[:blank:]]*#[[:blank:]]+@arg[[:blank:]]+/, "", arg_text)
 
-    next
+    # Trim text.
+    arg_text = trim(arg_text)
+
+    # Test if @arg is a numbered item (or $@).
+    if(match(arg_text, /^\$([0-9]+|@)[[:space:]]/, contents)) {
+        debug(" → → found arg $" arg_number)
+
+        # Fetch matched values.
+        arg_number = contents[1]
+
+        # Zero pad argument number for sorting.
+        if(arg_number ~ /[0-9]+/){
+            arg_number = sprintf("%03d", arg_number)
+        }
+
+        # Add arg description to arg docblock.
+        # arg_number is used as indice for sorting.
+        docblock["arg"][arg_number] = arg_text
+
+        # Stop processing current line, and process next line.
+        next
+    }
+
+    # Ignore badly formated @arg.
+    warn("Invalid format: @arg " arg_text)
 }
 
-/^[[:space:]]*# @noargs/ {
+# Select @noargs line with no additionnal text.
+/^[[:space:]]*#[[:blank:]]+@noargs[[:blank:]]*$/ {
     debug("→ @noargs")
     docblock["noargs"] = 1
 
+    # Stop processing current line, and process next line.
     next
 }
 
diff --git a/tests/testcases/numbered-arguments.test.sh b/tests/testcases/numbered-arguments.test.sh
new file mode 100644
index 0000000..15fdb8e
--- /dev/null
+++ b/tests/testcases/numbered-arguments.test.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# @file test/testcases/@numbered-arguments.test.sh
+# @author Pierre-Yves Landuré < contact at biapy dot fr >
+# @brief Test cases for @arg keyword.
+# @description
+#   Test these @arg comportements:
+#   - arg numbers in disorder.
+#   - arg numbers > 10
+#   - arg message with indentation and trailing spaces.
+#   - appears between @example and @set sections.
+
+tests:put input <<EOF
+# @name shdoc @arg tests
+# @brief Test @arg functionnality.
+# @description Tests for shdoc processing of @arg keyword.
+# @arg \$4 int 4th arg.
+# @arg \$6 string 6th arg.
+# @set ARG_TESTED A variable set by the function.
+# @arg \$5 int 5th arg.
+# @arg \$@ string All other arguments.
+# @arg \$1 string 1st arg.
+# @example
+#   test-arg 'my-tested-argument'
+#
+# @arg \$3    bool    3rd arg with indentation and trailing spaces.        
+# @arg \$2 string 2nd arg.
+    # @arg \$7 string 7th arg with indentation before #.
+#       @arg \$8 array[] 8th arg with indentation between # and @arg.
+# @arg      \$9 string 9th arg with indentation between @arg and number.
+# @arg \$10 string 10th arg.
+# @arg \$11 string 11th arg.
+test-arg() {
+}
+EOF
+
+tests:put expected <<EOF
+# shdoc @arg tests
+
+Test @arg functionnality.
+
+## Overview
+
+Tests for shdoc processing of @arg keyword.
+
+## Index
+
+* [test-arg](#test-arg)
+
+### test-arg
+
+Tests for shdoc processing of @arg keyword.
+
+#### Example
+
+\`\`\`bash
+test-arg 'my-tested-argument'
+\`\`\`
+
+#### Arguments
+
+* **\$1** (string): 1st arg.
+* **\$2** (string): 2nd arg.
+* **\$3** (bool): 3rd arg with indentation and trailing spaces.
+* **\$4** (int): 4th arg.
+* **\$5** (int): 5th arg.
+* **\$6** (string): 6th arg.
+* **\$7** (string): 7th arg with indentation before #.
+* **\$8** (array[]): 8th arg with indentation between # and @arg.
+* **\$9** (string): 9th arg with indentation between @arg and number.
+* **\$10** (string): 10th arg.
+* **\$11** (string): 11th arg.
+* **...** (string): All other arguments.
+
+#### Variables set
+
+* **ARG_TESTED** (A): variable set by the function.
+
+EOF
+
+assert