Skip to content

Commit

Permalink
Allow function bracket to be on next line, fix reconquest#56 (reconqu…
Browse files Browse the repository at this point in the history
…est#65)

* Allow function bracket to be on next line, fix reconquest#56

* - Fix function name extraction for `function name {}`.
  (function declared with function keyword, but without parenthesis.
- Add function declaraction unit tests.
  • Loading branch information
landure authored Jul 31, 2023
1 parent 8d28941 commit 12c3792
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 18 deletions.
113 changes: 95 additions & 18 deletions shdoc
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,59 @@ function warn(message) {
warn_message_color, NR, message, color_clear) > "/dev/stderr"
}

# @description Process a line of text as a function declaration.
# This is a function called when encountering a function declaration,
# or a line starting by a opening bracket `{` with a previous line matching
# a function declaration.
#
# @param text The line containing the function declaration,
# with or without opening bracket.
#
# @set is_internal Set internal to 0.
# @set func_name Set the function name.
# @set doc Add function documentation to doc output.
# @set toc Add link to function documentation to table of contents.
function process_function(text) {
if ( \
(length(docblock) == 0 && description == "") \
|| in_example \
) {
# If docblock and description are empty,
# or if function in example section,
# skip function declaration.
return
}

debug("→ function")
if (is_internal) {
debug("→ → function: it is internal, skip")
is_internal = 0
} else {
debug("→ → function: register")

is_internal = 0

func_name = gensub(\
/^[[:blank:]]*(function([[:blank:]])+)?([a-zA-Z0-9_\-:-\\.]+)[[:blank:]]*.*/, \
"\\3", \
"g", \
text \
)

# Add function documentation to output.
doc = concat(doc, render_docblock(func_name, description, docblock))
# Add function link to table of contents.
toc = concat(toc, render_toc_item(func_name))
}

# Function document has been added to output.
# Reset variables to allow for another function documentation processing.
reset()

# Process next line.
next
}

function render(type, text) {
return gensub( \
styles[style, type, "from"],
Expand Down Expand Up @@ -775,37 +828,61 @@ match($0, /^([[:blank:]]*#[[:blank:]]+)@(stdin|stdout|stderr)[[:blank:]]+(.*[^[:
next
}

/^[ \t]*(function([ \t])+)?([a-zA-Z0-9_\-:-\\.]+)([ \t]*)(\(([ \t]*)\))?[ \t]*\{/ \
&& (length(docblock) != 0 || description != "") && !in_example {
debug("→ function")
if (is_internal) {
debug("→ → function: it is internal, skip")
is_internal = 0
} else {
debug("→ → function: register")
# If docblock if not empty, and description is set,
# and if this is not an example,
# this regex matches:
# - `function function_name () {`
# - `function_name () {`
# - `function_name {`
/^[[:blank:]]*(function[[:blank:]]+)?([a-zA-Z0-9_\-:-\\.]+)[[:blank:]]*(\([[:blank:]]*\))?[[:blank:]]*\{/ \
{
process_function($0)
}

is_internal = 0
func_name = gensub(\
/^[ \t]*(function([ \t])+)?([a-zA-Z0-9_\-:-\\.]+)[ \t]*\(.*/, \
"\\3", \
"g" \
)
# If line look like a function declaration but is missing opening bracket,
/^[[:blank:]]*(function[[:blank:]]+)?([a-zA-Z0-9_\-:-\\.]+)[[:blank:]]*(\([[:blank:]]*\))?/ \
{
# store it for future use
debug("→ look like a function declaration, store line")
function_declaration = $0
next
}

doc = concat(doc, render_docblock(func_name, description, docblock))
toc = concat(toc, render_toc_item(func_name))
}
# Handle lone opening bracket if previous line is a function declaration.
/^[[:blank:]]*\{/ \
&& function_declaration != "" {
debug("→ multi-line function declaration.")
# Process function declaration.
process_function(function_declaration)
}

reset()
# Skip empty lines (allow for break in comment),
# if function_declaration is not empty (i.e. waiting for an opening bracket).
/^[[:blank:]]*$/ \
&& function_declaration != "" {
debug("→ waiting for opening bracket.")
next
}

# Handle non comment lines.
/^[^#]*$/ {
debug("→ break")

# Line is not an opening bracket,
# this is not a function declaration.
function_declaration = ""

# Add current (section) description to output.
handle_description();

# Reset docblock.
reset()

# Skip current line.
next
}

# Handle everything else. This should never occur.
{
debug("→ NOT HANDLED")
}
Expand Down
103 changes: 103 additions & 0 deletions tests/testcases/@function-declaration.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
#!/bin/bash

tests:put input <<EOF
# @name Project Name
# @brief Brief
# @description the file description
# with some more lines
# @description Function n°1
a() {
echo "a"
}
# @description Function n°2
b() { echo "b" ; }
# @description Function n°3
:c() { echo "c"; }
# @description Function n°4
d-method()
{ echo "d"; }
# @description Function n°5
function e:function { echo "e"; }
# @description Function n°6
function f() { echo "f"; }
# @description Function n°7
function g
{ echo "g"; }
# @description Function n°8
function h()
{ echo "h"; }
a
b
:c
d-method
e:function
f
g
h
EOF

tests:put expected <<EOF
# Project Name
Brief
## Overview
the file description
with some more lines
## Index
* [a](#a)
* [b](#b)
* [:c](#c)
* [d-method](#d-method)
* [e:function](#efunction)
* [f](#f)
* [g](#g)
* [h](#h)
### a
Function n°1
### b
Function n°2
### :c
Function n°3
### d-method
Function n°4
### e:function
Function n°5
### f
Function n°6
### g
Function n°7
### h
Function n°8
EOF

assert
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/bin/bash

tests:put input <<EOF
#!/sbin/sh
# @description My super function.
#
# @arg \$1 string A value to print
say-hello()
{
if [[ ! "\$1" ]]; then
return 1;
fi
echo "Hello \$1"
}
EOF

tests:put expected <<EOF
## Index
* [say-hello](#say-hello)
### say-hello
My super function.
#### Arguments
* **\$1** (string): A value to print
EOF

assert

0 comments on commit 12c3792

Please sign in to comment.