-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdocument
executable file
·179 lines (151 loc) · 5.59 KB
/
document
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env dash
# FAKE_COMPAT
# NOTE: a lot of boilerplate code is pulled from the pure sh bible:
# https://github.com/dylanaraps/pure-sh-bible
document2() {
local c=0 # line count
local d="#""#""#" # marker/delimiter, written this way to avoid self-matching
# NOTE: since the marker corresponds to a <h3> in markdown, it's used there too.
local e="${f#sh/}" # function name to expect
local f="$1" # file
local o=1 # when one, previous line was a one-liner (@- token).
[ "$f" != "$e" ] || e="" # only expect function names for stuff in sh/
while IFS= read -r line; do
: $((c+=1)) $((o+=1))
# we only care about lines with our docstring marker in them:
case "$line" in *"$d"*) :;; *) continue;; esac
# split by the marker:
local code="${line%%$d*}" docs="${line#*$d}"
code="${code#${code%%[! ]*}}" # ltrim
docs="${docs# }" # ltrim a single space
local s=' ' n='' # using a space to signify unset
case "$docs" in
@-*)
s="$code"
n="${s%%[!a-zA-Z0-9_-]*}" # substr first word (might not be one)
while [ -z "$n" ] || [ "$n" = function ] || [ "$n" = alias ]; do
[ -n "$s" ] || break
s="${s#${s%%[!a-zA-Z0-9_-]*}}" # lstrip to end of word
s="${s#*[!a-zA-Z0-9_-]}" # lstrip to next word
n="${s%%[!a-zA-Z0-9_-]*}" # substr that word
done
s="${docs#@-}" # substr the stuff after the hyphen
s="${s#${s%%[! ]*}}" # ltrim
[ -z "$s" ] || o=0
;;
@*-*)
# split by the hyphen:
n="${docs%%-*}"
s="${docs#*-}"
n="${n#@}" # substr the stuff after the at
n="${n#${n%%[! ]*}}" # ltrim
n="${n%${n##*[! ]}}" # rtrim
s="${s#${s%%[! ]*}}" # ltrim
[ -z "$s" ] || o=0
;;
@*)
n="${docs#@}" # substr the stuff after the at
n="${n#${n%%[! ]*}}" # ltrim
;;
*)
s="$docs" # leave whitespace intact
;;
esac
if [ -n "$n" ]; then
local url=
# different subdirs need to be handled differently:
[ "$f" != "${f#sh/}" ] && url="/sh/${f#sh/}#L$c" || url="/home/${f#.}#L$c"
if [ "$n" = "$e" ]; then
# function name matches the filename.
printf '\n%s [%s](%s)\n\n' "$d" "$n" "$url" || return 5
else
# this file contains some other function, so include the filename.
printf '\n%s [%s](%s)\n\n' "$d" "$n (${f#.})" "$url" || return 5
#printf '\n%s %s\n\n* defined in [%s](%s)\n\n' "%d" "$n" "$f" "$url" || return 5
fi
fi
if [ "$s" != ' ' ]; then # don't bother unless it was set to something
if [ -z "$n" ] || [ -n "$s" ]; then # might only be a name, check that
# just pass the remaining comment through:
if [ $o = 1 ]; then
# ensure one-liners are their in their own paragraph.
printf '\n' || return 5
fi
printf '%s\n' "$s" || return 5
fi
fi
done < "$f" || return 4
}
document1() {
# NOTE: in the future, it'd be nice to support arbitary files through arguments.
local in_='rc/README.md'
local out='rc/README.md~'
if [ $# -eq 0 ]; then
cd || return 2
[ -d rc ] || return 3 # sanity check
elif [ $# -eq 1 ]; then
in_='README.md'
out='README.md~'
cd "$1" || return 2
else
return 1
fi
# sanity check:
[ -d sh ] && [ -f .zshrc ] && [ -f .shrc ] && [ -f .bashrc ] || return 3
# create new output file (with a tilde as not to overwrite just yet):
: > "$out" || return 4
local line=
if [ -f "$in_" ]; then
# copy existing lines up to (and including) the "DOCUMENT" marker:
while IFS= read -r line; do
printf '%s\n' "$line" >> "$out" || return 5
case "$line" in *DOCUMENT*) break;; esac
done < "$in_" || return 4
fi
# first section:
printf '\n## %s\n' 'shell functions' >> "$out" || return 5
local f=
for f in sh/*; do
[ -e "$f" ] || continue # make sure glob went through
local fn="${f##*/}"
# ignore some stuff:
[ "$fn" = "${fn#_}" ] || continue # completion files
[ "$fn" = "${fn%.bak}" ] || continue # backup files
document2 "$f" >> "$out" || return
done
# second section:
printf '\n## %s\n' 'miscellaneous' >> "$out" || return 5
document2 .zshrc >> "$out" || return
document2 .bashrc >> "$out" || return
document2 .shrc >> "$out" || return
}
document() { ### @-
### generate a markdown file out of docstrings in shell scripts.
###
### **TODO:** describe. i have a rough outline written in my scrap file.
document1 "$@"
local ret=$?
case $ret in
0)
return 0;;
1)
printf '%s\n' "$0: too many arguments" >&2
return 1;;
2)
printf '%s\n' "$0: failed to change directory" >&2
return 1;;
3)
printf '%s\n' "$0: essential files are missing" >&2
return 1;;
4)
printf '%s\n' "$0: failed to open file" >&2
return 1;;
5)
printf '%s\n' "$0: failed to read line" >&2
return 1;;
*)
printf '%s\n' "$0: unknown error occurred" >&2
return 1;;
esac
}
[ -n "${preload+-}" ] || document "$@"