From bdc0374f49d32dd7a996113fc49d6abee2a50b24 Mon Sep 17 00:00:00 2001 From: Nathan Grigg Date: Tue, 7 Oct 2014 10:59:11 -0700 Subject: AlignCommodity and Incoming --- .gitignore | 1 + autoload/beancount.vim | 38 ++++++++++++++++++++++++++++++++++++++ doc/beancount.txt | 17 +++++++++++++++++ ftplugin/beancount.vim | 28 ++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 .gitignore create mode 100644 autoload/beancount.vim create mode 100644 doc/beancount.txt create mode 100644 ftplugin/beancount.vim diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0a56e3f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/doc/tags diff --git a/autoload/beancount.vim b/autoload/beancount.vim new file mode 100644 index 0000000..85adc3e --- /dev/null +++ b/autoload/beancount.vim @@ -0,0 +1,38 @@ +" Align currency on decimal point. +function! beancount#align_commodity(line1, line2) + " Saving cursor position to adjust it if necessary. + let cursor_col = col('.') + let cursor_line = line('.') + " This matches the line up to the first dot (or other separator), + " excluding comments. + " Note very nomagic so that the separator is not interpreted as regex. + let separator_regex = '^\V\[^;]\{-}' . g:beancount_decimal_separator + " This lets me increment at start of loop, because of continue statements. + let i = a:line1 - 1 + while i < a:line2 + let i += 1 + let s = getline(i) + " This matches an account name followed by a space. There may be + " some conflicts with non-transaction syntax that I don't know about. + " It won't match a comment or any non-indented line. + let end_acc = matchend(s, '^\v([-\d]+\s+(balance|price))? +\S+ ') + if end_acc < 0 | continue | endif + " Where does commodity amount begin? + let end_space = matchend(s, '^ *', end_acc) + " Find the first decimal point, not counting comments. + let separator = matchend(s, separator_regex, end_space) + if separator < 0 + " If there is no separator, pretend there's one after the last digit. + let separator = matchend(s, '^\v[^;]*\d+') + 1 + endif + if separator < 0 | continue | endif + let has_spaces = end_space - end_acc + let need_spaces = g:beancount_separator_col - separator + has_spaces + if need_spaces < 0 | continue | endif + call setline(i, s[0 : end_acc - 1] . repeat(" ", need_spaces) . s[ end_space : -1]) + if i == cursor_line && cursor_col >= end_acc + " Adjust cursor position for continuity. + call cursor(0, cursor_col + need_spaces - has_spaces) + endif + endwhile +endfunction diff --git a/doc/beancount.txt b/doc/beancount.txt new file mode 100644 index 0000000..6b070c9 --- /dev/null +++ b/doc/beancount.txt @@ -0,0 +1,17 @@ +* `:AlignCommodity` + + adds spaces between an account and commodity so that the decimal points of + the commodities all occur in the column given by `g:decimal_separator_col`. + 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. If the + cursor happens to be inside that range and to the right of the account name, + the cursor will be pushed to the right the appropriate amount, so that it + remains on the same character. + + The alignment character can be set using `g:beancount_decimal_separator`. + The script assumes the use of spaces for alignment. It does not understand + tabs. You might like the following remap: + + inoremap . .:AlignCommodity diff --git a/ftplugin/beancount.vim b/ftplugin/beancount.vim new file mode 100644 index 0000000..f073545 --- /dev/null +++ b/ftplugin/beancount.vim @@ -0,0 +1,28 @@ +" These two variables customize the behavior of the AlignCommodity command. + +if !exists("g:beancount_separator_col") + let g:beancount_separator_col = 50 +endif +if !exists("g:beancount_decimal_separator") + let g:beancount_decimal_separator = "." +endif + +command! -range AlignCommodity :call beancount#align_commodity(, ) + +" Align commodity to proper column +inoremap . .:AlignCommodity +nnoremap = :AlignCommodity +vnoremap = :AlignCommodity + +" Insert incoming transactions at the bottom +function! s:InsertIncoming() + let incoming = expand('%:h') . '/incoming.bean' + try + execute '$read' incoming + call system('mv ' . incoming . ' ' . incoming . '~') + catch /:E484/ + echom "Not found: incoming.bean" + endtry +endfunction + +command! -buffer Incoming call InsertIncoming() -- cgit v1.2.3-2-gb3c3