diff options
Diffstat (limited to 'src')
52 files changed, 740 insertions, 0 deletions
diff --git a/src/locale/ADDED_LOG.en.txt b/src/locale/ADDED_LOG.en.txt new file mode 100644 index 0000000..1d49c77 --- /dev/null +++ b/src/locale/ADDED_LOG.en.txt @@ -0,0 +1 @@ +%s added to %s. diff --git a/src/locale/ADDED_LOG.eo.txt b/src/locale/ADDED_LOG.eo.txt new file mode 100644 index 0000000..1d49c77 --- /dev/null +++ b/src/locale/ADDED_LOG.eo.txt @@ -0,0 +1 @@ +%s added to %s. diff --git a/src/locale/ADDED_LOG.es.txt b/src/locale/ADDED_LOG.es.txt new file mode 100644 index 0000000..1d49c77 --- /dev/null +++ b/src/locale/ADDED_LOG.es.txt @@ -0,0 +1 @@ +%s added to %s. diff --git a/src/locale/ADDED_LOG.fr.txt b/src/locale/ADDED_LOG.fr.txt new file mode 100644 index 0000000..1d49c77 --- /dev/null +++ b/src/locale/ADDED_LOG.fr.txt @@ -0,0 +1 @@ +%s added to %s. diff --git a/src/locale/ADDED_LOG.pt.txt b/src/locale/ADDED_LOG.pt.txt new file mode 100644 index 0000000..1d49c77 --- /dev/null +++ b/src/locale/ADDED_LOG.pt.txt @@ -0,0 +1 @@ +%s added to %s. diff --git a/src/locale/COMMIT_MSG.en.txt b/src/locale/COMMIT_MSG.en.txt new file mode 100644 index 0000000..062e0f2 --- /dev/null +++ b/src/locale/COMMIT_MSG.en.txt @@ -0,0 +1 @@ +$TD_FILE: Add $TD_IDREF diff --git a/src/locale/COMMIT_MSG.eo.txt b/src/locale/COMMIT_MSG.eo.txt new file mode 100644 index 0000000..062e0f2 --- /dev/null +++ b/src/locale/COMMIT_MSG.eo.txt @@ -0,0 +1 @@ +$TD_FILE: Add $TD_IDREF diff --git a/src/locale/COMMIT_MSG.es.txt b/src/locale/COMMIT_MSG.es.txt new file mode 100644 index 0000000..062e0f2 --- /dev/null +++ b/src/locale/COMMIT_MSG.es.txt @@ -0,0 +1 @@ +$TD_FILE: Add $TD_IDREF diff --git a/src/locale/COMMIT_MSG.fr.txt b/src/locale/COMMIT_MSG.fr.txt new file mode 100644 index 0000000..062e0f2 --- /dev/null +++ b/src/locale/COMMIT_MSG.fr.txt @@ -0,0 +1 @@ +$TD_FILE: Add $TD_IDREF diff --git a/src/locale/COMMIT_MSG.pt.txt b/src/locale/COMMIT_MSG.pt.txt new file mode 100644 index 0000000..062e0f2 --- /dev/null +++ b/src/locale/COMMIT_MSG.pt.txt @@ -0,0 +1 @@ +$TD_FILE: Add $TD_IDREF diff --git a/src/locale/FILE_DOESNT_EXIST_CREATING.en.txt b/src/locale/FILE_DOESNT_EXIST_CREATING.en.txt new file mode 100644 index 0000000..f76b7d2 --- /dev/null +++ b/src/locale/FILE_DOESNT_EXIST_CREATING.en.txt @@ -0,0 +1 @@ +File "%s" doesn't exist yet, creating a brand new one. diff --git a/src/locale/FILE_DOESNT_EXIST_CREATING.eo.txt b/src/locale/FILE_DOESNT_EXIST_CREATING.eo.txt new file mode 100644 index 0000000..f76b7d2 --- /dev/null +++ b/src/locale/FILE_DOESNT_EXIST_CREATING.eo.txt @@ -0,0 +1 @@ +File "%s" doesn't exist yet, creating a brand new one. diff --git a/src/locale/FILE_DOESNT_EXIST_CREATING.es.txt b/src/locale/FILE_DOESNT_EXIST_CREATING.es.txt new file mode 100644 index 0000000..f76b7d2 --- /dev/null +++ b/src/locale/FILE_DOESNT_EXIST_CREATING.es.txt @@ -0,0 +1 @@ +File "%s" doesn't exist yet, creating a brand new one. diff --git a/src/locale/FILE_DOESNT_EXIST_CREATING.fr.txt b/src/locale/FILE_DOESNT_EXIST_CREATING.fr.txt new file mode 100644 index 0000000..f76b7d2 --- /dev/null +++ b/src/locale/FILE_DOESNT_EXIST_CREATING.fr.txt @@ -0,0 +1 @@ +File "%s" doesn't exist yet, creating a brand new one. diff --git a/src/locale/FILE_DOESNT_EXIST_CREATING.pt.txt b/src/locale/FILE_DOESNT_EXIST_CREATING.pt.txt new file mode 100644 index 0000000..f76b7d2 --- /dev/null +++ b/src/locale/FILE_DOESNT_EXIST_CREATING.pt.txt @@ -0,0 +1 @@ +File "%s" doesn't exist yet, creating a brand new one. diff --git a/src/locale/HELP1.en.txt b/src/locale/HELP1.en.txt new file mode 100644 index 0000000..f443055 --- /dev/null +++ b/src/locale/HELP1.en.txt @@ -0,0 +1,21 @@ + +Options: + -c commit directly only with the title, without + adding a description. Assumes -m + -m MESSAGE_TITLE the title message of the entry + -t TYPE the type of entry to be added (default: |TYPE|) + -s STATE the state of entry to be added (default: |STATE|) + -H pre-process issues file before generating HTML + -l list the supported values for $TD_USE_BUILTIN_HOOKS + -L lint the issues file + -h, --help show this help message + -V, --version print the version number + +Examples: + Create a new entry with the default type with a custom title: + $ td -cm 'An entry title' + + Create a new entry with a custom type and state: + $ td -cm 'Another title' -t bug -s DONE + +States of an entry: diff --git a/src/locale/HELP1.eo.txt b/src/locale/HELP1.eo.txt new file mode 100644 index 0000000..f443055 --- /dev/null +++ b/src/locale/HELP1.eo.txt @@ -0,0 +1,21 @@ + +Options: + -c commit directly only with the title, without + adding a description. Assumes -m + -m MESSAGE_TITLE the title message of the entry + -t TYPE the type of entry to be added (default: |TYPE|) + -s STATE the state of entry to be added (default: |STATE|) + -H pre-process issues file before generating HTML + -l list the supported values for $TD_USE_BUILTIN_HOOKS + -L lint the issues file + -h, --help show this help message + -V, --version print the version number + +Examples: + Create a new entry with the default type with a custom title: + $ td -cm 'An entry title' + + Create a new entry with a custom type and state: + $ td -cm 'Another title' -t bug -s DONE + +States of an entry: diff --git a/src/locale/HELP1.es.txt b/src/locale/HELP1.es.txt new file mode 100644 index 0000000..f443055 --- /dev/null +++ b/src/locale/HELP1.es.txt @@ -0,0 +1,21 @@ + +Options: + -c commit directly only with the title, without + adding a description. Assumes -m + -m MESSAGE_TITLE the title message of the entry + -t TYPE the type of entry to be added (default: |TYPE|) + -s STATE the state of entry to be added (default: |STATE|) + -H pre-process issues file before generating HTML + -l list the supported values for $TD_USE_BUILTIN_HOOKS + -L lint the issues file + -h, --help show this help message + -V, --version print the version number + +Examples: + Create a new entry with the default type with a custom title: + $ td -cm 'An entry title' + + Create a new entry with a custom type and state: + $ td -cm 'Another title' -t bug -s DONE + +States of an entry: diff --git a/src/locale/HELP1.fr.txt b/src/locale/HELP1.fr.txt new file mode 100644 index 0000000..f443055 --- /dev/null +++ b/src/locale/HELP1.fr.txt @@ -0,0 +1,21 @@ + +Options: + -c commit directly only with the title, without + adding a description. Assumes -m + -m MESSAGE_TITLE the title message of the entry + -t TYPE the type of entry to be added (default: |TYPE|) + -s STATE the state of entry to be added (default: |STATE|) + -H pre-process issues file before generating HTML + -l list the supported values for $TD_USE_BUILTIN_HOOKS + -L lint the issues file + -h, --help show this help message + -V, --version print the version number + +Examples: + Create a new entry with the default type with a custom title: + $ td -cm 'An entry title' + + Create a new entry with a custom type and state: + $ td -cm 'Another title' -t bug -s DONE + +States of an entry: diff --git a/src/locale/HELP1.pt.txt b/src/locale/HELP1.pt.txt new file mode 100644 index 0000000..f443055 --- /dev/null +++ b/src/locale/HELP1.pt.txt @@ -0,0 +1,21 @@ + +Options: + -c commit directly only with the title, without + adding a description. Assumes -m + -m MESSAGE_TITLE the title message of the entry + -t TYPE the type of entry to be added (default: |TYPE|) + -s STATE the state of entry to be added (default: |STATE|) + -H pre-process issues file before generating HTML + -l list the supported values for $TD_USE_BUILTIN_HOOKS + -L lint the issues file + -h, --help show this help message + -V, --version print the version number + +Examples: + Create a new entry with the default type with a custom title: + $ td -cm 'An entry title' + + Create a new entry with a custom type and state: + $ td -cm 'Another title' -t bug -s DONE + +States of an entry: diff --git a/src/locale/HELP2.en.txt b/src/locale/HELP2.en.txt new file mode 100644 index 0000000..a050854 --- /dev/null +++ b/src/locale/HELP2.en.txt @@ -0,0 +1 @@ +Types of entry: diff --git a/src/locale/HELP2.eo.txt b/src/locale/HELP2.eo.txt new file mode 100644 index 0000000..a050854 --- /dev/null +++ b/src/locale/HELP2.eo.txt @@ -0,0 +1 @@ +Types of entry: diff --git a/src/locale/HELP2.es.txt b/src/locale/HELP2.es.txt new file mode 100644 index 0000000..a050854 --- /dev/null +++ b/src/locale/HELP2.es.txt @@ -0,0 +1 @@ +Types of entry: diff --git a/src/locale/HELP2.fr.txt b/src/locale/HELP2.fr.txt new file mode 100644 index 0000000..a050854 --- /dev/null +++ b/src/locale/HELP2.fr.txt @@ -0,0 +1 @@ +Types of entry: diff --git a/src/locale/HELP2.pt.txt b/src/locale/HELP2.pt.txt new file mode 100644 index 0000000..a050854 --- /dev/null +++ b/src/locale/HELP2.pt.txt @@ -0,0 +1 @@ +Types of entry: diff --git a/src/locale/HELP3.en.txt b/src/locale/HELP3.en.txt new file mode 100644 index 0000000..b3ff327 --- /dev/null +++ b/src/locale/HELP3.en.txt @@ -0,0 +1 @@ +See "man td.tutorial" for getting started. diff --git a/src/locale/HELP3.eo.txt b/src/locale/HELP3.eo.txt new file mode 100644 index 0000000..b3ff327 --- /dev/null +++ b/src/locale/HELP3.eo.txt @@ -0,0 +1 @@ +See "man td.tutorial" for getting started. diff --git a/src/locale/HELP3.es.txt b/src/locale/HELP3.es.txt new file mode 100644 index 0000000..b3ff327 --- /dev/null +++ b/src/locale/HELP3.es.txt @@ -0,0 +1 @@ +See "man td.tutorial" for getting started. diff --git a/src/locale/HELP3.fr.txt b/src/locale/HELP3.fr.txt new file mode 100644 index 0000000..b3ff327 --- /dev/null +++ b/src/locale/HELP3.fr.txt @@ -0,0 +1 @@ +See "man td.tutorial" for getting started. diff --git a/src/locale/HELP3.pt.txt b/src/locale/HELP3.pt.txt new file mode 100644 index 0000000..b3ff327 --- /dev/null +++ b/src/locale/HELP3.pt.txt @@ -0,0 +1 @@ +See "man td.tutorial" for getting started. diff --git a/src/locale/TYPE_DOESNT_EXIST_CREATING.en.txt b/src/locale/TYPE_DOESNT_EXIST_CREATING.en.txt new file mode 100644 index 0000000..d7eb7d0 --- /dev/null +++ b/src/locale/TYPE_DOESNT_EXIST_CREATING.en.txt @@ -0,0 +1 @@ +Type "%s" doesn't exist yet, creating new section with it. diff --git a/src/locale/TYPE_DOESNT_EXIST_CREATING.eo.txt b/src/locale/TYPE_DOESNT_EXIST_CREATING.eo.txt new file mode 100644 index 0000000..d7eb7d0 --- /dev/null +++ b/src/locale/TYPE_DOESNT_EXIST_CREATING.eo.txt @@ -0,0 +1 @@ +Type "%s" doesn't exist yet, creating new section with it. diff --git a/src/locale/TYPE_DOESNT_EXIST_CREATING.es.txt b/src/locale/TYPE_DOESNT_EXIST_CREATING.es.txt new file mode 100644 index 0000000..d7eb7d0 --- /dev/null +++ b/src/locale/TYPE_DOESNT_EXIST_CREATING.es.txt @@ -0,0 +1 @@ +Type "%s" doesn't exist yet, creating new section with it. diff --git a/src/locale/TYPE_DOESNT_EXIST_CREATING.fr.txt b/src/locale/TYPE_DOESNT_EXIST_CREATING.fr.txt new file mode 100644 index 0000000..d7eb7d0 --- /dev/null +++ b/src/locale/TYPE_DOESNT_EXIST_CREATING.fr.txt @@ -0,0 +1 @@ +Type "%s" doesn't exist yet, creating new section with it. diff --git a/src/locale/TYPE_DOESNT_EXIST_CREATING.pt.txt b/src/locale/TYPE_DOESNT_EXIST_CREATING.pt.txt new file mode 100644 index 0000000..d7eb7d0 --- /dev/null +++ b/src/locale/TYPE_DOESNT_EXIST_CREATING.pt.txt @@ -0,0 +1 @@ +Type "%s" doesn't exist yet, creating new section with it. diff --git a/src/locale/UNEDITED_ENTRY.en.txt b/src/locale/UNEDITED_ENTRY.en.txt new file mode 100644 index 0000000..ed413d0 --- /dev/null +++ b/src/locale/UNEDITED_ENTRY.en.txt @@ -0,0 +1 @@ +Abandoning unedited entry. diff --git a/src/locale/UNEDITED_ENTRY.eo.txt b/src/locale/UNEDITED_ENTRY.eo.txt new file mode 100644 index 0000000..ed413d0 --- /dev/null +++ b/src/locale/UNEDITED_ENTRY.eo.txt @@ -0,0 +1 @@ +Abandoning unedited entry. diff --git a/src/locale/UNEDITED_ENTRY.es.txt b/src/locale/UNEDITED_ENTRY.es.txt new file mode 100644 index 0000000..ed413d0 --- /dev/null +++ b/src/locale/UNEDITED_ENTRY.es.txt @@ -0,0 +1 @@ +Abandoning unedited entry. diff --git a/src/locale/UNEDITED_ENTRY.fr.txt b/src/locale/UNEDITED_ENTRY.fr.txt new file mode 100644 index 0000000..ed413d0 --- /dev/null +++ b/src/locale/UNEDITED_ENTRY.fr.txt @@ -0,0 +1 @@ +Abandoning unedited entry. diff --git a/src/locale/UNEDITED_ENTRY.pt.txt b/src/locale/UNEDITED_ENTRY.pt.txt new file mode 100644 index 0000000..ed413d0 --- /dev/null +++ b/src/locale/UNEDITED_ENTRY.pt.txt @@ -0,0 +1 @@ +Abandoning unedited entry. diff --git a/src/locale/UNREGISTERED_TYPE.en.txt b/src/locale/UNREGISTERED_TYPE.en.txt new file mode 100644 index 0000000..8c12971 --- /dev/null +++ b/src/locale/UNREGISTERED_TYPE.en.txt @@ -0,0 +1 @@ +Unregistered type: %s diff --git a/src/locale/UNREGISTERED_TYPE.eo.txt b/src/locale/UNREGISTERED_TYPE.eo.txt new file mode 100644 index 0000000..8c12971 --- /dev/null +++ b/src/locale/UNREGISTERED_TYPE.eo.txt @@ -0,0 +1 @@ +Unregistered type: %s diff --git a/src/locale/UNREGISTERED_TYPE.es.txt b/src/locale/UNREGISTERED_TYPE.es.txt new file mode 100644 index 0000000..8c12971 --- /dev/null +++ b/src/locale/UNREGISTERED_TYPE.es.txt @@ -0,0 +1 @@ +Unregistered type: %s diff --git a/src/locale/UNREGISTERED_TYPE.fr.txt b/src/locale/UNREGISTERED_TYPE.fr.txt new file mode 100644 index 0000000..8c12971 --- /dev/null +++ b/src/locale/UNREGISTERED_TYPE.fr.txt @@ -0,0 +1 @@ +Unregistered type: %s diff --git a/src/locale/UNREGISTERED_TYPE.pt.txt b/src/locale/UNREGISTERED_TYPE.pt.txt new file mode 100644 index 0000000..8c12971 --- /dev/null +++ b/src/locale/UNREGISTERED_TYPE.pt.txt @@ -0,0 +1 @@ +Unregistered type: %s diff --git a/src/locale/USAGE.en.txt b/src/locale/USAGE.en.txt new file mode 100644 index 0000000..fad86bd --- /dev/null +++ b/src/locale/USAGE.en.txt @@ -0,0 +1,4 @@ +Usage: + td [-c] [-t TYPE] [-m MESSAGE] + td [-HlL] + td [-hV] diff --git a/src/locale/USAGE.eo.txt b/src/locale/USAGE.eo.txt new file mode 100644 index 0000000..fad86bd --- /dev/null +++ b/src/locale/USAGE.eo.txt @@ -0,0 +1,4 @@ +Usage: + td [-c] [-t TYPE] [-m MESSAGE] + td [-HlL] + td [-hV] diff --git a/src/locale/USAGE.es.txt b/src/locale/USAGE.es.txt new file mode 100644 index 0000000..fad86bd --- /dev/null +++ b/src/locale/USAGE.es.txt @@ -0,0 +1,4 @@ +Usage: + td [-c] [-t TYPE] [-m MESSAGE] + td [-HlL] + td [-hV] diff --git a/src/locale/USAGE.fr.txt b/src/locale/USAGE.fr.txt new file mode 100644 index 0000000..fad86bd --- /dev/null +++ b/src/locale/USAGE.fr.txt @@ -0,0 +1,4 @@ +Usage: + td [-c] [-t TYPE] [-m MESSAGE] + td [-HlL] + td [-hV] diff --git a/src/locale/USAGE.pt.txt b/src/locale/USAGE.pt.txt new file mode 100644 index 0000000..fad86bd --- /dev/null +++ b/src/locale/USAGE.pt.txt @@ -0,0 +1,4 @@ +Usage: + td [-c] [-t TYPE] [-m MESSAGE] + td [-HlL] + td [-hV] diff --git a/src/locale/load-messages.sh.in b/src/locale/load-messages.sh.in new file mode 100644 index 0000000..6a3ffef --- /dev/null +++ b/src/locale/load-messages.sh.in @@ -0,0 +1,35 @@ +#!/bin/sh +set -eu + +get_lang() { + # LC_MESSAGES="ll_CC.CODESET@modifier" -> ll_CC, where quotes are + # optional + locale 2>/dev/null | + grep ^LC_MESSAGES | + cut -d. -f1 | + cut -d\" -f2 | + cut -d= -f2 +} + +locpath() { + lang="$1" + printf '@LOCALEDIR@/%s/LC_MESSAGES/@NAME@/%s.sh' "$lang" "$lang" +} + +ll_CC="$(get_lang)" +ll="$(echo "$ll_CC" | cut -d_ -f1)" + +if [ -r "$(locpath "$ll")" ]; then + # shellcheck source=/dev/null + . "$(locpath "$ll")" +fi + +if [ -r "$(locpath "$ll_CC")" ]; then + # shellcheck source=/dev/null + . "$(locpath "$ll_CC")" +fi + +# locale hierarchy: +# 1. the language+country specific message +# 2. the language specific message +# 3. the default fallback value diff --git a/src/td.in b/src/td.in new file mode 100755 index 0000000..6f1c516 --- /dev/null +++ b/src/td.in @@ -0,0 +1,540 @@ +#!/bin/sh +set -eu + +MSGS='' +add_msg() { + MSGS="$MSGS $1" +} + + +MSG_USAGE="$(cat <<-'EOF' + Usage: + @NAME@ [-c] [-t TYPE] [-m MESSAGE] + @NAME@ [-HlL] + @NAME@ [-hV] +EOF +)" +add_msg USAGE + +MSG_HELP1="$(cat <<-'EOF' + + Options: + -c commit directly only with the title, without + adding a description. Assumes -m + -m MESSAGE_TITLE the title message of the entry + -t TYPE the type of entry to be added (default: |TYPE|) + -s STATE the state of entry to be added (default: |STATE|) + -H pre-process issues file before generating HTML + -l list the supported values for $TD_USE_BUILTIN_HOOKS + -L lint the issues file + -h, --help show this help message + -V, --version print the version number + + Examples: + Create a new entry with the default type with a custom title: + $ td -cm 'An entry title' + + Create a new entry with a custom type and state: + $ td -cm 'Another title' -t bug -s DONE + + States of an entry: +EOF +)" +add_msg HELP1 + +MSG_HELP2="$(cat <<-'EOF' + Types of entry: +EOF +)" +add_msg HELP2 + +MSG_HELP3="$(cat <<-'EOF' + See "man @NAME@.tutorial" for getting started. +EOF +)" +add_msg HELP3 + +MSG_UNEDITED_ENTRY="$(cat <<-'EOF' + Abandoning unedited entry. +EOF +)" +add_msg UNEDITED_ENTRY + +MSG_UNREGISTERED_TYPE="$(cat <<-'EOF' + Unregistered type: %s +EOF +)" +add_msg UNREGISTERED_TYPE + +MSG_UNREGISTERED_STATE="$(cat <<-'EOF' + Unregistered state: %s +EOF +)" +add_msg UNREGISTERED_TYPE + +MSG_ADDED_LOG="$(cat <<-'EOF' + %s added to %s. +EOF +)" +add_msg ADDED_LOG + +MSG_COMMIT_MSG="$(cat <<-'EOF' + $TD_FILE: Add $TD_IDREF +EOF +)" +add_msg COMMIT_MSG + +MSG_TYPE_DOESNT_EXIST_CREATING="$(cat <<-'EOF' + Type "%s" doesn't exist yet, creating new section with it. +EOF +)" +add_msg TYPE_DOESNT_EXIST_CREATING + +MSG_FILE_DOESNT_EXIST_CREATING="$(cat <<-'EOF' + File "%s" doesn't exist yet, creating a brand new one. +EOF +)" +add_msg FILE_DOESNT_EXIST_CREATING + +# +# End translatable strings +# + + + +dump_translatable_strings() { + for msg in $MSGS; do + eval "echo \"\$MSG_$msg\"" > src/locale/"$msg".en.txt + done + + cat <<-'EOF' + #!/bin/sh + # shellcheck disable=2034 + set -eu + + EOF + for msg in $MSGS; do + printf 'MSG_%s="$(cat @LOCALEDIR@/@LANG@/LC_MESSAGES/@NAME@/%s.@LANG@.txt)"\n' \ + "$msg" "$msg" + done +} + +if [ -n "${TD_DUMP_TRANSLATABLE_STRINGS:-}" ]; then + dump_translatable_strings + exit +fi + +if [ -r '@LIBEXECDIR@/@NAME@/load-messages.sh' ]; then + . '@LIBEXECDIR@/@NAME@/load-messages.sh' +fi + + + +# +# Documentation functions +# + +usage() { + printf '%s\n' "$MSG_USAGE" +} + +help() { + printf '%s\n' "$MSG_HELP1" | + sed -e "s/|TYPE|/$DEFAULT_TYPE/" \ + -e "s/|STATE|/$DEFAULT_STATE/" + echo "$TD_STATES" | sed -e 's/^/ /' + + printf '\n%s\n' "$MSG_HELP2" + echo "$TD_TYPES" | awk -F: '{ printf " %s\n", $1 }' + + printf '\n%s\n' "$MSG_HELP3" +} + +version() { + printf '@NAME@-@VERSION@ @DATE@\n' +} + + +# +# Utilities +# + +uuid() { + # Taken from: + # https://serverfault.com/a/799198 + od -xN20 /dev/urandom | + head -n 1 | + awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}' +} + +mkstemp() { + F="${TMPDIR:-/tmp}/td-${1:-$(uuid)}" + touch "$F" + echo "$F" +} + +mkdtemp() { + F="${TMPDIR:-/tmp}/td-${1:-$(uuid)}" + mkdir -p "$F" + echo "$F" +} + + +# +# Core functions +# + +insert_at_line() { + N="$1" + F="$2" + TYPE="$3" + TMPF="$(mkstemp)" + + if [ ! -e "$F" ]; then + printf "$MSG_FILE_DOESNT_EXIST_CREATING\n" "$TD_FILE" >&2 + cat - > "$TMPF" + elif [ "$N" = 0 ]; then + printf "$MSG_TYPE_DOESNT_EXIST_CREATING\n" "$TYPE" >&2 + printf '%s\n\n\n%s\n' \ + "$(cat -)" \ + "$(cat "$F")" \ + > "$TMPF" + else + printf '%s\n\n%s\n\n%s\n' \ + "$(head "-n$N" "$F")" \ + "$(cat -)" \ + "$(tail "-n+$((N+1))" "$F")" \ + > "$TMPF" + fi + + cp "$TMPF" "$F" +} + +name_for_type() { + TYPE="$1" + echo "$TD_TYPES" | awk -F: "/^$TYPE:/ { print \$2; exit }" +} + +linenumber_for_type() { + TYPE="$1" + if [ ! -e "$TD_FILE" ]; then + echo '' + else + NAME="$(name_for_type "$TYPE")" + awk -F: "/^# $NAME\$/ {print NR; exit}" "$TD_FILE" + fi +} + + +GIT_BUILTIN_PRE_ADD_HOOK="$(cat <<-EOF + if ! git diff --exit-code --quiet -- "\$TD_FILE" || + ! git diff --exit-code --quiet --staged -- "\$TD_FILE" + then + git stash push --quiet -- "\$TD_FILE" + touch "\$TD_HOOKS_DIR/has-diff" + fi +EOF +)" +GIT_BUILTIN_POST_ADD_HOOK="$(cat <<-EOF + git add "\$TD_FILE" + git commit -m "$MSG_COMMIT_MSG" + if [ -e "\$TD_HOOKS_DIR/has-diff" ]; then + git stash pop --quiet + fi +EOF +)" +load_hooks() { + case "${TD_USE_BUILTIN_HOOKS:-}" in + git) + export TD_PRE_ADD_HOOK="${TD_PRE_ADD_HOOK:-$GIT_BUILTIN_PRE_ADD_HOOK}" + export TD_POST_ADD_HOOK="${TD_POST_ADD_HOOK:-$GIT_BUILTIN_POST_ADD_HOOK}" + ;; + *) + ;; + esac +} + +list_hooks() { + for t in git; do + TD_USE_BUILTIN_HOOKS="$t" + load_hooks + printf '%s:\n' "$t" + printf ' TD_PRE_ADD_HOOK:\n' + printf '%s\n' "$TD_PRE_ADD_HOOK" | sed 's/^/ /' + printf ' TD_POST_ADD_HOOK:\n' + printf '%s\n' "$TD_POST_ADD_HOOK" | sed 's/^/ /' + done +} + +pre_add_hook() { + sh -c "${TD_PRE_ADD_HOOK:-}" +} + +post_add_hook() { + sh -c "${TD_POST_ADD_HOOK:-}" +} + + + +# +# HTML pre-processing +# + +html_inject_checkboxes() { + awk '{ + if (match($0, /^(-|[0-9]*.) \[( |x)\] /)) { + printf \ + "%s <input type=\"checkbox\" disabled %s/> %s\n", + $1, + substr($2, 2, 1) == "x" ? "checked " : "", + substr($0, 1 + length($1) + length(" [ ] ")) + } else { + print + } + }' +} + +html_process_tags() { + sed 's|tag:\([^ ]*\)|<span class="tag">\1</span>|g' +} + +html_process_ids() { + STATES_REGEX="$( + echo "$TD_STATES" | + grep . | + paste -sd '|' | + sed 's/|/\\|/g' | + printf '\(%s\)' "$(cat -)" + )" + + sed 's:^## '"$STATES_REGEX"' \(.*\) {#\(.*\)}\(.*\)$:## <a href="#\3"><span class="\1">\1</span> \2</a>\4\ +<pre class="header-anchor" id="\3">#\3</pre>\ +:g' +} + +html_pre_process() { + html_inject_checkboxes | + html_process_tags | + html_process_ids +} + + + +# +# Linting +# + +lint_assert_order() { + GREP_FLAGS="$(echo "$TD_TYPES" | cut -d: -f2- | sed 's/\(.*\)/-e "\1"/' | tr '\n' ' ')" + echo eval "grep -F $GREP_FLAGS $TD_FILE" +} + +known_heading() { + line="$1" + TYPE_HEADINGS="$2" + while read -r heading; do + if [ "$heading" = "$line" ]; then + return 0 + fi + done < "$TYPE_HEADINGS" + return 1 +} + +warning() { + echo "$1" "$2" "$3" +} + +lint() { + TYPE_HEADINGS="$(mkstemp)" + echo "$TD_TYPES" | cut -d: -f2- | sed 's/^/# /' > "$TYPE_HEADINGS" + IN_TD_SECTION=false + IN_TD_ENTRY=false + LINE_NUMBER=0 + while read -r line; do + LINE_NUMBER=$((LINE_NUMBER + 1)) + if [ "$IN_TD_SECTION" = false ]; then + if known_heading "$line" "$TYPE_HEADINGS"; then + IN_TD_SECTION=true + fi + fi + + if [ "$IN_TD_SECTION" = false ]; then + continue + fi + + if echo "$line" | grep -q '^# .*' && + ! known_heading "$line" "$TYPE_HEADINGS"; then + break + else + IN_TD_ENTRY=false + echo "$line" | grep -q '^#.*' + # continue + fi + + if echo "$line" | grep -q '^## .*'; then + IN_TD_ENTRY=true + fi + + if [ "$IN_TD_ENTRY" = false ] && [ "$line" != '' ]; then + warning "$TD_FILE" "$LINE_NUMBER" \ + 'Content outside of td entry' + fi + done < "$TD_FILE" +} + + + +# +# Default values, config "run commands" file and derived values +# + +ID="$(uuid)" +export TD_IDREF="#td-$ID" +export TD_FILE='TODOs.md' +export TD_TYPES="$(cat <<-'EOF' + task:Tasks + bug:Bugs + improvement:Improvements + question:Questions + decision:Decisions + idea:Ideas + proposal:Proposals +EOF +)" +export TD_STATES="$(cat <<-'EOF' + TODO + DOING + WAITING + INACTIVE + NEXT + CANCELLED + DONE + WONTFIX +EOF +)" +export TD_HOOKS_DIR="$(mkdtemp)" + +if [ -r "$PWD/.tdrc" ]; then + . "$PWD/.tdrc" +fi + +DEFAULT_TYPE="$(echo "$TD_TYPES" | awk -F: '{ print $1; exit }')" +DEFAULT_STATE="$(echo "$TD_STATES" | awk -F: '{ print $1; exit }')" +TYPE="$DEFAULT_TYPE" +STATE="$DEFAULT_STATE" +NAME="$(name_for_type "$TYPE")" + +load_hooks + + + +# +# Main +# + +for flag in "$@"; do + case "$flag" in + --) + break + ;; + --help) + usage + help + exit + ;; + --version) + version + exit + ;; + *) + ;; + esac +done + +SHORT=false +MESSAGE=FIXME +while getopts 'ct:s:m:lLHhV' flag; do + case "$flag" in + c) + SHORT=true + ;; + t) + TYPE="$OPTARG" + NAME="$(name_for_type "$TYPE")" + if [ -z "$NAME" ]; then + printf "$MSG_UNREGISTERED_TYPE\n" "$TYPE" >&2 + exit 1 + fi + ;; + s) + STATE="$OPTARG" + if ! echo "$TD_STATES" | grep -q "$STATE"; then + printf "$MSG_UNREGISTERED_STATE\n" "$STATE" >&2 + exit 1 + fi + ;; + m) + MESSAGE="$OPTARG" + ;; + l) + list_hooks + exit + ;; + L) + lint + exit + ;; + H) + html_pre_process < "$TD_FILE" + exit + ;; + h) + usage + help + exit + ;; + V) + version + exit + ;; + *) + usage >&2 + exit 2 + ;; + esac +done +shift $((OPTIND - 1)) + + +TYPE_LINE="$(linenumber_for_type "$TYPE")" +if [ -z "$TYPE_LINE" ]; then + TYPE_LINE=-1 + PREAMBLE="# $(name_for_type "$TYPE")"' + +' +fi +INSERT_LINE=$((TYPE_LINE + 1)) +TITLE_LINE="${PREAMBLE:-}$(printf '## %s %s {%s}\n- %s in %s\n' "$STATE" "$MESSAGE" "$TD_IDREF" "$STATE" "$(date -I)")" + +if [ "$SHORT" = 'true' ] && [ "$MESSAGE" != 'FIXME' ]; then + pre_add_hook + echo "$TITLE_LINE" | insert_at_line "$INSERT_LINE" "$TD_FILE" "$TYPE" + post_add_hook +else + TMPFILE_ORIG="$(mkstemp)" + TMPFILE_COPY="$(mkstemp)" + printf '%s\n\n---\n\nFIXME\n' "$TITLE_LINE" > "$TMPFILE_ORIG" + cp "$TMPFILE_ORIG" "$TMPFILE_COPY" + CMD="${VISUAL:-${EDITOR:-vi}}" + $CMD "$TMPFILE_ORIG" + if diff "$TMPFILE_ORIG" "$TMPFILE_COPY" > /dev/null; then + echo "$MSG_UNEDITED_ENTRY" >&2 + exit 1 + fi + + pre_add_hook + insert_at_line "$INSERT_LINE" "$TD_FILE" "$TYPE" < "$TMPFILE_ORIG" + post_add_hook +fi + +printf "$MSG_ADDED_LOG\n" "$TD_IDREF" "$TD_FILE" >&2 |