diff options
author | John Wiegley <johnw@newartisans.com> | 2011-06-30 11:55:03 -0500 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2011-06-30 11:55:03 -0500 |
commit | 80f81bdd967838e9146f8a28b9017d531c976d58 (patch) | |
tree | 5ba8c948e80f56bdd96b0abf7a6537cb2df4744f | |
parent | 96dc3dcf9e757ebe4361a5f675b3de8dcf3ec416 (diff) | |
parent | 91d8061af470998ac7100b242f7eafb71a7b39d2 (diff) | |
download | fork-ledger-80f81bdd967838e9146f8a28b9017d531c976d58.tar.gz fork-ledger-80f81bdd967838e9146f8a28b9017d531c976d58.tar.bz2 fork-ledger-80f81bdd967838e9146f8a28b9017d531c976d58.zip |
Merge branch 'master' into next
-rw-r--r-- | contrib/vim/README | 51 | ||||
-rw-r--r-- | contrib/vim/ftplugin/ledger.vim | 133 | ||||
-rw-r--r-- | contrib/vim/syntax/ledger.vim | 11 | ||||
-rw-r--r-- | lisp/ledger.el | 24 |
4 files changed, 132 insertions, 87 deletions
diff --git a/contrib/vim/README b/contrib/vim/README index 368c9c71..a3f5a877 100644 --- a/contrib/vim/README +++ b/contrib/vim/README @@ -6,6 +6,22 @@ Then include the following line in your .vimrc or in ~/.vim/filetype.vim You can also use a modeline like this in every ledger file vim:filetype=ledger +Tips and useful commands +====================================================================== + • Try account-completion (as explained below) + • :call LedgerSetDate(line('.'), 'effective') + will set today's date as the effective date of the current + transaction. You can use also 'actual' in place of 'effective' + or pass in a different date measured as seconds since 1st Jan 1970. + • :call LedgerSetTransactionState(line('.'), '*') + sets the state of the current transaction to '*'. You can + use this in custom mappings. + • :call LedgerToggleTransactionState(line('.'), ' *?!') + will toggle through the provided transaction states. + You can map this to double-clicking for example: + noremap <silent><buffer> <2-LeftMouse> + \ :call LedgerToggleTransactionState(line('.'), ' *?!')<CR> + Configuration ====================================================================== Include the following let-statements somewhere in your .vimrc @@ -35,7 +51,7 @@ to modify the behaviour of the ledger filetype. Completion ====================================================================== -Omni completion is implemented for account names and tags. +Omni completion is currently implemented for account names only. Accounts ---------------------------------------------------------------------- @@ -52,38 +68,11 @@ 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. -Tags ----------------------------------------------------------------------- -The support for completing tags is pretty basic right now -but it's useful to keep the spelling of your tags consistent. -You can call the completion after the ';' to get a list of all tags. -When you have a list of tags (:like: :this:) you can call -the completion too and everything up to the last ':' (excluding whitespace) -will be considered the beginning of the tag to search for. - -Revision history (major changes) -====================================================================== - 2009-06-23 & 2009-06-25 - J. Klähn: Omni-Completion for account names and tags - 2009-06-17 J. Klähn: Highlight account text - Updated documentation and added fillstring option. - 2009-06-15 J. Klähn: Split into multiple files - 2009-06-12 J. Klähn: Use all available columns for foldtext - Also rewrote foldtext generation. - 2009-03-25 J. Klähn: Allow Metadata - in transactions and postings (Ledger 3.0) - Also fixed alignment for multi-byte-characters - 2009-01-28 S.Karrmann: minor fixes - 2009-01-27 third version by S.Karrmann. - better extraction of the amount of the posting - decimal separator can be one of '.' and ','. - 2005-02-05 first version (partly copied from ledger.vim 0.0.1) - License ====================================================================== -Copyright 2009 by Johann Klähn -Copyright 2009 by Stefan Karrmann -Copyright 2005 by Wolfgang Oertl +Copyright 2011-2009 by Johann Klähn +Copyright 2009 by Stefan Karrmann +Copyright 2005 by 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 diff --git a/contrib/vim/ftplugin/ledger.vim b/contrib/vim/ftplugin/ledger.vim index d1c8e1a9..9cc4ed91 100644 --- a/contrib/vim/ftplugin/ledger.vim +++ b/contrib/vim/ftplugin/ledger.vim @@ -1,6 +1,5 @@ " Vim filetype plugin file " filetype: ledger -" Version: 0.1.0 " by Johann Klähn; Use according to the terms of the GPL>=2. " vim:ts=2:sw=2:sts=2:foldmethod=marker @@ -137,22 +136,33 @@ function! LedgerComplete(findstart, base) "{{{1 if a:findstart let lnum = line('.') let line = getline('.') - let lastcol = col('.') - 2 let b:compl_context = '' if line =~ '^\s\+[^[:blank:];]' "{{{2 (account) - let b:compl_context = 'account' - if matchend(line, '^\s\+\%(\S \S\|\S\)\+') <= lastcol - " only allow completion when in or at end of account name - return -1 + " only allow completion when in or at end of account name + if matchend(line, '^\s\+\%(\S \S\|\S\)\+') >= col('.') - 1 + " the start of the first non-blank character + " (excluding virtual-transaction-marks) + " is the beginning of the account name + let b:compl_context = 'account' + return matchend(line, '^\s\+[\[(]\?') endif - " the start of the first non-blank character - " (excluding virtual-transaction-marks) - " is the beginning of the account name - return matchend(line, '^\s\+[\[(]\?') - else "}}} - return -1 - endif + elseif line =~ '^\d' "{{{2 (description) + let pre = matchend(line, '^\d\S\+\%(([^)]*)\|[*?!]\|\s\)\+') + if pre < col('.') - 1 + let b:compl_context = 'description' + return pre + endif + elseif line =~ '^$' "{{{2 (new line) + let b:compl_context = 'new' + endif "}}} + return -1 else + if ! exists('b:compl_cache') + let b:compl_cache = s:collect_completion_data() + let b:compl_cache['#'] = changenr() + endif + + let results = [] if b:compl_context == 'account' "{{{2 (account) unlet! b:compl_context let hierarchy = split(a:base, ':') @@ -160,7 +170,7 @@ function! LedgerComplete(findstart, base) "{{{1 call add(hierarchy, '') endif - let results = LedgerFindInTree(LedgerGetAccountHierarchy(), hierarchy) + let results = LedgerFindInTree(b:compl_cache.accounts, hierarchy) " sort by alphabet and reverse because it will get reversed one more time if g:ledger_detailed_first let results = reverse(sort(results, 's:sort_accounts_by_depth')) @@ -168,10 +178,19 @@ function! LedgerComplete(findstart, base) "{{{1 let results = sort(results) endif call insert(results, a:base) - return results - else "}}} + elseif b:compl_context == 'description' "{{{2 (description) + let results = [a:base] + s:filter_items(b:compl_cache.descriptions, a:base) + elseif b:compl_context == 'new' "{{{2 (new line) + return [strftime('%Y/%m/%d')] + endif "}}} + + " no completion (apart from a:base) found. update cache if file has changed + if len(results) <= 1 && b:compl_cache['#'] != changenr() + unlet b:compl_cache + return LedgerComplete(a:findstart, a:base) + else unlet! b:compl_context - return [] + return results endif endif endf "}}} @@ -195,21 +214,6 @@ function! LedgerFindInTree(tree, levels) "{{{1 return results endf "}}} -function! LedgerGetAccountHierarchy() "{{{1 - let hierarchy = {} - let accounts = s:grep_buffer('^\s\+\zs[^[:blank:];]\%(\S \S\|\S\)\+\ze') - for name in accounts - " remove virtual-transaction-marks - let name = substitute(name, '\%(^\s*[\[(]\?\|[\])]\?\s*$\)', '', 'g') - let last = hierarchy - for part in split(name, ':') - let last[part] = get(last, part, {}) - let last = last[part] - endfor - endfor - return hierarchy -endf "}}} - function! LedgerToggleTransactionState(lnum, ...) if a:0 == 1 let chars = a:1 @@ -278,6 +282,51 @@ function! LedgerSetDate(lnum, type, ...) "{{{1 call setline(trans['head'], trans.format_head()) endf "}}} +function! s:collect_completion_data() "{{{1 + let transactions = s:get_transactions() + let cache = {'descriptions': [], 'tags': {}, 'accounts': {}} + let accounts = [] + for xact in transactions + " collect descriptions + if index(cache.descriptions, xact['description']) < 0 + call add(cache.descriptions, xact['description']) + endif + let [t, postings] = xact.parse_body() + let tagdicts = [t] + + " collect account names + for posting in postings + if has_key(posting, 'tags') + call add(tagdicts, posting.tags) + endif + " remove virtual-transaction-marks + let name = substitute(posting.account, '\%(^\s*[\[(]\?\|[\])]\?\s*$\)', '', 'g') + if index(accounts, name) < 0 + call add(accounts, name) + endif + endfor + + " collect tags + for tags in tagdicts | for [tag, val] in items(tags) + let values = get(cache.tags, tag, []) + if index(values, val) < 0 + call add(values, val) + endif + let cache.tags[tag] = values + endfor | endfor + endfor + + for account in accounts + let last = cache.accounts + for part in split(account, ':') + let last[part] = get(last, part, {}) + let last = last[part] + endfor + endfor + + return cache +endf "}}} + let s:transaction = {} "{{{1 function! s:transaction.new() dict return copy(s:transaction) @@ -293,7 +342,15 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 let trans['head'] = head let trans['tail'] = tail - let parts = split(getline(head), '\s\+') + " split off eventual comments at the end of line + let line = split(getline(head), '\ze\s*\%(\t\| \);', 1) + if len(line) > 1 + let trans['appendix'] = join(line[1:], '') + endif + + " parse rest of line + " FIXME (minor): will not preserve spacing (see 'join(parts)') + let parts = split(line[0], '\s\+') if parts[0] ==# '~' let trans['expr'] = join(parts[1:]) return trans @@ -318,8 +375,6 @@ function! s:transaction.from_lnum(lnum) dict "{{{2 call remove(parts, 0) endfor - " FIXME: this will break comments at the end of this 'head' line - " they need 2 spaces in front of the semicolon let trans['description'] = join(parts) return trans endf "}}} @@ -402,7 +457,11 @@ function! s:transaction.format_head() dict "{{{2 if has_key(self, 'code') | call add(parts, '('.self['code'].')') | endif if has_key(self, 'state') | call add(parts, self['state']) | endif if has_key(self, 'description') | call add(parts, self['description']) | endif - return join(parts) + + let line = join(parts) + if has_key(self, 'appendix') | let line .= self['appendix'] | endif + + return line endf "}}} "}}} @@ -518,7 +577,7 @@ endf "}}} " return only those items that start with a specified keyword function! s:filter_items(list, keyword) "{{{2 - return filter(a:list, 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''') + return filter(copy(a:list), 'v:val =~ ''^\V'.substitute(a:keyword, '\\', '\\\\', 'g').'''') endf "}}} " return all lines matching an expression, returning only the matched part diff --git a/contrib/vim/syntax/ledger.vim b/contrib/vim/syntax/ledger.vim index c6845488..73aaa0c3 100644 --- a/contrib/vim/syntax/ledger.vim +++ b/contrib/vim/syntax/ledger.vim @@ -1,19 +1,8 @@ " Vim syntax file " filetype: ledger -" Version: 0.1.0 " 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. -" Revision history -" 2009-06-12 J. Klähn: Use all available columns for foldtext -" 2009-03-25 J. Klähn: Allow Metadata -" in transactions and postings (Ledger 3.0) -" Also fixed alignment for multi-byte-characters -" 2009-01-28 S.Karrmann: minor fixes -" 2009-01-27 third version by S.Karrmann. -" better extraction of the amount of the posting -" decimal separator can be one of '.' and ','. -" 2005-02-05 first version (partly copied from ledger.vim 0.0.1) " vim:ts=2:sw=2:sts=2:foldmethod=marker if version < 600 diff --git a/lisp/ledger.el b/lisp/ledger.el index 25bb485b..2d15f090 100644 --- a/lisp/ledger.el +++ b/lisp/ledger.el @@ -433,7 +433,9 @@ dropped." ;;;###autoload (define-derived-mode ledger-mode text-mode "Ledger" - "A mode for editing ledger data files." + "A mode for editing ledger data files. + +\\{ledger-mode-map}" (set (make-local-variable 'comment-start) " ; ") (set (make-local-variable 'comment-end) "") (set (make-local-variable 'indent-tabs-mode) nil) @@ -632,8 +634,7 @@ dropped." (defvar ledger-reconcile-mode-abbrev-table) -(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" - "A mode for reconciling ledger entries." +(defvar ledger-reconcile-mode-map (let ((map (make-sparse-keymap))) (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) @@ -647,7 +648,12 @@ dropped." (define-key map [?p] 'previous-line) (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) - (use-local-map map))) + map)) + +(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" + "A mode for reconciling ledger entries. + +\\{ledger-reconcile-mode-map}") ;; Context sensitivity @@ -807,8 +813,7 @@ specified line, returns nil." (defvar ledger-report-mode-abbrev-table) -(define-derived-mode ledger-report-mode text-mode "Ledger-Report" - "A mode for viewing ledger reports." +(defvar ledger-report-mode-map (let ((map (make-sparse-keymap))) (define-key map [? ] 'scroll-up) (define-key map [backspace] 'scroll-down) @@ -825,7 +830,10 @@ specified line, returns nil." 'ledger-report-kill) (define-key map [(control ?c) (control ?l) (control ?e)] 'ledger-report-edit) - (use-local-map map))) + map)) + +(define-derived-mode ledger-report-mode text-mode "Ledger-Report" + "A mode for viewing ledger reports.") (defun ledger-report-read-name () "Read the name of a ledger report to use, with completion. @@ -1201,7 +1209,7 @@ the default." ;; A sample function for $ users (defun ledger-next-amount (&optional end) - (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) + (when (re-search-forward "\\( \\|\t\\| \t\\)[ \t]*-?\\([A-Z$€£]+ *\\)?\\(-?[0-9,]+?\\)\\(.[0-9]+\\)?\\( *[A-Z$€£]+\\)?\\([ \t]*@@?[^\n;]+?\\)?\\([ \t]+;.+?\\)?$" (marker-position end) t) (goto-char (match-beginning 0)) (skip-syntax-forward " ") (- (or (match-end 4) |