#compdef hledger

# ------------------------------------------------------------------------------
# Description
# -----------
#
#  Completion script for hleder 0.23.2 ( http://hledger.org/ )
#  Last updated: 16.11.2014
#
# ------------------------------------------------------------------------------
# Authors
# -------
#
#  * Valodim ( https://github.com/Valodim )
#
# ------------------------------------------------------------------------------
# Notes
# -----
#
# account completion depends on availability of a ~/.hledger.journal file
#
# ------------------------------------------------------------------------------


local curcontext="$curcontext" curstate state line expl grp cmd ret=1
typeset -a args
typeset -A opt_args

args=(
  '(- *)'{-h,--help}'[print help information]'
  '(-f --file)'{-f,--file}'=[use a different input file]:input file:_files'
  '--rules-file=[CSV conversion rules file]:rules file:_files'
  '--alias=[display accounts named OLD as NEW]:alias specification'
  '(-b --begin)'{-b,--begin}'=[include postings/txns on or after this date]:date'
  '(-e --end)'{-e,--end}'=[include postings/txns before this date]:date'
  '(-D --daily)'{-D,--daily}'[multiperiod/multicolumn report by day]'
  '(-W --weekly)'{-W,--weekly}'[multiperiod/multicolumn report by week]'
  '(-M --monthly)'{-M,--monthly}'[multiperiod/multicolumn report by month]'
  '(-Q --quarterly)'{-Q,--quarterly}'[multiperiod/multicolumn report by quarter]'
  '(-Y --yearly)'{-Y,--yearly}'[multiperiod/multicolumn report by year]'
  '(-p --period)'{-p,--period}'=[set start date, end date, and/or reporting interval all at once]'
  '(-C --cleared)'{-C,--cleared}'[include only cleared postings/txns]'
  '(-U --uncleared)'{-U,--uncleared}'[include only uncleared postings/txns]'
  '(-R --real)'{-R,--real}'[include only non-virtual postings]'
  '(--depth)--depth=[hide accounts/postings deeper than N]:depth'
  '(-E --empty)'{-E,--empty}'[show empty/zero things which are normally omitted]'
  '(-B --cost)'{-B,--cost}'[show amounts in their cost price'\''s commodity]'
)

_arguments -C "$args[@]" -A "-*" \
  '(- *)--version[print version information]' \
  '--debug[show debug output]' \
  '1: :->cmds' \
  '*:: :->args' && ret=0

while (( $#state )); do
  curstate=$state
  shift state
  case $curstate in
    cmds)
        typeset -a cmds
        cmds=(
            'print:show transaction entries'
            'accounts:show account names'
            'balance:show accounts and balances (bal)'
            'register:show postings and running total (reg)'
            'incomestatement:show an income statement (is)'
            'balancesheet:show a balance sheet (bs)'
            'cashflow:show a cashflow statement (cf)'
            'activity:show an ascii barchart of posting counts per interval'
            'stats:show some journal statistics'
        )
        _describe 'subcommands' cmds && ret=0
        ;;
    args)
        : $words
        local cmd=$words[1]
        (( $+cmd )) || return 1
        # curcontext="${curcontext%:*:*}:$service-$cmd:"
        case $cmd in
            accounts)
                args+=(
                    '(--tree)--tree[show accounts as a tree (default in simple reports)]'
                    '(--flat)--flat[show accounts as a list (default in multicolumn)]'
                    '(--drop)--drop=[flat mode, omit N leading account name parts]:drop n'
                )
                ;;
            activity)
                ;;
            bal|balance)
                args+=(
                    '(--tree)--tree[show accounts as a tree (default in simple reports)]'
                    '(--flat)--flat[show accounts as a list (default in multicolumn)]'
                    '(--drop)--drop=[in flat mode, omit N leading account name parts]:drop n'
                    '(--format)--format=[in tree mode, use this custom line format]:custom line format'
                    '(--no-elide)--no-elide[tree mode, do not squash boring parent accounts]'
                    '(--no-total)--no-total[do not show the final total]'
                    '(--cumulative)--cumulative[multicolumn mode, show accumulated ending balances]'
                    '(-H --historical)'{-H,--historical}'[multicolumn mode, show historical ending balances]'
                )
                ;;
            cashflow|cf|balancesheet|bs|incomestatement|is)
                args+=(
                    '(--flat)--flat[show accounts as a list (default in multicolumn)]'
                    '(--drop)--drop=[in flat mode, omit N leading account name parts]:drop n'
                )
                ;;
            print)
                ;;
            register|reg)
                args+=(
                      '(-H --historical)'{-H,--historical}'[include prior postings in the running total]'
                      '(-A --average)'{-A,--average}'[show a running average instead of the running total]'
                      '(-r --related)'{-r,--related}'[show postings'\'' siblings instead]'
                      '(-w --width)'{-w,--width}'=[set output width to 120, or N]:width (default 80)'
                )
                ;;
            stats)
                ;;
            # fallback to _default
            *) _arguments -C -A "-*" "$args[@]" \
                    '*: :_default' && ret=0
               continue
        esac
        _arguments -C -A "-*" "$args[@]" \
            '*:query patterns:->query' && ret=0
        ;;
        query)

            local -a accs keywords
            keywords=(
                'code\::match by transaction code'
                'desc\::match transaction descriptions'
                'tag\::match by tag name'
                'depth\::match at or above depth'
                'status\::match cleared/uncleared transactions'
                'real\::match real/virtual transactions'
                'empty\::match if amount is/is not zero'
                'amt\::match transaction amount'
            )
            if compset -P 'amt:'; then
                _message 'match amount (<, <=, >, >=, add sign for non-absolute match)' && ret=0
                continue
            fi
            if compset -P '(#b)(code|desc|tag|depth|status|real|empty):'; then
                _message "'$match[1]' parameter" && ret=0
                continue
            fi

            accs=( ${(f)"$(_call_program hledger hledger accounts $PREFIX 2>/dev/null)"} )
            if (( $? )); then
                _message "error fetching accounts from hledger"
            fi

            # decided against partial matching here. these lines can
            # be uncommented to complete subaccounts hierarchically
            # (add -S '' -q to the compadd below, too)
            # if compset -P '(#b)(*):'; then
                # accs=( ${(M)accs:#$match[1]:*} )
                # accs=( ${accs#$IPREFIX} )
            # fi
            # accs=( ${accs%%:*} )

            _wanted accounts expl "accounts" compadd -a accs && ret=0
            _describe "matcher keywords" keywords -S '' && ret=0

            # not is special, it doesn't need the -S ''
            keywords=(
                'not:negate expression'
            )
            _describe "matcher keywords" keywords && ret=0

        ;;
    esac
done

return ret
