summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2011-06-30 11:55:03 -0500
committerJohn Wiegley <johnw@newartisans.com>2011-06-30 11:55:03 -0500
commit80f81bdd967838e9146f8a28b9017d531c976d58 (patch)
tree5ba8c948e80f56bdd96b0abf7a6537cb2df4744f
parent96dc3dcf9e757ebe4361a5f675b3de8dcf3ec416 (diff)
parent91d8061af470998ac7100b242f7eafb71a7b39d2 (diff)
downloadfork-ledger-80f81bdd967838e9146f8a28b9017d531c976d58.tar.gz
fork-ledger-80f81bdd967838e9146f8a28b9017d531c976d58.tar.bz2
fork-ledger-80f81bdd967838e9146f8a28b9017d531c976d58.zip
Merge branch 'master' into next
-rw-r--r--contrib/vim/README51
-rw-r--r--contrib/vim/ftplugin/ledger.vim133
-rw-r--r--contrib/vim/syntax/ledger.vim11
-rw-r--r--lisp/ledger.el24
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)