Merge branch 'master' into next
This commit is contained in:
commit
80f81bdd96
4 changed files with 132 additions and 87 deletions
|
|
@ -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
|
You can also use a modeline like this in every ledger file
|
||||||
vim:filetype=ledger
|
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
|
Configuration
|
||||||
======================================================================
|
======================================================================
|
||||||
Include the following let-statements somewhere in your .vimrc
|
Include the following let-statements somewhere in your .vimrc
|
||||||
|
|
@ -35,7 +51,7 @@ to modify the behaviour of the ledger filetype.
|
||||||
|
|
||||||
Completion
|
Completion
|
||||||
======================================================================
|
======================================================================
|
||||||
Omni completion is implemented for account names and tags.
|
Omni completion is currently implemented for account names only.
|
||||||
|
|
||||||
Accounts
|
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.
|
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.
|
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
|
License
|
||||||
======================================================================
|
======================================================================
|
||||||
Copyright 2009 by Johann Klähn
|
Copyright 2011-2009 by Johann Klähn
|
||||||
Copyright 2009 by Stefan Karrmann
|
Copyright 2009 by Stefan Karrmann
|
||||||
Copyright 2005 by Wolfgang Oertl
|
Copyright 2005 by Wolfgang Oertl
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
" Vim filetype plugin file
|
" Vim filetype plugin file
|
||||||
" filetype: ledger
|
" filetype: ledger
|
||||||
" Version: 0.1.0
|
|
||||||
" by Johann Klähn; Use according to the terms of the GPL>=2.
|
" by Johann Klähn; Use according to the terms of the GPL>=2.
|
||||||
" vim:ts=2:sw=2:sts=2:foldmethod=marker
|
" vim:ts=2:sw=2:sts=2:foldmethod=marker
|
||||||
|
|
||||||
|
|
@ -137,22 +136,33 @@ function! LedgerComplete(findstart, base) "{{{1
|
||||||
if a:findstart
|
if a:findstart
|
||||||
let lnum = line('.')
|
let lnum = line('.')
|
||||||
let line = getline('.')
|
let line = getline('.')
|
||||||
let lastcol = col('.') - 2
|
|
||||||
let b:compl_context = ''
|
let b:compl_context = ''
|
||||||
if line =~ '^\s\+[^[:blank:];]' "{{{2 (account)
|
if line =~ '^\s\+[^[:blank:];]' "{{{2 (account)
|
||||||
let b:compl_context = 'account'
|
" only allow completion when in or at end of account name
|
||||||
if matchend(line, '^\s\+\%(\S \S\|\S\)\+') <= lastcol
|
if matchend(line, '^\s\+\%(\S \S\|\S\)\+') >= col('.') - 1
|
||||||
" only allow completion when in or at end of account name
|
" the start of the first non-blank character
|
||||||
return -1
|
" (excluding virtual-transaction-marks)
|
||||||
|
" is the beginning of the account name
|
||||||
|
let b:compl_context = 'account'
|
||||||
|
return matchend(line, '^\s\+[\[(]\?')
|
||||||
endif
|
endif
|
||||||
" the start of the first non-blank character
|
elseif line =~ '^\d' "{{{2 (description)
|
||||||
" (excluding virtual-transaction-marks)
|
let pre = matchend(line, '^\d\S\+\%(([^)]*)\|[*?!]\|\s\)\+')
|
||||||
" is the beginning of the account name
|
if pre < col('.') - 1
|
||||||
return matchend(line, '^\s\+[\[(]\?')
|
let b:compl_context = 'description'
|
||||||
else "}}}
|
return pre
|
||||||
return -1
|
endif
|
||||||
endif
|
elseif line =~ '^$' "{{{2 (new line)
|
||||||
|
let b:compl_context = 'new'
|
||||||
|
endif "}}}
|
||||||
|
return -1
|
||||||
else
|
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)
|
if b:compl_context == 'account' "{{{2 (account)
|
||||||
unlet! b:compl_context
|
unlet! b:compl_context
|
||||||
let hierarchy = split(a:base, ':')
|
let hierarchy = split(a:base, ':')
|
||||||
|
|
@ -160,7 +170,7 @@ function! LedgerComplete(findstart, base) "{{{1
|
||||||
call add(hierarchy, '')
|
call add(hierarchy, '')
|
||||||
endif
|
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
|
" sort by alphabet and reverse because it will get reversed one more time
|
||||||
if g:ledger_detailed_first
|
if g:ledger_detailed_first
|
||||||
let results = reverse(sort(results, 's:sort_accounts_by_depth'))
|
let results = reverse(sort(results, 's:sort_accounts_by_depth'))
|
||||||
|
|
@ -168,10 +178,19 @@ function! LedgerComplete(findstart, base) "{{{1
|
||||||
let results = sort(results)
|
let results = sort(results)
|
||||||
endif
|
endif
|
||||||
call insert(results, a:base)
|
call insert(results, a:base)
|
||||||
return results
|
elseif b:compl_context == 'description' "{{{2 (description)
|
||||||
else "}}}
|
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
|
unlet! b:compl_context
|
||||||
return []
|
return results
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
endf "}}}
|
endf "}}}
|
||||||
|
|
@ -195,21 +214,6 @@ function! LedgerFindInTree(tree, levels) "{{{1
|
||||||
return results
|
return results
|
||||||
endf "}}}
|
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, ...)
|
function! LedgerToggleTransactionState(lnum, ...)
|
||||||
if a:0 == 1
|
if a:0 == 1
|
||||||
let chars = a:1
|
let chars = a:1
|
||||||
|
|
@ -278,6 +282,51 @@ function! LedgerSetDate(lnum, type, ...) "{{{1
|
||||||
call setline(trans['head'], trans.format_head())
|
call setline(trans['head'], trans.format_head())
|
||||||
endf "}}}
|
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
|
let s:transaction = {} "{{{1
|
||||||
function! s:transaction.new() dict
|
function! s:transaction.new() dict
|
||||||
return copy(s:transaction)
|
return copy(s:transaction)
|
||||||
|
|
@ -293,7 +342,15 @@ function! s:transaction.from_lnum(lnum) dict "{{{2
|
||||||
let trans['head'] = head
|
let trans['head'] = head
|
||||||
let trans['tail'] = tail
|
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] ==# '~'
|
if parts[0] ==# '~'
|
||||||
let trans['expr'] = join(parts[1:])
|
let trans['expr'] = join(parts[1:])
|
||||||
return trans
|
return trans
|
||||||
|
|
@ -318,8 +375,6 @@ function! s:transaction.from_lnum(lnum) dict "{{{2
|
||||||
call remove(parts, 0)
|
call remove(parts, 0)
|
||||||
endfor
|
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)
|
let trans['description'] = join(parts)
|
||||||
return trans
|
return trans
|
||||||
endf "}}}
|
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, 'code') | call add(parts, '('.self['code'].')') | endif
|
||||||
if has_key(self, 'state') | call add(parts, self['state']) | endif
|
if has_key(self, 'state') | call add(parts, self['state']) | endif
|
||||||
if has_key(self, 'description') | call add(parts, self['description']) | 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 "}}}
|
endf "}}}
|
||||||
"}}}
|
"}}}
|
||||||
|
|
||||||
|
|
@ -518,7 +577,7 @@ endf "}}}
|
||||||
|
|
||||||
" return only those items that start with a specified keyword
|
" return only those items that start with a specified keyword
|
||||||
function! s:filter_items(list, keyword) "{{{2
|
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 "}}}
|
endf "}}}
|
||||||
|
|
||||||
" return all lines matching an expression, returning only the matched part
|
" return all lines matching an expression, returning only the matched part
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,8 @@
|
||||||
" Vim syntax file
|
" Vim syntax file
|
||||||
" filetype: ledger
|
" filetype: ledger
|
||||||
" Version: 0.1.0
|
|
||||||
" by Johann Klähn; Use according to the terms of the GPL>=2.
|
" 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 Stefan Karrmann; Use according to the terms of the GPL>=2.
|
||||||
" by Wolfgang Oertl; 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
|
" vim:ts=2:sw=2:sts=2:foldmethod=marker
|
||||||
|
|
||||||
if version < 600
|
if version < 600
|
||||||
|
|
|
||||||
|
|
@ -433,7 +433,9 @@ dropped."
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(define-derived-mode ledger-mode text-mode "Ledger"
|
(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-start) " ; ")
|
||||||
(set (make-local-variable 'comment-end) "")
|
(set (make-local-variable 'comment-end) "")
|
||||||
(set (make-local-variable 'indent-tabs-mode) nil)
|
(set (make-local-variable 'indent-tabs-mode) nil)
|
||||||
|
|
@ -632,8 +634,7 @@ dropped."
|
||||||
|
|
||||||
(defvar ledger-reconcile-mode-abbrev-table)
|
(defvar ledger-reconcile-mode-abbrev-table)
|
||||||
|
|
||||||
(define-derived-mode ledger-reconcile-mode text-mode "Reconcile"
|
(defvar ledger-reconcile-mode-map
|
||||||
"A mode for reconciling ledger entries."
|
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
(define-key map [(control ?m)] 'ledger-reconcile-visit)
|
(define-key map [(control ?m)] 'ledger-reconcile-visit)
|
||||||
(define-key map [return] 'ledger-reconcile-visit)
|
(define-key map [return] 'ledger-reconcile-visit)
|
||||||
|
|
@ -647,7 +648,12 @@ dropped."
|
||||||
(define-key map [?p] 'previous-line)
|
(define-key map [?p] 'previous-line)
|
||||||
(define-key map [?s] 'ledger-reconcile-save)
|
(define-key map [?s] 'ledger-reconcile-save)
|
||||||
(define-key map [?q] 'ledger-reconcile-quit)
|
(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
|
;; Context sensitivity
|
||||||
|
|
||||||
|
|
@ -807,8 +813,7 @@ specified line, returns nil."
|
||||||
|
|
||||||
(defvar ledger-report-mode-abbrev-table)
|
(defvar ledger-report-mode-abbrev-table)
|
||||||
|
|
||||||
(define-derived-mode ledger-report-mode text-mode "Ledger-Report"
|
(defvar ledger-report-mode-map
|
||||||
"A mode for viewing ledger reports."
|
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
(define-key map [? ] 'scroll-up)
|
(define-key map [? ] 'scroll-up)
|
||||||
(define-key map [backspace] 'scroll-down)
|
(define-key map [backspace] 'scroll-down)
|
||||||
|
|
@ -825,7 +830,10 @@ specified line, returns nil."
|
||||||
'ledger-report-kill)
|
'ledger-report-kill)
|
||||||
(define-key map [(control ?c) (control ?l) (control ?e)]
|
(define-key map [(control ?c) (control ?l) (control ?e)]
|
||||||
'ledger-report-edit)
|
'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 ()
|
(defun ledger-report-read-name ()
|
||||||
"Read the name of a ledger report to use, with completion.
|
"Read the name of a ledger report to use, with completion.
|
||||||
|
|
@ -1201,7 +1209,7 @@ the default."
|
||||||
;; A sample function for $ users
|
;; A sample function for $ users
|
||||||
|
|
||||||
(defun ledger-next-amount (&optional end)
|
(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))
|
(goto-char (match-beginning 0))
|
||||||
(skip-syntax-forward " ")
|
(skip-syntax-forward " ")
|
||||||
(- (or (match-end 4)
|
(- (or (match-end 4)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue