summaryrefslogtreecommitdiff
path: root/contrib/vim/ftplugin/ledger.vim
diff options
context:
space:
mode:
authorCraig Earls <enderw88@gmail.com>2011-10-06 22:07:01 -0700
committerCraig Earls <enderw88@gmail.com>2011-10-06 22:07:01 -0700
commitb400d65be082165f44e769605aa6a78133cf6d9a (patch)
tree27b18ee35a5c4f60a10cf4f626e15ac30276040b /contrib/vim/ftplugin/ledger.vim
parente9ccb012c2c5ffe0e9f4916ee859bda95d9d4248 (diff)
parentf0791bbd7297e737d9e13d0b0bb21473b173b2a7 (diff)
downloadfork-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.vim133
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