Formatting changes and initial inclusion of ledger-schedule

This commit is contained in:
Craig Earls 2013-07-02 13:16:28 -07:00
parent a6cb179d8a
commit cf2fa5c32b
11 changed files with 746 additions and 761 deletions

View file

@ -34,50 +34,50 @@
:group 'ledger-reconcile) :group 'ledger-reconcile)
(defcustom ledger-scale 10000 (defcustom ledger-scale 10000
"The 10 ^ maximum number of digits you would expect to appear in your reports. "The 10 ^ maximum number of digits you would expect to appear in your reports.
This is a cheap way of getting around floating point silliness in subtraction") This is a cheap way of getting around floating point silliness in subtraction")
(defun ledger-split-commodity-string (str) (defun ledger-split-commodity-string (str)
"Split a commoditized string, STR, into two parts. "Split a commoditized string, STR, into two parts.
Returns a list with (value commodity)." Returns a list with (value commodity)."
(let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist) (let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist)
ledger-amount-decimal-comma-regex ledger-amount-decimal-comma-regex
ledger-amount-decimal-period-regex))) ledger-amount-decimal-period-regex)))
(if (> (length str) 0) (if (> (length str) 0)
(with-temp-buffer (with-temp-buffer
(insert str) (insert str)
(goto-char (point-min)) (goto-char (point-min))
(cond (cond
((re-search-forward "\"\\(.*\\)\"" nil t) ; look for quoted commodities ((re-search-forward "\"\\(.*\\)\"" nil t) ; look for quoted commodities
(let ((com (delete-and-extract-region (let ((com (delete-and-extract-region
(match-beginning 1) (match-beginning 1)
(match-end 1)))) (match-end 1))))
(if (re-search-forward (if (re-search-forward
number-regex nil t) number-regex nil t)
(list (list
(ledger-string-to-number (ledger-string-to-number
(delete-and-extract-region (match-beginning 0) (match-end 0))) (delete-and-extract-region (match-beginning 0) (match-end 0)))
com)))) com))))
((re-search-forward number-regex nil t) ((re-search-forward number-regex nil t)
;; found a number in the current locale, return it in the ;; found a number in the current locale, return it in the
;; car. Anything left over is annotation, the first ;; car. Anything left over is annotation, the first
;; thing should be the commodity, separated by ;; thing should be the commodity, separated by
;; whitespace, return it in the cdr. I can't think of ;; whitespace, return it in the cdr. I can't think of
;; any counterexamples ;; any counterexamples
(list (list
(ledger-string-to-number (ledger-string-to-number
(delete-and-extract-region (match-beginning 0) (match-end 0))) (delete-and-extract-region (match-beginning 0) (match-end 0)))
(nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max))))))
((re-search-forward "0" nil t) ((re-search-forward "0" nil t)
;; couldn't find a decimal number, look for a single 0, ;; couldn't find a decimal number, look for a single 0,
;; indicating account with zero balance ;; indicating account with zero balance
(list 0 ledger-reconcile-default-commodity)))) (list 0 ledger-reconcile-default-commodity))))
;; nothing found, return 0 ;; nothing found, return 0
(list 0 ledger-reconcile-default-commodity)))) (list 0 ledger-reconcile-default-commodity))))
(defun ledger-string-balance-to-commoditized-amount (str) (defun ledger-string-balance-to-commoditized-amount (str)
"Return a commoditized amount (val, 'comm') from STR." "Return a commoditized amount (val, 'comm') from STR."
; break any balances with multi commodities into a list ; break any balances with multi commodities into a list
(mapcar #'(lambda (st) (mapcar #'(lambda (st)
(ledger-split-commodity-string st)) (ledger-split-commodity-string st))
(split-string str "[\n\r]"))) (split-string str "[\n\r]")))
@ -85,8 +85,10 @@ Returns a list with (value commodity)."
(defun -commodity (c1 c2) (defun -commodity (c1 c2)
"Subtract C2 from C1, ensuring their commodities match." "Subtract C2 from C1, ensuring their commodities match."
(if (string= (cadr c1) (cadr c2)) (if (string= (cadr c1) (cadr c2))
; the scaling below is to get around inexact subtraction results where, for example ; the scaling below is to get around inexact
; 1.23 - 4.56 = -3.3299999999999996 instead of -3.33 ; subtraction results where, for example 1.23
; - 4.56 = -3.3299999999999996 instead of
; -3.33
(list (/ (- (* ledger-scale (car c1)) (* ledger-scale (car c2))) ledger-scale) (cadr c1)) (list (/ (- (* ledger-scale (car c1)) (* ledger-scale (car c2))) ledger-scale) (cadr c1))
(error "Can't subtract different commodities %S from %S" c2 c1))) (error "Can't subtract different commodities %S from %S" c2 c1)))
@ -97,50 +99,50 @@ Returns a list with (value commodity)."
(error "Can't add different commodities, %S to %S" c1 c2))) (error "Can't add different commodities, %S to %S" c1 c2)))
(defun ledger-strip (str char) (defun ledger-strip (str char)
(let (new-str) (let (new-str)
(concat (dolist (ch (append str nil) new-str) (concat (dolist (ch (append str nil) new-str)
(unless (= ch char) (unless (= ch char)
(setq new-str (append new-str (list ch)))))))) (setq new-str (append new-str (list ch))))))))
(defun ledger-string-to-number (str &optional decimal-comma) (defun ledger-string-to-number (str &optional decimal-comma)
"improve builtin string-to-number by handling internationalization, and return nil if number can't be parsed" "improve builtin string-to-number by handling internationalization, and return nil if number can't be parsed"
(let ((nstr (if (or decimal-comma (let ((nstr (if (or decimal-comma
(assoc "decimal-comma" ledger-environment-alist)) (assoc "decimal-comma" ledger-environment-alist))
(ledger-strip str ?.) (ledger-strip str ?.)
(ledger-strip str ?,)))) (ledger-strip str ?,))))
(while (string-match "," nstr) ;if there is a comma now, it is a thousands separator (while (string-match "," nstr) ;if there is a comma now, it is a thousands separator
(setq nstr (replace-match "." nil nil nstr))) (setq nstr (replace-match "." nil nil nstr)))
(string-to-number nstr))) (string-to-number nstr)))
(defun ledger-number-to-string (n &optional decimal-comma) (defun ledger-number-to-string (n &optional decimal-comma)
(let ((str (number-to-string n))) (let ((str (number-to-string n)))
(if (or decimal-comma (if (or decimal-comma
(assoc "decimal-comma" ledger-environment-alist)) (assoc "decimal-comma" ledger-environment-alist))
(while (string-match "\\." str) (while (string-match "\\." str)
(setq str (replace-match "," nil nil str))) (setq str (replace-match "," nil nil str)))
str))) str)))
(defun ledger-commodity-to-string (c1) (defun ledger-commodity-to-string (c1)
"Return string representing C1. "Return string representing C1.
Single character commodities are placed ahead of the value, Single character commodities are placed ahead of the value,
longer ones are after the value." longer ones are after the value."
(let ((str (ledger-number-to-string (car c1))) (let ((str (ledger-number-to-string (car c1)))
(commodity (cadr c1))) (commodity (cadr c1)))
(if (> (length commodity) 1) (if (> (length commodity) 1)
(concat str " " commodity) (concat str " " commodity)
(concat commodity " " str)))) (concat commodity " " str))))
(defun ledger-read-commodity-string (prompt) (defun ledger-read-commodity-string (prompt)
(let ((str (read-from-minibuffer (let ((str (read-from-minibuffer
(concat prompt " (" ledger-reconcile-default-commodity "): "))) (concat prompt " (" ledger-reconcile-default-commodity "): ")))
comm) comm)
(if (and (> (length str) 0) (if (and (> (length str) 0)
(ledger-split-commodity-string str)) (ledger-split-commodity-string str))
(progn (progn
(setq comm (ledger-split-commodity-string str)) (setq comm (ledger-split-commodity-string str))
(if (cadr comm) (if (cadr comm)
comm comm
(list (car comm) ledger-reconcile-default-commodity)))))) (list (car comm) ledger-reconcile-default-commodity))))))
(provide 'ldg-commodities) (provide 'ldg-commodities)

View file

