summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-04-15 17:06:52 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-04-15 17:19:47 -0400
commitbd1d554a35b543afa5a79dd483583bf2aad9cf47 (patch)
tree4c93824f367f0d0f95ce4231ee563ed8a865317e
parent080d2decb7e3aae1917de9d8a7d5089d74833d65 (diff)
libremessages:flag: Fix several things (also librexgettext)
- Fix a bug where it panicked if given an odd number of sub-headings. - Document the the ability to include sub-headings. - Fix librexgettext's handling of it. It only worked correctly for times when it was only called once in a program, or when it was only ever called with exactly one flag/description pair (and no headings).
-rw-r--r--src/lib/libremessages.1.ronn8
-rwxr-xr-xsrc/lib/librexgettext101
-rw-r--r--src/lib/messages.sh12
-rw-r--r--test/lib-messages-test.sh16
4 files changed, 108 insertions, 29 deletions
diff --git a/src/lib/libremessages.1.ronn b/src/lib/libremessages.1.ronn
index 9a976a8..d4fac85 100644
--- a/src/lib/libremessages.1.ronn
+++ b/src/lib/libremessages.1.ronn
@@ -101,7 +101,7 @@ routines by default.
Similar to `prose`, but prints a bullet point before the first
line, and indents the remaining lines.
- * `flag` <FLAG> <DESCRIPTION> [<FLAG2> <DESCRIPTION2>...]:
+ * `flag` [<FLAG> <DESCRIPTION>|<HEADING>:]...:
Print a flag and description formatted for `--help` text. For
example:<br>
`flag '-N' 'Disable networking in the chroot'`<br>
@@ -113,7 +113,11 @@ routines by default.
whitespace-collapsed (so newlines are stripped), then it is
re-word-wrapped, in the same way as `prose` and `bullet`. If you
pass in multiple flag/description pairs to the same invocation,
- the descriptions are all aligned together.
+ the descriptions are all aligned together. The ability to do
+ insert headings without resetting the alignment is the motivation
+ for also allowing headings to be in the list. In order to tell
+ the difference between a flag and a heading, a heading must end
+ with a colon (':'), and a flag must not.
### NOTIFICATION ROUTINES
diff --git a/src/lib/librexgettext b/src/lib/librexgettext
index 22a6df2..c82b9ae 100755
--- a/src/lib/librexgettext
+++ b/src/lib/librexgettext
@@ -65,49 +65,104 @@ xgettext-sh() {
xgettext-flag() {
{
- declare -i x=0
+ # Stage 1: Generate
+ #
+ # Get all of the arguments to `flag`. Because `flag`
+ # takes an arbitrary number of arguments, just iterate
+ # through arg1, arg2, ... argN; until we've come up
+ # empty 3 times. Why 3? Because each flag takes 2
+ # arguments, and because we don't keep track of which
+ # one of those we're on, waiting for 3 empties ensures
+ # us that we've had a complete "round" with nothing.
+ #
+ # Why can't I just do i+=2, and not have to keep track
+ # of empties? Because, we also allow for arguments
+ # ending in a colon to be headings, which changes the
+ # offsets.
+ declare -i empties=0
declare -i i
- for (( i=1; x < 3; i++ )); do
+ for (( i=1; empties < 3; i++ )); do
local out
out="$(xgettext-sh --keyword="flag:$i,\"$i\"" "$@")"
if [[ -n $out ]]; then
printf -- '%s\n' "$out"
else
- x+=1
+ empties+=1
fi
done
} | whitespace-collapse | sed '/^\#, sh-format/d' | {
- declare -i i
-
- IFS=''
- local segments=()
+ # Stage 2: Parse
+ #
+ # Read in the lines, and group them into an array of
+ # (multi-line) msgs. This just makes working with
+ # them easier.
+ local msgs=()
+ declare -i i=-1
local re='^#\. ([0-9]+)$'
+ IFS=''
local line
while read -r line; do
if [[ $line =~ $re ]]; then
- i=${BASH_REMATCH[1]}
- else
- segments[$i]+="$line"$'\n'
+ i+=1
fi
+ msgs[$i]+="$line"$'\n'
done
-
- declare -i last=$(printf '%s\n' "${!segments[@]}"|sed -n '$p')
-
+ # Stage 3: Sort
+ #
+ # Now, we have the `msgs` array, and it is
+ # sorted such that it is all of the arg1's to `flag`,
+ # then all of the arg2's, then all of the arg3's, and
+ # so on. We want to re-order them such that it's all
+ # of the args for the first invocation then all of the
+ # args for the second; and so on.
+ #
+ # We do this by simply sorting them by the location
+ # that they appear in the file. Then, when we see the
+ # argument number go back down to 1, we know that a
+ # new invocation has started!
IFS=$'\n'
- local flag=true
- for (( i=1; i <= last; i++ )); do
- if $flag; then
- local lines=(${segments[$i]})
+ local locations=($(
+ local i
+ for i in "${!msgs[@]}"; do
+ declare -i arg row
+ local lines=(${msgs[$i]})
+ arg=${lines[0]#'#. '}
+ row=${lines[1]##*:}
+ printf '%d.%d %d\n' "$row" "$arg" "$i"
+ done | sort -n
+ ))
+ # Stage 4: Output
+ #
+ # Now, we prune out the arguments that aren't
+ # localizable. Also, remove the "#." comment lines.
+ # As explained above (in stage 3), when we see $arg go
+ # to 1, that's the beginning of a new invocation.
+ local expectflag=true
+ local location
+ for location in "${locations[@]}"; do
+ IFS=' .'
+ local row arg i
+ read -r row arg i <<<"$location"
+ local msg="${msgs[$i]#*$'\n'}"
+ # Now we operate based on $row, $arg, and $msg
+ if [[ $arg == 1 ]]; then
+ expectflag=true
+ fi
+ if $expectflag; then
+ IFS=$'\n'
+ local lines=(${msg})
if [[ ${lines[1]} == *':"' ]]; then
- printf -- '%s\n' "${segments[$i]}"
+ # We expected a flag, but got
+ # a heading
+ printf -- '%s\n' "$msg"
else
- flag=false
+ # We expected a flag, and got
+ # one!
+ expectflag=false
fi
else
- if [[ -n ${segments[$i]} ]]; then
- printf -- '%s\n' "${segments[$i]}"
- fi
- flag=true
+ printf -- '%s\n' "$msg"
+ expectflag=true
fi
done
}
diff --git a/src/lib/messages.sh b/src/lib/messages.sh
index 4b4897e..0125003 100644
--- a/src/lib/messages.sh
+++ b/src/lib/messages.sh
@@ -92,14 +92,15 @@ bullet() {
printf -- "$mesg" "$@" | fmt -u -w 71 | sed -e '1s/^/ - /' -e '2,$s/^/ /'
}
-# Usage: flag FLAG DESCRIPTION [FLAG2 DESCRIPTION2...]
+# Usage: flag [FLAG DESCRIPTION|HEADING:]...
#
# Print a flag and description formatted for --help text.
#
# ex: flag '-C <FILE>' 'Use this file instead of pacman.conf'
#
-# The description is fed through gettext, the flag is not, so if part
-# of the flag needs to be translated, you must do that yourself:
+# The descriptions and headings are fed through gettext, the flags ar
+# not, so if part of a flag needs to be translated, you must do that
+# yourself:
#
# ex: flag "-C <$(_ FILE)>" 'Use this file instead of pacman.conf'
#
@@ -107,8 +108,10 @@ bullet() {
# crazy-long, feel free, it is reflowed/wrapped the same way as prose
# and bullet. If you pass in multiple flag/description pairs at once,
# the descriptions are all alligned together.
+#
+# A heading MUST end with a colon (':'), this is how it knows that it
+# is a heading. Similarly, a flag MUST NOT end with a colon.
flag() {
- [[ $# == $(($#/2*2)) ]] || panic
local args=("$@")
declare -i flaglen=0
@@ -147,6 +150,7 @@ flag() {
printf -- ' %s\n' "$(_ "$1")"
shift
else
+ [[ $# -gt 1 ]] || panic
local flag=$1
local desc="$(_ "$(whitespace_collapse <<<"$2")")"
shift 2
diff --git a/test/lib-messages-test.sh b/test/lib-messages-test.sh
index 3fcac63..d895d99 100644
--- a/test/lib-messages-test.sh
+++ b/test/lib-messages-test.sh
@@ -46,3 +46,19 @@ it_fails_with_msg_and_no_args() {
libremessages msg || ret=$?
[[ $ret != 0 ]]
}
+
+it_allows_subheadings_to_flag() {
+ # Note that old versions of `flag` panicked if given an odd
+ # number of headings, so give an odd number here.
+ libremessages flag \
+ -a adesc \
+ -b bdesc \
+ Head1: \
+ -c cdesc > $tmpdir/out
+ printf '%s\n' \
+ ' -a adesc' \
+ ' -b bdesc' \
+ ' Head1:' \
+ ' -c cdesc' > $tmpdir/exp
+ diff -u $tmpdir/exp $tmpdir/out
+}