From 04f564f01c9395188c1bc0d890745ad15eb3fc2f Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 7 Sep 2010 17:59:26 +0200 Subject: vim. use ledger print as 'formatprg' You can now try to select some lines using V (visual mode) and have them automatically formatted using gq --- contrib/vim/ftplugin/ledger.vim | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index d75a6869..c5354508 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -12,7 +12,7 @@ let b:did_ftplugin = 1 let b:undo_ftplugin = "setlocal ". \ "foldmethod< foldtext< ". - \ "include< comments< omnifunc< " + \ "include< comments< omnifunc< formatprg<" " don't fill fold lines --> cleaner look setl fillchars="fold: " @@ -22,6 +22,21 @@ setl include=^!include setl comments=b:; setl omnifunc=LedgerComplete +" set location of ledger binary for checking and auto-formatting +if ! exists("g:ledger_bin") || empty(g:ledger_bin) || ! executable(split(g:ledger_bin, '\s')[0]) + if executable('ledger') + let g:ledger_bin = 'ledger' + else + unlet g:ledger_bin + echoerr "ledger command not found. Set g:ledger_bin or extend $PATH ". + \ "to enable error checking and auto-formatting." + endif +endif + +if exists("g:ledger_bin") + exe 'setl formatprg='.substitute(g:ledger_bin, ' ', '\\ ', 'g').'\ -f\ -\ print' +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 -- cgit v1.2.3 From 2dff4dea3f27084c4daad5c6f89201eea7b4036b Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Tue, 7 Sep 2010 21:05:08 +0200 Subject: vim. add function to change item state ~ reconcile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To try this, map or call the following function: LedgerSetTransactionState('') – removes state LedgerSetTransactionState('*') – sets 'checked' state … The logic used to distinguish the different parts of the first line of a transaction is rather basic but proved to work so far. --- contrib/vim/ftplugin/ledger.vim | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index c5354508..665fc6f1 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -270,6 +270,41 @@ endf "}}} " Helper functions {{{1 +function! LedgerSetTransactionState(char) + " modifies or sets the state of the transaction at the cursor, + " removing the state alltogether if a:char is empty + let head = search('^\d\S\+', 'bcnW') + if ! head + return + endif + + let parts = split(getline(head), '\s\+') + + let result = [] + while 1 + let part = remove(parts, 0) + " add state after date or (code) + if part =~ '^\d' || part =~ '^([^)]*)$' + call add(result, part) + " replace existing state with new state + elseif part =~ '^[!?*]$' + if ! empty(a:char) + call add(result, a:char) + endif + break + " add state in front of anything else if it does not exist yet + else + if ! empty(a:char) + call add(result, a:char) + endif + call add(result, part) + break + end + endwhile + + call setline(head, join(extend(result, parts))) +endf + " return length of string with fix for multibyte characters function! s:multibyte_strlen(text) "{{{2 return strlen(substitute(a:text, ".", "x", "g")) -- cgit v1.2.3 From cf40d1c9d79c0237d65ef55b8b2d79780f9b8669 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 10:00:17 +0200 Subject: vim. introduce basic transaction 'class'/concept --- contrib/vim/ftplugin/ledger.vim | 81 +++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 27 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 665fc6f1..6bbdbb50 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -268,42 +268,69 @@ function! LedgerGetTags() "{{{1 return alltags endf "}}} -" Helper functions {{{1 - -function! LedgerSetTransactionState(char) +function! LedgerSetTransactionState(lnum, char) "{{{1 " modifies or sets the state of the transaction at the cursor, " removing the state alltogether if a:char is empty - let head = search('^\d\S\+', 'bcnW') +endf "}}} + +let s:transaction = {} "{{{1 +function! s:transaction.new() dict + return copy(s:transaction) +endf + +function! s:transaction.from_lnum(lnum) dict "{{{2 + let head = s:get_transaction_extents(a:lnum)[0] if ! head return endif + let trans = copy(s:transaction) let parts = split(getline(head), '\s\+') - - let result = [] - while 1 - let part = remove(parts, 0) - " add state after date or (code) - if part =~ '^\d' || part =~ '^([^)]*)$' - call add(result, part) - " replace existing state with new state - elseif part =~ '^[!?*]$' - if ! empty(a:char) - call add(result, a:char) - endif - break - " add state in front of anything else if it does not exist yet + let description = [] + 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 =~ '^[!?*]$' + let trans['state'] = part else - if ! empty(a:char) - call add(result, a:char) - endif - call add(result, part) - break - end - endwhile + call add(description, part) + endif + endfor + let trans['description'] = join(description) + return trans +endf "}}} - call setline(head, join(extend(result, parts))) -endf +function! s:transaction.format_head() dict "{{{2 + let parts = [] + if has_key(self, 'date') | call add(parts, self['date']) | endif + 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) +endf "}}} +"}}} + +" Helper functions {{{1 + +function! s:get_transaction_extents(lnum) "{{{2 + " safe view / position + let view = winsaveview() + let fe = &foldenable + set nofoldenable + + call cursor(a:lnum, 0) + let head = search('^\d\S\+', '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 "}}} " return length of string with fix for multibyte characters function! s:multibyte_strlen(text) "{{{2 -- cgit v1.2.3 From 66b39c46d1cff25c5191c3a55dd14e9414413dca Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 10:01:44 +0200 Subject: vim. add function to modify actual/effective date This allows you to set the effective date in a convenient way. Maybe I will add date selection using calendar.vim by Yasuhiro Matsumoto. Until then, you can map this to use today's date: call LedgerSetDate(line('.'), 'effective') --- contrib/vim/ftplugin/ledger.vim | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 6bbdbb50..1d624b14 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -273,6 +273,41 @@ function! LedgerSetTransactionState(lnum, char) "{{{1 " removing the state alltogether if a:char is empty endf "}}} +function! LedgerSetDate(lnum, type, ...) "{{{1 + let time = a:0 == 1 ? a:1 : localtime() + let trans = s:transaction.from_lnum(a:lnum) + if empty(trans) + return + endif + + let formatted = strftime('%Y/%m/%d', time) + if has_key(trans, 'date') && ! empty(trans['date']) + let date = split(trans['date'], '=') + else + let date = [formatted] + endif + + if a:type ==? 'actual' + let date[0] = formatted + elseif a:type ==? 'effective' + if time == 0 + " remove effective date + let date = [date[0]] + else + " set effective date + if len(date) >= 2 + let date[1] = formatted + else + call add(date, formatted) + endif + endif + endif + + let trans['date'] = join(date, '=') + + call setline(s:get_transaction_extents(a:lnum)[0], trans.format_head()) +endf "}}} + let s:transaction = {} "{{{1 function! s:transaction.new() dict return copy(s:transaction) -- cgit v1.2.3 From f8c804ac79a94fc8fd4c168f5d884d42a7c0bd08 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 10:10:09 +0200 Subject: vim. allow use of 0 as timestamp To remove the effective date you would now call the function like this: call LedgerSetDate(line('.'), 'effective', -1) --- contrib/vim/ftplugin/ledger.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 1d624b14..ec1173b8 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -290,7 +290,7 @@ function! LedgerSetDate(lnum, type, ...) "{{{1 if a:type ==? 'actual' let date[0] = formatted elseif a:type ==? 'effective' - if time == 0 + if time < 0 " remove effective date let date = [date[0]] else -- cgit v1.2.3 From 84fea7f136891416978e3608a0627be84176a928 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 10:23:06 +0200 Subject: vim. reimplement function to change state Note: You now have to provide the line number: call LedgerSetTransactionState(line('.', '*') --- contrib/vim/ftplugin/ledger.vim | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index ec1173b8..8a752c21 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -271,6 +271,18 @@ endf "}}} function! LedgerSetTransactionState(lnum, char) "{{{1 " modifies or sets the state of the transaction at the cursor, " removing the state alltogether if a:char is empty + let trans = s:transaction.from_lnum(a:lnum) + if empty(trans) + return + endif + + if empty(a:char) && has_key(trans, 'state') + call remove(trans, 'state') + else + let trans['state'] = a:char + endif + + call setline(trans['head'], trans.format_head()) endf "}}} function! LedgerSetDate(lnum, type, ...) "{{{1 @@ -305,7 +317,7 @@ function! LedgerSetDate(lnum, type, ...) "{{{1 let trans['date'] = join(date, '=') - call setline(s:get_transaction_extents(a:lnum)[0], trans.format_head()) + call setline(trans['head'], trans.format_head()) endf "}}} let s:transaction = {} "{{{1 @@ -320,6 +332,7 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 endif let trans = copy(s:transaction) + let trans['head'] = head let parts = split(getline(head), '\s\+') let description = [] for part in parts -- cgit v1.2.3 From ae3a8b6e11c6cc195282c005276220e6dc0218be Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 14:44:34 +0200 Subject: vim. add case of automatic transactions --- contrib/vim/ftplugin/ledger.vim | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 8a752c21..13fb24cc 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -326,14 +326,25 @@ function! s:transaction.new() dict endf function! s:transaction.from_lnum(lnum) dict "{{{2 - let head = s:get_transaction_extents(a:lnum)[0] + 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 + let parts = split(getline(head), '\s\+') + if parts[0] ==# '~' + let trans['expr'] = 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 + let description = [] for part in parts if ! has_key(trans, 'date') && part =~ '^\d' @@ -351,6 +362,10 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 endf "}}} function! s:transaction.format_head() dict "{{{2 + if has_key(self, 'expr') + return '~ '.self['expr'] + endif + let parts = [] if has_key(self, 'date') | call add(parts, self['date']) | endif if has_key(self, 'code') | call add(parts, '('.self['code'].')') | endif @@ -369,7 +384,7 @@ function! s:get_transaction_extents(lnum) "{{{2 set nofoldenable call cursor(a:lnum, 0) - let head = search('^\d\S\+', 'bcnW') + let head = search('^[~[:digit:]]\S\+', 'bcnW') let tail = search('^[^;[:blank:]]\S\+', 'nW') let tail = tail > head ? tail - 1 : line('$') -- cgit v1.2.3 From f7f8432c52e91031e452c5901cf6e20bfae8cc2a Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 14:45:27 +0200 Subject: vim. add function to parse postings --- contrib/vim/ftplugin/ledger.vim | 75 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 13fb24cc..67f692f1 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -361,6 +361,64 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 return trans 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 + 1 + let tags = {} + let postings = [] + while lnum <= tail + let line = getline(lnum) + + " 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 + + if line =~ '^\s\+;\s*:' + " tags without values + for t in s:findall(line, ':\zs[^:[:blank:]]\([^:]*[^:[:blank:]]\)\?\ze:') + let tag_container[t] = '' + endfor + elseif line =~ '^\s\+;\s*[^:[:blank:]][^:]\+:' + " tag with value + let key = matchstr(line, '^\s\+;\s*\zs[^:]\+\ze:') + if ! empty(key) + let val = matchstr(line, ':\s*\zs.*\ze\s*$') + let tag_container[key] = val + endif + elseif line =~ '^\s\+[^[:blank:];]' + " posting + " FIXME: comments at the eol + " FIXME: replaces original spacing in amount with single spaces + let parts = split(line, '\(\t\|\s\{2,}\)') + call add(postings, {'account': parts[0], 'amount': join(parts[1:])}) + endif + let lnum += 1 + endw + return [tags, postings] +endf "}}} + function! s:transaction.format_head() dict "{{{2 if has_key(self, 'expr') return '~ '.self['expr'] @@ -395,6 +453,23 @@ function! s:get_transaction_extents(lnum) "{{{2 return head ? [head, tail] : [0, 0] endf "}}} +function! s:findall(text, rx) " {{{2 + " 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 "}}} + " return length of string with fix for multibyte characters function! s:multibyte_strlen(text) "{{{2 return strlen(substitute(a:text, ".", "x", "g")) -- cgit v1.2.3 From eea6f33a2e47913db11bfaeb3181cc2e4d05fddd Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 17:34:05 +0200 Subject: vim. fix return type of s:transaction.from_lnum() --- contrib/vim/ftplugin/ledger.vim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 67f692f1..72588712 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -328,7 +328,7 @@ endf function! s:transaction.from_lnum(lnum) dict "{{{2 let [head, tail] = s:get_transaction_extents(a:lnum) if ! head - return + return {} endif let trans = copy(s:transaction) @@ -342,7 +342,7 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 elseif parts[0] !~ '^\d' " this case is avoided in s:get_transaction_extents(), " but we'll check anyway. - return + return {} endif let description = [] -- cgit v1.2.3 From e4060eb4219dab5c787d1823e39bc6f77e06b018 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 17:34:38 +0200 Subject: vim. get transactions in a range of lines --- contrib/vim/ftplugin/ledger.vim | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 72588712..4490f3e0 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -435,6 +435,41 @@ endf "}}} " Helper functions {{{1 +function! s:get_transactions(...) "{{{2 + 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:]]\S\+', 'cW') + endw + + " restore view / position + let &foldenable = fe + call winrestview(view) + + return transactions +endf "}}} + function! s:get_transaction_extents(lnum) "{{{2 " safe view / position let view = winsaveview() -- cgit v1.2.3 From 019a60e6d15a271f590084fa3b5c86aae317667b Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 17:59:18 +0200 Subject: vim. update s:get_columns() --- contrib/vim/ftplugin/ledger.vim | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 4490f3e0..6719529f 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -107,7 +107,7 @@ function! LedgerFoldText() "{{{1 \ '\(^\s\+\|\s\+$\)', '', 'g') " number of columns foldtext can use - let columns = s:get_columns(0) + let columns = s:get_columns() if g:ledger_maxwidth let columns = min([columns, g:ledger_maxwidth]) endif @@ -122,9 +122,9 @@ function! LedgerFoldText() "{{{1 let foldtext .= repeat(' ', filen - (folen%filen)) let foldtext .= repeat(g:ledger_fillstring, - \ s:get_columns(0)/filen) + \ s:get_columns()/filen) else - let foldtext .= repeat(' ', s:get_columns(0)) + let foldtext .= repeat(' ', s:get_columns()) endif " we don't use slices[:5], because that messes up multibyte characters @@ -511,19 +511,27 @@ function! s:multibyte_strlen(text) "{{{2 endfunction "}}} " get # of visible/usable columns in current window -function! s:get_columns(win) "{{{2 +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()/ - " FIXME: Although this will propably never be used with debug mode enabled - " this should take the signs column into account (:help sign.txt) - let columns = (winwidth(a:win) == 0 ? 80 : winwidth(a:win)) - &foldcolumn + + 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 -endfunction "}}} +endf "}}} " remove spaces at start and end of string function! s:strip_spaces(text) "{{{2 -- cgit v1.2.3 From 58fcb0f30f850f1e3140b42419c280a5dd731e30 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 22:31:42 +0200 Subject: vim. make sure cursor/line is on a transaction Thanks to Chad Voegele for reporting and fixing this in the first place. --- contrib/vim/ftplugin/ledger.vim | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 6719529f..1cced35c 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -471,6 +471,11 @@ function! s:get_transactions(...) "{{{2 endf "}}} function! s:get_transaction_extents(lnum) "{{{2 + if ! (indent(a:lnum) || getline(a:lnum) =~ '^[~[:digit:]]\S\+') + " only do something if lnum is in a transaction + return [0, 0] + endif + " safe view / position let view = winsaveview() let fe = &foldenable -- cgit v1.2.3 From 6c0ccd5ffd0a9ac1f97adeca1dc22a7c9db844c5 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 23:24:39 +0200 Subject: vim. add LedgerToggleTransactionState() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit By using call LedgerToggleTransactionState(line('.'), ' *?') the state of the transaction will toggle through: no state -> * -> ? -> no state -> … beginning at what ever state it currently has. Adjust to your liking. Thanks to Chad Voegele for the suggestion. --- contrib/vim/ftplugin/ledger.vim | 37 +++++++++++++++++++++++++++++++------ 1 file changed, 31 insertions(+), 6 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 1cced35c..623b0795 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -268,6 +268,26 @@ function! LedgerGetTags() "{{{1 return alltags endf "}}} +function! LedgerToggleTransactionState(lnum, ...) + if a:0 == 1 + let chars = a:1 + else + let chars = ' *' + endif + let trans = s:transaction.from_lnum(a:lnum) + if empty(trans) + 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! LedgerSetTransactionState(lnum, char) "{{{1 " modifies or sets the state of the transaction at the cursor, " removing the state alltogether if a:char is empty @@ -276,11 +296,7 @@ function! LedgerSetTransactionState(lnum, char) "{{{1 return endif - if empty(a:char) && has_key(trans, 'state') - call remove(trans, 'state') - else - let trans['state'] = a:char - endif + call trans.set_state(a:char) call setline(trans['head'], trans.format_head()) endf "}}} @@ -351,7 +367,8 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 let trans['date'] = part elseif ! has_key(trans, 'code') && part =~ '^([^)]*)$' let trans['code'] = part[1:-2] - elseif ! has_key(trans, 'state') && part =~ '^[!?*]$' + elseif ! has_key(trans, 'state') && part =~ '^.$' + " the first character by itself is assumed to be the state of the transaction. let trans['state'] = part else call add(description, part) @@ -361,6 +378,14 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 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 -- cgit v1.2.3 From 1be3a793857204a8baf935af063675a0b14c09b1 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 8 Sep 2010 18:10:48 +0200 Subject: vim. check for most common case first (parse_body) --- contrib/vim/ftplugin/ledger.vim | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 623b0795..a50a5510 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -420,7 +420,13 @@ function! s:transaction.parse_body(...) dict "{{{2 let tag_container = postings[-1]['tags'] endif - if line =~ '^\s\+;\s*:' + if line =~ '^\s\+[^[:blank:];]' + " posting + " FIXME: comments at the eol + " FIXME: replaces original spacing in amount with single spaces + let parts = split(line, '\(\t\|\s\{2,}\)') + call add(postings, {'account': parts[0], 'amount': join(parts[1:])}) + elseif line =~ '^\s\+;\s*:' " tags without values for t in s:findall(line, ':\zs[^:[:blank:]]\([^:]*[^:[:blank:]]\)\?\ze:') let tag_container[t] = '' @@ -432,12 +438,6 @@ function! s:transaction.parse_body(...) dict "{{{2 let val = matchstr(line, ':\s*\zs.*\ze\s*$') let tag_container[key] = val endif - elseif line =~ '^\s\+[^[:blank:];]' - " posting - " FIXME: comments at the eol - " FIXME: replaces original spacing in amount with single spaces - let parts = split(line, '\(\t\|\s\{2,}\)') - call add(postings, {'account': parts[0], 'amount': join(parts[1:])}) endif let lnum += 1 endw -- cgit v1.2.3 From 3a679a695da865a78a401e5fc6166a91082cd004 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sun, 12 Sep 2010 14:18:06 +0200 Subject: vim. avoid misinterpretion of 1 char words --- contrib/vim/ftplugin/ledger.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index a50a5510..77df4b09 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -367,7 +367,7 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 let trans['date'] = part elseif ! has_key(trans, 'code') && part =~ '^([^)]*)$' let trans['code'] = part[1:-2] - elseif ! has_key(trans, 'state') && part =~ '^.$' + 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 -- cgit v1.2.3 From 86153f670d45c9d1b5d1da8fbed05fb801223f06 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Sun, 12 Sep 2010 14:23:30 +0200 Subject: vim. remove tag completion for now --- contrib/vim/ftplugin/ledger.vim | 69 +++-------------------------------------- 1 file changed, 5 insertions(+), 64 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 77df4b09..7c2c1d73 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -138,37 +138,7 @@ function! LedgerComplete(findstart, base) "{{{1 let lnum = line('.') let line = getline('.') let lastcol = col('.') - 2 - if line =~ '^\d' "{{{2 (date / payee / description) - let b:compl_context = 'payee' - return -1 - elseif line =~ '^\s\+;' "{{{2 (metadata / tags) - let b:compl_context = 'meta-tag' - let first_possible = matchend(line, '^\s\+;') - - " find first column of text to be replaced - let firstcol = lastcol - while firstcol >= 0 - if firstcol <= first_possible - " Stop before the ';' don't ever include it - let firstcol = first_possible - break - elseif line[firstcol] =~ ':' - " Stop before first ':' - let firstcol += 1 - break - endif - - let firstcol -= 1 - endwhile - - " strip whitespace starting from firstcol - let end_of_whitespace = matchend(line, '^\s\+', firstcol) - if end_of_whitespace != -1 - let firstcol = end_of_whitespace - endif - - return firstcol - elseif line =~ '^\s\+' "{{{2 (account) + 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 @@ -191,16 +161,12 @@ function! LedgerComplete(findstart, base) "{{{1 let results = LedgerFindInTree(LedgerGetAccountHierarchy(), hierarchy) " sort by alphabet and reverse because it will get reversed one more time - let results = reverse(sort(results)) if g:ledger_detailed_first - let results = sort(results, 's:sort_accounts_by_depth') + let results = reverse(sort(results, 's:sort_accounts_by_depth')) + else + let results = sort(results) endif - call add(results, a:base) - return reverse(results) - elseif b:compl_context == 'meta-tag' "{{{2 - unlet! b:compl_context - let results = [a:base] - call extend(results, sort(s:filter_items(keys(LedgerGetTags()), a:base))) + call insert(results, a:base) return results else "}}} unlet! b:compl_context @@ -243,31 +209,6 @@ function! LedgerGetAccountHierarchy() "{{{1 return hierarchy endf "}}} -function! LedgerGetTags() "{{{1 - let alltags = {} - let metalines = s:grep_buffer('^\s\+;\s*\zs.*$') - for line in metalines - " (spaces at beginning are stripped by matchstr!) - if line[0] == ':' - " multiple tags - for val in split(line, ':') - if val !~ '^\s*$' - let name = s:strip_spaces(val) - let alltags[name] = get(alltags, name, []) - endif - endfor - elseif line =~ '^.*:.*$' - " line with tag=value - let name = s:strip_spaces(split(line, ':')[0]) - let val = s:strip_spaces(join(split(line, ':')[1:], ':')) - let values = get(alltags, name, []) - call add(values, val) - let alltags[name] = values - endif - endfor - return alltags -endf "}}} - function! LedgerToggleTransactionState(lnum, ...) if a:0 == 1 let chars = a:1 -- cgit v1.2.3 From 453327a1806d728668ffa190ea67f5d693e30362 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 15 Sep 2010 20:03:27 +0200 Subject: vim. fix issue with description in from_lnum() Thanks to Chad Voegele, see mailing list ledger-cli@googlegroups.com: Whenever I had a transaction such as 2010/09/10 * castle bar, nyc (beer) the transaction.from_lnum function would recognize (beer) as the code for the transaction which is incorrect since it comes at the end of the line. Message ID: 73e397f4-234e-46fe-87e5-45f86f934bf1@k30g2000vbn.googlegroups.com --- contrib/vim/ftplugin/ledger.vim | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 7c2c1d73..326c6c72 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -302,7 +302,6 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 return {} endif - let description = [] for part in parts if ! has_key(trans, 'date') && part =~ '^\d' let trans['date'] = part @@ -312,10 +311,12 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 " the first character by itself is assumed to be the state of the transaction. let trans['state'] = part else - call add(description, part) + " everything after date/code or state belongs to the description + break endif + call remove(parts, 0) endfor - let trans['description'] = join(description) + let trans['description'] = join(parts) return trans endf "}}} -- cgit v1.2.3 From 48866466141d1ad0874c676a251cee9d57d99fdb Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 15 Sep 2010 20:08:22 +0200 Subject: vim. fix off-by-one bug in ToggleTransactionState --- contrib/vim/ftplugin/ledger.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 326c6c72..2a0ce9eb 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -222,7 +222,7 @@ function! LedgerToggleTransactionState(lnum, ...) let old = has_key(trans, 'state') ? trans['state'] : ' ' let i = stridx(chars, old) + 1 - let new = chars[i > len(chars) ? 0 : i] + let new = chars[i >= len(chars) ? 0 : i] call trans.set_state(new) -- cgit v1.2.3 From 4d56417f750fe9eb473ae59eefb1a79bdc7d42f1 Mon Sep 17 00:00:00 2001 From: Johann Klähn Date: Wed, 15 Sep 2010 21:18:23 +0200 Subject: vim. parse comments at eol in parse_body() --- contrib/vim/ftplugin/ledger.vim | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) (limited to 'contrib/vim/ftplugin/ledger.vim') diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index 2a0ce9eb..13602e5d 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -316,6 +316,9 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 endif 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 "}}} @@ -344,11 +347,18 @@ function! s:transaction.parse_body(...) dict "{{{2 return [] endif - let lnum = head + 1 + let lnum = head let tags = {} let postings = [] while lnum <= tail - let line = getline(lnum) + let line = split(getline(lnum), '\s*\%(\t\| \);', 1) + + if line[0] =~ '^\s\+[^[:blank:];]' + " posting + " FIXME: replaces original spacing in amount with single spaces + let parts = split(line[0], '\%(\t\| \)\s*') + call add(postings, {'account': parts[0], 'amount': join(parts[1:], ' ')}) + end " where are tags to be stored? if empty(postings) @@ -362,22 +372,17 @@ function! s:transaction.parse_body(...) dict "{{{2 let tag_container = postings[-1]['tags'] endif - if line =~ '^\s\+[^[:blank:];]' - " posting - " FIXME: comments at the eol - " FIXME: replaces original spacing in amount with single spaces - let parts = split(line, '\(\t\|\s\{2,}\)') - call add(postings, {'account': parts[0], 'amount': join(parts[1:])}) - elseif line =~ '^\s\+;\s*:' + let comment = join(line[1:], ' ;') + if comment =~ '^\s*:' " tags without values - for t in s:findall(line, ':\zs[^:[:blank:]]\([^:]*[^:[:blank:]]\)\?\ze:') + for t in s:findall(comment, ':\zs[^:[:blank:]]\([^:]*[^:[:blank:]]\)\?\ze:') let tag_container[t] = '' endfor - elseif line =~ '^\s\+;\s*[^:[:blank:]][^:]\+:' + elseif comment =~ '^\s*[^:[:blank:]][^:]\+:' " tag with value - let key = matchstr(line, '^\s\+;\s*\zs[^:]\+\ze:') + let key = matchstr(comment, '^\s*\zs[^:]\+\ze:') if ! empty(key) - let val = matchstr(line, ':\s*\zs.*\ze\s*$') + let val = matchstr(comment, ':\s*\zs.*\ze\s*$') let tag_container[key] = val endif endif -- cgit v1.2.3