Imported vim-ledger https://github.com/ledger/vim-ledger @ 6eb3bb2
authorTomas Zeman <tzeman@volny.cz>
Wed, 23 May 2018 20:33:08 +0200
changeset 54 21fabe8ab141
parent 53 09b1d3c0aa20
child 55 abd59697f009
Imported vim-ledger https://github.com/ledger/vim-ledger @ 6eb3bb2
config/.vim/autoload/ledger.vim
config/.vim/compiler/ledger.vim
config/.vim/doc/ledger.txt
config/.vim/ftdetect/ledger.vim
config/.vim/ftplugin/ledger.vim
config/.vim/indent/ledger.vim
config/.vim/syntax/ledger.vim
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/.vim/autoload/ledger.vim	Wed May 23 20:33:08 2018 +0200
@@ -0,0 +1,685 @@
+" vim:ts=2:sw=2:sts=2:foldmethod=marker
+function! ledger#transaction_state_toggle(lnum, ...)
+  if a:0 == 1
+    let chars = a:1
+  else
+    let chars = ' *'
+  endif
+  let trans = s:transaction.from_lnum(a:lnum)
+  if empty(trans) || has_key(trans, 'expr')
+    return
+  endif
+
+  let old = has_key(trans, 'state') ? trans['state'] : ' '
+  let i = stridx(chars, old) + 1
+  let new = chars[i >= len(chars) ? 0 : i]
+
+  call trans.set_state(new)
+
+  call setline(trans['head'], trans.format_head())
+endf
+
+function! ledger#transaction_state_set(lnum, char)
+  " modifies or sets the state of the transaction at the cursor,
+  " removing the state altogether if a:char is empty
+  let trans = s:transaction.from_lnum(a:lnum)
+  if empty(trans) || has_key(trans, 'expr')
+    return
+  endif
+
+  call trans.set_state(a:char)
+
+  call setline(trans['head'], trans.format_head())
+endf
+
+function! ledger#transaction_date_set(lnum, type, ...) "{{{1
+  let time = a:0 == 1 ? a:1 : localtime()
+  let trans = s:transaction.from_lnum(a:lnum)
+  if empty(trans) || has_key(trans, 'expr')
+    return
+  endif
+
+  let formatted = strftime(g:ledger_date_format, time)
+  if has_key(trans, 'date') && ! empty(trans['date'])
+    let date = split(trans['date'], '=')
+  else
+    let date = [formatted]
+  endif
+
+  if a:type =~? 'effective\|actual'
+    echoerr "actual/effective arguments were replaced by primary/auxiliary"
+    return
+  endif
+
+  if a:type ==? 'primary'
+    let date[0] = formatted
+  elseif a:type ==? 'auxiliary'
+    if time < 0
+      " remove auxiliary date
+      let date = [date[0]]
+    else
+      " set auxiliary date
+      if len(date) >= 2
+        let date[1] = formatted
+      else
+        call add(date, formatted)
+      endif
+    endif
+  elseif a:type ==? 'unshift'
+    let date = [formatted, date[0]]
+  endif
+
+  let trans['date'] = join(date[0:1], '=')
+
+  call setline(trans['head'], trans.format_head())
+endf "}}}
+
+" == get transactions ==
+
+function! ledger#transaction_from_lnum(lnum)
+  return s:transaction.from_lnum(a:lnum)
+endf
+
+function! ledger#transactions(...)
+  if a:0 == 2
+    let lnum = a:1
+    let end = a:2
+  elseif a:0 == 0
+    let lnum = 1
+    let end = line('$')
+  else
+    throw "wrong number of arguments for get_transactions()"
+    return []
+  endif
+
+  " safe view / position
+  let view = winsaveview()
+  let fe = &foldenable
+  set nofoldenable
+
+  let transactions = []
+  call cursor(lnum, 0)
+  while lnum && lnum <= end
+    let trans = s:transaction.from_lnum(lnum)
+    if ! empty(trans)
+      call add(transactions, trans)
+      call cursor(trans['tail'], 0)
+    endif
+    let lnum = search('^[~=[:digit:]]', 'cW')
+  endw
+
+  " restore view / position
+  let &foldenable = fe
+  call winrestview(view)
+
+  return transactions
+endf
+
+" == transaction object implementation ==
+
+let s:transaction = {} "{{{1
+function! s:transaction.new() dict
+  return copy(s:transaction)
+endf
+
+function! s:transaction.from_lnum(lnum) dict "{{{2
+  let [head, tail] = s:get_transaction_extents(a:lnum)
+  if ! head
+    return {}
+  endif
+
+  let trans = copy(s:transaction)
+  let trans['head'] = head
+  let trans['tail'] = tail
+
+  " 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
+  elseif parts[0] ==# '='
+    let trans['auto'] = join(parts[1:])
+    return trans
+  elseif parts[0] !~ '^\d'
+    " this case is avoided in s:get_transaction_extents(),
+    " but we'll check anyway.
+    return {}
+  endif
+
+  for part in parts
+    if     ! has_key(trans, 'date')  && part =~ '^\d'
+      let trans['date'] = part
+    elseif ! has_key(trans, 'code')  && part =~ '^([^)]*)$'
+      let trans['code'] = part[1:-2]
+    elseif ! has_key(trans, 'state') && part =~ '^[[:punct:]]$'
+      " the first character by itself is assumed to be the state of the transaction.
+      let trans['state'] = part
+    else
+      " everything after date/code or state belongs to the description
+      break
+    endif
+    call remove(parts, 0)
+  endfor
+
+  let trans['description'] = join(parts)
+  return trans
+endf "}}}
+
+function! s:transaction.set_state(char) dict "{{{2
+  if has_key(self, 'state') && a:char =~ '^\s*$'
+    call remove(self, 'state')
+  else
+    let self['state'] = a:char
+  endif
+endf "}}}
+
+function! s:transaction.parse_body(...) dict "{{{2
+  if a:0 == 2
+    let head = a:1
+    let tail = a:2
+  elseif a:0 == 0
+    let head = self['head']
+    let tail = self['tail']
+  else
+    throw "wrong number of arguments for parse_body()"
+    return []
+  endif
+
+  if ! head || tail <= head
+    return []
+  endif
+
+  let lnum = head
+  let tags = {}
+  let postings = []
+  while lnum <= tail
+    let line = split(getline(lnum), '\s*\%(\t\|  \);', 1)
+
+    if line[0] =~ '^\s\+[^[:blank:];]'
+      " posting
+      let [state, rest] = matchlist(line[0], '^\s\+\([*!]\?\)\s*\(.*\)$')[1:2]
+      if rest =~ '\t\|  '
+        let [account, amount] = matchlist(rest, '^\(.\{-}\)\%(\t\|  \)\s*\(.\{-}\)\s*$')[1:2]
+      else
+        let amount = ''
+        let account = matchstr(rest, '^\s*\zs.\{-}\ze\s*$')
+      endif
+      call add(postings, {'account': account, 'amount': amount, 'state': state})
+    end
+
+    " where are tags to be stored?
+    if empty(postings)
+      " they belong to the transaction
+      let tag_container = tags
+    else
+      " they belong to last posting
+      if ! has_key(postings[-1], 'tags')
+        let postings[-1]['tags'] = {}
+      endif
+      let tag_container = postings[-1]['tags']
+    endif
+
+    let comment = join(line[1:], '  ;')
+    if comment =~ '^\s*:'
+      " tags without values
+      for t in s:findall(comment, ':\zs[^:[:blank:]]\([^:]*[^:[:blank:]]\)\?\ze:')
+        let tag_container[t] = ''
+      endfor
+    elseif comment =~ '^\s*[^:[:blank:]][^:]\+:'
+      " tag with value
+      let key = matchstr(comment, '^\s*\zs[^:]\+\ze:')
+      if ! empty(key)
+        let val = matchstr(comment, ':\s*\zs.*\ze\s*$')
+        let tag_container[key] = val
+      endif
+    endif
+    let lnum += 1
+  endw
+  return [tags, postings]
+endf "}}}
+
+function! s:transaction.format_head() dict "{{{2
+  if has_key(self, 'expr')
+    return '~ '.self['expr']
+  elseif has_key(self, 'auto')
+    return '= '.self['auto']
+  endif
+
+  let parts = []
+  if has_key(self, 'date') | call add(parts, self['date']) | endif
+  if has_key(self, 'state') | call add(parts, self['state']) | endif
+  if has_key(self, 'code') | call add(parts, '('.self['code'].')') | endif
+  if has_key(self, 'description') | call add(parts, self['description']) | endif
+
+  let line = join(parts)
+  if has_key(self, 'appendix') | let line .= self['appendix'] | endif
+
+  return line
+endf "}}}
+"}}}
+
+" == helper functions ==
+
+function! s:get_transaction_extents(lnum)
+  if ! (indent(a:lnum) || getline(a:lnum) =~ '^[~=[:digit:]]')
+    " only do something if lnum is in a transaction
+    return [0, 0]
+  endif
+
+  " safe view / position
+  let view = winsaveview()
+  let fe = &foldenable
+  set nofoldenable
+
+  call cursor(a:lnum, 0)
+  let head = search('^[~=[:digit:]]', 'bcnW')
+  let tail = search('^[^;[:blank:]]\S\+', 'nW')
+  let tail = tail > head ? tail - 1 : line('$')
+
+  " restore view / position
+  let &foldenable = fe
+  call winrestview(view)
+
+  return head ? [head, tail] : [0, 0]
+endf
+
+function! ledger#find_in_tree(tree, levels)
+  if empty(a:levels)
+    return []
+  endif
+  let results = []
+  let currentlvl = a:levels[0]
+  let nextlvls = a:levels[1:]
+  let branches = ledger#filter_items(keys(a:tree), currentlvl)
+  for branch in branches
+    let exact = empty(nextlvls)
+    call add(results, [branch, exact])
+    if ! empty(nextlvls)
+      for [result, exact] in ledger#find_in_tree(a:tree[branch], nextlvls)
+        call add(results, [branch.':'.result, exact])
+      endfor
+    endif
+  endfor
+  return results
+endf
+
+function! ledger#filter_items(list, keyword)
+  " return only those items that start with a specified keyword
+  return filter(copy(a:list), 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''')
+endf
+
+function! s:findall(text, rx)
+  " returns all the matches in a string,
+  " there will be overlapping matches according to :help match()
+  let matches = []
+
+  while 1
+    let m = matchstr(a:text, a:rx, 0, len(matches)+1)
+    if empty(m)
+      break
+    endif
+
+    call add(matches, m)
+  endw
+
+  return matches
+endf
+
+" Move the cursor to the specified column, filling the line with spaces if necessary.
+function! s:goto_col(pos)
+  exec "normal!" a:pos . "|"
+  let diff = a:pos - virtcol('.')
+  if diff > 0 | exec "normal!" diff . "a " | endif
+endf
+
+" Return substring position (in chars).
+function! s:strpos(expr, pat)
+  let pos = match(a:expr, a:pat)
+  if pos > 0
+    let pos = strchars(a:expr[:pos]) - 1
+  endif
+  return pos
+endf
+
+" Align the amount expression after an account name at the decimal point.
+"
+" This function moves the amount expression of a posting so that the decimal
+" separator is aligned at the column specified by g:ledger_align_at.
+"
+" For example, after selecting:
+"
+"   2015/05/09 Some Payee
+"     Expenses:Other    $120,23  ; Tags here
+"     Expenses:Something  $-4,99
+"     Expenses:More                 ($12,34 + $16,32)
+"
+"  :'<,'>call ledger#align_commodity() produces:
+"
+"   2015/05/09 Some Payee
+"      Expenses:Other                                    $120,23  ; Tags here
+"      Expenses:Something                                 $-4,99
+"      Expenses:More                                     ($12,34 + $16,32)
+"
+function! ledger#align_commodity()
+  " Extract the part of the line after the account name (excluding spaces):
+  let rhs = matchstr(getline('.'), '\m^\s\+[^;[:space:]].\{-}\(\t\|  \)\s*\zs.*$')
+  if rhs != ''
+    " Remove everything after the account name (including spaces):
+    .s/\m^\s\+[^[:space:]].\{-}\zs\(\t\|  \).*$//
+    if g:ledger_decimal_sep == ''
+      let pos = matchend(rhs, '\m\d[^[:space:]]*')
+    else
+      " Find the position of the first decimal separator:
+      let pos = s:strpos(rhs, '\V' . g:ledger_decimal_sep)
+    endif
+    " Go to the column that allows us to align the decimal separator at g:ledger_align_at:
+    if pos > 0
+      call s:goto_col(g:ledger_align_at - pos - 1)
+    else
+      call s:goto_col(g:ledger_align_at - strdisplaywidth(rhs) - 2)
+    endif
+    " Append the part of the line that was previously removed:
+    exe 'normal! a' . rhs
+  endif
+endf!
+
+" Align the amount under the cursor and append/prepend the default currency.
+function! ledger#align_amount_at_cursor()
+  " Select and cut text:
+  normal! viWd
+  " Find the position of the decimal separator
+  let pos = s:strpos(@", '\V' . g:ledger_decimal_sep) " Returns zero when the separator is the empty string
+  if pos <= 0
+    let pos = len(@")
+  endif
+  " Paste text at the correct column and append/prepend default commodity:
+  if g:ledger_commodity_before
+    call s:goto_col(g:ledger_align_at - pos - len(g:ledger_default_commodity) - len(g:ledger_commodity_sep) - 1)
+    exe 'normal! a' . g:ledger_default_commodity . g:ledger_commodity_sep
+    normal! p
+  else
+    call s:goto_col(g:ledger_align_at - pos - 1)
+    exe 'normal! pa' . g:ledger_commodity_sep . g:ledger_default_commodity
+  endif
+endf!
+
+" Report generation {{{1
+
+" Helper functions and variables {{{2
+" Position of report windows
+let s:winpos_map = {
+      \ "T": "to new",  "t": "abo new", "B": "bo new",  "b": "bel new",
+      \ "L": "to vnew", "l": "abo vnew", "R": "bo vnew", "r": "bel vnew"
+      \ }
+
+function! s:error_message(msg)
+  redraw  " See h:echo-redraw
+  echohl ErrorMsg
+  echo "\r"
+  echomsg a:msg
+  echohl NONE
+endf
+
+function! s:warning_message(msg)
+  redraw  " See h:echo-redraw
+  echohl WarningMsg
+  echo "\r"
+  echomsg a:msg
+  echohl NONE
+endf
+
+" Open the quickfix/location window when it is not empty,
+" closes it if it is empty.
+"
+" Optional parameters:
+" a:1  Quickfix window title.
+" a:2  Message to show when the window is empty.
+"
+" Returns 0 if the quickfix window is empty, 1 otherwise.
+function! s:quickfix_toggle(...)
+  if g:ledger_use_location_list
+    let l:list = 'l'
+    let l:open = (len(getloclist(winnr())) > 0)
+  else
+    let l:list = 'c'
+    let l:open = (len(getqflist()) > 0)
+  endif
+
+  if l:open
+    execute (g:ledger_qf_vertical ? 'vert' : 'botright') l:list.'open' g:ledger_qf_size
+    " Set local mappings to quit the quickfix window  or lose focus.
+    nnoremap <silent> <buffer> <tab> <c-w><c-w>
+    execute 'nnoremap <silent> <buffer> q :' l:list.'close<CR>'
+    " Note that the following settings do not persist (e.g., when you close and re-open the quickfix window).
+    " See: https://superuser.com/questions/356912/how-do-i-change-the-quickix-title-status-bar-in-vim
+    if g:ledger_qf_hide_file
+      setl conceallevel=2
+      setl concealcursor=nc
+      syntax match qfFile /^[^|]*/ transparent conceal
+    endif
+    if a:0 > 0
+      let w:quickfix_title = a:1
+    endif
+    return 1
+  endif
+
+  execute l:list.'close'
+  call s:warning_message((a:0 > 1) ? a:2 : 'No results')
+  return 0
+endf
+
+" Populate a quickfix/location window with data. The argument must be a String
+" or a List.
+function! s:quickfix_populate(data)
+  " Note that cexpr/lexpr always uses the global value of errorformat
+  let l:efm = &errorformat  " Save global errorformat
+  set errorformat=%EWhile\ parsing\ file\ \"%f\"\\,\ line\ %l:,%ZError:\ %m,%-C%.%#
+  set errorformat+=%tarning:\ \"%f\"\\,\ line\ %l:\ %m
+  " Format to parse command-line errors:
+  set errorformat+=Error:\ %m
+  " Format to parse reports:
+  set errorformat+=%f:%l\ %m
+  set errorformat+=%-G%.%#
+  execute (g:ledger_use_location_list ? 'l' : 'c').'getexpr' 'a:data'
+  let &errorformat = l:efm  " Restore global errorformat
+  return
+endf
+
+" Build a ledger command to process the given file.
+function! s:ledger_cmd(file, args)
+  return join([g:ledger_bin, g:ledger_extra_options, '-f', shellescape(expand(a:file)), a:args])
+endf
+" }}}
+
+function! ledger#autocomplete_and_align()
+  if pumvisible()
+    return "\<c-n>"
+  endif
+  " Align an amount only if there is a digit immediately before the cursor and
+  " such digit is preceded by at least one space (the latter condition is
+  " necessary to avoid situations where a date starting at the first column is
+  " confused with a commodity to be aligned).
+  if match(getline('.'), '\s.*\d\%'.col('.').'c') > -1
+    norm h
+    call ledger#align_amount_at_cursor()
+    return "\<c-o>A"
+  endif
+  return "\<c-x>\<c-o>"
+endf
+
+" Use current line as input to ledger entry and replace with output. If there
+" are errors, they are echoed instead.
+func! ledger#entry()
+  let l:output = systemlist(s:ledger_cmd(g:ledger_main, join(["entry", getline('.')])))
+  " Filter out warnings
+  let l:output = filter(l:output, "v:val !~? '^Warning: '")
+  " Errors may occur
+  if v:shell_error
+    echomsg join(l:output)
+    return
+  endif
+  " Append output so we insert instead of overwrite, then delete line
+  call append('.', l:output)
+  normal! "_dd
+endfunc
+
+" Run an arbitrary ledger command and show the output in a new buffer. If
+" there are errors, no new buffer is opened: the errors are displayed in a
+" quickfix window instead.
+"
+" Parameters:
+" file  The file to be processed.
+" args  A string of Ledger command-line arguments.
+"
+" Returns:
+" Ledger's output as a String.
+function! ledger#report(file, args)
+  let l:output = systemlist(s:ledger_cmd(a:file, a:args))
+  if v:shell_error  " If there are errors, show them in a quickfix/location list.
+    call s:quickfix_populate(l:output)
+    call s:quickfix_toggle('Errors', 'Unable to parse errors')
+  endif
+  return l:output
+endf
+
+" Open the output of a Ledger's command in a new buffer.
+"
+" Parameters:
+" report  A String containing the output of a Ledger's command.
+"
+" Returns:
+" 1 if a new buffer is created; 0 otherwise.
+function! ledger#output(report)
+  if empty(a:report)
+    call s:warning_message('No results')
+    return 0
+  endif
+  " Open a new buffer to show Ledger's output.
+  execute get(s:winpos_map, g:ledger_winpos, "bo new")
+  setlocal buftype=nofile bufhidden=wipe modifiable nobuflisted noswapfile nowrap
+  call append(0, a:report)
+  setlocal nomodifiable
+  " Set local mappings to quit window or lose focus.
+  nnoremap <silent> <buffer> <tab> <c-w><c-p>
+  nnoremap <silent> <buffer> q <c-w><c-p>@=winnr("#")<cr><c-w>c
+  " Add some coloring to the report
+  syntax match LedgerNumber /-\@1<!\d\+\([,.]\d\+\)\+/
+  syntax match LedgerNegativeNumber /-\d\+\([,.]\d\+\)\+/
+  syntax match LedgerImproperPerc /\d\d\d\+%/
+  return 1
+endf
+
+" Show an arbitrary register report in a quickfix list.
+"
+" Parameters:
+" file  The file to be processed
+" args  A string of Ledger command-line arguments.
+function! ledger#register(file, args)
+  let l:cmd = s:ledger_cmd(a:file, join([
+        \ "register",
+        \ "--format='" . g:ledger_qf_register_format . "'",
+        \ "--prepend-format='%(filename):%(beg_line) '",
+        \ a:args
+        \ ]))
+  call s:quickfix_populate(systemlist(l:cmd))
+  call s:quickfix_toggle('Register report')
+endf
+
+" Reconcile the given account.
+" This function accepts a file path as a third optional argument.
+" The default is to use the value of g:ledger_main.
+"
+" Parameters:
+" file  The file to be processed
+" account  An account name (String)
+" target_amount The target amount (Float)
+function! ledger#reconcile(file, account, target_amount)
+  let l:cmd = s:ledger_cmd(a:file, join([
+        \ "register",
+        \ "--uncleared",
+        \ "--format='" . g:ledger_qf_reconcile_format . "'",
+        \ "--prepend-format='%(filename):%(beg_line) %(pending ? \"P\" : \"U\") '",
+        \ a:account
+        \ ]))
+  let l:file = expand(a:file) " Needed for #show_balance() later
+  call s:quickfix_populate(systemlist(l:cmd))
+  if s:quickfix_toggle("Reconcile " . a:account, "Nothing to reconcile")
+    let g:ledger_target_amount = a:target_amount
+    " Show updated account balance upon saving, as long as the quickfix window is open
+    augroup reconcile
+      autocmd!
+      execute "autocmd BufWritePost *.ldg,*.ledger call ledger#show_balance('" . l:file . "','" . a:account . "')"
+      autocmd BufWipeout <buffer> call <sid>finish_reconciling()
+    augroup END
+    " Add refresh shortcut
+    execute "nnoremap <silent> <buffer> <c-l> :<c-u>call ledger#reconcile('"
+          \ . l:file . "','" . a:account . "'," . string(a:target_amount) . ")<cr>"
+    call ledger#show_balance(l:file, a:account)
+  endif
+endf
+
+function! s:finish_reconciling()
+  unlet g:ledger_target_amount
+  augroup reconcile
+    autocmd!
+  augroup END
+  augroup! reconcile
+endf
+
+" Show the pending/cleared balance of an account.
+" This function has an optional parameter:
+"
+" a:1  An account name
+"
+" If no account if given, the account in the current line is used.
+function! ledger#show_balance(file, ...)
+  let l:account = a:0 > 0 && !empty(a:1) ? a:1 : matchstr(getline('.'), '\m\(  \|\t\)\zs\S.\{-}\ze\(  \|\t\|$\)')
+  if empty(l:account)
+    call s:error_message('No account found')
+    return
+  endif
+  let l:cmd = s:ledger_cmd(a:file, join([
+        \ "cleared",
+        \ l:account,
+        \ "--empty",
+        \ "--collapse",
+        \ "--format='%(scrub(get_at(display_total, 0)))|%(scrub(get_at(display_total, 1)))|%(quantity(scrub(get_at(display_total, 1))))'",
+        \ (empty(g:ledger_default_commodity) ? '' : "-X " . shellescape(g:ledger_default_commodity))
+        \ ]))
+  let l:output = systemlist(l:cmd)
+  " Errors may occur, for example,  when the account has multiple commodities
+  " and g:ledger_default_commodity is empty.
+  if v:shell_error
+    call s:quickfix_populate(l:output)
+    call s:quickfix_toggle('Errors', 'Unable to parse errors')
+    return
+  endif
+  let l:amounts = split(l:output[-1], '|')
+  redraw  " Necessary in some cases to overwrite previous messages. See :h echo-redraw
+  if len(l:amounts) < 3
+    call s:error_message("Could not determine balance. Did you use a valid account?")
+    return
+  endif
+  echo g:ledger_pending_string
+  echohl LedgerPending
+  echon l:amounts[0]
+  echohl NONE
+  echon ' ' g:ledger_cleared_string
+  echohl LedgerCleared
+  echon l:amounts[1]
+  echohl NONE
+  if exists('g:ledger_target_amount')
+    echon ' ' g:ledger_target_string
+    echohl LedgerTarget
+    echon printf('%.2f', (g:ledger_target_amount - str2float(l:amounts[2])))
+    echohl NONE
+  endif
+endf
+" }}}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/.vim/compiler/ledger.vim	Wed May 23 20:33:08 2018 +0200
@@ -0,0 +1,29 @@
+" Vim Compiler File
+" Compiler:	ledger
+" by Johann Klähn; Use according to the terms of the GPL>=2.
+" vim:ts=2:sw=2:sts=2:foldmethod=marker
+
+if exists("current_compiler")
+  finish
+endif
+let current_compiler = "ledger"
+
+if exists(":CompilerSet") != 2
+  command -nargs=* CompilerSet setlocal <args>
+endif
+
+" default value will be set in ftplugin
+if ! exists("g:ledger_bin") || empty(g:ledger_bin) || ! executable(g:ledger_bin)
+  finish
+endif
+
+" Capture Ledger errors (%-C ignores all lines between "While parsing..." and "Error:..."):
+CompilerSet errorformat=%EWhile\ parsing\ file\ \"%f\"\\,\ line\ %l:,%ZError:\ %m,%-C%.%#
+" Capture Ledger warnings:
+CompilerSet errorformat+=%tarning:\ \"%f\"\\,\ line\ %l:\ %m
+" Skip all other lines:
+CompilerSet errorformat+=%-G%.%#
+
+" Check file syntax
+exe 'CompilerSet makeprg='.substitute(g:ledger_bin, ' ', '\\ ', 'g').'\ '.substitute(g:ledger_extra_options, ' ', '\\ ', 'g').'\ source\ %:S'
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/.vim/doc/ledger.txt	Wed May 23 20:33:08 2018 +0200
@@ -0,0 +1,418 @@
+*ledger.txt* Plugin for the ledger filetype.
+
+
+                                                  *ledger* *ledger-plugin*
+
+Contents:
+
+        Commands............|ledger-invoking|
+        Source................|ledger-source|
+        Usage..................|ledger-usage|
+        Tips....................|ledger-tips|
+        Reports..............|ledger-reports|
+        Settings............|ledger-settings|
+        Completion........|ledger-completion|
+        License..............|ledger-license|
+
+
+==============================================================================
+USAGE                                                           *ledger-usage*
+
+Copy each file to the corresponding directory in your ~/.vim directory or
+install using Pathogen.
+
+You can also use a modeline like this in every ledger file:
+
+    vim:filetype=ledger
+
+==============================================================================
+TIPS                                                             *ledger-tips*
+
+Tips and useful commands
+
+* vim-ledger can do syntax-sensitive folding when you set `foldmethod=syntax`
+  in the |modeline| of your ledger file. This way transactions can shrink down
+  to just one line.
+
+* Try account-completion (as explained below). If you use YouCompleteMe, you
+  should disable it for Ledger files. Put this in your .vimrc:
+
+        if exists('g:ycm_filetype_blacklist')
+          call extend(g:ycm_filetype_blacklist, { 'ledger': 1 })
+        endif
+
+* You may use `:make` for syntax checking. It may be convenient to define a
+  mapping for the following command:
+
+	:silent make | redraw! | cwindow
+
+  It is recommended to set the value of `g:ledger_extra_options` (see below)
+  as follows:
+
+        let g:ledger_extra_options = '--pedantic --explicit --check-payees'
+
+  to catch most potential problems in your source file.
+
+* Remap vim paragraph motion to move by transaction.
+
+  In vim, the "{" and "}" keystrokes move the cursor up and down by whole
+  paragraphs. They can be redefined in ledger files to move by transaction
+  instead. Add these lines to .vimrc:
+
+        au FileType ledger noremap { ?^\d<CR>
+        au FileType ledger noremap } /^\d<CR>
+
+  The default definitions already work in ledger files that separate
+  transactions with blank lines.
+
+* `:call ledger#transaction_date_set('.'), "auxiliary")`
+
+  will set today's date as the auxiliary date of the current transaction. You
+  can use also "primary" or "unshift" in place of "auxiliary". When you pass
+  "unshift" the old primary date will be set as the auxiliary date and today's
+  date will be set as the new primary date.
+  To use a different date pass a date measured in seconds since 1st Jan 1970
+  as the third argument.
+
+* `:call ledger#transaction_state_set(line('.'), '*')`
+
+  sets the state of the current transaction to '*'. You can use this in custom
+  mappings.
+
+* `:call ledger#transaction_state_toggle(line('.'), ' *?!')`
+
+  will toggle through the provided transaction states. You can map this to
+  double-clicking for example:
+
+        noremap <silent><buffer> <2-LeftMouse>\
+        :call ledger#transaction_state_toggle(line('.'), ' *?!')<CR>
+
+* `:LedgerAlign`
+
+  moves the amount expression of a posting so that the decimal separator is
+  aligned at the column specified by g:ledger_align_at. If an amount has no
+  decimal point, the imaginary decimal point to the right of the least
+  significant digit will align. The command acts on a range, with the default
+  being the current line.
+
+  The decimal separator can be set using `g:ledger_decimal_sep`. The default
+  value of `g:ledger_decimal_sep` is `'.'`.
+
+  See below for the recommended mappings.
+
+* `:call ledger#align_amount_at_cursor()`
+
+  aligns the amount under the cursor and append/prepend the default currency.
+  The default currency can be set using `g:ledger_default_commodity`. Whether
+  the commodity should be inserted before the amount or appended to it can be
+  configured with the boolean flag `g:ledger_commodity_before` (the default
+  value is 1). A separator between the commodity and the amount may be set
+  using `g:ledger_commodity_sep`.
+
+  See below for the recommended mappings.
+
+* `:call ledger#autocomplete_and_align()`
+
+  when the cursor is on a number or immediately after it, invokes
+  `ledger#align_amount_at_cursor()` to align it and add the default currency;
+  otherwise, performs autocompletion. If you define the following mappings in
+  your `.vimrc` then you may perform both autocompletion and alignment using
+  the <Tab> key:
+
+        au FileType ledger inoremap <silent> <Tab> \
+        <C-r>=ledger#autocomplete_and_align()<CR>
+        au FileType ledger vnoremap <silent> <Tab> :LedgerAlign<CR>
+
+  Alternatively, you may create a file `.vim/after/ftplugin/ledger.vim`
+  containing the following definitions:
+
+        inoremap <silent> <buffer> <Tab> \
+        <C-r>=ledger#autocomplete_and_align()<CR>
+        vnoremap <silent> <buffer> <Tab> :LedgerAlign<CR>
+
+  Now, you may type `asset:check<Tab><Space>123.45<Tab>`, and have the
+  account name autocompleted and `$123.45` properly aligned (assuming your
+  default commodity is set to `'$'`). Or you may press <Tab> in Visual mode
+  to align a number of transactions at once.
+
+* `:call ledger#entry()`
+
+  enters a new transaction based on the text in the current line.
+  The text in the current line is replaced by the new transaction.
+  This is a front end to `ledger entry`.
+
+==============================================================================
+REPORTS                                                      *ledger-reports*
+
+* `:Ledger`
+
+  Executes an arbitrary Ledger command and sends the output to a new buffer.
+  For example:
+
+        :Ledger bal ^assets ^liab
+
+  Errors are displayed in a quickfix window. The command offers account and
+  payee autocompletion (by pressing <Tab>): every name starting with `@` is
+  autocompleted as a payee; any other name is autocompleted as an account.
+
+  In a report buffer or in the quickfix window, you may press <Tab> to switch
+  back to your source file, and you may press `q` to dismiss the current window.
+
+  There are three highlight groups that are used to color the report:
+
+  * `LedgerNumber`
+
+    This is used to color nonnegative numbers.
+
+  * `LedgerNegativeNumber`
+
+    This is used to color negative numbers.
+
+  * `LedgerImproperPerc`
+
+    This is used to color improper percentages.
+
+* `:Balance`
+
+  Show the pending and cleared balance of a given account below the status
+  line. For example:
+
+	:Balance checking:savings
+
+  The command offers payee and account autocompletion (see `:Ledger`). The
+  account argument is optional: if no argument is given, the first account
+  name found in the current line is used.
+
+  Two highlight groups can be used to customize the colors of the line:
+
+  * `LedgerCleared`
+
+    This is used to color the cleared balance.
+
+  * `LedgerPending`
+
+    This is used to color the pending balance.
+
+* `:Register`
+
+  Opens an arbitrary register report in the quickfix window. For example:
+
+	:Register groceries -p 'this month'
+
+  The command offers account and payee autocompletion (see |:Ledger|). You
+  may use the standard quickfix commands to jump from an entry in the register
+  report to the corresponding location in the source file. If you use GUI Vim
+  or if your terminal has support for the mouse (e.g., iTerm2, or even
+  Terminal.app in OS X 10.11 or later), you may also double-click on a line
+  number in the quickfix window to jump to the corresponding posting.
+
+  It is strongly recommended that you add mappings for common quickfix
+  commands like `:cprev` and `:cnext`, or that you use T. Pope's Unimpaired
+  plugin.
+
+* :`Reconcile`
+
+  Reconcile an account. For example:
+
+	:Reconcile checking
+
+  After you press Enter, you will be asked to enter a target amount (use
+  Vim's syntax for numbers, not your ledger's format). For example, for a
+  checking account, the target amount may be the balance of your latest bank
+  statement. The list of uncleared postings appears in the quickfix window.
+  The current balance of the account, together with the difference between the
+  target amount and the cleared balance, is shown at the bottom of the screen.
+  You may use standard quickfix commands to navigate through the postings. You
+  may use |ledger#transaction_state_set()| to update a transaction's state.
+  Every time you save your file, the balance and the difference from the
+  target amount are updated at the bottom of the screen. The goal, of course,
+  is to get such difference to zero. You may press `<C-l>` to refresh the
+  Reconcile buffer. To finish reconciling an account, simply close the
+  quickfix window.
+
+  There is a highlight group to customize the color of the difference from
+  target:
+
+  * `LedgerTarget`
+
+    This is used to color the difference between the target amount and the
+    cleared balance.
+
+==============================================================================
+SETTINGS                                                     *ledger-settings*
+
+Configuration
+
+Include the following let-statements somewhere in your `.vimrc` to modify the
+behaviour of the ledger filetype.
+
+* Path to the `ledger` executable:
+
+	let g:ledger_bin = 'ledger'
+
+* Additional default options for the `ledger` executable:
+
+	let g:ledger_extra_options = ''
+
+* Number of columns that will be used to display the foldtext. Set this when
+  you think that the amount is too far off to the right.
+
+        let g:ledger_maxwidth = 80
+
+* String that will be used to fill the space between account name and amount in
+  the foldtext. Set this to get some kind of lines or visual aid.
+
+        let g:ledger_fillstring = '    -'
+
+* If you want the account completion to be sorted by level of detail/depth
+  instead of alphabetical, include the following line:
+
+        let g:ledger_detailed_first = 1
+
+* By default vim will fold ledger transactions, leaving surrounding blank lines
+  unfolded. You can use 'g:ledger_fold_blanks' to hide blank lines following a
+  transaction.
+
+        let g:ledger_fold_blanks = 0
+
+  A value of 0 will disable folding of blank lines, 1 will allow folding of a
+  single blank line between transactions; any larger value will enable folding
+  unconditionally.
+
+  Note that only lines containing no trailing spaces are considered for
+  folding. You can take advantage of this to disable this feature on a
+  case-by-case basis.
+
+* Decimal separator:
+
+        let g:ledger_decimal_sep = '.'
+
+* Specify at which column decimal separators should be aligned:
+
+        let g:ledger_align_at = 60
+
+* Default commodity used by `ledger#align_amount_at_cursor()`:
+
+        let g:ledger_default_commodity = ''
+
+* Flag that tells whether the commodity should be prepended or appended to the
+  amount:
+
+        let g:ledger_commodity_before = 1
+
+* String to be put between the commodity and the amount:
+
+        let g:ledger_commodity_sep = ''
+
+* Format of transaction date:
+
+        let g:ledger_date_format = '%Y/%m/%d'
+
+* The file to be used to generate reports:
+
+        let g:ledger_main = '%'
+
+  The default is to use the current file.
+
+* Position of a report buffer:
+
+        let g:ledger_winpos = 'B'
+
+  Use `b` for bottom, `t` for top, `l` for left, `r` for right. Use uppercase letters
+  if you want the window to always occupy the full width or height.
+
+* Format of quickfix register reports (see |:Register|):
+
+	let g:ledger_qf_register_format = \
+        '%(date) %-50(payee) %-30(account) %15(amount) %15(total)\n'
+
+  The format is specified using the standard Ledger syntax for --format.
+
+* Format of the reconcile quickfix window (see |:Reconcile|):
+
+	let g:ledger_qf_reconcile_format = \
+        '%(date) %-4(code) %-50(payee) %-30(account) %15(amount)\n'
+
+  The format is specified using the standard Ledger syntax for --format.
+
+* Flag that tells whether a location list or a quickfix list should be used:
+
+	let g:ledger_use_location_list = 0
+
+  The default is to use the quickfix window. Set to 1 to use a location list.
+
+* Position of the quickfix/location list:
+
+	let g:ledger_qf_vertical = 0
+
+  Set to 1 to open the quickfix window in a vertical split.
+
+* Size of the quickfix window:
+
+	let g:ledger_qf_size = 10
+
+  This is the number of lines of a horizontal quickfix window, or the number
+  of columns of a vertical quickfix window.
+
+* Flag to show or hide filenames in the quickfix window:
+
+	let g:ledger_qf_hide_file = 1
+
+  Filenames in the quickfix window are hidden by default. Set this to 1 is
+  you want filenames to be visible.
+
+* Text of the output of the |:Balance| command:
+
+	let g:ledger_cleared_string = 'Cleared: '
+	let g:ledger_pending_string = 'Cleared or pending: '
+	let g:ledger_target_string = 'Difference from target: '
+
+==============================================================================
+COMPLETION                                                 *ledger-completion*
+
+Omni completion is currently implemented for account names only.
+
+### Accounts
+
+Account names are matched by the start of every sub-level. When you
+insert an account name like this:
+
+    Asse<C-X><C-O>
+
+You will get a list of top-level accounts that start like this.
+
+Go ahead and try something like:
+
+    As:Ban:Che<C-X><C-O>
+
+When you have an account like this, 'Assets:Bank:Checking' should show up.
+
+When you want to complete on a virtual transaction, it's currently best
+to keep the cursor in front of the closing bracket. Of course you can
+insert the closing bracket after calling the completion, too.
+
+==============================================================================
+LICENSE                                                       *ledger-license*
+
+https://github.com/ledger/vim-ledger
+
+Copyright 2009-2013 Johann Klähn
+Copyright 2009 Stefan Karrmann
+Copyright 2005 Wolfgang Oertl
+
+This program is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation, either version 2 of the License, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with this program. If not, see <https://www.gnu.org/licenses/>.
+
+
+vim:ts=8 sw=8 noexpandtab tw=78 ft=help:
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/.vim/ftdetect/ledger.vim	Wed May 23 20:33:08 2018 +0200
@@ -0,0 +1,1 @@
+autocmd BufEnter,BufRead *.ldg,*.ledger setlocal filetype=ledger | compiler ledger
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/.vim/ftplugin/ledger.vim	Wed May 23 20:33:08 2018 +0200
@@ -0,0 +1,445 @@
+" Vim filetype plugin file
+" filetype: ledger
+" by Johann Klähn; Use according to the terms of the GPL>=2.
+" vim:ts=2:sw=2:sts=2:foldmethod=marker
+
+if exists("b:did_ftplugin")
+  finish
+endif
+
+let b:did_ftplugin = 1
+
+let b:undo_ftplugin = "setlocal ".
+                    \ "foldtext< ".
+                    \ "include< comments< commentstring< omnifunc< formatprg<"
+
+setl foldtext=LedgerFoldText()
+setl include=^!\\?include
+setl comments=b:;
+setl commentstring=;%s
+setl omnifunc=LedgerComplete
+
+" set location of ledger binary for checking and auto-formatting
+if ! exists("g:ledger_bin") || empty(g:ledger_bin) || ! executable(g:ledger_bin)
+  if executable('ledger')
+    let g:ledger_bin = 'ledger'
+  else
+    unlet! g:ledger_bin
+    echohl WarningMsg
+    echomsg "ledger command not found. Set g:ledger_bin or extend $PATH ".
+          \ "to enable error checking and auto-formatting."
+    echohl None
+  endif
+endif
+
+if exists("g:ledger_bin")
+  exe 'setl formatprg='.substitute(g:ledger_bin, ' ', '\\ ', 'g').'\ -f\ -\ print'
+endif
+
+if !exists('g:ledger_extra_options')
+  let g:ledger_extra_options = ''
+endif
+
+if !exists('g:ledger_date_format')
+  let g:ledger_date_format = '%Y/%m/%d'
+endif
+
+" You can set a maximal number of columns the fold text (excluding amount)
+" will use by overriding g:ledger_maxwidth in your .vimrc.
+" When maxwidth is zero, the amount will be displayed at the far right side
+" of the screen.
+if !exists('g:ledger_maxwidth')
+  let g:ledger_maxwidth = 0
+endif
+
+if !exists('g:ledger_fillstring')
+  let g:ledger_fillstring = ' '
+endif
+
+if !exists('g:ledger_decimal_sep')
+  let g:ledger_decimal_sep = '.'
+endif
+
+if !exists('g:ledger_align_at')
+  let g:ledger_align_at = 60
+endif
+
+if !exists('g:ledger_default_commodity')
+  let g:ledger_default_commodity = ''
+endif
+
+if !exists('g:ledger_commodity_before')
+  let g:ledger_commodity_before = 1
+endif
+
+if !exists('g:ledger_commodity_sep')
+  let g:ledger_commodity_sep = ''
+endif
+
+" If enabled this will list the most detailed matches at the top {{{
+" of the completion list.
+" For example when you have some accounts like this:
+"   A:Ba:Bu
+"   A:Bu:Bu
+" and you complete on A:B:B normal behaviour may be the following
+"   A:B:B
+"   A:Bu:Bu
+"   A:Bu
+"   A:Ba:Bu
+"   A:Ba
+"   A
+" with this option turned on it will be
+"   A:B:B
+"   A:Bu:Bu
+"   A:Ba:Bu
+"   A:Bu
+"   A:Ba
+"   A
+" }}}
+if !exists('g:ledger_detailed_first')
+  let g:ledger_detailed_first = 1
+endif
+
+" only display exact matches (no parent accounts etc.)
+if !exists('g:ledger_exact_only')
+  let g:ledger_exact_only = 0
+endif
+
+" display original text / account name as completion
+if !exists('g:ledger_include_original')
+  let g:ledger_include_original = 0
+endif
+
+" Settings for Ledger reports {{{
+if !exists('g:ledger_main')
+  let g:ledger_main = '%'
+endif
+
+if !exists('g:ledger_winpos')
+  let g:ledger_winpos = 'B'  " Window position (see s:winpos_map)
+endif
+
+if !exists('g:ledger_use_location_list')
+  let g:ledger_use_location_list = 0  " Use quickfix list by default
+endif
+
+if !exists('g:ledger_cleared_string')
+  let g:ledger_cleared_string = 'Cleared: '
+endif
+
+if !exists('g:ledger_pending_string')
+  let g:ledger_pending_string = 'Cleared or pending: '
+endif
+
+if !exists('g:ledger_target_string')
+  let g:ledger_target_string = 'Difference from target: '
+endif
+" }}}
+
+" Settings for the quickfix window {{{
+if !exists('g:ledger_qf_register_format')
+  let g:ledger_qf_register_format = '%(date) %-50(payee) %-30(account) %15(amount) %15(total)\n'
+endif
+
+if !exists('g:ledger_qf_reconcile_format')
+  let g:ledger_qf_reconcile_format = '%(date) %-4(code) %-50(payee) %-30(account) %15(amount)\n'
+endif
+
+if !exists('g:ledger_qf_size')
+  let g:ledger_qf_size = 10  " Size of the quickfix window
+endif
+
+if !exists('g:ledger_qf_vertical')
+  let g:ledger_qf_vertical = 0
+endif
+
+if !exists('g:ledger_qf_hide_file')
+  let g:ledger_qf_hide_file = 1
+endif
+" }}}
+
+" Highlight groups for Ledger reports {{{
+hi! link LedgerNumber Number
+hi! link LedgerNegativeNumber Special
+hi! link LedgerCleared Constant
+hi! link LedgerPending Todo
+hi! link LedgerTarget Statement
+hi! link LedgerImproperPerc Special
+" }}}
+
+let s:rx_amount = '\('.
+                \   '\%([0-9]\+\)'.
+                \   '\%([,.][0-9]\+\)*'.
+                \ '\|'.
+                \   '[,.][0-9]\+'.
+                \ '\)'.
+                \ '\s*\%([[:alpha:]¢$€£]\+\s*\)\?'.
+                \ '\%(\s*;.*\)\?$'
+
+function! LedgerFoldText() "{{{1
+  " find amount
+  let amount = ""
+  let lnum = v:foldstart
+  while lnum <= v:foldend
+    let line = getline(lnum)
+
+    " Skip metadata/leading comment
+    if line !~ '^\%(\s\+;\|\d\)'
+      " No comment, look for amount...
+      let groups = matchlist(line, s:rx_amount)
+      if ! empty(groups)
+        let amount = groups[1]
+        break
+      endif
+    endif
+    let lnum += 1
+  endwhile
+
+  let fmt = '%s %s '
+  " strip whitespace at beginning and end of line
+  let foldtext = substitute(getline(v:foldstart),
+                          \ '\(^\s\+\|\s\+$\)', '', 'g')
+
+  " number of columns foldtext can use
+  let columns = s:get_columns()
+  if g:ledger_maxwidth
+    let columns = min([columns, g:ledger_maxwidth])
+  endif
+  let columns -= s:multibyte_strlen(printf(fmt, '', amount))
+
+  " add spaces so the text is always long enough when we strip it
+  " to a certain width (fake table)
+  if strlen(g:ledger_fillstring)
+    " add extra spaces so fillstring aligns
+    let filen = s:multibyte_strlen(g:ledger_fillstring)
+    let folen = s:multibyte_strlen(foldtext)
+    let foldtext .= repeat(' ', filen - (folen%filen))
+
+    let foldtext .= repeat(g:ledger_fillstring,
+                  \ s:get_columns()/filen)
+  else
+    let foldtext .= repeat(' ', s:get_columns())
+  endif
+
+  " we don't use slices[:5], because that messes up multibyte characters
+  let foldtext = substitute(foldtext, '.\{'.columns.'}\zs.*$', '', '')
+
+  return printf(fmt, foldtext, amount)
+endfunction "}}}
+
+function! LedgerComplete(findstart, base) "{{{1
+  if a:findstart
+    let lnum = line('.')
+    let line = getline('.')
+    let b:compl_context = ''
+    if line =~ '^\s\+[^[:blank:];]' "{{{2 (account)
+      " 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 and 'cleared' marks)
+        " is the beginning of the account name
+        let b:compl_context = 'account'
+        return matchend(line, '^\s\+[*!]\?\s*[\[(]\?')
+      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 update_cache = 0
+
+    let results = []
+    if b:compl_context == 'account' "{{{2 (account)
+      let hierarchy = split(a:base, ':')
+      if a:base =~ ':$'
+        call add(hierarchy, '')
+      endif
+
+      let results = ledger#find_in_tree(b:compl_cache.accounts, hierarchy)
+      let exacts = filter(copy(results), 'v:val[1]')
+
+      if len(exacts) < 1
+        " update cache if we have no exact matches
+        let update_cache = 1
+      endif
+
+      if g:ledger_exact_only
+        let results = exacts
+      endif
+
+      call map(results, 'v:val[0]')
+
+      if g:ledger_detailed_first
+        let results = reverse(sort(results, 's:sort_accounts_by_depth'))
+      else
+        let results = sort(results)
+      endif
+    elseif b:compl_context == 'description' "{{{2 (description)
+      let results = ledger#filter_items(b:compl_cache.descriptions, a:base)
+
+      if len(results) < 1
+        let update_cache = 1
+      endif
+    elseif b:compl_context == 'new' "{{{2 (new line)
+      return [strftime(g:ledger_date_format)]
+    endif "}}}
+
+
+    if g:ledger_include_original
+      call insert(results, a:base)
+    endif
+
+    " no completion (apart from a:base) found. update cache if file has changed
+    if update_cache && b:compl_cache['#'] != changenr()
+      unlet b:compl_cache
+      return LedgerComplete(a:findstart, a:base)
+    else
+      unlet! b:compl_context
+      return results
+    endif
+  endif
+endf "}}}
+
+" Deprecated functions {{{1
+let s:deprecated = {
+  \ 'LedgerToggleTransactionState': 'ledger#transaction_state_toggle',
+  \ 'LedgerSetTransactionState': 'ledger#transaction_state_set',
+  \ 'LedgerSetDate': 'ledger#transaction_date_set'
+  \ }
+
+for [s:old, s:new] in items(s:deprecated)
+  let s:fun = "function! {s:old}(...)\nechohl WarningMsg\necho '" . s:old .
+            \ " is deprecated. Use ".s:new." instead!'\nechohl None\n" .
+            \ "call call('" . s:new . "', a:000)\nendf"
+  exe s:fun
+endfor
+unlet s:old s:new s:fun
+" }}}1
+
+function! s:collect_completion_data() "{{{1
+  let transactions = ledger#transactions()
+  let cache = {'descriptions': [], 'tags': {}, 'accounts': {}}
+  let accounts = []
+  for xact in transactions
+    " collect descriptions
+    if has_key(xact, 'description') && 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 "}}}
+
+" Helper functions {{{1
+
+" return length of string with fix for multibyte characters
+function! s:multibyte_strlen(text) "{{{2
+   return strlen(substitute(a:text, ".", "x", "g"))
+endfunction "}}}
+
+" get # of visible/usable columns in current window
+function! s:get_columns() " {{{2
+  " As long as vim doesn't provide a command natively,
+  " we have to compute the available columns.
+  " see :help todo.txt -> /Add argument to winwidth()/
+
+  let columns = (winwidth(0) == 0 ? 80 : winwidth(0)) - &foldcolumn
+  if &number
+    " line('w$') is the line number of the last line
+    let columns -= max([len(line('w$'))+1, &numberwidth])
+  endif
+
+  " are there any signs/is the sign column displayed?
+  redir => signs
+  silent execute 'sign place buffer='.string(bufnr("%"))
+  redir END
+  if signs =~# 'id='
+    let columns -= 2
+  endif
+
+  return columns
+endf "}}}
+
+function! s:sort_accounts_by_depth(name1, name2) "{{{2
+  let depth1 = s:count_expression(a:name1, ':')
+  let depth2 = s:count_expression(a:name2, ':')
+  return depth1 == depth2 ? 0 : depth1 > depth2 ? 1 : -1
+endf "}}}
+
+function! s:count_expression(text, expression) "{{{2
+  return len(split(a:text, a:expression, 1))-1
+endf "}}}
+
+function! s:autocomplete_account_or_payee(argLead, cmdLine, cursorPos) "{{{2
+  return (a:argLead =~ '^@') ?
+        \ map(filter(systemlist(g:ledger_bin . ' -f ' . shellescape(expand(g:ledger_main)) . ' payees'),
+        \ "v:val =~? '" . strpart(a:argLead, 1) . "' && v:val !~? '^Warning: '"), '"@" . escape(v:val, " ")')
+        \ :
+        \ map(filter(systemlist(g:ledger_bin . ' -f ' . shellescape(expand(g:ledger_main)) . ' accounts'),
+        \ "v:val =~? '" . a:argLead . "' && v:val !~? '^Warning: '"), 'escape(v:val, " ")')
+endf "}}}
+
+function! s:reconcile(file, account) "{{{2
+  " call inputsave()
+  let l:amount = input('Target amount' . (empty(g:ledger_default_commodity) ? ': ' : ' (' . g:ledger_default_commodity . '): '))
+  " call inputrestore()
+  call ledger#reconcile(a:file, a:account, str2float(l:amount))
+endf "}}}
+
+" Commands {{{1
+command! -buffer -nargs=? -complete=customlist,s:autocomplete_account_or_payee
+      \ Balance call ledger#show_balance(g:ledger_main, <q-args>)
+
+command! -buffer -nargs=+ -complete=customlist,s:autocomplete_account_or_payee
+      \ Ledger call ledger#output(ledger#report(g:ledger_main, <q-args>))
+
+command! -buffer -range LedgerAlign <line1>,<line2>call ledger#align_commodity()
+
+command! -buffer -nargs=1 -complete=customlist,s:autocomplete_account_or_payee
+      \ Reconcile call <sid>reconcile(g:ledger_main, <q-args>)
+
+command! -buffer -complete=customlist,s:autocomplete_account_or_payee -nargs=*
+      \ Register call ledger#register(g:ledger_main, <q-args>)
+" }}}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/.vim/indent/ledger.vim	Wed May 23 20:33:08 2018 +0200
@@ -0,0 +1,46 @@
+" Vim filetype indent file
+" filetype: ledger
+" by Johann Klähn; Use according to the terms of the GPL>=2.
+" vim:ts=2:sw=2:sts=2:foldmethod=marker
+
+if exists("b:did_indent")
+  finish
+endif
+let b:did_indent = 1
+
+setl autoindent
+setl indentexpr=GetLedgerIndent()
+
+if exists("*GetLedgerIndent")
+  finish
+endif
+
+function GetLedgerIndent(...)
+  " You can pass in a line number when calling this function manually.
+  let lnum = a:0 > 0 ? a:1 : v:lnum
+  " If this line is empty look at (the indentation of) the last line.
+  " Note that inside of a transaction no blank lines are allowed.
+  let line = getline(lnum)
+  let prev = getline(lnum - 1)
+
+  if line =~ '^\s\+\S'
+    " Lines that already are indented (→postings, sub-directives) keep their indentation.
+    return &sw
+  elseif line =~ '^\s*$'
+    " Current line is empty, try to guess its type based on the previous line.
+    if prev =~ '^\([[:digit:]~=]\|\s\+\S\)'
+      " This is very likely a posting or a sub-directive.
+      " While lines following the start of a transaction are automatically
+      " indented you will have to indent the first line following a
+      " pre-declaration manually. This makes it easier to type long lists of
+      " 'account' pre-declarations without sub-directives, for example.
+      return &sw
+    else
+      return 0
+    endif
+  else
+    " Everything else is not indented:
+    " start of transactions, pre-declarations, apply/end-lines
+    return 0
+  endif
+endf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/config/.vim/syntax/ledger.vim	Wed May 23 20:33:08 2018 +0200
@@ -0,0 +1,102 @@
+" Vim syntax file
+" filetype: ledger
+" by Johann Klähn; Use according to the terms of the GPL>=2.
+" by Stefan Karrmann; Use according to the terms of the GPL>=2.
+" by Wolfgang Oertl; Use according to the terms of the GPL>=2.
+" vim:ts=2:sw=2:sts=2:foldmethod=marker
+
+if version < 600
+  syntax clear
+elseif exists("b:current_sytax")
+  finish
+endif
+
+" Force old regex engine (:help two-engines)
+let s:oe = v:version < 704 ? '' : '\%#=1'
+let s:lb1 = v:version < 704 ? '\@<=' : '\@1<='
+
+let s:fb = get(g:, 'ledger_fold_blanks', 0)
+let s:skip = s:fb > 0 ? '\|^\n' : ''
+if s:fb == 1
+  let s:skip .= '\n\@!'
+endif
+
+" for debugging
+syntax clear
+
+" DATE[=EDATE] [*|!] [(CODE)] DESC <-- first line of transaction
+"   ACCOUNT AMOUNT [; NOTE]  <-- posting
+
+exe 'syn region ledgerTransaction start=/^[[:digit:]~=]/ '.
+  \ 'skip=/^\s'. s:skip . '/ end=/^/ fold keepend transparent '.
+  \ 'contains=ledgerTransactionDate,ledgerMetadata,ledgerPosting,ledgerTransactionExpression'
+syn match ledgerTransactionDate /^\d\S\+/ contained
+syn match ledgerTransactionExpression /^[=~]\s\+\zs.*/ contained
+syn match ledgerPosting /^\s\+[^[:blank:];][^;]*\ze\%($\|;\)/
+    \ contained transparent contains=ledgerAccount,ledgerAmount,ledgerMetadata
+" every space in an account name shall be surrounded by two non-spaces
+" every account name ends with a tab, two spaces or the end of the line
+exe 'syn match ledgerAccount '.
+  \ '/'.s:oe.'^\s\+\zs\%(\S'.s:lb1.' \S\|\S\)\+\ze\%(  \|\t\|\s*$\)/ contained'
+exe 'syn match ledgerAmount '.
+  \ '/'.s:oe.'\S'.s:lb1.'\%(  \|\t\)\s*\zs\%([^;[:space:]]\|\s\+[^;[:space:]]\)\+/ contained'
+
+syn region ledgerPreDeclaration start=/^\(account\|payee\|commodity\|tag\)/ skip=/^\s/ end=/^/
+    \ keepend transparent
+    \ contains=ledgerPreDeclarationType,ledgerPreDeclarationName,ledgerPreDeclarationDirective
+syn match ledgerPreDeclarationType /^\(account\|payee\|commodity\|tag\)/ contained
+syn match ledgerPreDeclarationName /^\S\+\s\+\zs.*/ contained
+syn match ledgerPreDeclarationDirective /^\s\+\zs\S\+/ contained
+
+syn match ledgerDirective
+  \ /^\%(alias\|assert\|bucket\|capture\|check\|define\|expr\|fixed\|include\|year\)\s/
+syn match ledgerOneCharDirective /^\%(P\|A\|Y\|N\|D\|C\)\s/
+
+syn region ledgerBlockComment start=/^comment/ end=/^end comment/
+syn region ledgerBlockTest start=/^test/ end=/^end test/
+syn match ledgerComment /^[;|*#].*$/
+" comments at eol must be preceded by at least 2 spaces / 1 tab
+syn region ledgerMetadata start=/\%(  \|\t\|^\s\+\);/ skip=/^\s\+;/ end=/^/
+    \ keepend contained contains=ledgerTags,ledgerValueTag,ledgerTypedTag
+exe 'syn match ledgerTags '.
+    \ '/'.s:oe.'\%(\%(;\s*\|^tag\s\+\)\)\@<='.
+    \ ':[^:[:space:]][^:]*\%(::\?[^:[:space:]][^:]*\)*:\s*$/ '.
+    \ 'contained contains=ledgerTag'
+syn match ledgerTag /:\zs[^:]\+\ze:/ contained
+exe 'syn match ledgerValueTag '.
+  \ '/'.s:oe.'\%(\%(;\|^tag\)[^:]\+\)\@<=[^:]\+:\ze.\+$/ contained'
+exe 'syn match ledgerTypedTag '.
+  \ '/'.s:oe.'\%(\%(;\|^tag\)[^:]\+\)\@<=[^:]\+::\ze.\+$/ contained'
+
+syn region ledgerApply
+    \ matchgroup=ledgerStartApply start=/^apply\>/
+    \ matchgroup=ledgerEndApply end=/^end\s\+apply\>/
+    \ contains=ledgerApplyHead,ledgerApply,ledgerTransaction,ledgerComment
+exe 'syn match ledgerApplyHead '.
+  \ '/'.s:oe.'\%(^apply\s\+\)\@<=\S.*$/ contained'
+
+highlight default link ledgerComment Comment
+highlight default link ledgerBlockComment Comment
+highlight default link ledgerBlockTest Comment
+highlight default link ledgerTransactionDate Constant
+highlight default link ledgerTransactionExpression Statement
+highlight default link ledgerMetadata Tag
+highlight default link ledgerTypedTag Keyword
+highlight default link ledgerValueTag Type
+highlight default link ledgerTag Type
+highlight default link ledgerStartApply Tag
+highlight default link ledgerEndApply Tag
+highlight default link ledgerApplyHead Type
+highlight default link ledgerAccount Identifier
+highlight default link ledgerAmount Number
+highlight default link ledgerPreDeclarationType Type
+highlight default link ledgerPreDeclarationName Identifier
+highlight default link ledgerPreDeclarationDirective Type
+highlight default link ledgerDirective Type
+highlight default link ledgerOneCharDirective Type
+ 
+" syncinc is easy: search for the first transaction.
+syn sync clear
+syn sync match ledgerSync grouphere ledgerTransaction "^[[:digit:]~=]"
+ 
+let b:current_syntax = "ledger"