aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Grigg2015-05-14 19:11:11 -0700
committerNathan Grigg2015-05-15 06:33:43 -0700
commitc3ed247909501c093a1c9ccb7f47e1b4a960c06f (patch)
treeb4191c787e6451680bac768c9f72195827ad8a5b
parent81c47b3c2a72e494c47d6ec2b2c7b5cae348eeda (diff)
downloadvim-beancount-c3ed247909501c093a1c9ccb7f47e1b4a960c06f.tar.gz
Follow include statements when completing accounts
Uses Python script to seek through multiple files for accounts, following 'include' statements. The list of accounts is cached to 'b:beancount_accounts'. You can specify the root file using 'b:beancount_root', and if this is not set, we assume the current file is the root. Included files that are not found are silently skipped. Closes #5.
-rw-r--r--autoload/beancount.vim66
1 files changed, 55 insertions, 11 deletions
diff --git a/autoload/beancount.vim b/autoload/beancount.vim
index 49b06df..9cd1168 100644
--- a/autoload/beancount.vim
+++ b/autoload/beancount.vim
@@ -48,19 +48,63 @@ function! beancount#complete_account(findstart, base)
endif
endif
- let l:pattern = '^\V\.\{10\}\s\+open\s\+\zs\S\*' .
- \ substitute(a:base, ":", '\\S\\*:\\S\\*', "g")
- let l:view = winsaveview()
- let l:fe = &foldenable
- set nofoldenable
- call cursor(1, 1)
+ if !exists('b:beancount_accounts')
+ if exists('b:beancount_root')
+ let l:root = b:beancount_root
+ else
+ let l:root = expand('%')
+ endif
+ let b:beancount_accounts = beancount#find_accounts(l:root)
+ endif
+ let l:pattern = '\V' . substitute(a:base, ":", '\\S\\*:\\S\\*', "g")
let l:matches = []
+ let l:index = -1
while 1
- let l:cline = search(pattern, "W")
- if l:cline == 0 | break | endif
- call add(matches, expand("<cWORD>"))
+ let l:index = match(b:beancount_accounts, l:pattern, l:index + 1)
+ if l:index == -1 | break | endif
+ call add(l:matches, b:beancount_accounts[l:index])
endwhile
- let &foldenable = l:fe
- call winrestview(l:view)
return l:matches
endfunction
+
+" Get list of acounts.
+function! beancount#find_accounts(root_file)
+ python << EOM
+import collections
+import os
+import re
+import sys
+import vim
+
+RE_INCLUDE = re.compile(r'^include\s+"([^\n"]+)"')
+RE_ACCOUNT = re.compile(r'^\d{4,}-\d{2}-\d{2}\s+open\s+(\S+)')
+
+def combine_paths(old, new):
+ return os.path.normpath(
+ new if os.path.isabs(new) else os.path.join(old, new))
+
+def parse_file(fh, files, accounts):
+ regexes = ((RE_INCLUDE, files), (RE_ACCOUNT, accounts))
+ for line in fh:
+ m = RE_INCLUDE.match(line)
+ if m: files.append(combine_paths(os.path.dirname(fh.name), m.group(1)))
+ m = RE_ACCOUNT.match(line)
+ if m: accounts.add(m.group(1))
+
+files = collections.deque([vim.eval("a:root_file")])
+accounts = set()
+seen = set()
+while files:
+ current = files.popleft()
+ if current in seen:
+ continue
+ seen.add(current)
+ try:
+ with open(current, 'r') as fh:
+ parse_file(fh, files, accounts)
+ except IOError as err:
+ pass
+
+vim.command('return [{}]'.format(','.join(repr(x) for x in sorted(accounts))))
+EOM
+endfunction