diff options
author | Craig Earls <enderw88@gmail.com> | 2011-10-06 22:07:01 -0700 |
---|---|---|
committer | Craig Earls <enderw88@gmail.com> | 2011-10-06 22:07:01 -0700 |
commit | b400d65be082165f44e769605aa6a78133cf6d9a (patch) | |
tree | 27b18ee35a5c4f60a10cf4f626e15ac30276040b /contrib/vim/ftplugin/ledger.vim | |
parent | e9ccb012c2c5ffe0e9f4916ee859bda95d9d4248 (diff) | |
parent | f0791bbd7297e737d9e13d0b0bb21473b173b2a7 (diff) | |
download | fork-ledger-b400d65be082165f44e769605aa6a78133cf6d9a.tar.gz fork-ledger-b400d65be082165f44e769605aa6a78133cf6d9a.tar.bz2 fork-ledger-b400d65be082165f44e769605aa6a78133cf6d9a.zip |
Merge remote branch 'upstream/next' into next
Diffstat (limited to 'contrib/vim/ftplugin/ledger.vim')
-rw-r--r-- | contrib/vim/ftplugin/ledger.vim | 133 |
1 files changed, 96 insertions, 37 deletions
diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index d1c8e1a9..9cc4ed91 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -1,6 +1,5 @@ " Vim filetype plugin file " filetype: ledger -" Version: 0.1.0 " by Johann Klähn; Use according to the terms of the GPL>=2. " vim:ts=2:sw=2:sts=2:foldmethod=marker @@ -137,22 +136,33 @@ function! LedgerComplete(findstart, base) "{{{1 if a:findstart let lnum = line('.') let line = getline('.') - let lastcol = col('.') - 2 let b:compl_context = '' if line =~ '^\s\+[^[:blank:];]' "{{{2 (account) - let b:compl_context = 'account' - if matchend(line, '^\s\+\%(\S \S\|\S\)\+') <= lastcol - " only allow completion when in or at end of account name - return -1 + " only allow completion when in or at end of account name + if matchend(line, '^\s\+\%(\S \S\|\S\)\+') >= col('.') - 1 + " the start of the first non-blank character + " (excluding virtual-transaction-marks) + " is the beginning of the account name + let b:compl_context = 'account' + return matchend(line, '^\s\+[\[(]\?') endif - " the start of the first non-blank character - " (excluding virtual-transaction-marks) - " is the beginning of the account name - return matchend(line, '^\s\+[\[(]\?') - else "}}} - return -1 - endif + elseif line =~ '^\d' "{{{2 (description) + let pre = matchend(line, '^\d\S\+\%(([^)]*)\|[*?!]\|\s\)\+') + if pre < col('.') - 1 + let b:compl_context = 'description' + return pre + endif + elseif line =~ '^$' "{{{2 (new line) + let b:compl_context = 'new' + endif "}}} + return -1 else + if ! exists('b:compl_cache') + let b:compl_cache = s:collect_completion_data() + let b:compl_cache['#'] = changenr() + endif + + let results = [] if b:compl_context == 'account' "{{{2 (account) unlet! b:compl_context let hierarchy = split(a:base, ':') @@ -160,7 +170,7 @@ function! LedgerComplete(findstart, base) "{{{1 call add(hierarchy, '') endif - let results = LedgerFindInTree(LedgerGetAccountHierarchy(), hierarchy) + let results = LedgerFindInTree(b:compl_cache.accounts, hierarchy) " sort by alphabet and reverse because it will get reversed one more time if g:ledger_detailed_first let results = reverse(sort(results, 's:sort_accounts_by_depth')) @@ -168,10 +178,19 @@ function! LedgerComplete(findstart, base) "{{{1 let results = sort(results) endif call insert(results, a:base) - return results - else "}}} + elseif b:compl_context == 'description' "{{{2 (description) + let results = [a:base] + s:filter_items(b:compl_cache.descriptions, a:base) + elseif b:compl_context == 'new' "{{{2 (new line) + return [strftime('%Y/%m/%d')] + endif "}}} + + " no completion (apart from a:base) found. update cache if file has changed + if len(results) <= 1 && b:compl_cache['#'] != changenr() + unlet b:compl_cache + return LedgerComplete(a:findstart, a:base) + else unlet! b:compl_context - return [] + return results endif endif endf "}}} @@ -195,21 +214,6 @@ function! LedgerFindInTree(tree, levels) "{{{1 return results endf "}}} -function! LedgerGetAccountHierarchy() "{{{1 - let hierarchy = {} - let accounts = s:grep_buffer('^\s\+\zs[^[:blank:];]\%(\S \S\|\S\)\+\ze') - for name in accounts - " remove virtual-transaction-marks - let name = substitute(name, '\%(^\s*[\[(]\?\|[\])]\?\s*$\)', '', 'g') - let last = hierarchy - for part in split(name, ':') - let last[part] = get(last, part, {}) - let last = last[part] - endfor - endfor - return hierarchy -endf "}}} - function! LedgerToggleTransactionState(lnum, ...) if a:0 == 1 let chars = a:1 @@ -278,6 +282,51 @@ function! LedgerSetDate(lnum, type, ...) "{{{1 call setline(trans['head'], trans.format_head()) endf "}}} +function! s:collect_completion_data() "{{{1 + let transactions = s:get_transactions() + let cache = {'descriptions': [], 'tags': {}, 'accounts': {}} + let accounts = [] + for xact in transactions + " collect descriptions + if index(cache.descriptions, xact['description']) < 0 + call add(cache.descriptions, xact['description']) + endif + let [t, postings] = xact.parse_body() + let tagdicts = [t] + + " collect account names + for posting in postings + if has_key(posting, 'tags') + call add(tagdicts, posting.tags) + endif + " remove virtual-transaction-marks + let name = substitute(posting.account, '\%(^\s*[\[(]\?\|[\])]\?\s*$\)', '', 'g') + if index(accounts, name) < 0 + call add(accounts, name) + endif + endfor + + " collect tags + for tags in tagdicts | for [tag, val] in items(tags) + let values = get(cache.tags, tag, []) + if index(values, val) < 0 + call add(values, val) + endif + let cache.tags[tag] = values + endfor | endfor + endfor + + for account in accounts + let last = cache.accounts + for part in split(account, ':') + let last[part] = get(last, part, {}) + let last = last[part] + endfor + endfor + + return cache +endf "}}} + let s:transaction = {} "{{{1 function! s:transaction.new() dict return copy(s:transaction) @@ -293,7 +342,15 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 let trans['head'] = head let trans['tail'] = tail - let parts = split(getline(head), '\s\+') + " split off eventual comments at the end of line + let line = split(getline(head), '\ze\s*\%(\t\| \);', 1) + if len(line) > 1 + let trans['appendix'] = join(line[1:], '') + endif + + " parse rest of line + " FIXME (minor): will not preserve spacing (see 'join(parts)') + let parts = split(line[0], '\s\+') if parts[0] ==# '~' let trans['expr'] = join(parts[1:]) return trans @@ -318,8 +375,6 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 call remove(parts, 0) endfor - " FIXME: this will break comments at the end of this 'head' line - " they need 2 spaces in front of the semicolon let trans['description'] = join(parts) return trans endf "}}} @@ -402,7 +457,11 @@ function! s:transaction.format_head() dict "{{{2 if has_key(self, 'code') | call add(parts, '('.self['code'].')') | endif if has_key(self, 'state') | call add(parts, self['state']) | endif if has_key(self, 'description') | call add(parts, self['description']) | endif - return join(parts) + + let line = join(parts) + if has_key(self, 'appendix') | let line .= self['appendix'] | endif + + return line endf "}}} "}}} @@ -518,7 +577,7 @@ endf "}}} " return only those items that start with a specified keyword function! s:filter_items(list, keyword) "{{{2 - return filter(a:list, 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''') + return filter(copy(a:list), 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''') endf "}}} " return all lines matching an expression, returning only the matched part |