@ -34,8 +34,8 @@
;; with pcomplete. See pcomplete-parse-arguments-function for ;; with pcomplete. See pcomplete-parse-arguments-function for
;; details ;; details
(let* ((begin (save-excursion (let* ((begin (save-excursion
(ledger-thing-at-point) ;; leave point at beginning of thing under point (ledger-thing-at-point) ;; leave point at beginning of thing under point
(point))) (point)))
(end (point)) (end (point))
begins args) begins args)
;; to support end of line metadata ;; to support end of line metadata
@ -65,42 +65,42 @@
(unless (and (>= origin (match-beginning 0)) (unless (and (>= origin (match-beginning 0))
(< origin (match-end 0))) (< origin (match-end 0)))
(setq payees-list (cons (match-string-no-properties 3) (setq payees-list (cons (match-string-no-properties 3)
payees-list))))) ;; add the payee payees-list))))) ;; add the payee
;; to the list ;; to the list
(pcomplete-uniqify-list (nreverse payees-list)))) (pcomplete-uniqify-list (nreverse payees-list))))
(defun ledger-find-accounts-in-buffer () (defun ledger-find-accounts-in-buffer ()
(interactive) (interactive)
(let ((origin (point)) (let ((origin (point))
accounts accounts
(account-tree (list t)) (account-tree (list t))
(account-elements nil) (account-elements nil)
(seed-regex (ledger-account-any-status-with-seed-regex (seed-regex (ledger-account-any-status-with-seed-regex
(regexp-quote (car pcomplete-args))))) (regexp-quote (car pcomplete-args)))))
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
(dolist (account (dolist (account
(delete-dups (delete-dups
(progn (progn
(while (re-search-forward seed-regex nil t) (while (re-search-forward seed-regex nil t)
(unless (between origin (match-beginning 0) (match-end 0)) (unless (between origin (match-beginning 0) (match-end 0))
(setq accounts (cons (match-string-no-properties 2) accounts)))) (setq accounts (cons (match-string-no-properties 2) accounts))))
accounts))) accounts)))
(let ((root account-tree)) (let ((root account-tree))
(setq account-elements (setq account-elements
(split-string (split-string
account ":")) account ":"))
(while account-elements (while account-elements
(let ((xact (assoc (car account-elements) root))) (let ((xact (assoc (car account-elements) root)))
(if xact (if xact
(setq root (cdr xact)) (setq root (cdr xact))
(setq xact (cons (car account-elements) (list t))) (setq xact (cons (car account-elements) (list t)))
(nconc root (list xact)) (nconc root (list xact))
(setq root (cdr xact)))) (setq root (cdr xact))))
(setq account-elements (cdr account-elements)))))) (setq account-elements (cdr account-elements))))))
account-tree)) account-tree))
(defun ledger-find-metadata-in-buffer () (defun ledger-find-metadata-in-buffer ()
"Search through buffer and build list of metadata. "Search through buffer and build list of metadata.
@ -129,19 +129,19 @@ Return list."
(setq prefix (concat prefix (and prefix ":") (setq prefix (concat prefix (and prefix ":")
(car elements)) (car elements))
root (cdr xact)) root (cdr xact))
(setq root nil elements nil))) (setq root nil elements nil)))
(setq elements (cdr elements))) (setq elements (cdr elements)))
(setq root (delete (list (car elements) t) root)) (setq root (delete (list (car elements) t) root))
(and root (and root
(sort (sort
(mapcar (function (mapcar (function
(lambda (x) (lambda (x)
(let ((term (if prefix (let ((term (if prefix
(concat prefix ":" (car x)) (concat prefix ":" (car x))
(car x)))) (car x))))
(if (> (length (cdr x)) 1) (if (> (length (cdr x)) 1)
(concat term ":") (concat term ":")
term)))) term))))
(cdr root)) (cdr root))
'string-lessp)))) 'string-lessp))))
@ -155,39 +155,39 @@ Return list."
(delete (delete
(caar (ledger-parse-arguments)) (caar (ledger-parse-arguments))
(ledger-payees-in-buffer)) ;; this completes against payee names (ledger-payees-in-buffer)) ;; this completes against payee names
(progn (progn
(let ((text (buffer-substring-no-properties (let ((text (buffer-substring-no-properties
(line-beginning-position) (line-beginning-position)
(line-end-position)))) (line-end-position))))
(delete-region (line-beginning-position) (delete-region (line-beginning-position)
(line-end-position)) (line-end-position))
(condition-case nil (condition-case nil
(ledger-add-transaction text t) (ledger-add-transaction text t)
(error nil))) (error nil)))
(forward-line) (forward-line)
(goto-char (line-end-position)) (goto-char (line-end-position))
(search-backward ";" (line-beginning-position) t) (search-backward ";" (line-beginning-position) t)
(skip-chars-backward " \t0123456789.,") (skip-chars-backward " \t0123456789.,")
(throw 'pcompleted t))) (throw 'pcompleted t)))
(ledger-accounts))))) (ledger-accounts)))))
(defun ledger-fully-complete-xact () (defun ledger-fully-complete-xact ()
"Completes a transaction if there is another matching payee in the buffer. "Completes a transaction if there is another matching payee in the buffer.
Does not use ledger xact" Does not use ledger xact"
(interactive) (interactive)
(let* ((name (caar (ledger-parse-arguments))) (let* ((name (caar (ledger-parse-arguments)))
(rest-of-name name) (rest-of-name name)
xacts) xacts)
(save-excursion (save-excursion
(when (eq 'transaction (ledger-thing-at-point)) (when (eq 'transaction (ledger-thing-at-point))
(delete-region (point) (+ (length name) (point))) (delete-region (point) (+ (length name) (point)))
;; Search backward for a matching payee ;; Search backward for a matching payee
(when (re-search-backward (when (re-search-backward
(concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+\\(.*" (concat "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.*?)\\)?\\s-+\\(.*"
(regexp-quote name) ".*\\)" ) nil t) (regexp-quote name) ".*\\)" ) nil t)
(setq rest-of-name (match-string 3)) (setq rest-of-name (match-string 3))
;; Start copying the postings ;; Start copying the postings
(forward-line) (forward-line)
(while (looking-at ledger-account-any-status-regex) (while (looking-at ledger-account-any-status-regex)
(setq xacts (cons (buffer-substring-no-properties (setq xacts (cons (buffer-substring-no-properties
(line-beginning-position) (line-beginning-position)
@ -198,7 +198,7 @@ Does not use ledger xact"
;; Insert rest-of-name and the postings ;; Insert rest-of-name and the postings
(when xacts (when xacts
(save-excursion (save-excursion
(insert rest-of-name ?\n) (insert rest-of-name ?\n)
(while xacts (while xacts
(insert (car xacts) ?\n) (insert (car xacts) ?\n)
(setq xacts (cdr xacts)))) (setq xacts (cdr xacts))))
@ -227,30 +227,30 @@ ledger-magic-tab would cycle properly"
(push (car (last pcomplete-current-completions)) (push (car (last pcomplete-current-completions))
pcomplete-current-completions) pcomplete-current-completions)
(setcdr (last pcomplete-current-completions 2) nil)) (setcdr (last pcomplete-current-completions 2) nil))
(nconc pcomplete-current-completions (nconc pcomplete-current-completions
(list (car pcomplete-current-completions))) (list (car pcomplete-current-completions)))
(setq pcomplete-current-completions (setq pcomplete-current-completions
(cdr pcomplete-current-completions))) (cdr pcomplete-current-completions)))
(pcomplete-insert-entry pcomplete-last-completion-stub (pcomplete-insert-entry pcomplete-last-completion-stub
(car pcomplete-current-completions) (car pcomplete-current-completions)
nil pcomplete-last-completion-raw)) nil pcomplete-last-completion-raw))
(setq pcomplete-current-completions nil (setq pcomplete-current-completions nil
pcomplete-last-completion-raw nil) pcomplete-last-completion-raw nil)
(catch 'pcompleted (catch 'pcompleted
(let* ((pcomplete-stub) (let* ((pcomplete-stub)
pcomplete-seen pcomplete-norm-func pcomplete-seen pcomplete-norm-func
pcomplete-args pcomplete-last pcomplete-index pcomplete-args pcomplete-last pcomplete-index
(pcomplete-autolist pcomplete-autolist) (pcomplete-autolist pcomplete-autolist)
(pcomplete-suffix-list pcomplete-suffix-list) (pcomplete-suffix-list pcomplete-suffix-list)
(completions (pcomplete-completions)) (completions (pcomplete-completions))
(result (pcomplete-do-complete pcomplete-stub completions))) (result (pcomplete-do-complete pcomplete-stub completions)))
(and result (and result
(not (eq (car result) 'listed)) (not (eq (car result) 'listed))
(cdr result) (cdr result)
(pcomplete-insert-entry pcomplete-stub (cdr result) (pcomplete-insert-entry pcomplete-stub (cdr result)
(memq (car result) (memq (car result)
'(sole shortest)) '(sole shortest))
pcomplete-last-completion-raw)))))) pcomplete-last-completion-raw))))))
(provide 'ldg-complete) (provide 'ldg-complete)

View file

@ -51,14 +51,14 @@
(concat (symbol-name e) "-string")))))) "[ \t]*$"))) (concat (symbol-name e) "-string")))))) "[ \t]*$")))
(defmacro single-line-config2 (&rest elements) (defmacro single-line-config2 (&rest elements)
"Take list of ELEMENTS and return regex and element list for use in context-at-point" "Take list of ELEMENTS and return regex and element list for use in context-at-point"
(let (regex-string) (let (regex-string)
`'(,(concat (dolist (e elements regex-string) `'(,(concat (dolist (e elements regex-string)
(setq regex-string (setq regex-string
(concat regex-string (concat regex-string
(eval (eval
(intern (intern
(concat (symbol-name e) "-string")))))) "[ \t]*$") (concat (symbol-name e) "-string")))))) "[ \t]*$")
,elements))) ,elements)))
(defmacro single-line-config (&rest elements) (defmacro single-line-config (&rest elements)
@ -68,8 +68,8 @@
(defconst ledger-line-config (defconst ledger-line-config
(list (list 'xact (list (single-line-config date nil status nil code nil payee nil comment) (list (list 'xact (list (single-line-config date nil status nil code nil payee nil comment)
(single-line-config date nil status nil code nil payee) (single-line-config date nil status nil code nil payee)
(single-line-config date nil status nil payee))) (single-line-config date nil status nil payee)))
(list 'acct-transaction (list (single-line-config indent comment) (list 'acct-transaction (list (single-line-config indent comment)
(single-line-config2 indent status account nil commodity amount nil comment) (single-line-config2 indent status account nil commodity amount nil comment)
(single-line-config2 indent status account nil commodity amount) (single-line-config2 indent status account nil commodity amount)

View file

@ -38,7 +38,7 @@
(let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it (let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it
(matche (match-end 0))) (matche (match-end 0)))
(end-of-line) (end-of-line)
(setq environment-alist (setq environment-alist
(append environment-alist (append environment-alist
(list (cons (let ((flag (buffer-substring-no-properties (+ 2 matchb) matche))) (list (cons (let ((flag (buffer-substring-no-properties (+ 2 matchb) matche)))
(if (string-match "[ \t\n\r]+\\'" flag) (if (string-match "[ \t\n\r]+\\'" flag)
@ -55,13 +55,13 @@
(let ((init-base-name (file-name-nondirectory ledger-init-file-name))) (let ((init-base-name (file-name-nondirectory ledger-init-file-name)))
(if (get-buffer init-base-name) ;; init file already loaded, parse it and leave it (if (get-buffer init-base-name) ;; init file already loaded, parse it and leave it
(ledger-init-parse-initialization init-base-name) (ledger-init-parse-initialization init-base-name)
(when (and ledger-init-file-name (when (and ledger-init-file-name
(file-exists-p ledger-init-file-name) (file-exists-p ledger-init-file-name)
(file-readable-p ledger-init-file-name)) (file-readable-p ledger-init-file-name))
(find-file-noselect ledger-init-file-name) (find-file-noselect ledger-init-file-name)
(setq ledger-environment-alist (setq ledger-environment-alist
(ledger-init-parse-initialization init-base-name)) (ledger-init-parse-initialization init-base-name))
(kill-buffer init-base-name))))) (kill-buffer init-base-name)))))
(provide 'ldg-init) (provide 'ldg-init)

View file

@ -41,31 +41,31 @@
(defun ledger-read-account-with-prompt (prompt) (defun ledger-read-account-with-prompt (prompt)
(let* ((context (ledger-context-at-point)) (let* ((context (ledger-context-at-point))
(default (if (and (eq (ledger-context-line-type context) 'acct-transaction) (default (if (and (eq (ledger-context-line-type context) 'acct-transaction)
(eq (ledger-context-current-field context) 'account)) (eq (ledger-context-current-field context) 'account))
(regexp-quote (ledger-context-field-value context 'account)) (regexp-quote (ledger-context-field-value context 'account))
nil))) nil)))
(ledger-read-string-with-default prompt default))) (ledger-read-string-with-default prompt default)))
(defun ledger-read-string-with-default (prompt default) (defun ledger-read-string-with-default (prompt default)
"Return user supplied string after PROMPT, or DEFAULT." "Return user supplied string after PROMPT, or DEFAULT."
(read-string (concat prompt (read-string (concat prompt
(if default (if default
(concat " (" default "): ") (concat " (" default "): ")
": ")) ": "))
nil 'ledger-minibuffer-history default)) nil 'ledger-minibuffer-history default))
(defun ledger-display-balance-at-point () (defun ledger-display-balance-at-point ()
"Display the cleared-or-pending balance. "Display the cleared-or-pending balance.
And calculate the target-delta of the account being reconciled." And calculate the target-delta of the account being reconciled."
(interactive) (interactive)
(let* ((account (ledger-read-account-with-prompt "Account balance to show")) (let* ((account (ledger-read-account-with-prompt "Account balance to show"))
(buffer (current-buffer)) (buffer (current-buffer))
(balance (with-temp-buffer (balance (with-temp-buffer
(ledger-exec-ledger buffer (current-buffer) "cleared" account) (ledger-exec-ledger buffer (current-buffer) "cleared" account)
(if (> (buffer-size) 0) (if (> (buffer-size) 0)
(buffer-substring-no-properties (point-min) (1- (point-max))) (buffer-substring-no-properties (point-min) (1- (point-max)))
(concat account " is empty."))))) (concat account " is empty.")))))
(when balance (when balance
(message balance)))) (message balance))))
@ -74,9 +74,9 @@ And calculate the target-delta of the account being reconciled."
And calculate the target-delta of the account being reconciled." And calculate the target-delta of the account being reconciled."
(interactive) (interactive)
(let* ((buffer (current-buffer)) (let* ((buffer (current-buffer))
(balance (with-temp-buffer (balance (with-temp-buffer
(ledger-exec-ledger buffer (current-buffer) "stats") (ledger-exec-ledger buffer (current-buffer) "stats")
(buffer-substring-no-properties (point-min) (1- (point-max)))))) (buffer-substring-no-properties (point-min) (1- (point-max))))))
(when balance (when balance
(message balance)))) (message balance))))
@ -84,144 +84,146 @@ And calculate the target-delta of the account being reconciled."
"Decide what to with with <TAB>. "Decide what to with with <TAB>.
Can indent, complete or align depending on context." Can indent, complete or align depending on context."
(interactive "p") (interactive "p")
(if (= (point) (line-beginning-position)) (if (= (point) (line-beginning-position))
(indent-to ledger-post-account-alignment-column) (indent-to ledger-post-account-alignment-column)
(if (and (> (point) 1) (if (and (> (point) 1)
(looking-back "\\([^ \t]\\)" 1)) (looking-back "\\([^ \t]\\)" 1))
(ledger-pcomplete interactively) (ledger-pcomplete interactively)
(ledger-post-align-postings)))) (ledger-post-align-postings))))
(defvar ledger-mode-abbrev-table) (defvar ledger-mode-abbrev-table)
(defun ledger-insert-effective-date () (defun ledger-insert-effective-date ()
(interactive) (interactive)
(let ((context (car (ledger-context-at-point))) (let ((context (car (ledger-context-at-point)))
(date-string (format-time-string (cdr (assoc "date-format" ledger-environment-alist))))) (date-string (format-time-string (cdr (assoc "date-format" ledger-environment-alist)))))
(cond ((eq 'xact context) (cond ((eq 'xact context)
(beginning-of-line) (beginning-of-line)
(insert date-string "=")) (insert date-string "="))
((eq 'acct-transaction context) ((eq 'acct-transaction context)
(end-of-line) (end-of-line)
(insert " ; [=" date-string "]"))))) (insert " ; [=" date-string "]")))))
(defun ledger-mode-remove-extra-lines () (defun ledger-mode-remove-extra-lines ()
(goto-char (point-min)) (goto-char (point-min))
(while (re-search-forward "\n\n\\(\n\\)+" nil t) (while (re-search-forward "\n\n\\(\n\\)+" nil t)
(replace-match "\n\n"))) (replace-match "\n\n")))
(defun ledger-mode-clean-buffer () (defun ledger-mode-clean-buffer ()
"indent, remove multiple linfe feeds and sort the buffer" "indent, remove multiple linfe feeds and sort the buffer"
(interactive) (interactive)
(ledger-sort-buffer) (ledger-sort-buffer)
(ledger-post-align-postings (point-min) (point-max)) (ledger-post-align-postings (point-min) (point-max))
(ledger-mode-remove-extra-lines)) (ledger-mode-remove-extra-lines))
;;;###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-check-version) (ledger-check-version)
(ledger-post-setup) (ledger-check-schedule-available)
(ledger-post-setup)
(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)
(if (boundp 'font-lock-defaults) (if (boundp 'font-lock-defaults)
(set (make-local-variable 'font-lock-defaults) (set (make-local-variable 'font-lock-defaults)
'(ledger-font-lock-keywords nil t))) '(ledger-font-lock-keywords nil t)))
(setq font-lock-extend-region-functions (setq font-lock-extend-region-functions
(list #'font-lock-extend-region-wholelines)) (list #'font-lock-extend-region-wholelines))
(setq font-lock-multiline nil) (setq font-lock-multiline nil)
(set (make-local-variable 'pcomplete-parse-arguments-function) (set (make-local-variable 'pcomplete-parse-arguments-function)
'ledger-parse-arguments) 'ledger-parse-arguments)
(set (make-local-variable 'pcomplete-command-completion-function) (set (make-local-variable 'pcomplete-command-completion-function)
'ledger-complete-at-point) 'ledger-complete-at-point)
(set (make-local-variable 'pcomplete-termination-string) "") (set (make-local-variable 'pcomplete-termination-string) "")
(add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t) (add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t)
(add-hook 'before-revert-hook 'ledger-occur-remove-all-overlays nil t) (add-hook 'before-revert-hook 'ledger-occur-remove-all-overlays nil t)
(make-variable-buffer-local 'highlight-overlay) (make-variable-buffer-local 'highlight-overlay)
(ledger-init-load-init-file) (ledger-init-load-init-file)
(set (make-local-variable 'indent-region-function) 'ledger-post-align-postings) (set (make-local-variable 'indent-region-function) 'ledger-post-align-postings)
(let ((map (current-local-map))) (let ((map (current-local-map)))
(define-key map [(control ?c) (control ?a)] 'ledger-add-transaction) (define-key map [(control ?c) (control ?a)] 'ledger-add-transaction)
(define-key map [(control ?c) (control ?b)] 'ledger-post-edit-amount) (define-key map [(control ?c) (control ?b)] 'ledger-post-edit-amount)
(define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current)
(define-key map [(control ?c) (control ?d)] 'ledger-delete-current-transaction) (define-key map [(control ?c) (control ?d)] 'ledger-delete-current-transaction)
(define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-transaction) (define-key map [(control ?c) (control ?e)] 'ledger-toggle-current-transaction)
(define-key map [(control ?c) (control ?f)] 'ledger-occur) (define-key map [(control ?c) (control ?f)] 'ledger-occur)
(define-key map [(control ?c) (control ?k)] 'ledger-copy-transaction-at-point) (define-key map [(control ?c) (control ?k)] 'ledger-copy-transaction-at-point)
(define-key map [(control ?c) (control ?m)] 'ledger-set-month) (define-key map [(control ?c) (control ?m)] 'ledger-set-month)
(define-key map [(control ?c) (control ?r)] 'ledger-reconcile) (define-key map [(control ?c) (control ?r)] 'ledger-reconcile)
(define-key map [(control ?c) (control ?s)] 'ledger-sort-region) (define-key map [(control ?c) (control ?s)] 'ledger-sort-region)
(define-key map [(control ?c) (control ?t)] 'ledger-insert-effective-date) (define-key map [(control ?c) (control ?t)] 'ledger-insert-effective-date)
(define-key map [(control ?c) (control ?u)] 'ledger-schedule-upcoming) (define-key map [(control ?c) (control ?u)] 'ledger-schedule-upcoming)
(define-key map [(control ?c) (control ?y)] 'ledger-set-year) (define-key map [(control ?c) (control ?y)] 'ledger-set-year)
(define-key map [(control ?c) (control ?p)] 'ledger-display-balance-at-point) (define-key map [(control ?c) (control ?p)] 'ledger-display-balance-at-point)
(define-key map [(control ?c) (control ?l)] 'ledger-display-ledger-stats) (define-key map [(control ?c) (control ?l)] 'ledger-display-ledger-stats)
(define-key map [(control ?c) (control ?q)] 'ledger-post-align-xact) (define-key map [(control ?c) (control ?q)] 'ledger-post-align-xact)
(define-key map [tab] 'ledger-magic-tab) (define-key map [tab] 'ledger-magic-tab)
(define-key map [(control tab)] 'ledger-post-align-xact) (define-key map [(control tab)] 'ledger-post-align-xact)
(define-key map [(control ?i)] 'ledger-magic-tab) (define-key map [(control ?i)] 'ledger-magic-tab)
(define-key map [(control ?c) tab] 'ledger-fully-complete-xact) (define-key map [(control ?c) tab] 'ledger-fully-complete-xact)
(define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-xact) (define-key map [(control ?c) (control ?i)] 'ledger-fully-complete-xact)
(define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo) (define-key map [(control ?c) (control ?o) (control ?a)] 'ledger-report-redo)
(define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit) (define-key map [(control ?c) (control ?o) (control ?e)] 'ledger-report-edit)
(define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto) (define-key map [(control ?c) (control ?o) (control ?g)] 'ledger-report-goto)
(define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill) (define-key map [(control ?c) (control ?o) (control ?k)] 'ledger-report-kill)
(define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report) (define-key map [(control ?c) (control ?o) (control ?r)] 'ledger-report)
(define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save) (define-key map [(control ?c) (control ?o) (control ?s)] 'ledger-report-save)
(define-key map [(meta ?p)] 'ledger-post-prev-xact) (define-key map [(meta ?p)] 'ledger-post-prev-xact)
(define-key map [(meta ?n)] 'ledger-post-next-xact) (define-key map [(meta ?n)] 'ledger-post-next-xact)
(define-key map [menu-bar] (make-sparse-keymap "ldg-menu")) (define-key map [menu-bar] (make-sparse-keymap "ldg-menu"))
(define-key map [menu-bar ldg-menu] (cons "Ledger" map)) (define-key map [menu-bar ldg-menu] (cons "Ledger" map))
(define-key map [report-kill] '(menu-item "Kill Report" ledger-report-kill :enable ledger-works)) (define-key map [report-kill] '(menu-item "Kill Report" ledger-report-kill :enable ledger-works))
(define-key map [report-edit] '(menu-item "Edit Report" ledger-report-edit :enable ledger-works)) (define-key map [report-edit] '(menu-item "Edit Report" ledger-report-edit :enable ledger-works))
(define-key map [report-save] '(menu-item "Save Report" ledger-report-save :enable ledger-works)) (define-key map [report-save] '(menu-item "Save Report" ledger-report-save :enable ledger-works))
(define-key map [report-rrun] '(menu-item "Re-run Report" ledger-report-redo :enable ledger-works)) (define-key map [report-rrun] '(menu-item "Re-run Report" ledger-report-redo :enable ledger-works))
(define-key map [report-goto] '(menu-item "Goto Report" ledger-report-goto :enable ledger-works)) (define-key map [report-goto] '(menu-item "Goto Report" ledger-report-goto :enable ledger-works))
(define-key map [report-run] '(menu-item "Run Report" ledger-report :enable ledger-works)) (define-key map [report-run] '(menu-item "Run Report" ledger-report :enable ledger-works))
(define-key map [sep5] '(menu-item "--")) (define-key map [sep5] '(menu-item "--"))
(define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works)) (define-key map [set-month] '(menu-item "Set Month" ledger-set-month :enable ledger-works))
(define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works)) (define-key map [set-year] '(menu-item "Set Year" ledger-set-year :enable ledger-works))
(define-key map [cust] '(menu-item "Customize Ledger Mode" (lambda () (define-key map [cust] '(menu-item "Customize Ledger Mode" (lambda ()
(interactive) (interactive)
(customize-group 'ledger)))) (customize-group 'ledger))))
(define-key map [sep1] '("--")) (define-key map [sep1] '("--"))
(define-key map [effective-date] '(menu-item "Set effective date" ledger-insert-effective-date)) (define-key map [effective-date] '(menu-item "Set effective date" ledger-insert-effective-date))
(define-key map [sort-end] '(menu-item "Mark Sort End" ledger-sort-insert-end-mark)) (define-key map [sort-end] '(menu-item "Mark Sort End" ledger-sort-insert-end-mark))
(define-key map [sort-start] '(menu-item "Mark Sort Beginning" ledger-sort-insert-start-mark)) (define-key map [sort-start] '(menu-item "Mark Sort Beginning" ledger-sort-insert-start-mark))
(define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer)) (define-key map [sort-buff] '(menu-item "Sort Buffer" ledger-sort-buffer))
(define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active)) (define-key map [sort-reg] '(menu-item "Sort Region" ledger-sort-region :enable mark-active))
(define-key map [align-xact] '(menu-item "Align Xact" ledger-post-align-xact)) (define-key map [align-xact] '(menu-item "Align Xact" ledger-post-align-xact))
(define-key map [align-reg] '(menu-item "Align Region" ledger-post-align-postings :enable mark-active)) (define-key map [align-reg] '(menu-item "Align Region" ledger-post-align-postings :enable mark-active))
(define-key map [clean-buf] '(menu-item "Clean-up Buffer" ledger-mode-clean-buffer)) (define-key map [clean-buf] '(menu-item "Clean-up Buffer" ledger-mode-clean-buffer))
(define-key map [sep2] '(menu-item "--")) (define-key map [sep2] '(menu-item "--"))
(define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction-at-point)) (define-key map [copy-xact] '(menu-item "Copy Trans at Point" ledger-copy-transaction-at-point))
(define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current)) (define-key map [toggle-post] '(menu-item "Toggle Current Posting" ledger-toggle-current))
(define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-transaction)) (define-key map [toggle-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-transaction))
(define-key map [sep4] '(menu-item "--")) (define-key map [sep4] '(menu-item "--"))
(define-key map [recon-account] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works)) (define-key map [recon-account] '(menu-item "Reconcile Account" ledger-reconcile :enable ledger-works))
(define-key map [check-balance] '(menu-item "Check Balance" ledger-display-balance-at-point :enable ledger-works)) (define-key map [check-balance] '(menu-item "Check Balance" ledger-display-balance-at-point :enable ledger-works))
(define-key map [sep6] '(menu-item "--")) (define-key map [sep6] '(menu-item "--"))
(define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount))
(define-key map [sep] '(menu-item "--")) (define-key map [sep] '(menu-item "--"))
(define-key map [delete-xact] '(menu-item "Delete Transaction" ledger-delete-current-transaction)) (define-key map [delete-xact] '(menu-item "Delete Transaction" ledger-delete-current-transaction))
(define-key map [cmp-xact] '(menu-item "Complete Transaction" ledger-fully-complete-xact)) (define-key map [cmp-xact] '(menu-item "Complete Transaction" ledger-fully-complete-xact))
(define-key map [add-xact] '(menu-item "Add Transaction (ledger xact)" ledger-add-transaction :enable ledger-works)) (define-key map [add-xact] '(menu-item "Add Transaction (ledger xact)" ledger-add-transaction :enable ledger-works))
(define-key map [sep3] '(menu-item "--")) (define-key map [generate-scheduled] '(menu-item "Show Upcoming Transactions" ledger-schedule-upcoming :enable ledger-schedule-available))
(define-key map [stats] '(menu-item "Ledger Statistics" ledger-display-ledger-stats :enable ledger-works)) (define-key map [sep3] '(menu-item "--"))
(define-key map [fold-buffer] '(menu-item "Narrow to REGEX" ledger-occur)))) (define-key map [stats] '(menu-item "Ledger Statistics" ledger-display-ledger-stats :enable ledger-works))
(define-key map [fold-buffer] '(menu-item "Narrow to REGEX" ledger-occur))))

View file

@ -39,7 +39,7 @@
(defvar ledger-occur-mode nil (defvar ledger-occur-mode nil
"name of the minor mode, shown in the mode-line") "name of the minor mode, shown in the mode-line")
(make-variable-buffer-local 'ledger-occur-mode) (make-variable-buffer-local 'ledger-occur-mode)
@ -65,19 +65,19 @@
When REGEX is nil, unhide everything, and remove higlight" When REGEX is nil, unhide everything, and remove higlight"
(set-buffer buffer) (set-buffer buffer)
(setq ledger-occur-mode (setq ledger-occur-mode
(if (or (null regex) (if (or (null regex)
(zerop (length regex))) (zerop (length regex)))
nil nil
(concat " Ledger-Narrowed: " regex))) (concat " Ledger-Narrowed: " regex)))
(force-mode-line-update) (force-mode-line-update)
(ledger-occur-remove-overlays) (ledger-occur-remove-overlays)
(when ledger-occur-mode (when ledger-occur-mode
(ledger-occur-create-overlays (ledger-occur-create-overlays
(ledger-occur-compress-matches (ledger-occur-compress-matches
(ledger-occur-find-matches regex))) (ledger-occur-find-matches regex)))
(setq ledger-occur-last-match regex) (setq ledger-occur-last-match regex)
(if (get-buffer-window buffer) (if (get-buffer-window buffer)
(select-window (get-buffer-window buffer)))) (select-window (get-buffer-window buffer))))
(recenter)) (recenter))
(defun ledger-occur (regex) (defun ledger-occur (regex)
@ -90,7 +90,7 @@ When REGEX is nil, unhide everything, and remove higlight"
(if ledger-occur-mode (if ledger-occur-mode
(list nil) (list nil)
(list (read-string (concat "Regexp<" (ledger-occur-prompt) ">: ") (list (read-string (concat "Regexp<" (ledger-occur-prompt) ">: ")
nil 'ledger-occur-history (ledger-occur-prompt))))) nil 'ledger-occur-history (ledger-occur-prompt)))))
(ledger-occur-mode regex (current-buffer))) (ledger-occur-mode regex (current-buffer)))
(defun ledger-occur-prompt () (defun ledger-occur-prompt ()
@ -108,32 +108,32 @@ When REGEX is nil, unhide everything, and remove higlight"
(if (= (line-number-at-pos pos1) (if (= (line-number-at-pos pos1)
(line-number-at-pos pos2)) (line-number-at-pos pos2))
(buffer-substring-no-properties pos1 pos2))) (buffer-substring-no-properties pos1 pos2)))
(current-word)))) (current-word))))
prompt)) prompt))
(defun ledger-occur-make-visible-overlay (beg end) (defun ledger-occur-make-visible-overlay (beg end)
(let ((ovl (make-overlay beg end (current-buffer)))) (let ((ovl (make-overlay beg end (current-buffer))))
(overlay-put ovl ledger-occur-overlay-property-name t) (overlay-put ovl ledger-occur-overlay-property-name t)
(overlay-put ovl 'face 'ledger-occur-xact-face))) (overlay-put ovl 'face 'ledger-occur-xact-face)))
(defun ledger-occur-make-invisible-overlay (beg end) (defun ledger-occur-make-invisible-overlay (beg end)
(let ((ovl (make-overlay beg end (current-buffer)))) (let ((ovl (make-overlay beg end (current-buffer))))
(overlay-put ovl ledger-occur-overlay-property-name t) (overlay-put ovl ledger-occur-overlay-property-name t)
(overlay-put ovl 'invisible t))) (overlay-put ovl 'invisible t)))
(defun ledger-occur-create-overlays (ovl-bounds) (defun ledger-occur-create-overlays (ovl-bounds)
"Create the overlays for the visible transactions. "Create the overlays for the visible transactions.
Argument OVL-BOUNDS contains bounds for the transactions to be left visible." Argument OVL-BOUNDS contains bounds for the transactions to be left visible."
(let* ((beg (caar ovl-bounds)) (let* ((beg (caar ovl-bounds))
(end (cadar ovl-bounds))) (end (cadar ovl-bounds)))
(ledger-occur-make-invisible-overlay (point-min) (1- beg)) (ledger-occur-make-invisible-overlay (point-min) (1- beg))
(dolist (visible (cdr ovl-bounds)) (dolist (visible (cdr ovl-bounds))
(ledger-occur-make-visible-overlay beg end) (ledger-occur-make-visible-overlay beg end)
(ledger-occur-make-invisible-overlay (1+ end) (1- (car visible))) (ledger-occur-make-invisible-overlay (1+ end) (1- (car visible)))
(setq beg (car visible)) (setq beg (car visible))
(setq end (cadr visible))) (setq end (cadr visible)))
(ledger-occur-make-invisible-overlay (1+ end) (point-max)))) (ledger-occur-make-invisible-overlay (1+ end) (point-max))))
(defun ledger-occur-quit-buffer (buffer) (defun ledger-occur-quit-buffer (buffer)
"Quits hidings transaction in the given BUFFER. "Quits hidings transaction in the given BUFFER.
@ -148,7 +148,7 @@ Used for coordinating `ledger-occur' with other buffers, like reconcile."
"Remove the transaction hiding overlays." "Remove the transaction hiding overlays."
(interactive) (interactive)
(remove-overlays (point-min) (remove-overlays (point-min)
(point-max) ledger-occur-overlay-property-name t) (point-max) ledger-occur-overlay-property-name t)
(setq ledger-occur-overlay-list nil)) (setq ledger-occur-overlay-list nil))
(defun ledger-occur-find-matches (regex) (defun ledger-occur-find-matches (regex)
@ -157,35 +157,35 @@ Used for coordinating `ledger-occur' with other buffers, like reconcile."
(goto-char (point-min)) (goto-char (point-min))
;; Set initial values for variables ;; Set initial values for variables
(let (curpoint (let (curpoint
endpoint endpoint
(lines (list))) (lines (list)))
;; Search loop ;; Search loop
(while (not (eobp)) (while (not (eobp))
(setq curpoint (point)) (setq curpoint (point))
;; if something found ;; if something found
(when (setq endpoint (re-search-forward regex nil 'end)) (when (setq endpoint (re-search-forward regex nil 'end))
(save-excursion (save-excursion
(let ((bounds (ledger-find-xact-extents (match-beginning 0)))) (let ((bounds (ledger-find-xact-extents (match-beginning 0))))
(push bounds lines) (push bounds lines)
(setq curpoint (cadr bounds)))) ;; move to the end of (setq curpoint (cadr bounds)))) ;; move to the end of
;; the xact, no need to ;; the xact, no need to
;; search inside it more ;; search inside it more
(goto-char curpoint)) (goto-char curpoint))
(forward-line 1)) (forward-line 1))
(setq lines (nreverse lines))))) (setq lines (nreverse lines)))))
(defun ledger-occur-compress-matches (buffer-matches) (defun ledger-occur-compress-matches (buffer-matches)
"identify sequential xacts to reduce number of overlays required" "identify sequential xacts to reduce number of overlays required"
(let ((points (list)) (let ((points (list))
(current-beginning (caar buffer-matches)) (current-beginning (caar buffer-matches))
(current-end (cadar buffer-matches))) (current-end (cadar buffer-matches)))
(dolist (match (cdr buffer-matches)) (dolist (match (cdr buffer-matches))
(if (< (- (car match) current-end) 2) (if (< (- (car match) current-end) 2)
(setq current-end (cadr match)) (setq current-end (cadr match))
(push (list current-beginning current-end) points) (push (list current-beginning current-end) points)
(setq current-beginning (car match)) (setq current-beginning (car match))
(setq current-end (cadr match)))) (setq current-end (cadr match))))
(nreverse (push (list current-beginning current-end) points)))) (nreverse (push (list current-beginning current-end) points))))
(provide 'ldg-occur) (provide 'ldg-occur)

View file

@ -44,10 +44,10 @@
(defcustom ledger-post-use-completion-engine :built-in (defcustom ledger-post-use-completion-engine :built-in
"Which completion engine to use, :iswitchb or :ido chose those engines, "Which completion engine to use, :iswitchb or :ido chose those engines,
:built-in uses built-in Ledger-mode completion" :built-in uses built-in Ledger-mode completion"
:type '(radio (const :tag "built in completion" :built-in) :type '(radio (const :tag "built in completion" :built-in)
(const :tag "ido completion" :ido) (const :tag "ido completion" :ido)
(const :tag "iswitchb completion" :iswitchb) ) (const :tag "iswitchb completion" :iswitchb) )
:group 'ledger-post) :group 'ledger-post)
(defun ledger-post-all-accounts () (defun ledger-post-all-accounts ()
"Return a list of all accounts in the buffer." "Return a list of all accounts in the buffer."
@ -72,15 +72,15 @@
PROMPT is a string to prompt with. CHOICES is a list of strings PROMPT is a string to prompt with. CHOICES is a list of strings
to choose from." to choose from."
(cond ((eq ledger-post-use-completion-engine :iswitchb) (cond ((eq ledger-post-use-completion-engine :iswitchb)
(let* ((iswitchb-use-virtual-buffers nil) (let* ((iswitchb-use-virtual-buffers nil)
(iswitchb-make-buflist-hook (iswitchb-make-buflist-hook
(lambda () (lambda ()
(setq iswitchb-temp-buflist choices)))) (setq iswitchb-temp-buflist choices))))
(iswitchb-read-buffer prompt))) (iswitchb-read-buffer prompt)))
((eq ledger-post-use-completion-engine :ido) ((eq ledger-post-use-completion-engine :ido)
(ido-completing-read prompt choices)) (ido-completing-read prompt choices))
(t (t
(completing-read prompt choices)))) (completing-read prompt choices))))
(defvar ledger-post-current-list nil) (defvar ledger-post-current-list nil)
@ -102,12 +102,12 @@ to choose from."
(match-end ledger-regex-post-line-group-account)) (match-end ledger-regex-post-line-group-account))
(insert account) (insert account)
(cond (cond
((> existing-len account-len) ((> existing-len account-len)
(insert (make-string (- existing-len account-len) ? ))) (insert (make-string (- existing-len account-len) ? )))
((< existing-len account-len) ((< existing-len account-len)
(dotimes (n (- account-len existing-len)) (dotimes (n (- account-len existing-len))
(if (looking-at "[ \t]\\( [ \t]\\|\t\\)") (if (looking-at "[ \t]\\( [ \t]\\|\t\\)")
(delete-char 1))))))) (delete-char 1)))))))
(goto-char pos))) (goto-char pos)))
@ -128,18 +128,18 @@ point at beginning of the commodity."
"Move point to the beginning of the next account, or status marker (!*), as long as it is not past END. "Move point to the beginning of the next account, or status marker (!*), as long as it is not past END.
Return the column of the beginning of the account and leave point Return the column of the beginning of the account and leave point
at beginning of account" at beginning of account"
(if (> end (point)) (if (> end (point))
(when (re-search-forward ledger-account-any-status-regex (1+ end) t) (when (re-search-forward ledger-account-any-status-regex (1+ end) t)
;; the 1+ is to make sure we can catch the newline ;; the 1+ is to make sure we can catch the newline
(if (match-beginning 1) (if (match-beginning 1)
(goto-char (match-beginning 1)) (goto-char (match-beginning 1))
(goto-char (match-beginning 2))) (goto-char (match-beginning 2)))
(current-column)))) (current-column))))
(defun ledger-post-align-xact (pos) (defun ledger-post-align-xact (pos)
(interactive "d") (interactive "d")
(let ((bounds (ledger-find-xact-extents pos))) (let ((bounds (ledger-find-xact-extents pos)))
(ledger-post-align-postings (car bounds) (cadr bounds)))) (ledger-post-align-postings (car bounds) (cadr bounds))))
(defun ledger-post-align-postings (&optional beg end) (defun ledger-post-align-postings (&optional beg end)
"Align all accounts and amounts within region, if there is no "Align all accounts and amounts within region, if there is no
@ -149,52 +149,52 @@ region align the posting on the current line."
(save-excursion (save-excursion
(if (or (not (mark)) (if (or (not (mark))
(not (use-region-p))) (not (use-region-p)))
(set-mark (point))) (set-mark (point)))
(let* ((inhibit-modification-hooks t) (let* ((inhibit-modification-hooks t)
(mark-first (< (mark) (point))) (mark-first (< (mark) (point)))
(begin-region (if beg (begin-region (if beg
beg beg
(if mark-first (mark) (point)))) (if mark-first (mark) (point))))
(end-region (if end (end-region (if end
end end
(if mark-first (point) (mark)))) (if mark-first (point) (mark))))
acct-start-column acct-end-column acct-adjust amt-width acct-start-column acct-end-column acct-adjust amt-width
(lines-left 1)) (lines-left 1))
;; Condition point and mark to the beginning and end of lines ;; Condition point and mark to the beginning and end of lines
(goto-char end-region) (goto-char end-region)
(setq end-region (line-end-position)) (setq end-region (line-end-position))
(goto-char begin-region) (goto-char begin-region)
(goto-char (goto-char
(setq begin-region (setq begin-region
(line-beginning-position))) (line-beginning-position)))
;; This is the guts of the alignment loop ;; This is the guts of the alignment loop
(while (and (or (setq acct-start-column (ledger-next-account (line-end-position))) (while (and (or (setq acct-start-column (ledger-next-account (line-end-position)))
lines-left) lines-left)
(< (point) end-region)) (< (point) end-region))
(when acct-start-column (when acct-start-column
(setq acct-end-column (save-excursion (setq acct-end-column (save-excursion
(goto-char (match-end 2)) (goto-char (match-end 2))
(current-column))) (current-column)))
(when (/= (setq acct-adjust (- ledger-post-account-alignment-column acct-start-column)) 0) (when (/= (setq acct-adjust (- ledger-post-account-alignment-column acct-start-column)) 0)
(setq acct-end-column (+ acct-end-column acct-adjust)) ;;adjust the account ending column (setq acct-end-column (+ acct-end-column acct-adjust)) ;;adjust the account ending column
(if (> acct-adjust 0) (if (> acct-adjust 0)
(insert (make-string acct-adjust ? )) (insert (make-string acct-adjust ? ))
(delete-char acct-adjust))) (delete-char acct-adjust)))
(when (setq amt-width (ledger-next-amount (line-end-position))) (when (setq amt-width (ledger-next-amount (line-end-position)))
(if (/= 0 (setq amt-adjust (- (if (> (- ledger-post-amount-alignment-column amt-width) (if (/= 0 (setq amt-adjust (- (if (> (- ledger-post-amount-alignment-column amt-width)
(+ 2 acct-end-column)) (+ 2 acct-end-column))
ledger-post-amount-alignment-column ;;we have room ledger-post-amount-alignment-column ;;we have room
(+ acct-end-column 2 amt-width)) (+ acct-end-column 2 amt-width))
amt-width amt-width
(current-column)))) (current-column))))
(if (> amt-adjust 0) (if (> amt-adjust 0)
(insert (make-string amt-adjust ? )) (insert (make-string amt-adjust ? ))
(delete-char amt-adjust))))) (delete-char amt-adjust)))))
(forward-line) (forward-line)
(setq lines-left (not (eobp)))) (setq lines-left (not (eobp))))
(setq inhibit-modification-hooks nil)))) (setq inhibit-modification-hooks nil))))
@ -208,16 +208,16 @@ region align the posting on the current line."
(let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t)))
;; determine if there is an amount to edit ;; determine if there is an amount to edit
(if end-of-amount (if end-of-amount
(let ((val (ledger-string-to-number (match-string 0)))) (let ((val (ledger-string-to-number (match-string 0))))
(goto-char (match-beginning 0)) (goto-char (match-beginning 0))
(delete-region (match-beginning 0) (match-end 0)) (delete-region (match-beginning 0) (match-end 0))
(calc) (calc)
(calc-eval val 'push)) ;; edit the amount (calc-eval val 'push)) ;; edit the amount
(progn ;;make sure there are two spaces after the account name and go to calc (progn ;;make sure there are two spaces after the account name and go to calc
(if (search-backward " " (- (point) 3) t) (if (search-backward " " (- (point) 3) t)
(goto-char (line-end-position)) (goto-char (line-end-position))
(insert " ")) (insert " "))
(calc)))))) (calc))))))
(defun ledger-post-prev-xact () (defun ledger-post-prev-xact ()
"Move point to the previous transaction." "Move point to the previous transaction."

View file

@ -33,7 +33,7 @@
(defvar ledger-target nil) (defvar ledger-target nil)
(defgroup ledger-reconcile nil (defgroup ledger-reconcile nil
"Options for Ledger-mode reconciliation" "Options for Ledger-mode reconciliation"
:group 'ledger) :group 'ledger)
(defcustom ledger-recon-buffer-name "*Reconcile*" (defcustom ledger-recon-buffer-name "*Reconcile*"
@ -59,8 +59,8 @@ Then that transaction will be shown in its source buffer."
(defcustom ledger-reconcile-toggle-to-pending t (defcustom ledger-reconcile-toggle-to-pending t
"If true then toggle between uncleared and pending. "If true then toggle between uncleared and pending.
reconcile-finish will mark all pending posting cleared." reconcile-finish will mark all pending posting cleared."
:type 'boolean :type 'boolean
:group 'ledger-reconcile) :group 'ledger-reconcile)
(defcustom ledger-reconcile-default-date-format "%Y/%m/%d" (defcustom ledger-reconcile-default-date-format "%Y/%m/%d"
"Default date format for the reconcile buffer" "Default date format for the reconcile buffer"
@ -73,7 +73,7 @@ reconcile-finish will mark all pending posting cleared."
:group 'ledger-reconcile) :group 'ledger-reconcile)
(defvar ledger-reconcile-sort-key "(date)" (defvar ledger-reconcile-sort-key "(date)"
"Default key for sorting reconcile buffer") "Default key for sorting reconcile buffer")
(defun ledger-reconcile-get-cleared-or-pending-balance (buffer account) (defun ledger-reconcile-get-cleared-or-pending-balance (buffer account)
"Calculate the cleared or pending balance of the account." "Calculate the cleared or pending balance of the account."
@ -87,10 +87,10 @@ reconcile-finish will mark all pending posting cleared."
;; split arguments like the shell does, so you need to ;; split arguments like the shell does, so you need to
;; specify the individual fields in the command line. ;; specify the individual fields in the command line.
(if (ledger-exec-ledger buffer (current-buffer) (if (ledger-exec-ledger buffer (current-buffer)
"balance" "--limit" "cleared or pending" "--empty" "--collapse" "balance" "--limit" "cleared or pending" "--empty" "--collapse"
"--format" "%(display_total)" account) "--format" "%(display_total)" account)
(ledger-split-commodity-string (ledger-split-commodity-string
(buffer-substring-no-properties (point-min) (point-max)))))) (buffer-substring-no-properties (point-min) (point-max))))))
(defun ledger-display-balance () (defun ledger-display-balance ()
"Display the cleared-or-pending balance. "Display the cleared-or-pending balance.
@ -98,12 +98,12 @@ And calculate the target-delta of the account being reconciled."
(interactive) (interactive)
(let* ((pending (ledger-reconcile-get-cleared-or-pending-balance ledger-buf ledger-acct))) (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance ledger-buf ledger-acct)))
(when pending (when pending
(if ledger-target (if ledger-target
(message "Pending balance: %s, Difference from target: %s" (message "Pending balance: %s, Difference from target: %s"
(ledger-commodity-to-string pending) (ledger-commodity-to-string pending)
(ledger-commodity-to-string (-commodity ledger-target pending))) (ledger-commodity-to-string (-commodity ledger-target pending)))
(message "Pending balance: %s" (message "Pending balance: %s"
(ledger-commodity-to-string pending)))))) (ledger-commodity-to-string pending))))))
(defun is-stdin (file) (defun is-stdin (file)
"True if ledger FILE is standard input." "True if ledger FILE is standard input."
@ -127,27 +127,27 @@ And calculate the target-delta of the account being reconciled."
status) status)
(when (ledger-reconcile-get-buffer where) (when (ledger-reconcile-get-buffer where)
(with-current-buffer (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where)
(ledger-goto-line (cdr where)) (ledger-goto-line (cdr where))
(forward-char) (forward-char)
(setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending
'pending 'pending
'cleared)))) 'cleared))))
;; remove the existing face and add the new face ;; remove the existing face and add the new face
(remove-text-properties (line-beginning-position) (remove-text-properties (line-beginning-position)
(line-end-position) (line-end-position)
(list 'face)) (list 'face))
(cond ((eq status 'pending) (cond ((eq status 'pending)
(add-text-properties (line-beginning-position) (add-text-properties (line-beginning-position)
(line-end-position) (line-end-position)
(list 'face 'ledger-font-reconciler-pending-face ))) (list 'face 'ledger-font-reconciler-pending-face )))
((eq status 'cleared) ((eq status 'cleared)
(add-text-properties (line-beginning-position) (add-text-properties (line-beginning-position)
(line-end-position) (line-end-position)
(list 'face 'ledger-font-reconciler-cleared-face ))) (list 'face 'ledger-font-reconciler-cleared-face )))
(t (t
(add-text-properties (line-beginning-position) (add-text-properties (line-beginning-position)
(line-end-position) (line-end-position)
(list 'face 'ledger-font-reconciler-uncleared-face ))))) (list 'face 'ledger-font-reconciler-uncleared-face )))))
(forward-line) (forward-line)
(beginning-of-line) (beginning-of-line)
(ledger-display-balance))) (ledger-display-balance)))
@ -159,18 +159,18 @@ Return the number of uncleared xacts found."
(let ((inhibit-read-only t)) (let ((inhibit-read-only t))
(erase-buffer) (erase-buffer)
(prog1 (prog1
(ledger-do-reconcile ledger-reconcile-sort-key) (ledger-do-reconcile ledger-reconcile-sort-key)
(set-buffer-modified-p t)))) (set-buffer-modified-p t))))
(defun ledger-reconcile-refresh-after-save () (defun ledger-reconcile-refresh-after-save ()
"Refresh the recon-window after the ledger buffer is saved." "Refresh the recon-window after the ledger buffer is saved."
(let ((curbuf (current-buffer)) (let ((curbuf (current-buffer))
(curpoint (point)) (curpoint (point))
(recon-buf (get-buffer ledger-recon-buffer-name))) (recon-buf (get-buffer ledger-recon-buffer-name)))
(when (buffer-live-p recon-buf) (when (buffer-live-p recon-buf)
(with-current-buffer recon-buf (with-current-buffer recon-buf
(ledger-reconcile-refresh) (ledger-reconcile-refresh)
(set-buffer-modified-p nil)) (set-buffer-modified-p nil))
(select-window (get-buffer-window curbuf)) (select-window (get-buffer-window curbuf))
(goto-char curpoint)))) (goto-char curpoint))))
@ -200,19 +200,19 @@ Return the number of uncleared xacts found."
(progn (progn
(beginning-of-line) (beginning-of-line)
(let* ((where (get-text-property (1+ (point)) 'where)) (let* ((where (get-text-property (1+ (point)) 'where))
(target-buffer (if where (target-buffer (if where
(ledger-reconcile-get-buffer where) (ledger-reconcile-get-buffer where)
nil)) nil))
(cur-win (get-buffer-window (get-buffer ledger-recon-buffer-name)))) (cur-win (get-buffer-window (get-buffer ledger-recon-buffer-name))))
(when target-buffer (when target-buffer
(switch-to-buffer-other-window target-buffer) (switch-to-buffer-other-window target-buffer)
(ledger-goto-line (cdr where)) (ledger-goto-line (cdr where))
(forward-char) (forward-char)
(recenter) (recenter)
(ledger-highlight-xact-under-point) (ledger-highlight-xact-under-point)
(forward-char -1) (forward-char -1)
(if (and come-back cur-win) (if (and come-back cur-win)
(select-window cur-win)))))) (select-window cur-win))))))
(defun ledger-reconcile-save () (defun ledger-reconcile-save ()
"Save the ledger buffer." "Save the ledger buffer."
@ -220,7 +220,7 @@ Return the number of uncleared xacts found."
(let ((curpoint (point))) (let ((curpoint (point)))
(dolist (buf (cons ledger-buf ledger-bufs)) (dolist (buf (cons ledger-buf ledger-bufs))
(with-current-buffer buf (with-current-buffer buf
(save-buffer))) (save-buffer)))
(with-current-buffer (get-buffer ledger-recon-buffer-name) (with-current-buffer (get-buffer ledger-recon-buffer-name)
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
(ledger-display-balance) (ledger-display-balance)
@ -243,94 +243,94 @@ and exit reconcile mode"
(ledger-toggle-current 'cleared)))) (ledger-toggle-current 'cleared))))
(forward-line 1))) (forward-line 1)))
(ledger-reconcile-save) (ledger-reconcile-save)
(ledger-reconcile-quit)) (ledger-reconcile-quit))
(defun ledger-reconcile-quit () (defun ledger-reconcile-quit ()
"Quit the reconcile window without saving ledger buffer." "Quit the reconcile window without saving ledger buffer."
(interactive) (interactive)
(let ((recon-buf (get-buffer ledger-recon-buffer-name)) (let ((recon-buf (get-buffer ledger-recon-buffer-name))
buf) buf)
(if recon-buf (if recon-buf
(with-current-buffer recon-buf (with-current-buffer recon-buf
(ledger-reconcile-quit-cleanup) (ledger-reconcile-quit-cleanup)
(setq buf ledger-buf) (setq buf ledger-buf)
;; Make sure you delete the window before you delete the buffer, ;; Make sure you delete the window before you delete the buffer,
;; otherwise, madness ensues ;; otherwise, madness ensues
(delete-window (get-buffer-window recon-buf)) (delete-window (get-buffer-window recon-buf))
(kill-buffer recon-buf) (kill-buffer recon-buf)
(set-window-buffer (selected-window) buf))))) (set-window-buffer (selected-window) buf)))))
(defun ledger-reconcile-quit-cleanup () (defun ledger-reconcile-quit-cleanup ()
"Cleanup all hooks established by reconcile mode." "Cleanup all hooks established by reconcile mode."
(interactive) (interactive)
(let ((buf ledger-buf)) (let ((buf ledger-buf))
(if (buffer-live-p buf) (if (buffer-live-p buf)
(with-current-buffer buf (with-current-buffer buf
(remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t)
(when ledger-narrow-on-reconcile (when ledger-narrow-on-reconcile
(ledger-occur-quit-buffer buf) (ledger-occur-quit-buffer buf)
(ledger-highlight-xact-under-point)))))) (ledger-highlight-xact-under-point))))))
(defun ledger-marker-where-xact-is (emacs-xact posting) (defun ledger-marker-where-xact-is (emacs-xact posting)
"Find the position of the EMACS-XACT in the `ledger-buf'. "Find the position of the EMACS-XACT in the `ledger-buf'.
POSTING is used in `ledger-clear-whole-transactions' is nil." POSTING is used in `ledger-clear-whole-transactions' is nil."
(let ((buf (if (is-stdin (nth 0 emacs-xact)) (let ((buf (if (is-stdin (nth 0 emacs-xact))
ledger-buf ledger-buf
(find-file-noselect (nth 0 emacs-xact))))) (find-file-noselect (nth 0 emacs-xact)))))
(cons (cons
buf buf
(if ledger-clear-whole-transactions (if ledger-clear-whole-transactions
(nth 1 emacs-xact) ;; return line-no of xact (nth 1 emacs-xact) ;; return line-no of xact
(nth 0 posting))))) ;; return line-no of posting (nth 0 posting))))) ;; return line-no of posting
(defun ledger-do-reconcile (&optional sort) (defun ledger-do-reconcile (&optional sort)
"Return the number of uncleared transactions in the account and display them in the *Reconcile* buffer." "Return the number of uncleared transactions in the account and display them in the *Reconcile* buffer."
(let* ((buf ledger-buf) (let* ((buf ledger-buf)
(account ledger-acct) (account ledger-acct)
(ledger-success nil) (ledger-success nil)
(sort-by (if sort (sort-by (if sort
sort sort
"(date)")) "(date)"))
(xacts (xacts
(with-temp-buffer (with-temp-buffer
(when (ledger-exec-ledger buf (current-buffer) (when (ledger-exec-ledger buf (current-buffer)
"--uncleared" "--real" "emacs" "--sort" sort-by account) "--uncleared" "--real" "emacs" "--sort" sort-by account)
(setq ledger-success t) (setq ledger-success t)
(goto-char (point-min)) (goto-char (point-min))
(unless (eobp) (unless (eobp)
(if (looking-at "(") (if (looking-at "(")
(read (current-buffer)))))))) ;current-buffer is the *temp* created above (read (current-buffer)))))))) ;current-buffer is the *temp* created above
(if (and ledger-success (> (length xacts) 0)) (if (and ledger-success (> (length xacts) 0))
(let ((date-format (cdr (assoc "date-format" ledger-environment-alist)))) (let ((date-format (cdr (assoc "date-format" ledger-environment-alist))))
(dolist (xact xacts) (dolist (xact xacts)
(dolist (posting (nthcdr 5 xact)) (dolist (posting (nthcdr 5 xact))
(let ((beg (point)) (let ((beg (point))
(where (ledger-marker-where-xact-is xact posting))) (where (ledger-marker-where-xact-is xact posting)))
(insert (format "%s %-4s %-30s %-30s %15s\n" (insert (format "%s %-4s %-30s %-30s %15s\n"
(format-time-string (if date-format (format-time-string (if date-format
date-format date-format
ledger-reconcile-default-date-format) (nth 2 xact)) ledger-reconcile-default-date-format) (nth 2 xact))
(if (nth 3 xact) (if (nth 3 xact)
(nth 3 xact) (nth 3 xact)
"") "")
(nth 4 xact) (nth 1 posting) (nth 2 posting))) (nth 4 xact) (nth 1 posting) (nth 2 posting)))
(if (nth 3 posting) (if (nth 3 posting)
(if (eq (nth 3 posting) 'pending) (if (eq (nth 3 posting) 'pending)
(set-text-properties beg (1- (point)) (set-text-properties beg (1- (point))
(list 'face 'ledger-font-reconciler-pending-face (list 'face 'ledger-font-reconciler-pending-face
'where where)) 'where where))
(set-text-properties beg (1- (point)) (set-text-properties beg (1- (point))
(list 'face 'ledger-font-reconciler-cleared-face (list 'face 'ledger-font-reconciler-cleared-face
'where where))) 'where where)))
(set-text-properties beg (1- (point)) (set-text-properties beg (1- (point))
(list 'face 'ledger-font-reconciler-uncleared-face (list 'face 'ledger-font-reconciler-uncleared-face
'where where)))) )) 'where where)))) ))
(goto-char (point-max)) (goto-char (point-max))
(delete-char -1)) ;gets rid of the extra line feed at the bottom of the list (delete-char -1)) ;gets rid of the extra line feed at the bottom of the list
(if ledger-success (if ledger-success
(insert (concat "There are no uncleared entries for " account)) (insert (concat "There are no uncleared entries for " account))
(insert "Ledger has reported a problem. Check *Ledger Error* buffer."))) (insert "Ledger has reported a problem. Check *Ledger Error* buffer.")))
(goto-char (point-min)) (goto-char (point-min))
(set-buffer-modified-p nil) (set-buffer-modified-p nil)
(toggle-read-only t) (toggle-read-only t)
@ -344,30 +344,30 @@ ledger buffer is at the bottom of the main window. The key to
this is to ensure the window is selected when the buffer point is this is to ensure the window is selected when the buffer point is
moved and recentered. If they aren't strange things happen." moved and recentered. If they aren't strange things happen."
(let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) (let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name))))
(when recon-window (when recon-window
(fit-window-to-buffer recon-window) (fit-window-to-buffer recon-window)
(with-current-buffer buf (with-current-buffer buf
(add-hook 'kill-buffer-hook 'ledger-reconcile-quit nil t) (add-hook 'kill-buffer-hook 'ledger-reconcile-quit nil t)
(if (get-buffer-window buf) (if (get-buffer-window buf)
(select-window (get-buffer-window buf))) (select-window (get-buffer-window buf)))
(goto-char (point-max)) (goto-char (point-max))
(recenter -1)) (recenter -1))
(select-window recon-window) (select-window recon-window)
(ledger-reconcile-visit t)) (ledger-reconcile-visit t))
(add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t))) (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t)))
(defun ledger-reconcile-track-xact () (defun ledger-reconcile-track-xact ()
"Force the ledger buffer to recenter on the transaction at point in the reconcile buffer." "Force the ledger buffer to recenter on the transaction at point in the reconcile buffer."
(if (and ledger-buffer-tracks-reconcile-buffer (if (and ledger-buffer-tracks-reconcile-buffer
(member this-command (list 'next-line (member this-command (list 'next-line
'previous-line 'previous-line
'mouse-set-point 'mouse-set-point
'ledger-reconcile-toggle 'ledger-reconcile-toggle
'end-of-buffer 'end-of-buffer
'beginning-of-buffer))) 'beginning-of-buffer)))
(save-excursion (save-excursion
(ledger-reconcile-visit t)))) (ledger-reconcile-visit t))))
(defun ledger-reconcile-open-windows (buf rbuf) (defun ledger-reconcile-open-windows (buf rbuf)
"Ensure that the ledger buffer BUF is split by RBUF." "Ensure that the ledger buffer BUF is split by RBUF."
@ -380,39 +380,39 @@ moved and recentered. If they aren't strange things happen."
"Start reconciling, prompt for account." "Start reconciling, prompt for account."
(interactive) (interactive)
(let ((account (ledger-read-account-with-prompt "Account to reconcile")) (let ((account (ledger-read-account-with-prompt "Account to reconcile"))
(buf (current-buffer)) (buf (current-buffer))
(rbuf (get-buffer ledger-recon-buffer-name))) (rbuf (get-buffer ledger-recon-buffer-name)))
(add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t) (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save nil t)
(if rbuf ;; *Reconcile* already exists (if rbuf ;; *Reconcile* already exists
(with-current-buffer rbuf (with-current-buffer rbuf
(set 'ledger-acct account) ;; already buffer local (set 'ledger-acct account) ;; already buffer local
(when (not (eq buf rbuf)) (when (not (eq buf rbuf))
;; called from some other ledger-mode buffer ;; called from some other ledger-mode buffer
(ledger-reconcile-quit-cleanup) (ledger-reconcile-quit-cleanup)
(set 'ledger-buf buf)) ;; should already be buffer-local (set 'ledger-buf buf)) ;; should already be buffer-local
(unless (get-buffer-window rbuf) (unless (get-buffer-window rbuf)
(ledger-reconcile-open-windows buf rbuf))) (ledger-reconcile-open-windows buf rbuf)))
;; no recon-buffer, starting from scratch. ;; no recon-buffer, starting from scratch.
(with-current-buffer (setq rbuf (with-current-buffer (setq rbuf
(get-buffer-create ledger-recon-buffer-name)) (get-buffer-create ledger-recon-buffer-name))
(ledger-reconcile-open-windows buf rbuf) (ledger-reconcile-open-windows buf rbuf)
(ledger-reconcile-mode) (ledger-reconcile-mode)
(make-local-variable 'ledger-target) (make-local-variable 'ledger-target)
(set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-buf) buf)
(set (make-local-variable 'ledger-acct) account))) (set (make-local-variable 'ledger-acct) account)))
;; Narrow the ledger buffer ;; Narrow the ledger buffer
(with-current-buffer rbuf (with-current-buffer rbuf
(save-excursion (save-excursion
(if ledger-narrow-on-reconcile (if ledger-narrow-on-reconcile
(ledger-occur-mode account ledger-buf))) (ledger-occur-mode account ledger-buf)))
(if (> (ledger-reconcile-refresh) 0) (if (> (ledger-reconcile-refresh) 0)
(ledger-reconcile-change-target)) (ledger-reconcile-change-target))
(ledger-display-balance)))) (ledger-display-balance))))
(defvar ledger-reconcile-mode-abbrev-table) (defvar ledger-reconcile-mode-abbrev-table)
@ -423,62 +423,62 @@ moved and recentered. If they aren't strange things happen."
(setq ledger-target (ledger-read-commodity-string ledger-reconcile-target-prompt-string))) (setq ledger-target (ledger-read-commodity-string ledger-reconcile-target-prompt-string)))
(defmacro ledger-reconcile-change-sort-key-and-refresh (sort-by) (defmacro ledger-reconcile-change-sort-key-and-refresh (sort-by)
`(lambda () `(lambda ()
(interactive) (interactive)
(setq ledger-reconcile-sort-key ,sort-by) (setq ledger-reconcile-sort-key ,sort-by)
(ledger-reconcile-refresh))) (ledger-reconcile-refresh)))
(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" (define-derived-mode ledger-reconcile-mode text-mode "Reconcile"
"A mode for reconciling ledger entries." "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)
(define-key map [(control ?l)] 'ledger-reconcile-refresh) (define-key map [(control ?l)] 'ledger-reconcile-refresh)
(define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish)
(define-key map [? ] 'ledger-reconcile-toggle) (define-key map [? ] 'ledger-reconcile-toggle)
(define-key map [?a] 'ledger-reconcile-add) (define-key map [?a] 'ledger-reconcile-add)
(define-key map [?d] 'ledger-reconcile-delete) (define-key map [?d] 'ledger-reconcile-delete)
(define-key map [?g] 'ledger-reconcile); (define-key map [?g] 'ledger-reconcile);
(define-key map [?n] 'next-line) (define-key map [?n] 'next-line)
(define-key map [?p] 'previous-line) (define-key map [?p] 'previous-line)
(define-key map [?t] 'ledger-reconcile-change-target) (define-key map [?t] 'ledger-reconcile-change-target)
(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)
(define-key map [?b] 'ledger-display-balance) (define-key map [?b] 'ledger-display-balance)
(define-key map [(control ?c) (control ?a)] (ledger-reconcile-change-sort-key-and-refresh "(amount)")) (define-key map [(control ?c) (control ?a)] (ledger-reconcile-change-sort-key-and-refresh "(amount)"))
(define-key map [(control ?c) (control ?d)] (ledger-reconcile-change-sort-key-and-refresh "(date)")) (define-key map [(control ?c) (control ?d)] (ledger-reconcile-change-sort-key-and-refresh "(date)"))
(define-key map [(control ?c) (control ?p)] (ledger-reconcile-change-sort-key-and-refresh "(payee)")) (define-key map [(control ?c) (control ?p)] (ledger-reconcile-change-sort-key-and-refresh "(payee)"))
(define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu")) (define-key map [menu-bar] (make-sparse-keymap "ldg-recon-menu"))
(define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map)) (define-key map [menu-bar ldg-recon-menu] (cons "Reconcile" map))
(define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit)) (define-key map [menu-bar ldg-recon-menu qui] '("Quit" . ledger-reconcile-quit))
(define-key map [menu-bar ldg-recon-menu sep1] '("--")) (define-key map [menu-bar ldg-recon-menu sep1] '("--"))
(define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line)) (define-key map [menu-bar ldg-recon-menu pre] '("Previous Entry" . previous-line))
(define-key map [menu-bar ldg-recon-menu vis] '("Visit Source" . ledger-reconcile-visit)) (define-key map [menu-bar ldg-recon-menu vis] '("Visit Source" . ledger-reconcile-visit))
(define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line)) (define-key map [menu-bar ldg-recon-menu nex] '("Next Entry" . next-line))
(define-key map [menu-bar ldg-recon-menu sep2] '("--")) (define-key map [menu-bar ldg-recon-menu sep2] '("--"))
(define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) (define-key map [menu-bar ldg-recon-menu del] '("Delete Entry" . ledger-reconcile-delete))
(define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add)) (define-key map [menu-bar ldg-recon-menu add] '("Add Entry" . ledger-reconcile-add))
(define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) (define-key map [menu-bar ldg-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle))
(define-key map [menu-bar ldg-recon-menu sep3] '("--")) (define-key map [menu-bar ldg-recon-menu sep3] '("--"))
(define-key map [menu-bar ldg-recon-menu sort-amt] `("Sort by amount" . ,(ledger-reconcile-change-sort-key-and-refresh "(amount)"))) (define-key map [menu-bar ldg-recon-menu sort-amt] `("Sort by amount" . ,(ledger-reconcile-change-sort-key-and-refresh "(amount)")))
(define-key map [menu-bar ldg-recon-menu sort-pay] `("Sort by date" . ,(ledger-reconcile-change-sort-key-and-refresh "(date)"))) (define-key map [menu-bar ldg-recon-menu sort-pay] `("Sort by date" . ,(ledger-reconcile-change-sort-key-and-refresh "(date)")))
(define-key map [menu-bar ldg-recon-menu sort-dat] `("Sort by payee" . ,(ledger-reconcile-change-sort-key-and-refresh "(payee)"))) (define-key map [menu-bar ldg-recon-menu sort-dat] `("Sort by payee" . ,(ledger-reconcile-change-sort-key-and-refresh "(payee)")))
(define-key map [menu-bar ldg-recon-menu sep4] '("--")) (define-key map [menu-bar ldg-recon-menu sep4] '("--"))
(define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) (define-key map [menu-bar ldg-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance))
(define-key map [menu-bar ldg-recon-menu tgt] '("Change Target Balance" . ledger-reconcile-change-target)) (define-key map [menu-bar ldg-recon-menu tgt] '("Change Target Balance" . ledger-reconcile-change-target))
(define-key map [menu-bar ldg-recon-menu sep5] '("--")) (define-key map [menu-bar ldg-recon-menu sep5] '("--"))
(define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile)) (define-key map [menu-bar ldg-recon-menu rna] '("Reconcile New Account" . ledger-reconcile))
(define-key map [menu-bar ldg-recon-menu sep6] '("--")) (define-key map [menu-bar ldg-recon-menu sep6] '("--"))
(define-key map [menu-bar ldg-recon-menu fin] '("Finish" . ledger-reconcile-finish)) (define-key map [menu-bar ldg-recon-menu fin] '("Finish" . ledger-reconcile-finish))
(define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) (define-key map [menu-bar ldg-recon-menu ref] '("Refresh" . ledger-reconcile-refresh))
(define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save)) (define-key map [menu-bar ldg-recon-menu sav] '("Save" . ledger-reconcile-save))
(use-local-map map))) (use-local-map map)))
(provide 'ldg-reconcile) (provide 'ldg-reconcile)

View file

@ -20,7 +20,7 @@
;; Boston, MA 02111-1307, USA. ;; Boston, MA 02111-1307, USA.
;;; Commentary: ;;; Commentary:
;; ;;
;; This module provides for automatically adding transactions to a ;; This module provides for automatically adding transactions to a
;; ledger buffer on a periodic basis. Recurrence expressions are ;; ledger buffer on a periodic basis. Recurrence expressions are
;; inspired by Martin Fowler's "Recurring Events for Calendars", ;; inspired by Martin Fowler's "Recurring Events for Calendars",
@ -49,14 +49,20 @@
:type 'integer :type 'integer
:group 'ledger-schedule) :group 'ledger-schedule)
(defcustom ledger-schedule-file "~/FinanceData/ledger-schedule.ledger" (defcustom ledger-schedule-file "~/ledger-schedule.ledger"
"File to find scheduled transactions." "File to find scheduled transactions."
:type 'file :type 'file
:group 'ledger-schedule) :group 'ledger-schedule)
(defvar ledger-schedule-available nil)
(defsubst between (val low high) (defsubst between (val low high)
(and (>= val low) (<= val high))) (and (>= val low) (<= val high)))
(defun ledger-check-schedule-available ()
(setq ledger-schedule-available (and ledger-schedule-file
(file-exists-p ledger-schedule-file))))
(defun ledger-schedule-days-in-month (month year) (defun ledger-schedule-days-in-month (month year)
"Return number of days in the MONTH, MONTH is from 1 to 12. "Return number of days in the MONTH, MONTH is from 1 to 12.
If year is nil, assume it is not a leap year" If year is nil, assume it is not a leap year"
@ -67,7 +73,7 @@ If year is nil, assume it is not a leap year"
(error "Month out of range, MONTH=%S" month))) (error "Month out of range, MONTH=%S" month)))
;; Macros to handle date expressions ;; Macros to handle date expressions
(defun ledger-schedule-constrain-day-in-month (count day-of-week) (defun ledger-schedule-constrain-day-in-month (count day-of-week)
"Return a form that evaluates DATE that returns true for the COUNT DAY-OF-WEEK. "Return a form that evaluates DATE that returns true for the COUNT DAY-OF-WEEK.
For example, return true if date is the 3rd Thursday of the For example, return true if date is the 3rd Thursday of the
@ -80,24 +86,24 @@ COUNT 0) means EVERY day-of-week (eg. every Saturday)"
(let ((decoded (gensym))) (let ((decoded (gensym)))
`(let ((,decoded (decode-time date))) `(let ((,decoded (decode-time date)))
(and (eq (nth 6 ,decoded) ,day-of-week) (and (eq (nth 6 ,decoded) ,day-of-week)
(between (nth 3 ,decoded) (between (nth 3 ,decoded)
,(* (1- count) 7) ,(* (1- count) 7)
,(* count 7)))))) ,(* count 7))))))
((< count 0) ((< count 0)
(let ((days-in-month (gensym)) (let ((days-in-month (gensym))
(decoded (gensym))) (decoded (gensym)))
`(let* ((,decoded (decode-time date)) `(let* ((,decoded (decode-time date))
(,days-in-month (ledger-schedule-days-in-month (,days-in-month (ledger-schedule-days-in-month
(nth 4 ,decoded) (nth 4 ,decoded)
(nth 5 ,decoded)))) (nth 5 ,decoded))))
(and (eq (nth 6 ,decoded) ,day-of-week) (and (eq (nth 6 ,decoded) ,day-of-week)
(between (nth 3 ,decoded) (between (nth 3 ,decoded)
(+ ,days-in-month ,(* count 7)) (+ ,days-in-month ,(* count 7))
(+ ,days-in-month ,(* (1+ count) 7))))))) (+ ,days-in-month ,(* (1+ count) 7)))))))
(t (t
(error "COUNT out of range, COUNT=%S" count))) (error "COUNT out of range, COUNT=%S" count)))
(error "Invalid argument to ledger-schedule-day-in-month-macro %S %S" (error "Invalid argument to ledger-schedule-day-in-month-macro %S %S"
count count
day-of-week))) day-of-week)))
(defun ledger-schedule-constrain-every-count-day (day-of-week skip start-date) (defun ledger-schedule-constrain-every-count-day (day-of-week skip start-date)
@ -138,10 +144,10 @@ the transaction should be logged for that day."
(let ((date-descriptor "") (let ((date-descriptor "")
(transaction nil) (transaction nil)
(xact-start (match-end 0))) (xact-start (match-end 0)))
(setq date-descriptors (setq date-descriptors
(ledger-schedule-read-descriptor-tree (ledger-schedule-read-descriptor-tree
(buffer-substring-no-properties (buffer-substring-no-properties
(match-beginning 0) (match-beginning 0)
(match-end 0)))) (match-end 0))))
(forward-paragraph) (forward-paragraph)
(setq transaction (list date-descriptors (setq transaction (list date-descriptors
@ -150,7 +156,7 @@ the transaction should be logged for that day."
(point)))) (point))))
(setq xact-list (cons transaction xact-list)))) (setq xact-list (cons transaction xact-list))))
xact-list))) xact-list)))
(defun ledger-schedule-replace-brackets () (defun ledger-schedule-replace-brackets ()
"Replace all brackets with parens" "Replace all brackets with parens"
(goto-char (point-min)) (goto-char (point-min))
@ -166,7 +172,7 @@ the transaction should be logged for that day."
"\\([\*]\\|\\([0-3][0-9]\\)\\|" "\\([\*]\\|\\([0-3][0-9]\\)\\|"
"\\([0-5]" "\\([0-5]"
"\\(\\(Su\\)\\|" "\\(\\(Su\\)\\|"
"\\(Mo\\)\\|" "\\(Mo\\)\\|"
"\\(Tu\\)\\|" "\\(Tu\\)\\|"
"\\(We\\)\\|" "\\(We\\)\\|"
"\\(Th\\)\\|" "\\(Th\\)\\|"
@ -182,19 +188,19 @@ returns true if the date meets the requirements"
;; Replace brackets with parens ;; Replace brackets with parens
(insert descriptor-string) (insert descriptor-string)
(ledger-schedule-replace-brackets) (ledger-schedule-replace-brackets)
(goto-char (point-max)) (goto-char (point-max))
;; double quote all the descriptors for string processing later ;; double quote all the descriptors for string processing later
(while (re-search-backward ledger-schedule-descriptor-regex nil t) ;; Day slot (while (re-search-backward ledger-schedule-descriptor-regex nil t) ;; Day slot
(goto-char (goto-char
(match-end 0)) (match-end 0))
(insert ?\") (insert ?\")
(goto-char (match-beginning 0)) (goto-char (match-beginning 0))
(insert "\"" ))) (insert "\"" )))
;; read the descriptor string into a lisp object the transform the ;; read the descriptor string into a lisp object the transform the
;; string descriptor into useable things ;; string descriptor into useable things
(ledger-schedule-transform-auto-tree (ledger-schedule-transform-auto-tree
(read (buffer-substring-no-properties (point-min) (point-max)))))) (read (buffer-substring-no-properties (point-min) (point-max))))))
(defun ledger-schedule-transform-auto-tree (descriptor-string-list) (defun ledger-schedule-transform-auto-tree (descriptor-string-list)
@ -207,7 +213,7 @@ returns true if the date meets the requirements"
(if (consp newcar) (if (consp newcar)
(setq newcar (ledger-schedule-transform-auto-tree (car descriptor-string-list)))) (setq newcar (ledger-schedule-transform-auto-tree (car descriptor-string-list))))
;; newcar may be a cons now, after ledger-schedule-transfrom-auto-tree ;; newcar may be a cons now, after ledger-schedule-transfrom-auto-tree
(if (consp newcar) (if (consp newcar)
(push newcar result) (push newcar result)
;; this is where we actually turn the string descriptor into useful lisp ;; this is where we actually turn the string descriptor into useful lisp
(push (ledger-schedule-compile-constraints newcar) result)) ) (push (ledger-schedule-compile-constraints newcar) result)) )
@ -215,7 +221,7 @@ returns true if the date meets the requirements"
;; tie up all the clauses in a big or and lambda, and return ;; tie up all the clauses in a big or and lambda, and return
;; the lambda function as list to be executed by funcall ;; the lambda function as list to be executed by funcall
`(lambda (date) `(lambda (date)
,(nconc (list 'or) (nreverse result) descriptor-string-list))))) ,(nconc (list 'or) (nreverse result) descriptor-string-list)))))
(defun ledger-schedule-compile-constraints (descriptor-string) (defun ledger-schedule-compile-constraints (descriptor-string)
@ -238,8 +244,8 @@ returns true if the date meets the requirements"
(error "Improperly specified year constraint: " str))))) (error "Improperly specified year constraint: " str)))))
(defun ledger-schedule-constrain-month (str) (defun ledger-schedule-constrain-month (str)
(let ((month-match t)) (let ((month-match t))
(cond ((string= str "*") (cond ((string= str "*")
month-match) ;; always match month-match) ;; always match
((/= 0 (setq month-match (string-to-number str))) ((/= 0 (setq month-match (string-to-number str)))
@ -291,35 +297,10 @@ returns true if the date meets the requirements"
(ledger-mode)) (ledger-mode))
(length candidates))) (length candidates)))
;;
;; Test harnesses for use in ielm
;;
(defvar auto-items)
(defun ledger-schedule-test ( early horizon)
(ledger-schedule-create-auto-buffer
(ledger-schedule-scan-transactions ledger-schedule-file)
early
horizon
(get-buffer "2013.ledger")))
(defun ledger-schedule-test-predict ()
(let ((today (current-time))
test-date items)
(loop for day from 0 to ledger-schedule-look-forward by 1 do
(setq test-date (time-add today (days-to-time day)))
(dolist (item auto-items items)
(if (funcall (car item) test-date)
(setq items (append items (list (decode-time test-date) (cdr item)))))))
items))
(defun ledger-schedule-upcoming () (defun ledger-schedule-upcoming ()
(interactive) (interactive)
(ledger-schedule-create-auto-buffer (ledger-schedule-create-auto-buffer
(ledger-schedule-scan-transactions ledger-schedule-file) (ledger-schedule-scan-transactions ledger-schedule-file)
ledger-schedule-look-backward ledger-schedule-look-backward
ledger-schedule-look-forward ledger-schedule-look-forward
(current-buffer))) (current-buffer)))

View file

@ -49,7 +49,7 @@
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
(if (ledger-sort-find-start) (if (ledger-sort-find-start)
(delete-region (match-beginning 0) (match-end 0)))) (delete-region (match-beginning 0) (match-end 0))))
(beginning-of-line) (beginning-of-line)
(insert "\n; Ledger-mode: Start sort\n\n")) (insert "\n; Ledger-mode: Start sort\n\n"))
@ -58,7 +58,7 @@
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
(if (ledger-sort-find-end) (if (ledger-sort-find-end)
(delete-region (match-beginning 0) (match-end 0)))) (delete-region (match-beginning 0) (match-end 0))))
(beginning-of-line) (beginning-of-line)
(insert "\n; Ledger-mode: End sort\n\n")) (insert "\n; Ledger-mode: End sort\n\n"))
@ -69,57 +69,57 @@
(defun ledger-sort-region (beg end) (defun ledger-sort-region (beg end)
"Sort the region from BEG to END in chronological order." "Sort the region from BEG to END in chronological order."
(interactive "r") ;; load beg and end from point and mark (interactive "r") ;; load beg and end from point and mark
;; automagically ;; automagically
(let ((new-beg beg) (let ((new-beg beg)
(new-end end) (new-end end)
point-delta point-delta
(bounds (ledger-find-xact-extents (point))) (bounds (ledger-find-xact-extents (point)))
target-xact) target-xact)
(setq point-delta (- (point) (car bounds))) (setq point-delta (- (point) (car bounds)))
(setq target-xact (buffer-substring (car bounds) (cadr bounds))) (setq target-xact (buffer-substring (car bounds) (cadr bounds)))
(setq inhibit-modification-hooks t) (setq inhibit-modification-hooks t)
(save-excursion (save-excursion
(save-restriction (save-restriction
(goto-char beg) (goto-char beg)
(ledger-next-record-function) ;; make sure point is at the (ledger-next-record-function) ;; make sure point is at the
;; beginning of a xact ;; beginning of a xact
(setq new-beg (point)) (setq new-beg (point))
(goto-char end) (goto-char end)
(ledger-next-record-function) ;; make sure end of region is at (ledger-next-record-function) ;; make sure end of region is at
;; the beginning of next record ;; the beginning of next record
;; after the region ;; after the region
(setq new-end (point)) (setq new-end (point))
(narrow-to-region new-beg new-end) (narrow-to-region new-beg new-end)
(goto-char new-beg) (goto-char new-beg)
(let ((inhibit-field-text-motion t)) (let ((inhibit-field-text-motion t))
(sort-subr (sort-subr
nil nil
'ledger-next-record-function 'ledger-next-record-function
'ledger-end-record-function 'ledger-end-record-function
'ledger-sort-startkey)))) 'ledger-sort-startkey))))
(goto-char (point-min)) (goto-char (point-min))
(re-search-forward (regexp-quote target-xact)) (re-search-forward (regexp-quote target-xact))
(goto-char (+ (match-beginning 0) point-delta)) (goto-char (+ (match-beginning 0) point-delta))
(setq inhibit-modification-hooks nil))) (setq inhibit-modification-hooks nil)))
(defun ledger-sort-buffer () (defun ledger-sort-buffer ()
"Sort the entire buffer." "Sort the entire buffer."
(interactive) (interactive)
(let (sort-start (let (sort-start
sort-end) sort-end)
(save-excursion (save-excursion
(goto-char (point-min)) (goto-char (point-min))
(setq sort-start (ledger-sort-find-start) (setq sort-start (ledger-sort-find-start)
sort-end (ledger-sort-find-end))) sort-end (ledger-sort-find-end)))
(ledger-sort-region (if sort-start (ledger-sort-region (if sort-start
sort-start sort-start
(point-min)) (point-min))
(if sort-end (if sort-end
sort-end sort-end
(point-max))))) (point-max)))))
(provide 'ldg-sort) (provide 'ldg-sort)

View file

@ -46,28 +46,28 @@ within the transaction."
(save-excursion (save-excursion
(goto-char pos) (goto-char pos)
(list (progn (list (progn
(backward-paragraph) (backward-paragraph)
(if (/= (point) (point-min)) (if (/= (point) (point-min))
(forward-line)) (forward-line))
(line-beginning-position)) (line-beginning-position))
(progn (progn
(forward-paragraph) (forward-paragraph)
(line-beginning-position))))) (line-beginning-position)))))
(defun ledger-highlight-xact-under-point () (defun ledger-highlight-xact-under-point ()
"Move the highlight overlay to the current transaction." "Move the highlight overlay to the current transaction."
(if ledger-highlight-xact-under-point (if ledger-highlight-xact-under-point
(let ((exts (ledger-find-xact-extents (point))) (let ((exts (ledger-find-xact-extents (point)))
(ovl highlight-overlay)) (ovl highlight-overlay))
(if (not highlight-overlay) (if (not highlight-overlay)
(setq ovl (setq ovl
(setq highlight-overlay (setq highlight-overlay
(make-overlay (car exts) (make-overlay (car exts)
(cadr exts) (cadr exts)
(current-buffer) t nil))) (current-buffer) t nil)))
(move-overlay ovl (car exts) (cadr exts))) (move-overlay ovl (car exts) (cadr exts)))
(overlay-put ovl 'face 'ledger-font-xact-highlight-face) (overlay-put ovl 'face 'ledger-font-xact-highlight-face)
(overlay-put ovl 'priority 100)))) (overlay-put ovl 'priority 100))))
(defun ledger-xact-payee () (defun ledger-xact-payee ()
"Return the payee of the transaction containing point or nil." "Return the payee of the transaction containing point or nil."
@ -77,7 +77,7 @@ within the transaction."
(let ((context-info (ledger-context-other-line i))) (let ((context-info (ledger-context-other-line i)))
(if (eq (ledger-context-line-type context-info) 'xact) (if (eq (ledger-context-line-type context-info) 'xact)
(ledger-context-field-value context-info 'payee) (ledger-context-field-value context-info 'payee)
nil)))) nil))))
(defun ledger-time-less-p (t1 t2) (defun ledger-time-less-p (t1 t2)
"Say whether time value T1 is less than time value T2." "Say whether time value T1 is less than time value T2."
@ -93,7 +93,7 @@ MOMENT is an encoded date"
(function (function
(lambda (start date mark desc) (lambda (start date mark desc)
(if (ledger-time-less-p moment date) (if (ledger-time-less-p moment date)
(throw 'found t))))))) (throw 'found t)))))))
(defun ledger-xact-iterate-transactions (callback) (defun ledger-xact-iterate-transactions (callback)
"Iterate through each transaction call CALLBACK for each." "Iterate through each transaction call CALLBACK for each."
@ -105,19 +105,19 @@ MOMENT is an encoded date"
(let ((found-y-p (match-string 2))) (let ((found-y-p (match-string 2)))
(if found-y-p (if found-y-p
(setq current-year (string-to-number found-y-p)) ;; a Y directive was found (setq current-year (string-to-number found-y-p)) ;; a Y directive was found
(let ((start (match-beginning 0)) (let ((start (match-beginning 0))
(year (match-string 4)) (year (match-string 4))
(month (string-to-number (match-string 5))) (month (string-to-number (match-string 5)))
(day (string-to-number (match-string 6))) (day (string-to-number (match-string 6)))
(mark (match-string 7)) (mark (match-string 7))
(code (match-string 8)) (code (match-string 8))
(desc (match-string 9))) (desc (match-string 9)))
(if (and year (> (length year) 0)) (if (and year (> (length year) 0))
(setq year (string-to-number year))) (setq year (string-to-number year)))
(funcall callback start (funcall callback start
(encode-time 0 0 0 day month (encode-time 0 0 0 day month
(or year current-year)) (or year current-year))
mark desc))))) mark desc)))))
(forward-line)))) (forward-line))))
(defsubst ledger-goto-line (line-number) (defsubst ledger-goto-line (line-number)
@ -128,8 +128,8 @@ MOMENT is an encoded date"
(defun ledger-year-and-month () (defun ledger-year-and-month ()
(let ((sep (if ledger-use-iso-dates (let ((sep (if ledger-use-iso-dates
"-" "-"
"/"))) "/")))
(concat ledger-year sep ledger-month sep))) (concat ledger-year sep ledger-month sep)))
(defun ledger-copy-transaction-at-point (date) (defun ledger-copy-transaction-at-point (date)
"Ask for a new DATE and copy the transaction under point to that date. Leave point on the first amount." "Ask for a new DATE and copy the transaction under point to that date. Leave point on the first amount."
@ -137,14 +137,14 @@ MOMENT is an encoded date"
(read-string "Copy to date: " (ledger-year-and-month) (read-string "Copy to date: " (ledger-year-and-month)
'ledger-minibuffer-history))) 'ledger-minibuffer-history)))
(let* ((here (point)) (let* ((here (point))
(extents (ledger-find-xact-extents (point))) (extents (ledger-find-xact-extents (point)))
(transaction (buffer-substring-no-properties (car extents) (cadr extents))) (transaction (buffer-substring-no-properties (car extents) (cadr extents)))
encoded-date) encoded-date)
(if (string-match ledger-iso-date-regexp date) (if (string-match ledger-iso-date-regexp date)
(setq encoded-date (setq encoded-date
(encode-time 0 0 0 (string-to-number (match-string 4 date)) (encode-time 0 0 0 (string-to-number (match-string 4 date))
(string-to-number (match-string 3 date)) (string-to-number (match-string 3 date))
(string-to-number (match-string 2 date))))) (string-to-number (match-string 2 date)))))
(ledger-xact-find-slot encoded-date) (ledger-xact-find-slot encoded-date)
(insert transaction "\n") (insert transaction "\n")
(backward-paragraph 2) (backward-paragraph 2)
@ -179,20 +179,20 @@ correct chronological place in the buffer."
(string-to-number (match-string 2 date))))) (string-to-number (match-string 2 date)))))
(ledger-xact-find-slot date))) (ledger-xact-find-slot date)))
(if (> (length args) 1) (if (> (length args) 1)
(save-excursion (save-excursion
(insert (insert
(with-temp-buffer (with-temp-buffer
(setq exit-code (setq exit-code
(apply #'ledger-exec-ledger ledger-buf (current-buffer) "xact" (apply #'ledger-exec-ledger ledger-buf (current-buffer) "xact"
(mapcar 'eval args))) (mapcar 'eval args)))
(goto-char (point-min)) (goto-char (point-min))
(if (looking-at "Error: ") (if (looking-at "Error: ")
(error (concat "Error in ledger-add-transaction: " (buffer-string))) (error (concat "Error in ledger-add-transaction: " (buffer-string)))
(buffer-string))) (buffer-string)))
"\n")) "\n"))
(progn (progn
(insert (car args) " \n\n") (insert (car args) " \n\n")
(end-of-line -1))))) (end-of-line -1)))))
(provide 'ldg-xact) (provide 'ldg-xact)