diff options
Diffstat (limited to 'lisp')
-rw-r--r-- | lisp/CMakeLists.txt | 52 | ||||
-rw-r--r-- | lisp/ledger-commodities.el | 147 | ||||
-rw-r--r-- | lisp/ledger-complete.el | 167 | ||||
-rw-r--r-- | lisp/ledger-context.el | 79 | ||||
-rw-r--r-- | lisp/ledger-exec.el | 15 | ||||
-rw-r--r-- | lisp/ledger-fonts.el | 12 | ||||
-rw-r--r-- | lisp/ledger-init.el | 51 | ||||
-rw-r--r-- | lisp/ledger-mode.el | 313 | ||||
-rw-r--r-- | lisp/ledger-occur.el | 100 | ||||
-rw-r--r-- | lisp/ledger-post.el | 24 | ||||
-rw-r--r-- | lisp/ledger-reconcile.el | 407 | ||||
-rw-r--r-- | lisp/ledger-regex.el | 12 | ||||
-rw-r--r-- | lisp/ledger-report.el | 86 | ||||
-rw-r--r-- | lisp/ledger-schedule.el | 75 | ||||
-rw-r--r-- | lisp/ledger-sort.el | 92 | ||||
-rw-r--r-- | lisp/ledger-state.el | 6 | ||||
-rw-r--r-- | lisp/ledger-test.el | 6 | ||||
-rw-r--r-- | lisp/ledger-texi.el | 6 | ||||
-rw-r--r-- | lisp/ledger-xact.el | 130 |
19 files changed, 952 insertions, 828 deletions
diff --git a/lisp/CMakeLists.txt b/lisp/CMakeLists.txt index 2258fd5d..525e91aa 100644 --- a/lisp/CMakeLists.txt +++ b/lisp/CMakeLists.txt @@ -1,23 +1,24 @@ set(EMACS_LISP_SOURCES - ldg-commodities.el - ldg-complete.el - ldg-exec.el - ldg-fonts.el - ldg-init.el - ldg-mode.el - ldg-new.el - ldg-occur.el - ldg-post.el - ldg-reconcile.el - ldg-regex.el - ldg-report.el - ldg-sort.el - ldg-state.el - ldg-test.el - ldg-texi.el - ldg-xact.el - ldg-context.el - ldg-schedule.el) + ledger-commodities.el + ledger-complete.el + ledger-exec.el + ledger-fonts.el + ledger-init.el + ledger-mode.el + ledger-occur.el + ledger-post.el + ledger-reconcile.el + ledger-regex.el + ledger-report.el + ledger-schedule.el + ledger-sort.el + ledger-state.el + ledger-test.el + ledger-texi.el + ledger-xact.el) + +set(EMACS_LISP_SOURCES_UNCOMPILABLE + ledger-context.el) # find emacs and complain if not found find_program(EMACS_EXECUTABLE emacs) @@ -30,7 +31,7 @@ macro(add_emacs_lisp_target el) OUTPUT ${el}c COMMAND ${EMACS_EXECUTABLE} -L ${CMAKE_CURRENT_BINARY_DIR} - -l ${CMAKE_CURRENT_BINARY_DIR}/ldg-regex.el + -l ${CMAKE_CURRENT_BINARY_DIR}/ledger-regex.el -batch -f batch-byte-compile ${CMAKE_CURRENT_BINARY_DIR}/${el} DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${el} @@ -39,6 +40,13 @@ macro(add_emacs_lisp_target el) endmacro(add_emacs_lisp_target el) if(EMACS_EXECUTABLE) + # uncompilable .el files + foreach(el ${EMACS_LISP_SOURCES_UNCOMPILABLE}) + configure_file(${el} ${CMAKE_CURRENT_BINARY_DIR}/${el}) + list(APPEND EMACS_LISP_UNCOMPILABLE ${CMAKE_CURRENT_BINARY_DIR}/${el}) + endforeach() + + # compilable .el files foreach(el ${EMACS_LISP_SOURCES}) add_emacs_lisp_target(${el}) list(APPEND EMACS_LISP_BINARIES ${CMAKE_CURRENT_BINARY_DIR}/${el}c) @@ -47,8 +55,8 @@ if(EMACS_EXECUTABLE) add_custom_target(emacs_lisp_byte_compile ALL DEPENDS ${EMACS_LISP_BINARIES}) # install the byte-compiled emacs-lisp sources - install(FILES ${EMACS_LISP_SOURCES} ${EMACS_LISP_BINARIES} - DESTINATION share/emacs/site-lisp) + install(FILES ${EMACS_LISP_SOURCES} ${EMACS_LISP_BINARIES} ${EMACS_LISP_UNCOMPILABLE} + DESTINATION share/emacs/site-lisp/ledger-mode) endif() ### CMakeLists.txt ends here diff --git a/lisp/ledger-commodities.el b/lisp/ledger-commodities.el index 48d41979..a2cdf6ac 100644 --- a/lisp/ledger-commodities.el +++ b/lisp/ledger-commodities.el @@ -1,6 +1,6 @@ ;;; ledger-commodities.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: ;; Helper functions to deal with commoditized numbers. A commoditized @@ -34,50 +34,51 @@ :group 'ledger-reconcile) (defcustom ledger-scale 10000 - "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") + "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" + :group 'ledger) (defun ledger-split-commodity-string (str) "Split a commoditized string, STR, into two parts. Returns a list with (value commodity)." (let ((number-regex (if (assoc "decimal-comma" ledger-environment-alist) - ledger-amount-decimal-comma-regex - ledger-amount-decimal-period-regex))) - (if (> (length str) 0) - (with-temp-buffer - (insert str) - (goto-char (point-min)) - (cond - ((re-search-forward "\"\\(.*\\)\"" nil t) ; look for quoted commodities - (let ((com (delete-and-extract-region - (match-beginning 1) - (match-end 1)))) - (if (re-search-forward - number-regex nil t) - (list - (ledger-string-to-number - (delete-and-extract-region (match-beginning 0) (match-end 0))) - com)))) - ((re-search-forward number-regex nil t) - ;; found a number in the current locale, return it in the - ;; car. Anything left over is annotation, the first - ;; thing should be the commodity, separated by - ;; whitespace, return it in the cdr. I can't think of - ;; any counterexamples - (list - (ledger-string-to-number - (delete-and-extract-region (match-beginning 0) (match-end 0))) - (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) - ((re-search-forward "0" nil t) - ;; couldn't find a decimal number, look for a single 0, - ;; indicating account with zero balance - (list 0 ledger-reconcile-default-commodity)))) - ;; nothing found, return 0 - (list 0 ledger-reconcile-default-commodity)))) + ledger-amount-decimal-comma-regex + ledger-amount-decimal-period-regex))) + (if (> (length str) 0) + (with-temp-buffer + (insert str) + (goto-char (point-min)) + (cond + ((re-search-forward "\"\\(.*\\)\"" nil t) ; look for quoted commodities + (let ((com (delete-and-extract-region + (match-beginning 1) + (match-end 1)))) + (if (re-search-forward + number-regex nil t) + (list + (ledger-string-to-number + (delete-and-extract-region (match-beginning 0) (match-end 0))) + com)))) + ((re-search-forward number-regex nil t) + ;; found a number in the current locale, return it in the + ;; car. Anything left over is annotation, the first + ;; thing should be the commodity, separated by + ;; whitespace, return it in the cdr. I can't think of + ;; any counterexamples + (list + (ledger-string-to-number + (delete-and-extract-region (match-beginning 0) (match-end 0))) + (nth 0 (split-string (buffer-substring-no-properties (point-min) (point-max)))))) + ((re-search-forward "0" nil t) + ;; couldn't find a decimal number, look for a single 0, + ;; indicating account with zero balance + (list 0 ledger-reconcile-default-commodity)))) + ;; nothing found, return 0 + (list 0 ledger-reconcile-default-commodity)))) (defun ledger-string-balance-to-commoditized-amount (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) (ledger-split-commodity-string st)) (split-string str "[\n\r]"))) @@ -85,8 +86,10 @@ Returns a list with (value commodity)." (defun -commodity (c1 c2) "Subtract C2 from C1, ensuring their commodities match." (if (string= (cadr c1) (cadr c2)) - ; the scaling below is to get around inexact subtraction results where, for example - ; 1.23 - 4.56 = -3.3299999999999996 instead of -3.33 + ; the scaling below is to get around inexact + ; 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)) (error "Can't subtract different commodities %S from %S" c2 c1))) @@ -97,50 +100,50 @@ Returns a list with (value commodity)." (error "Can't add different commodities, %S to %S" c1 c2))) (defun ledger-strip (str char) - (let (new-str) - (concat (dolist (ch (append str nil) new-str) - (unless (= ch char) - (setq new-str (append new-str (list ch)))))))) + (let (new-str) + (concat (dolist (ch (append str nil) new-str) + (unless (= ch char) + (setq new-str (append new-str (list ch)))))))) (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" - (let ((nstr (if (or decimal-comma - (assoc "decimal-comma" ledger-environment-alist)) - (ledger-strip str ?.) - (ledger-strip str ?,)))) - (while (string-match "," nstr) ;if there is a comma now, it is a thousands separator - (setq nstr (replace-match "." nil nil nstr))) - (string-to-number nstr))) + "improve builtin string-to-number by handling internationalization, and return nil if number can't be parsed" + (let ((nstr (if (or decimal-comma + (assoc "decimal-comma" ledger-environment-alist)) + (ledger-strip str ?.) + (ledger-strip str ?,)))) + (while (string-match "," nstr) ;if there is a comma now, it is a thousands separator + (setq nstr (replace-match "." nil nil nstr))) + (string-to-number nstr))) (defun ledger-number-to-string (n &optional decimal-comma) - (let ((str (number-to-string n))) - (if (or decimal-comma - (assoc "decimal-comma" ledger-environment-alist)) - (while (string-match "\\." str) - (setq str (replace-match "," nil nil str))) - str))) + (let ((str (number-to-string n))) + (when (or decimal-comma + (assoc "decimal-comma" ledger-environment-alist)) + (while (string-match "\\." str) + (setq str (replace-match "," nil nil str)))) + str)) (defun ledger-commodity-to-string (c1) "Return string representing C1. Single character commodities are placed ahead of the value, longer ones are after the value." - (let ((str (ledger-number-to-string (car c1))) - (commodity (cadr c1))) - (if (> (length commodity) 1) - (concat str " " commodity) - (concat commodity " " str)))) + (let ((str (ledger-number-to-string (car c1))) + (commodity (cadr c1))) + (if (> (length commodity) 1) + (concat str " " commodity) + (concat commodity " " str)))) (defun ledger-read-commodity-string (prompt) (let ((str (read-from-minibuffer - (concat prompt " (" ledger-reconcile-default-commodity "): "))) - comm) + (concat prompt " (" ledger-reconcile-default-commodity "): "))) + comm) (if (and (> (length str) 0) - (ledger-split-commodity-string str)) - (progn - (setq comm (ledger-split-commodity-string str)) - (if (cadr comm) - comm - (list (car comm) ledger-reconcile-default-commodity)))))) + (ledger-split-commodity-string str)) + (progn + (setq comm (ledger-split-commodity-string str)) + (if (cadr comm) + comm + (list (car comm) ledger-reconcile-default-commodity)))))) (provide 'ledger-commodities) diff --git a/lisp/ledger-complete.el b/lisp/ledger-complete.el index a8ef9a8a..fd4cbcc0 100644 --- a/lisp/ledger-complete.el +++ b/lisp/ledger-complete.el @@ -1,6 +1,6 @@ ;;; ledger-complete.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: ;; Functions providing payee and account auto complete. @@ -34,8 +34,8 @@ ;; with pcomplete. See pcomplete-parse-arguments-function for ;; details (let* ((begin (save-excursion - (ledger-thing-at-point) ;; leave point at beginning of thing under point - (point))) + (ledger-thing-at-point) ;; leave point at beginning of thing under point + (point))) (end (point)) begins args) ;; to support end of line metadata @@ -65,42 +65,42 @@ (unless (and (>= origin (match-beginning 0)) (< origin (match-end 0))) (setq payees-list (cons (match-string-no-properties 3) - payees-list))))) ;; add the payee - ;; to the list + payees-list))))) ;; add the payee + ;; to the list (pcomplete-uniqify-list (nreverse payees-list)))) (defun ledger-find-accounts-in-buffer () - (interactive) - (let ((origin (point)) - accounts - (account-tree (list t)) - (account-elements nil) - (seed-regex (ledger-account-any-status-with-seed-regex - (regexp-quote (car pcomplete-args))))) - (save-excursion - (goto-char (point-min)) + (interactive) + (let ((origin (point)) + accounts + (account-tree (list t)) + (account-elements nil) + (seed-regex (ledger-account-any-status-with-seed-regex + (regexp-quote (car pcomplete-args))))) + (save-excursion + (goto-char (point-min)) - (dolist (account - (delete-dups - (progn - (while (re-search-forward seed-regex nil t) - (unless (between origin (match-beginning 0) (match-end 0)) - (setq accounts (cons (match-string-no-properties 2) accounts)))) - accounts))) - (let ((root account-tree)) + (dolist (account + (delete-dups + (progn + (while (re-search-forward seed-regex nil t) + (unless (between origin (match-beginning 0) (match-end 0)) + (setq accounts (cons (match-string-no-properties 2) accounts)))) + accounts))) + (let ((root account-tree)) (setq account-elements - (split-string - account ":")) - (while account-elements - (let ((xact (assoc (car account-elements) root))) - (if xact - (setq root (cdr xact)) - (setq xact (cons (car account-elements) (list t))) - (nconc root (list xact)) - (setq root (cdr xact)))) - (setq account-elements (cdr account-elements)))))) - account-tree)) + (split-string + account ":")) + (while account-elements + (let ((xact (assoc (car account-elements) root))) + (if xact + (setq root (cdr xact)) + (setq xact (cons (car account-elements) (list t))) + (nconc root (list xact)) + (setq root (cdr xact)))) + (setq account-elements (cdr account-elements)))))) + account-tree)) (defun ledger-find-metadata-in-buffer () "Search through buffer and build list of metadata. @@ -129,19 +129,19 @@ Return list." (setq prefix (concat prefix (and prefix ":") (car elements)) root (cdr xact)) - (setq root nil elements nil))) + (setq root nil elements nil))) (setq elements (cdr elements))) (setq root (delete (list (car elements) t) root)) (and root (sort (mapcar (function (lambda (x) - (let ((term (if prefix - (concat prefix ":" (car x)) - (car x)))) - (if (> (length (cdr x)) 1) - (concat term ":") - term)))) + (let ((term (if prefix + (concat prefix ":" (car x)) + (car x)))) + (if (> (length (cdr x)) 1) + (concat term ":") + term)))) (cdr root)) 'string-lessp)))) @@ -155,27 +155,32 @@ Return list." (delete (caar (ledger-parse-arguments)) (ledger-payees-in-buffer)) ;; this completes against payee names - (progn - (let ((text (buffer-substring-no-properties - (line-beginning-position) - (line-end-position)))) - (delete-region (line-beginning-position) - (line-end-position)) - (condition-case nil - (ledger-add-transaction text t) - (error nil))) - (forward-line) - (goto-char (line-end-position)) - (search-backward ";" (line-beginning-position) t) - (skip-chars-backward " \t0123456789.,") - (throw 'pcompleted t))) - (ledger-accounts))))) + (progn + (let ((text (buffer-substring-no-properties + (line-beginning-position) + (line-end-position)))) + (delete-region (line-beginning-position) + (line-end-position)) + (condition-case nil + (ledger-add-transaction text t) + (error nil))) + (forward-line) + (goto-char (line-end-position)) + (search-backward ";" (line-beginning-position) t) + (skip-chars-backward " \t0123456789.,") + (throw 'pcompleted t))) + (ledger-accounts))))) + +(defun ledger-trim-trailing-whitespace (str) + (let ((s str)) + (when (string-match "[ \t]*$" s) + (replace-match "" nil nil s)))) (defun ledger-fully-complete-xact () "Completes a transaction if there is another matching payee in the buffer. Does not use ledger xact" (interactive) - (let* ((name (caar (ledger-parse-arguments))) + (let* ((name (ledger-trim-trailing-whitespace (caar (ledger-parse-arguments)))) (rest-of-name name) xacts) (save-excursion @@ -208,35 +213,41 @@ Does not use ledger xact" (goto-char (match-end 0)))))) +(defcustom ledger-complete-ignore-case t + "Non-nil means that ledger-complete-at-point will be case-insensitive" + :type 'boolean + :group 'ledger) + (defun ledger-pcomplete (&optional interactively) "Complete rip-off of pcomplete from pcomplete.el, only added ledger-magic-tab in the previous commands list so that ledger-magic-tab would cycle properly" (interactive "p") - (if (and interactively - pcomplete-cycle-completions - pcomplete-current-completions - (memq last-command '(ledger-magic-tab - ledger-pcomplete - pcomplete-expand-and-complete - pcomplete-reverse))) - (progn - (delete-backward-char pcomplete-last-completion-length) - (if (eq this-command 'pcomplete-reverse) - (progn - (push (car (last pcomplete-current-completions)) - pcomplete-current-completions) - (setcdr (last pcomplete-current-completions 2) nil)) + (let ((pcomplete-ignore-case ledger-complete-ignore-case)) + (if (and interactively + pcomplete-cycle-completions + pcomplete-current-completions + (memq last-command '(ledger-magic-tab + ledger-pcomplete + pcomplete-expand-and-complete + pcomplete-reverse))) + (progn + (delete-backward-char pcomplete-last-completion-length) + (if (eq this-command 'pcomplete-reverse) + (progn + (push (car (last pcomplete-current-completions)) + pcomplete-current-completions) + (setcdr (last pcomplete-current-completions 2) nil)) (nconc pcomplete-current-completions (list (car pcomplete-current-completions))) (setq pcomplete-current-completions (cdr pcomplete-current-completions))) - (pcomplete-insert-entry pcomplete-last-completion-stub - (car pcomplete-current-completions) - nil pcomplete-last-completion-raw)) - (setq pcomplete-current-completions nil + (pcomplete-insert-entry pcomplete-last-completion-stub + (car pcomplete-current-completions) + nil pcomplete-last-completion-raw)) + (setq pcomplete-current-completions nil pcomplete-last-completion-raw nil) - (catch 'pcompleted + (catch 'pcompleted (let* ((pcomplete-stub) pcomplete-seen pcomplete-norm-func pcomplete-args pcomplete-last pcomplete-index @@ -250,7 +261,7 @@ ledger-magic-tab would cycle properly" (pcomplete-insert-entry pcomplete-stub (cdr result) (memq (car result) '(sole shortest)) - pcomplete-last-completion-raw)))))) + pcomplete-last-completion-raw))))))) (provide 'ledger-complete) diff --git a/lisp/ledger-context.el b/lisp/ledger-context.el index b1bcd870..064ac380 100644 --- a/lisp/ledger-context.el +++ b/lisp/ledger-context.el @@ -1,6 +1,6 @@ ;;; ledger-context.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: @@ -28,56 +28,57 @@ (eval-when-compile (require 'cl)) -;; *-string constants are assembled in the single-line-config macro to -;; form the regex and list of elements -(defconst indent-string "\\(^[ \t]+\\)") -(defconst status-string "\\([*! ]?\\)") -(defconst account-string "[\\[(]?\\(.*?\\)[])]?") -(defconst amount-string "[ \t]?\\(-?[0-9]+\\.[0-9]*\\)") -(defconst comment-string "[ \t]*;[ \t]*\\(.*?\\)") -(defconst nil-string "\\([ \t]+\\)") -(defconst commodity-string "\\(.+?\\)") -(defconst date-string "^\\([0-9]\\{4\\}[/-][01]?[0-9][/-][0123]?[0-9]\\)") -(defconst code-string "\\((.*)\\)?") -(defconst payee-string "\\(.*\\)") - -(defmacro line-regex (&rest elements) +;; ledger-*-string constants are assembled in the +;; `ledger-single-line-config' macro to form the regex and list of +;; elements +(defconst ledger-indent-string "\\(^[ \t]+\\)") +(defconst ledger-status-string "\\([*! ]?\\)") +(defconst ledger-account-string "[\\[(]?\\(.*?\\)[])]?") +(defconst ledger-amount-string "[ \t]?\\(-?[0-9]+\\.[0-9]*\\)") +(defconst ledger-comment-string "[ \t]*;[ \t]*\\(.*?\\)") +(defconst ledger-nil-string "\\([ \t]+\\)") +(defconst ledger-commodity-string "\\(.+?\\)") +(defconst ledger-date-string "^\\([0-9]\\{4\\}[/-][01]?[0-9][/-][0123]?[0-9]\\)") +(defconst ledger-code-string "\\((.*)\\)?") +(defconst ledger-payee-string "\\(.*\\)") + +(defmacro ledger-line-regex (&rest elements) (let (regex-string) (concat (dolist (e elements regex-string) (setq regex-string (concat regex-string (eval (intern - (concat (symbol-name e) "-string")))))) "[ \t]*$"))) + (concat "ledger-" (symbol-name e) "-string")))))) "[ \t]*$"))) -(defmacro single-line-config2 (&rest elements) -"Take list of ELEMENTS and return regex and element list for use in context-at-point" +(defmacro ledger-single-line-config2 (&rest elements) + "Take list of ELEMENTS and return regex and element list for use in context-at-point" (let (regex-string) `'(,(concat (dolist (e elements regex-string) - (setq regex-string - (concat regex-string - (eval - (intern - (concat (symbol-name e) "-string")))))) "[ \t]*$") + (setq regex-string + (concat regex-string + (eval + (intern + (concat "ledger-" (symbol-name e) "-string")))))) "[ \t]*$") ,elements))) -(defmacro single-line-config (&rest elements) +(defmacro ledger-single-line-config (&rest elements) "Take list of ELEMENTS and return regex and element list for use in context-at-point" - `'(,(eval `(line-regex ,@elements)) + `'(,(eval `(ledger-line-regex ,@elements)) ,elements)) (defconst ledger-line-config - (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 payee))) - (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) - (single-line-config2 indent status account nil amount nil commodity comment) - (single-line-config2 indent status account nil amount nil commodity) - (single-line-config2 indent status account nil amount) - (single-line-config2 indent status account nil comment) - (single-line-config2 indent status account))))) + (list (list 'xact (list (ledger-single-line-config date nil status nil code nil payee nil comment) + (ledger-single-line-config date nil status nil code nil payee) + (ledger-single-line-config date nil status nil payee))) + (list 'acct-transaction (list (ledger-single-line-config indent comment) + (ledger-single-line-config2 indent status account nil commodity amount nil comment) + (ledger-single-line-config2 indent status account nil commodity amount) + (ledger-single-line-config2 indent status account nil amount nil commodity comment) + (ledger-single-line-config2 indent status account nil amount nil commodity) + (ledger-single-line-config2 indent status account nil amount) + (ledger-single-line-config2 indent status account nil comment) + (ledger-single-line-config2 indent status account))))) (defun ledger-extract-context-info (line-type pos) "Get context info for current line with LINE-TYPE. @@ -113,7 +114,7 @@ Leave point at the beginning of the thing under point" (cond ((looking-at "^[0-9/.=-]+\\(\\s-+\\*\\)?\\(\\s-+(.+?)\\)?\\s-+") (goto-char (match-end 0)) 'transaction) - ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\(.\\)") + ((looking-at "^\\s-+\\([*!]\\s-+\\)?[[(]?\\([^\\s-]\\)") (goto-char (match-beginning 2)) 'posting) ((looking-at "^\\(sun\\|mon\\|tue\\|wed\\|thu\\|fri\\|sat\\)\\s-+") diff --git a/lisp/ledger-exec.el b/lisp/ledger-exec.el index 95b28ec2..13a99125 100644 --- a/lisp/ledger-exec.el +++ b/lisp/ledger-exec.el @@ -1,6 +1,6 @@ ;;; ledger-exec.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: @@ -97,11 +97,10 @@ (defun ledger-check-version () "Verify that ledger works and is modern enough." (interactive) - (if ledger-mode-should-check-version - (if (setq ledger-works (ledger-version-greater-p ledger-version-needed)) - (message "Good Ledger Version") - (message "Bad Ledger Version")) - setq ledger-works t)) + (if ledger-mode-should-check-version + (if (setq ledger-works (ledger-version-greater-p ledger-version-needed)) + (message "Good Ledger Version") + (message "Bad Ledger Version")))) (provide 'ledger-exec) diff --git a/lisp/ledger-fonts.el b/lisp/ledger-fonts.el index 28f1f98d..5194e876 100644 --- a/lisp/ledger-fonts.el +++ b/lisp/ledger-fonts.el @@ -1,6 +1,6 @@ ;;; ledger-fonts.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. @@ -40,7 +40,8 @@ :group 'ledger-faces) (defface ledger-font-xact-highlight-face - `((t :background "#eee8d5")) + `((((background dark)) :background "#1a1a1a" ) + (t :background "#eee8d5")) "Default face for transaction under point" :group 'ledger-faces) @@ -80,7 +81,8 @@ :group 'ledger-faces) (defface ledger-occur-xact-face - `((t :background "#eee8d5" )) + `((((background dark)) :background "#1a1a1a" ) + (t :background "#eee8d5" )) "Default face for Ledger occur mode shown transactions" :group 'ledger-faces) diff --git a/lisp/ledger-init.el b/lisp/ledger-init.el index fd06d4c5..531f2c45 100644 --- a/lisp/ledger-init.el +++ b/lisp/ledger-init.el @@ -1,6 +1,6 @@ ;;; ledger-init.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: ;; Determine the ledger environment @@ -30,38 +30,41 @@ (defvar ledger-environment-alist nil) +(defvar ledger-default-date-format "%Y/%m/%d") + (defun ledger-init-parse-initialization (buffer) (with-current-buffer buffer (let (environment-alist) (goto-char (point-min)) (while (re-search-forward ledger-init-string-regex nil t ) - (let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it - (matche (match-end 0))) - (end-of-line) - (setq environment-alist - (append environment-alist - (list (cons (let ((flag (buffer-substring-no-properties (+ 2 matchb) matche))) - (if (string-match "[ \t\n\r]+\\'" flag) - (replace-match "" t t flag) - flag)) - (let ((value (buffer-substring-no-properties matche (point) ))) - (if (> (length value) 0) - value - t)))))))) + (let ((matchb (match-beginning 0)) ;; save the match data, string-match stamp on it + (matche (match-end 0))) + (end-of-line) + (setq environment-alist + (append environment-alist + (list (cons (let ((flag (buffer-substring-no-properties (+ 2 matchb) matche))) + (if (string-match "[ \t\n\r]+\\'" flag) + (replace-match "" t t flag) + flag)) + (let ((value (buffer-substring-no-properties matche (point) ))) + (if (> (length value) 0) + value + t)))))))) environment-alist))) (defun ledger-init-load-init-file () (interactive) (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 - (ledger-init-parse-initialization init-base-name) - (when (and ledger-init-file-name - (file-exists-p ledger-init-file-name) - (file-readable-p ledger-init-file-name)) - (find-file-noselect ledger-init-file-name) - (setq ledger-environment-alist - (ledger-init-parse-initialization init-base-name)) - (kill-buffer init-base-name))))) + (setq ledger-environment-alist + (ledger-init-parse-initialization init-base-name)) + (when (and ledger-init-file-name + (file-exists-p ledger-init-file-name) + (file-readable-p ledger-init-file-name)) + (find-file-noselect ledger-init-file-name) + (setq ledger-environment-alist + (ledger-init-parse-initialization init-base-name)) + (kill-buffer init-base-name))))) (provide 'ledger-init) diff --git a/lisp/ledger-mode.el b/lisp/ledger-mode.el index 387ace97..07e6732a 100644 --- a/lisp/ledger-mode.el +++ b/lisp/ledger-mode.el @@ -1,6 +1,6 @@ ;;; ledger-mode.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. @@ -29,6 +29,7 @@ (require 'ledger-regex) (require 'esh-util) (require 'esh-arg) +(require 'easymenu) (require 'ledger-commodities) (require 'ledger-complete) (require 'ledger-context) @@ -92,31 +93,43 @@ (defun ledger-read-account-with-prompt (prompt) (let* ((context (ledger-context-at-point)) - (default (if (and (eq (ledger-context-line-type context) 'acct-transaction) - (eq (ledger-context-current-field context) 'account)) - (regexp-quote (ledger-context-field-value context 'account)) - nil))) + (default (if (and (eq (ledger-context-line-type context) 'acct-transaction) + (eq (ledger-context-current-field context) 'account)) + (regexp-quote (ledger-context-field-value context 'account)) + nil))) (ledger-read-string-with-default prompt default))) +(defun ledger-read-date (prompt) + "Returns user-supplied date after `PROMPT', defaults to today." + (let* ((default (ledger-year-and-month)) + (date (read-string prompt default + 'ledger-minibuffer-history))) + (if (or (string= date default) + (string= "" date)) + (format-time-string + (or (cdr (assoc "date-format" ledger-environment-alist)) + ledger-default-date-format)) + date))) + (defun ledger-read-string-with-default (prompt default) "Return user supplied string after PROMPT, or DEFAULT." (read-string (concat prompt - (if default - (concat " (" default "): ") - ": ")) - nil 'ledger-minibuffer-history default)) + (if default + (concat " (" default "): ") + ": ")) + nil 'ledger-minibuffer-history default)) (defun ledger-display-balance-at-point () "Display the cleared-or-pending balance. And calculate the target-delta of the account being reconciled." (interactive) (let* ((account (ledger-read-account-with-prompt "Account balance to show")) - (buffer (current-buffer)) - (balance (with-temp-buffer - (ledger-exec-ledger buffer (current-buffer) "cleared" account) - (if (> (buffer-size) 0) - (buffer-substring-no-properties (point-min) (1- (point-max))) - (concat account " is empty."))))) + (buffer (current-buffer)) + (balance (with-temp-buffer + (ledger-exec-ledger buffer (current-buffer) "cleared" account) + (if (> (buffer-size) 0) + (buffer-substring-no-properties (point-min) (1- (point-max))) + (concat account " is empty."))))) (when balance (message balance)))) @@ -125,9 +138,9 @@ And calculate the target-delta of the account being reconciled." And calculate the target-delta of the account being reconciled." (interactive) (let* ((buffer (current-buffer)) - (balance (with-temp-buffer - (ledger-exec-ledger buffer (current-buffer) "stats") - (buffer-substring-no-properties (point-min) (1- (point-max)))))) + (balance (with-temp-buffer + (ledger-exec-ledger buffer (current-buffer) "stats") + (buffer-substring-no-properties (point-min) (1- (point-max)))))) (when balance (message balance)))) @@ -135,71 +148,95 @@ And calculate the target-delta of the account being reconciled." "Decide what to with with <TAB>. Can indent, complete or align depending on context." (interactive "p") - (if (= (point) (line-beginning-position)) - (indent-to ledger-post-account-alignment-column) - (if (and (> (point) 1) - (looking-back "\\([^ \t]\\)" 1)) - (ledger-pcomplete interactively) - (ledger-post-align-postings)))) + (if (= (point) (line-beginning-position)) + (indent-to ledger-post-account-alignment-column) + (if (and (> (point) 1) + (looking-back "\\([^ \t]\\)" 1)) + (ledger-pcomplete interactively) + (ledger-post-align-postings)))) (defvar ledger-mode-abbrev-table) -(defun ledger-insert-effective-date () +(defvar ledger-date-string-today + (format-time-string (or + (cdr (assoc "date-format" ledger-environment-alist)) + ledger-default-date-format))) + +(defun ledger-remove-effective-date () + "Removes the effective date from a transaction or posting." (interactive) - (let ((context (car (ledger-context-at-point))) - (date-string (format-time-string (cdr (assoc "date-format" ledger-environment-alist))))) - (cond ((eq 'xact context) - (beginning-of-line) - (insert date-string "=")) - ((eq 'acct-transaction context) - (end-of-line) - (insert " ; [=" date-string "]"))))) + (let ((context (car (ledger-context-at-point)))) + (save-excursion + (save-restriction + (narrow-to-region (point-at-bol) (point-at-eol)) + (beginning-of-line) + (cond ((eq 'pmnt-transaction context) + (re-search-forward ledger-iso-date-regexp) + (when (= (char-after) ?=) + (let ((eq-pos (point))) + (delete-region + eq-pos + (re-search-forward ledger-iso-date-regexp))))) + ((eq 'acct-transaction context) + ;; Match "; [=date]" & delete string + (when (re-search-forward + (concat ledger-comment-regex + "\\[=" ledger-iso-date-regexp "\\]") + nil 'noerr) + (replace-match "")))))))) + +(defun ledger-insert-effective-date (&optional date) + "Insert effective date `DATE' to the transaction or posting. + +If `DATE' is nil, prompt the user a date. + +Replace the current effective date if there's one in the same +line. + +With a prefix argument, remove the effective date. " + (interactive) + (if (and (listp current-prefix-arg) + (= 4 (prefix-numeric-value current-prefix-arg))) + (ledger-remove-effective-date) + (let* ((context (car (ledger-context-at-point))) + (date-string (or date (ledger-read-date "Effective date: ")))) + (save-restriction + (narrow-to-region (point-at-bol) (point-at-eol)) + (cond + ((eq 'pmnt-transaction context) + (beginning-of-line) + (re-search-forward ledger-iso-date-regexp) + (when (= (char-after) ?=) + (ledger-remove-effective-date)) + (insert "=" date-string)) + ((eq 'acct-transaction context) + (end-of-line) + (ledger-remove-effective-date) + (insert " ; [=" date-string "]"))))))) (defun ledger-mode-remove-extra-lines () - (goto-char (point-min)) - (while (re-search-forward "\n\n\\(\n\\)+" nil t) - (replace-match "\n\n"))) + (goto-char (point-min)) + (while (re-search-forward "\n\n\\(\n\\)+" nil t) + (replace-match "\n\n"))) (defun ledger-mode-clean-buffer () - "indent, remove multiple linfe feeds and sort the buffer" - (interactive) - (ledger-sort-buffer) - (ledger-post-align-postings (point-min) (point-max)) - (ledger-mode-remove-extra-lines)) - - -;;;###autoload -(define-derived-mode ledger-mode text-mode "Ledger" - "A mode for editing ledger data files." - (ledger-check-version) - (ledger-post-setup) - - (set (make-local-variable 'comment-start) "; ") - (set (make-local-variable 'comment-end) "") - (set (make-local-variable 'indent-tabs-mode) nil) - - (if (boundp 'font-lock-defaults) - (set (make-local-variable 'font-lock-defaults) - '(ledger-font-lock-keywords nil t))) - (setq font-lock-extend-region-functions - (list #'font-lock-extend-region-wholelines)) - (setq font-lock-multiline nil) - - (set (make-local-variable 'pcomplete-parse-arguments-function) - 'ledger-parse-arguments) - (set (make-local-variable 'pcomplete-command-completion-function) - 'ledger-complete-at-point) - (set (make-local-variable 'pcomplete-termination-string) "") - - (add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t) - (add-hook 'before-revert-hook 'ledger-occur-remove-all-overlays nil t) - (make-variable-buffer-local 'highlight-overlay) + "indent, remove multiple linfe feeds and sort the buffer" + (interactive) + (ledger-sort-buffer) + (ledger-post-align-postings (point-min) (point-max)) + (ledger-mode-remove-extra-lines)) - (ledger-init-load-init-file) - (set (make-local-variable 'indent-region-function) 'ledger-post-align-postings) +(defvar ledger-mode-syntax-table + (let ((table (make-syntax-table))) + ;; Support comments via the syntax table + (modify-syntax-entry ?\; "< b" table) + (modify-syntax-entry ?\n "> b" table) + table) + "Syntax table for `ledger-mode' buffers.") - (let ((map (current-local-map))) +(defvar ledger-mode-map + (let ((map (make-sparse-keymap))) (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 ?c)] 'ledger-toggle-current) @@ -232,67 +269,101 @@ Can indent, complete or align depending on context." (define-key map [(meta ?p)] 'ledger-post-prev-xact) (define-key map [(meta ?n)] 'ledger-post-next-xact) + map) + "Keymap for `ledger-mode'.") + +(easy-menu-define ledger-mode-menu ledger-mode-map + "Ledger menu" + '("Ledger" + ["Narrow to REGEX" ledger-occur] + ["Ledger Statistics" ledger-display-ledger-stats ledger-works] + "---" + ["Show upcoming transactions" ledger-schedule-upcoming ledger-schedule-available] + ["Add Transaction (ledger xact)" ledger-add-transaction ledger-works] + ["Complete Transaction" ledger-fully-complete-xact] + ["Delete Transaction" ledger-delete-current-transaction] + "---" + ["Calc on Amount" ledger-post-edit-amount] + "---" + ["Check Balance" ledger-display-balance-at-point ledger-works] + ["Reconcile Account" ledger-reconcile ledger-works] + "---" + ["Toggle Current Transaction" ledger-toggle-current-transaction] + ["Toggle Current Posting" ledger-toggle-current] + ["Copy Trans at Point" ledger-copy-transaction-at-point] + "---" + ["Clean-up Buffer" ledger-mode-clean-buffer] + ["Align Region" ledger-post-align-postings mark-active] + ["Align Xact" ledger-post-align-xact] + ["Sort Region" ledger-sort-region mark-active] + ["Sort Buffer" ledger-sort-buffer] + ["Mark Sort Beginning" ledger-sort-insert-start-mark] + ["Mark Sort End" ledger-sort-insert-end-mark] + ["Set effective date" ledger-insert-effective-date] + "---" + ["Customize Ledger Mode" (lambda () (interactive) (customize-group 'ledger))] + ["Set Year" ledger-set-year ledger-works] + ["Set Month" ledger-set-month ledger-works] + "---" + ["Run Report" ledger-report ledger-works] + ["Goto Report" ledger-report-goto ledger-works] + ["Re-run Report" ledger-report-redo ledger-works] + ["Save Report" ledger-report-save ledger-works] + ["Edit Report" ledger-report-edit ledger-works] + ["Kill Report" ledger-report-kill ledger-works] + )) + +;;;###autoload +(define-derived-mode ledger-mode text-mode "Ledger" + "A mode for editing ledger data files." + (ledger-check-version) + (ledger-schedule-check-available) + (ledger-post-setup) + + (set-syntax-table ledger-mode-syntax-table) + (set (make-local-variable 'comment-start) "; ") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'indent-tabs-mode) nil) + + (if (boundp 'font-lock-defaults) + (set (make-local-variable 'font-lock-defaults) + '(ledger-font-lock-keywords nil t))) + (setq font-lock-extend-region-functions + (list #'font-lock-extend-region-wholelines)) + (setq font-lock-multiline nil) + + (set (make-local-variable 'pcomplete-parse-arguments-function) + 'ledger-parse-arguments) + (set (make-local-variable 'pcomplete-command-completion-function) + 'ledger-complete-at-point) + (add-hook 'completion-at-point-functions 'pcomplete-completions-at-point nil t) - (define-key map [menu-bar] (make-sparse-keymap "ledger-menu")) - (define-key map [menu-bar ledger-menu] (cons "Ledger" map)) - - (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-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-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 [sep5] '(menu-item "--")) - (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 [cust] '(menu-item "Customize Ledger Mode" (lambda () - (interactive) - (customize-group 'ledger)))) - (define-key map [sep1] '("--")) - (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-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-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-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 [sep2] '(menu-item "--")) - (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-xact] '(menu-item "Toggle Current Transaction" ledger-toggle-current-transaction)) - (define-key map [sep4] '(menu-item "--")) - (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 [sep6] '(menu-item "--")) - (define-key map [edit-amount] '(menu-item "Calc on Amount" ledger-post-edit-amount)) - (define-key map [sep] '(menu-item "--")) - (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 [add-xact] '(menu-item "Add Transaction (ledger xact)" ledger-add-transaction :enable ledger-works)) - (define-key map [sep3] '(menu-item "--")) - (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)))) + (add-hook 'post-command-hook 'ledger-highlight-xact-under-point nil t) + (add-hook 'before-revert-hook 'ledger-occur-remove-all-overlays nil t) + (ledger-init-load-init-file) + (set (make-local-variable 'indent-region-function) 'ledger-post-align-postings)) (defun ledger-set-year (newyear) "Set ledger's idea of the current year to the prefix argument NEWYEAR." (interactive "p") - (if (= newyear 1) - (setq ledger-year (read-string "Year: " (ledger-current-year))) - (setq ledger-year (number-to-string newyear)))) + (setq ledger-year + (if (= newyear 1) + (read-string "Year: " (ledger-current-year)) + (number-to-string newyear)))) (defun ledger-set-month (newmonth) "Set ledger's idea of the current month to the prefix argument NEWMONTH." (interactive "p") - (if (= newmonth 1) - (setq ledger-month (read-string "Month: " (ledger-current-month))) - (setq ledger-month (format "%02d" newmonth)))) + (setq ledger-month + (if (= newmonth 1) + (read-string "Month: " (ledger-current-month)) + (format "%02d" newmonth)))) -(provide 'ledger) +(provide 'ledger-mode) ;;; ledger-mode.el ends here diff --git a/lisp/ledger-occur.el b/lisp/ledger-occur.el index 33d3a56c..24ded4ca 100644 --- a/lisp/ledger-occur.el +++ b/lisp/ledger-occur.el @@ -1,6 +1,6 @@ ;;; ledger-mode.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: ;; Provide buffer narrowing to ledger mode. Adapted from original loccur @@ -39,7 +39,7 @@ (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) @@ -65,19 +65,19 @@ When REGEX is nil, unhide everything, and remove higlight" (set-buffer buffer) (setq ledger-occur-mode - (if (or (null regex) - (zerop (length regex))) - nil - (concat " Ledger-Narrowed: " regex))) + (if (or (null regex) + (zerop (length regex))) + nil + (concat " Ledger-Narrowed: " regex))) (force-mode-line-update) (ledger-occur-remove-overlays) (when ledger-occur-mode - (ledger-occur-create-overlays - (ledger-occur-compress-matches - (ledger-occur-find-matches regex))) - (setq ledger-occur-last-match regex) - (if (get-buffer-window buffer) - (select-window (get-buffer-window buffer)))) + (ledger-occur-create-overlays + (ledger-occur-compress-matches + (ledger-occur-find-matches regex))) + (setq ledger-occur-last-match regex) + (if (get-buffer-window buffer) + (select-window (get-buffer-window buffer)))) (recenter)) (defun ledger-occur (regex) @@ -90,7 +90,7 @@ When REGEX is nil, unhide everything, and remove higlight" (if ledger-occur-mode (list nil) (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))) (defun ledger-occur-prompt () @@ -108,32 +108,32 @@ When REGEX is nil, unhide everything, and remove higlight" (if (= (line-number-at-pos pos1) (line-number-at-pos pos2)) (buffer-substring-no-properties pos1 pos2))) - (current-word)))) + (current-word)))) prompt)) (defun ledger-occur-make-visible-overlay (beg end) - (let ((ovl (make-overlay beg end (current-buffer)))) - (overlay-put ovl ledger-occur-overlay-property-name t) - (overlay-put ovl 'face 'ledger-occur-xact-face))) + (let ((ovl (make-overlay beg end (current-buffer)))) + (overlay-put ovl ledger-occur-overlay-property-name t) + (overlay-put ovl 'face 'ledger-occur-xact-face))) (defun ledger-occur-make-invisible-overlay (beg end) - (let ((ovl (make-overlay beg end (current-buffer)))) - (overlay-put ovl ledger-occur-overlay-property-name t) - (overlay-put ovl 'invisible t))) + (let ((ovl (make-overlay beg end (current-buffer)))) + (overlay-put ovl ledger-occur-overlay-property-name t) + (overlay-put ovl 'invisible t))) (defun ledger-occur-create-overlays (ovl-bounds) "Create the overlays for the visible transactions. Argument OVL-BOUNDS contains bounds for the transactions to be left visible." - (let* ((beg (caar ovl-bounds)) - (end (cadar ovl-bounds))) - (ledger-occur-make-invisible-overlay (point-min) (1- beg)) - (dolist (visible (cdr ovl-bounds)) - (ledger-occur-make-visible-overlay beg end) - (ledger-occur-make-invisible-overlay (1+ end) (1- (car visible))) - (setq beg (car visible)) - (setq end (cadr visible))) - (ledger-occur-make-invisible-overlay (1+ end) (point-max)))) + (let* ((beg (caar ovl-bounds)) + (end (cadar ovl-bounds))) + (ledger-occur-make-invisible-overlay (point-min) (1- beg)) + (dolist (visible (cdr ovl-bounds)) + (ledger-occur-make-visible-overlay beg end) + (ledger-occur-make-invisible-overlay (1+ end) (1- (car visible))) + (setq beg (car visible)) + (setq end (cadr visible))) + (ledger-occur-make-invisible-overlay (1+ end) (point-max)))) (defun ledger-occur-quit-buffer (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." (interactive) (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)) (defun ledger-occur-find-matches (regex) @@ -157,35 +157,35 @@ Used for coordinating `ledger-occur' with other buffers, like reconcile." (goto-char (point-min)) ;; Set initial values for variables (let (curpoint - endpoint - (lines (list))) + endpoint + (lines (list))) ;; Search loop (while (not (eobp)) (setq curpoint (point)) ;; if something found (when (setq endpoint (re-search-forward regex nil 'end)) (save-excursion - (let ((bounds (ledger-find-xact-extents (match-beginning 0)))) - (push bounds lines) - (setq curpoint (cadr bounds)))) ;; move to the end of - ;; the xact, no need to - ;; search inside it more + (let ((bounds (ledger-find-xact-extents (match-beginning 0)))) + (push bounds lines) + (setq curpoint (cadr bounds)))) ;; move to the end of + ;; the xact, no need to + ;; search inside it more (goto-char curpoint)) (forward-line 1)) (setq lines (nreverse lines))))) (defun ledger-occur-compress-matches (buffer-matches) - "identify sequential xacts to reduce number of overlays required" - (let ((points (list)) - (current-beginning (caar buffer-matches)) - (current-end (cadar buffer-matches))) - (dolist (match (cdr buffer-matches)) - (if (< (- (car match) current-end) 2) - (setq current-end (cadr match)) - (push (list current-beginning current-end) points) - (setq current-beginning (car match)) - (setq current-end (cadr match)))) - (nreverse (push (list current-beginning current-end) points)))) + "identify sequential xacts to reduce number of overlays required" + (let ((points (list)) + (current-beginning (caar buffer-matches)) + (current-end (cadar buffer-matches))) + (dolist (match (cdr buffer-matches)) + (if (< (- (car match) current-end) 2) + (setq current-end (cadr match)) + (push (list current-beginning current-end) points) + (setq current-beginning (car match)) + (setq current-end (cadr match)))) + (nreverse (push (list current-beginning current-end) points)))) (provide 'ledger-occur) diff --git a/lisp/ledger-post.el b/lisp/ledger-post.el index 5d30e954..b8fa36ca 100644 --- a/lisp/ledger-post.el +++ b/lisp/ledger-post.el @@ -1,6 +1,6 @@ ;;; ledger-post.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: @@ -44,10 +44,10 @@ (defcustom ledger-post-use-completion-engine :built-in "Which completion engine to use, :iswitchb or :ido chose those engines, :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 "iswitchb completion" :iswitchb) ) - :group 'ledger-post) + :group 'ledger-post) (defun ledger-post-all-accounts () "Return a list of all accounts in the buffer." @@ -129,8 +129,8 @@ 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. Return the column of the beginning of the account and leave point at beginning of account" - (if (> end (point)) - (when (re-search-forward ledger-account-any-status-regex (1+ end) t) + (if (> end (point)) + (when (re-search-forward ledger-account-any-status-regex (1+ end) t) ;; the 1+ is to make sure we can catch the newline (if (match-beginning 1) (goto-char (match-beginning 1)) @@ -138,9 +138,9 @@ at beginning of account" (current-column)))) (defun ledger-post-align-xact (pos) - (interactive "d") - (let ((bounds (ledger-find-xact-extents pos))) - (ledger-post-align-postings (car bounds) (cadr bounds)))) + (interactive "d") + (let ((bounds (ledger-find-xact-extents pos))) + (ledger-post-align-postings (car bounds) (cadr bounds)))) (defun ledger-post-align-postings (&optional beg end) "Align all accounts and amounts within region, if there is no @@ -209,11 +209,11 @@ region align the posting on the current line." (let ((end-of-amount (re-search-forward "[-.,0-9]+" (line-end-position) t))) ;; determine if there is an amount to edit (if end-of-amount - (let ((val (ledger-string-to-number (match-string 0)))) + (let ((val-string (match-string 0))) (goto-char (match-beginning 0)) (delete-region (match-beginning 0) (match-end 0)) (calc) - (calc-eval val 'push)) ;; edit the amount + (calc-eval val-string 'push)) ;; edit the amount (progn ;;make sure there are two spaces after the account name and go to calc (if (search-backward " " (- (point) 3) t) (goto-char (line-end-position)) diff --git a/lisp/ledger-reconcile.el b/lisp/ledger-reconcile.el index 4725c6e4..bdd530d2 100644 --- a/lisp/ledger-reconcile.el +++ b/lisp/ledger-reconcile.el @@ -1,6 +1,6 @@ ;;; ledger-reconcile.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;; Reconcile mode @@ -27,13 +27,16 @@ ;;; Code: +(require 'easymenu) +(require 'ledger-init) + (defvar ledger-buf nil) (defvar ledger-bufs nil) (defvar ledger-acct nil) (defvar ledger-target nil) (defgroup ledger-reconcile nil - "Options for Ledger-mode reconciliation" + "Options for Ledger-mode reconciliation" :group 'ledger) (defcustom ledger-recon-buffer-name "*Reconcile*" @@ -59,10 +62,10 @@ Then that transaction will be shown in its source buffer." (defcustom ledger-reconcile-toggle-to-pending t "If true then toggle between uncleared and pending. reconcile-finish will mark all pending posting cleared." - :type 'boolean - :group 'ledger-reconcile) + :type 'boolean + :group 'ledger-reconcile) -(defcustom ledger-reconcile-default-date-format "%Y/%m/%d" +(defcustom ledger-reconcile-default-date-format ledger-default-date-format "Default date format for the reconcile buffer" :type 'string :group 'ledger-reconcile) @@ -72,8 +75,15 @@ reconcile-finish will mark all pending posting cleared." :type 'string :group 'ledger-reconcile) -(defvar ledger-reconcile-sort-key "(date)" - "Default key for sorting reconcile buffer") +(defcustom ledger-reconcile-sort-key "(date)" + "Default key for sorting reconcile buffer. For no sorting by default, use '(0)'." + :type 'string + :group 'ledger-reconcile) + +(defcustom ledger-reconcile-insert-effective-date nil + "If t, prompt for effective date when clearing transactions during reconciliation." + :type 'boolean + :group 'ledger-reconcile) (defun ledger-reconcile-get-cleared-or-pending-balance (buffer account) "Calculate the cleared or pending balance of the account." @@ -87,10 +97,10 @@ reconcile-finish will mark all pending posting cleared." ;; split arguments like the shell does, so you need to ;; specify the individual fields in the command line. (if (ledger-exec-ledger buffer (current-buffer) - "balance" "--limit" "cleared or pending" "--empty" "--collapse" - "--format" "%(display_total)" account) - (ledger-split-commodity-string - (buffer-substring-no-properties (point-min) (point-max)))))) + "balance" "--limit" "cleared or pending" "--empty" "--collapse" + "--format" "%(display_total)" account) + (ledger-split-commodity-string + (buffer-substring-no-properties (point-min) (point-max)))))) (defun ledger-display-balance () "Display the cleared-or-pending balance. @@ -98,14 +108,14 @@ And calculate the target-delta of the account being reconciled." (interactive) (let* ((pending (ledger-reconcile-get-cleared-or-pending-balance ledger-buf ledger-acct))) (when pending - (if ledger-target - (message "Pending balance: %s, Difference from target: %s" - (ledger-commodity-to-string pending) - (ledger-commodity-to-string (-commodity ledger-target pending))) - (message "Pending balance: %s" - (ledger-commodity-to-string pending)))))) - -(defun is-stdin (file) + (if ledger-target + (message "Pending balance: %s, Difference from target: %s" + (ledger-commodity-to-string pending) + (ledger-commodity-to-string (-commodity ledger-target pending))) + (message "Pending balance: %s" + (ledger-commodity-to-string pending)))))) + +(defun ledger-is-stdin (file) "True if ledger FILE is standard input." (or (equal file "") @@ -127,27 +137,30 @@ And calculate the target-delta of the account being reconciled." status) (when (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where) - (ledger-goto-line (cdr where)) - (forward-char) - (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending - 'pending - 'cleared)))) - ;; remove the existing face and add the new face + (ledger-goto-line (cdr where)) + (forward-char) + (setq status (ledger-toggle-current (if ledger-reconcile-toggle-to-pending + 'pending + 'cleared))) + (when ledger-reconcile-insert-effective-date + ;; Ask for effective date & insert it + (ledger-insert-effective-date))) + ;; remove the existing face and add the new face (remove-text-properties (line-beginning-position) - (line-end-position) - (list 'face)) + (line-end-position) + (list 'face)) (cond ((eq status 'pending) - (add-text-properties (line-beginning-position) - (line-end-position) - (list 'face 'ledger-font-reconciler-pending-face ))) - ((eq status 'cleared) - (add-text-properties (line-beginning-position) - (line-end-position) - (list 'face 'ledger-font-reconciler-cleared-face ))) - (t - (add-text-properties (line-beginning-position) - (line-end-position) - (list 'face 'ledger-font-reconciler-uncleared-face ))))) + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'ledger-font-reconciler-pending-face ))) + ((eq status 'cleared) + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'ledger-font-reconciler-cleared-face ))) + (t + (add-text-properties (line-beginning-position) + (line-end-position) + (list 'face 'ledger-font-reconciler-uncleared-face ))))) (forward-line) (beginning-of-line) (ledger-display-balance))) @@ -159,18 +172,18 @@ Return the number of uncleared xacts found." (let ((inhibit-read-only t)) (erase-buffer) (prog1 - (ledger-do-reconcile ledger-reconcile-sort-key) + (ledger-do-reconcile ledger-reconcile-sort-key) (set-buffer-modified-p t)))) (defun ledger-reconcile-refresh-after-save () "Refresh the recon-window after the ledger buffer is saved." (let ((curbuf (current-buffer)) - (curpoint (point)) - (recon-buf (get-buffer ledger-recon-buffer-name))) + (curpoint (point)) + (recon-buf (get-buffer ledger-recon-buffer-name))) (when (buffer-live-p recon-buf) (with-current-buffer recon-buf - (ledger-reconcile-refresh) - (set-buffer-modified-p nil)) + (ledger-reconcile-refresh) + (set-buffer-modified-p nil)) (select-window (get-buffer-window curbuf)) (goto-char curpoint)))) @@ -188,7 +201,7 @@ Return the number of uncleared xacts found." (when (ledger-reconcile-get-buffer where) (with-current-buffer (ledger-reconcile-get-buffer where) (ledger-goto-line (cdr where)) - (ledger-delete-current-transaction)) + (ledger-delete-current-transaction (point))) (let ((inhibit-read-only t)) (goto-char (line-beginning-position)) (delete-region (point) (1+ (line-end-position))) @@ -200,19 +213,19 @@ Return the number of uncleared xacts found." (progn (beginning-of-line) (let* ((where (get-text-property (1+ (point)) 'where)) - (target-buffer (if where - (ledger-reconcile-get-buffer where) - nil)) - (cur-win (get-buffer-window (get-buffer ledger-recon-buffer-name)))) + (target-buffer (if where + (ledger-reconcile-get-buffer where) + nil)) + (cur-win (get-buffer-window (get-buffer ledger-recon-buffer-name)))) (when target-buffer - (switch-to-buffer-other-window target-buffer) - (ledger-goto-line (cdr where)) - (forward-char) - (recenter) - (ledger-highlight-xact-under-point) - (forward-char -1) - (if (and come-back cur-win) - (select-window cur-win)))))) + (switch-to-buffer-other-window target-buffer) + (ledger-goto-line (cdr where)) + (forward-char) + (recenter) + (ledger-highlight-xact-under-point) + (forward-char -1) + (if (and come-back cur-win) + (select-window cur-win)))))) (defun ledger-reconcile-save () "Save the ledger buffer." @@ -220,7 +233,7 @@ Return the number of uncleared xacts found." (let ((curpoint (point))) (dolist (buf (cons ledger-buf ledger-bufs)) (with-current-buffer buf - (save-buffer))) + (save-buffer))) (with-current-buffer (get-buffer ledger-recon-buffer-name) (set-buffer-modified-p nil) (ledger-display-balance) @@ -243,94 +256,93 @@ and exit reconcile mode" (ledger-toggle-current 'cleared)))) (forward-line 1))) (ledger-reconcile-save) - (ledger-reconcile-quit)) + (ledger-reconcile-quit)) (defun ledger-reconcile-quit () "Quit the reconcile window without saving ledger buffer." (interactive) (let ((recon-buf (get-buffer ledger-recon-buffer-name)) - buf) + buf) (if recon-buf - (with-current-buffer recon-buf - (ledger-reconcile-quit-cleanup) - (setq buf ledger-buf) - ;; Make sure you delete the window before you delete the buffer, - ;; otherwise, madness ensues - (delete-window (get-buffer-window recon-buf)) - (kill-buffer recon-buf) - (set-window-buffer (selected-window) buf))))) + (with-current-buffer recon-buf + (ledger-reconcile-quit-cleanup) + (setq buf ledger-buf) + ;; Make sure you delete the window before you delete the buffer, + ;; otherwise, madness ensues + (delete-window (get-buffer-window recon-buf)) + (kill-buffer recon-buf) + (set-window-buffer (selected-window) buf))))) (defun ledger-reconcile-quit-cleanup () "Cleanup all hooks established by reconcile mode." (interactive) (let ((buf ledger-buf)) (if (buffer-live-p buf) - (with-current-buffer buf - (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) - (when ledger-narrow-on-reconcile - (ledger-occur-quit-buffer buf) - (ledger-highlight-xact-under-point)))))) + (with-current-buffer buf + (remove-hook 'after-save-hook 'ledger-reconcile-refresh-after-save t) + (when ledger-narrow-on-reconcile + (ledger-occur-quit-buffer buf) + (ledger-highlight-xact-under-point)))))) (defun ledger-marker-where-xact-is (emacs-xact posting) "Find the position of the EMACS-XACT in the `ledger-buf'. POSTING is used in `ledger-clear-whole-transactions' is nil." - (let ((buf (if (is-stdin (nth 0 emacs-xact)) - ledger-buf - (find-file-noselect (nth 0 emacs-xact))))) + (let ((buf (if (ledger-is-stdin (nth 0 emacs-xact)) + ledger-buf + (find-file-noselect (nth 0 emacs-xact))))) (cons buf (if ledger-clear-whole-transactions - (nth 1 emacs-xact) ;; return line-no of xact - (nth 0 posting))))) ;; return line-no of posting + (nth 1 emacs-xact) ;; return line-no of xact + (nth 0 posting))))) ;; return line-no of posting (defun ledger-do-reconcile (&optional sort) "Return the number of uncleared transactions in the account and display them in the *Reconcile* buffer." (let* ((buf ledger-buf) (account ledger-acct) - (ledger-success nil) - (sort-by (if sort - sort - "(date)")) + (ledger-success nil) + (sort-by (if sort + sort + "(date)")) (xacts (with-temp-buffer - (when (ledger-exec-ledger buf (current-buffer) - "--uncleared" "--real" "emacs" "--sort" sort-by account) - (setq ledger-success t) - (goto-char (point-min)) - (unless (eobp) - (if (looking-at "(") - (read (current-buffer)))))))) ;current-buffer is the *temp* created above + (when (ledger-exec-ledger buf (current-buffer) + "--uncleared" "--real" "emacs" "--sort" sort-by account) + (setq ledger-success t) + (goto-char (point-min)) + (unless (eobp) + (if (looking-at "(") + (read (current-buffer)))))))) ;current-buffer is the *temp* created above (if (and ledger-success (> (length xacts) 0)) - (let ((date-format (cdr (assoc "date-format" ledger-environment-alist)))) - (dolist (xact xacts) - (dolist (posting (nthcdr 5 xact)) - (let ((beg (point)) - (where (ledger-marker-where-xact-is xact posting))) - (insert (format "%s %-4s %-30s %-30s %15s\n" - (format-time-string (if date-format - date-format - ledger-reconcile-default-date-format) (nth 2 xact)) - (if (nth 3 xact) - (nth 3 xact) - "") - (nth 4 xact) (nth 1 posting) (nth 2 posting))) - (if (nth 3 posting) - (if (eq (nth 3 posting) 'pending) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-pending-face - 'where where)) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-cleared-face - 'where where))) - (set-text-properties beg (1- (point)) - (list 'face 'ledger-font-reconciler-uncleared-face - 'where where)))) )) - (goto-char (point-max)) - (delete-char -1)) ;gets rid of the extra line feed at the bottom of the list - (if ledger-success - (insert (concat "There are no uncleared entries for " account)) - (insert "Ledger has reported a problem. Check *Ledger Error* buffer."))) + (let ((date-format (or (cdr (assoc "date-format" ledger-environment-alist)) + ledger-default-date-format))) + (dolist (xact xacts) + (dolist (posting (nthcdr 5 xact)) + (let ((beg (point)) + (where (ledger-marker-where-xact-is xact posting))) + (insert (format "%s %-4s %-30s %-30s %15s\n" + (format-time-string date-format (nth 2 xact)) + (if (nth 3 xact) + (nth 3 xact) + "") + (nth 4 xact) (nth 1 posting) (nth 2 posting))) + (if (nth 3 posting) + (if (eq (nth 3 posting) 'pending) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-pending-face + 'where where)) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-cleared-face + 'where where))) + (set-text-properties beg (1- (point)) + (list 'face 'ledger-font-reconciler-uncleared-face + 'where where)))) )) + (goto-char (point-max)) + (delete-char -1)) ;gets rid of the extra line feed at the bottom of the list + (if ledger-success + (insert (concat "There are no uncleared entries for " account)) + (insert "Ledger has reported a problem. Check *Ledger Error* buffer."))) (goto-char (point-min)) (set-buffer-modified-p nil) (toggle-read-only t) @@ -344,30 +356,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 moved and recentered. If they aren't strange things happen." - (let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) - (when recon-window - (fit-window-to-buffer recon-window) - (with-current-buffer buf - (add-hook 'kill-buffer-hook 'ledger-reconcile-quit nil t) - (if (get-buffer-window buf) - (select-window (get-buffer-window buf))) - (goto-char (point-max)) - (recenter -1)) - (select-window recon-window) - (ledger-reconcile-visit t)) - (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t))) + (let ((recon-window (get-buffer-window (get-buffer ledger-recon-buffer-name)))) + (when recon-window + (fit-window-to-buffer recon-window) + (with-current-buffer buf + (add-hook 'kill-buffer-hook 'ledger-reconcile-quit nil t) + (if (get-buffer-window buf) + (select-window (get-buffer-window buf))) + (goto-char (point-max)) + (recenter -1)) + (select-window recon-window) + (ledger-reconcile-visit t)) + (add-hook 'post-command-hook 'ledger-reconcile-track-xact nil t))) (defun ledger-reconcile-track-xact () "Force the ledger buffer to recenter on the transaction at point in the reconcile buffer." (if (and ledger-buffer-tracks-reconcile-buffer - (member this-command (list 'next-line - 'previous-line - 'mouse-set-point - 'ledger-reconcile-toggle - 'end-of-buffer - 'beginning-of-buffer))) + (member this-command (list 'next-line + 'previous-line + 'mouse-set-point + 'ledger-reconcile-toggle + 'end-of-buffer + 'beginning-of-buffer))) (save-excursion - (ledger-reconcile-visit t)))) + (ledger-reconcile-visit t)))) (defun ledger-reconcile-open-windows (buf rbuf) "Ensure that the ledger buffer BUF is split by RBUF." @@ -380,39 +392,39 @@ moved and recentered. If they aren't strange things happen." "Start reconciling, prompt for account." (interactive) (let ((account (ledger-read-account-with-prompt "Account to reconcile")) - (buf (current-buffer)) + (buf (current-buffer)) (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 - (with-current-buffer rbuf - (set 'ledger-acct account) ;; already buffer local - (when (not (eq buf rbuf)) - ;; called from some other ledger-mode buffer - (ledger-reconcile-quit-cleanup) - (set 'ledger-buf buf)) ;; should already be buffer-local - - (unless (get-buffer-window rbuf) - (ledger-reconcile-open-windows buf rbuf))) - - ;; no recon-buffer, starting from scratch. - - (with-current-buffer (setq rbuf - (get-buffer-create ledger-recon-buffer-name)) - (ledger-reconcile-open-windows buf rbuf) - (ledger-reconcile-mode) - (make-local-variable 'ledger-target) - (set (make-local-variable 'ledger-buf) buf) - (set (make-local-variable 'ledger-acct) account))) + (with-current-buffer rbuf + (set 'ledger-acct account) ;; already buffer local + (when (not (eq buf rbuf)) + ;; called from some other ledger-mode buffer + (ledger-reconcile-quit-cleanup) + (set 'ledger-buf buf)) ;; should already be buffer-local + + (unless (get-buffer-window rbuf) + (ledger-reconcile-open-windows buf rbuf))) + + ;; no recon-buffer, starting from scratch. + + (with-current-buffer (setq rbuf + (get-buffer-create ledger-recon-buffer-name)) + (ledger-reconcile-open-windows buf rbuf) + (ledger-reconcile-mode) + (make-local-variable 'ledger-target) + (set (make-local-variable 'ledger-buf) buf) + (set (make-local-variable 'ledger-acct) account))) ;; Narrow the ledger buffer (with-current-buffer rbuf (save-excursion - (if ledger-narrow-on-reconcile - (ledger-occur-mode account ledger-buf))) + (if ledger-narrow-on-reconcile + (ledger-occur-mode account ledger-buf))) (if (> (ledger-reconcile-refresh) 0) - (ledger-reconcile-change-target)) + (ledger-reconcile-change-target)) (ledger-display-balance)))) (defvar ledger-reconcile-mode-abbrev-table) @@ -423,14 +435,13 @@ moved and recentered. If they aren't strange things happen." (setq ledger-target (ledger-read-commodity-string ledger-reconcile-target-prompt-string))) (defmacro ledger-reconcile-change-sort-key-and-refresh (sort-by) - `(lambda () - (interactive) + `(lambda () + (interactive) - (setq ledger-reconcile-sort-key ,sort-by) - (ledger-reconcile-refresh))) + (setq ledger-reconcile-sort-key ,sort-by) + (ledger-reconcile-refresh))) -(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" - "A mode for reconciling ledger entries." +(defvar ledger-reconcile-mode-map (let ((map (make-sparse-keymap))) (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) @@ -447,38 +458,46 @@ moved and recentered. If they aren't strange things happen." (define-key map [?q] 'ledger-reconcile-quit) (define-key map [?b] 'ledger-display-balance) + (define-key map [(control ?c) (control ?o)] (ledger-reconcile-change-sort-key-and-refresh "(0)")) + (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 ?p)] (ledger-reconcile-change-sort-key-and-refresh "(payee)")) + map) + "Keymap for `ledger-reconcile-mode'.") + +(easy-menu-define ledger-reconcile-mode-menu ledger-reconcile-mode-map + "Ledger reconcile menu" + `("Reconcile" + ["Save" ledger-reconcile-save] + ["Refresh" ledger-reconcile-refresh] + ["Finish" ledger-reconcile-finish] + "---" + ["Reconcile New Account" ledger-reconcile] + "---" + ["Change Target Balance" ledger-reconcile-change-target] + ["Show Cleared Balance" ledger-display-balance] + "---" + ["Sort by payee" ,(ledger-reconcile-change-sort-key-and-refresh "(payee)")] + ["Sort by date" ,(ledger-reconcile-change-sort-key-and-refresh "(date)")] + ["Sort by amount" ,(ledger-reconcile-change-sort-key-and-refresh "(amount)")] + ["Sort by file order" ,(ledger-reconcile-change-sort-key-and-refresh "(0)")] + "---" + ["Toggle Entry" ledger-reconcile-toggle] + ["Add Entry" ledger-reconcile-add] + ["Delete Entry" ledger-reconcile-delete] + "---" + ["Next Entry" next-line] + ["Visit Source" ledger-reconcile-visit] + ["Previous Entry" previous-line] + "---" + ["Quit" ledger-reconcile-quit] + )) - (define-key map [menu-bar] (make-sparse-keymap "ledger-recon-menu")) - (define-key map [menu-bar ledger-recon-menu] (cons "Reconcile" map)) - (define-key map [menu-bar ledger-recon-menu qui] '("Quit" . ledger-reconcile-quit)) - (define-key map [menu-bar ledger-recon-menu sep1] '("--")) - (define-key map [menu-bar ledger-recon-menu pre] '("Previous Entry" . previous-line)) - (define-key map [menu-bar ledger-recon-menu vis] '("Visit Source" . ledger-reconcile-visit)) - (define-key map [menu-bar ledger-recon-menu nex] '("Next Entry" . next-line)) - (define-key map [menu-bar ledger-recon-menu sep2] '("--")) - (define-key map [menu-bar ledger-recon-menu del] '("Delete Entry" . ledger-reconcile-delete)) - (define-key map [menu-bar ledger-recon-menu add] '("Add Entry" . ledger-reconcile-add)) - (define-key map [menu-bar ledger-recon-menu tog] '("Toggle Entry" . ledger-reconcile-toggle)) - (define-key map [menu-bar ledger-recon-menu sep3] '("--")) - (define-key map [menu-bar ledger-recon-menu sort-amt] `("Sort by amount" . ,(ledger-reconcile-change-sort-key-and-refresh "(amount)"))) - (define-key map [menu-bar ledger-recon-menu sort-pay] `("Sort by date" . ,(ledger-reconcile-change-sort-key-and-refresh "(date)"))) - (define-key map [menu-bar ledger-recon-menu sort-dat] `("Sort by payee" . ,(ledger-reconcile-change-sort-key-and-refresh "(payee)"))) - (define-key map [menu-bar ledger-recon-menu sep4] '("--")) - (define-key map [menu-bar ledger-recon-menu bal] '("Show Cleared Balance" . ledger-display-balance)) - (define-key map [menu-bar ledger-recon-menu tgt] '("Change Target Balance" . ledger-reconcile-change-target)) - (define-key map [menu-bar ledger-recon-menu sep5] '("--")) - (define-key map [menu-bar ledger-recon-menu rna] '("Reconcile New Account" . ledger-reconcile)) - (define-key map [menu-bar ledger-recon-menu sep6] '("--")) - (define-key map [menu-bar ledger-recon-menu fin] '("Finish" . ledger-reconcile-finish)) - (define-key map [menu-bar ledger-recon-menu ref] '("Refresh" . ledger-reconcile-refresh)) - (define-key map [menu-bar ledger-recon-menu sav] '("Save" . ledger-reconcile-save)) - - (use-local-map map))) +(define-derived-mode ledger-reconcile-mode text-mode "Reconcile" + "A mode for reconciling ledger entries.") (provide 'ledger-reconcile) diff --git a/lisp/ledger-regex.el b/lisp/ledger-regex.el index 77ce38c6..8d838892 100644 --- a/lisp/ledger-regex.el +++ b/lisp/ledger-regex.el @@ -1,6 +1,6 @@ ;;; ledger-regex.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. (require 'rx) @@ -27,7 +27,7 @@ (defconst ledger-amount-regex (concat "\\( \\|\t\\| \t\\)[ \t]*-?" "\\([A-Z$€£_]+ *\\)?" - "\\(-?[0-9,]+?\\)" + "\\(-?[0-9,\\.]+?\\)" "\\(.[0-9]+\\)?" "\\( *[[:word:]€£_\"]+\\)?" "\\([ \t]*[@={]@?[^\n;]+?\\)?" @@ -68,10 +68,10 @@ "^--.+?\\($\\|[ ]\\)") (defconst ledger-account-any-status-regex - "^[ \t]+\\([*!]\\s-+\\)?\\([[(]?.+?\\)\\(\t\\|\n\\| [ \t]\\)") + "^[ \t]+\\([*!]\\s-+\\)?\\([[(]?.+?\\)\\(\t\\|\n\\| [ \t]\\)") (defun ledger-account-any-status-with-seed-regex (seed) - (concat "^[ \t]+\\([*!]\\s-+\\)?\\([[(]?" seed ".+?\\)\\(\t\\|\n\\| [ \t]\\)")) + (concat "^[ \t]+\\([*!]\\s-+\\)?\\([[(]?" seed ".+?\\)\\(\t\\|\n\\| [ \t]\\)")) (defconst ledger-account-pending-regex "\\(^[ \t]+\\)\\(!\\s-*.*?\\)\\( \\|\t\\|$\\)") diff --git a/lisp/ledger-report.el b/lisp/ledger-report.el index e785bc1b..af9ae62c 100644 --- a/lisp/ledger-report.el +++ b/lisp/ledger-report.el @@ -1,6 +1,6 @@ ;;; ledger-report.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: @@ -25,6 +25,7 @@ ;;; Code: +(require 'easymenu) (eval-when-compile (require 'cl)) @@ -84,45 +85,48 @@ text that should replace the format specifier." (setq inhibit-read-only t) (reverse-region (point) (point-max)))) +(defvar ledger-report-mode-map + (let ((map (make-sparse-keymap))) + (define-key map [? ] 'scroll-up) + (define-key map [backspace] 'scroll-down) + (define-key map [?r] 'ledger-report-redo) + (define-key map [(shift ?r)] 'ledger-report-reverse-lines) + (define-key map [?s] 'ledger-report-save) + (define-key map [?k] 'ledger-report-kill) + (define-key map [?e] 'ledger-report-edit) + (define-key map [?q] 'ledger-report-quit) + (define-key map [?g] 'ledger-report-redo) + (define-key map [(control ?c) (control ?l) (control ?r)] + 'ledger-report-redo) + (define-key map [(control ?c) (control ?l) (control ?S)] + 'ledger-report-save) + (define-key map [(control ?c) (control ?l) (control ?k)] + 'ledger-report-kill) + (define-key map [(control ?c) (control ?l) (control ?e)] + 'ledger-report-edit) + (define-key map [return] 'ledger-report-visit-source) + map) + "Keymap for `ledger-report-mode'.") + +(easy-menu-define ledger-report-mode-menu ledger-report-mode-map + "Ledger report menu" + '("Reports" + ["Save Report" ledger-report-save] + ["Edit Report" ledger-report-edit] + ["Re-run Report" ledger-report-redo] + ["Kill Report" ledger-report-kill] + "---" + ["Reverse report order" ledger-report-reverse-lines] + "---" + ["Scroll Up" scroll-up] + ["Visit Source" ledger-report-visit-source] + ["Scroll Down" scroll-down] + "---" + ["Quit" ledger-report-quit] + )) + (define-derived-mode ledger-report-mode text-mode "Ledger-Report" - "A mode for viewing ledger reports." - (let ((map (make-sparse-keymap))) - (define-key map [? ] 'scroll-up) - (define-key map [backspace] 'scroll-down) - (define-key map [?r] 'ledger-report-redo) - (define-key map [(shift ?r)] 'ledger-report-reverse-lines) - (define-key map [?s] 'ledger-report-save) - (define-key map [?k] 'ledger-report-kill) - (define-key map [?e] 'ledger-report-edit) - (define-key map [?q] 'ledger-report-quit) - (define-key map [(control ?c) (control ?l) (control ?r)] - 'ledger-report-redo) - (define-key map [(control ?c) (control ?l) (control ?S)] - 'ledger-report-save) - (define-key map [(control ?c) (control ?l) (control ?k)] - 'ledger-report-kill) - (define-key map [(control ?c) (control ?l) (control ?e)] - 'ledger-report-edit) - (define-key map [return] 'ledger-report-visit-source) - - - (define-key map [menu-bar] (make-sparse-keymap "ledger-rep")) - (define-key map [menu-bar ledger-rep] (cons "Reports" map)) - - (define-key map [menu-bar ledger-rep lrq] '("Quit" . ledger-report-quit)) - (define-key map [menu-bar ledger-rep s2] '("--")) - (define-key map [menu-bar ledger-rep lrd] '("Scroll Down" . scroll-down)) - (define-key map [menu-bar ledger-rep vis] '("Visit Source" . ledger-report-visit-source)) - (define-key map [menu-bar ledger-rep lru] '("Scroll Up" . scroll-up)) - (define-key map [menu-bar ledger-rep s1] '("--")) - (define-key map [menu-bar ledger-rep rev] '("Reverse report order" . ledger-report-reverse-lines)) - (define-key map [menu-bar ledger-rep s0] '("--")) - (define-key map [menu-bar ledger-rep lrk] '("Kill Report" . ledger-report-kill)) - (define-key map [menu-bar ledger-rep lrr] '("Re-run Report" . ledger-report-redo)) - (define-key map [menu-bar ledger-rep lre] '("Edit Report" . ledger-report-edit)) - (define-key map [menu-bar ledger-rep lrs] '("Save Report" . ledger-report-save)) - - (use-local-map map))) + "A mode for viewing ledger reports.") (defun ledger-report-value-format-specifier () "Return a valid meta-data tag name" diff --git a/lisp/ledger-schedule.el b/lisp/ledger-schedule.el index 7497c7d0..e1e06d69 100644 --- a/lisp/ledger-schedule.el +++ b/lisp/ledger-schedule.el @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, -;; Boston, MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: ;; @@ -30,6 +30,8 @@ ;; function slot of the symbol VARNAME. Then use VARNAME as the ;; function without have to use funcall. +(require 'ledger-init) + (defgroup ledger-schedule nil "Support for automatically recommendation transactions." :group 'ledger) @@ -49,14 +51,20 @@ :type 'integer :group 'ledger-schedule) -(defcustom ledger-schedule-file "~/FinanceData/ledger-schedule.ledger" +(defcustom ledger-schedule-file "~/ledger-schedule.ledger" "File to find scheduled transactions." :type 'file :group 'ledger-schedule) +(defvar ledger-schedule-available nil) + (defsubst between (val low high) (and (>= val low) (<= val high))) +(defun ledger-schedule-check-available () + (setq ledger-schedule-available (and ledger-schedule-file + (file-exists-p ledger-schedule-file)))) + (defun ledger-schedule-days-in-month (month year) "Return number of days in the MONTH, MONTH is from 1 to 12. If year is nil, assume it is not a leap year" @@ -235,7 +243,7 @@ returns true if the date meets the requirements" ((/= 0 (setq year-match (string-to-number str))) `(eq (nth 5 (decode-time date)) ,year-match)) (t - (error "Improperly specified year constraint: " str))))) + (error "Improperly specified year constraint: %s" str))))) (defun ledger-schedule-constrain-month (str) @@ -247,7 +255,7 @@ returns true if the date meets the requirements" `(eq (nth 4 (decode-time date)) ,month-match) (error "ledger-schedule-constrain-numerical-month: month out of range %S" month-match))) (t - (error "Improperly specified month constraint: " str))))) + (error "Improperly specified month constraint: %s" str))))) (defun ledger-schedule-constrain-day (str) (let ((day-match t)) @@ -256,7 +264,7 @@ returns true if the date meets the requirements" ((/= 0 (setq day-match (string-to-number str))) `(eq (nth 3 (decode-time date)) ,day-match)) (t - (error "Improperly specified day constraint: " str))))) + (error "Improperly specified day constraint: %s" str))))) (defun ledger-schedule-parse-date-descriptor (descriptor) "Parse the date descriptor, return the evaluator" @@ -282,7 +290,8 @@ returns true if the date meets the requirements" "Format CANDIDATE-ITEMS for display." (let ((candidates (ledger-schedule-list-upcoming-xacts candidate-items early horizon)) (schedule-buf (get-buffer-create ledger-schedule-buffer-name)) - (date-format (cdr (assoc "date-format" ledger-environment-alist)))) + (date-format (or (cdr (assoc "date-format" ledger-environment-alist)) + ledger-default-date-format))) (with-current-buffer schedule-buf (erase-buffer) (dolist (candidate candidates) @@ -291,38 +300,28 @@ returns true if the date meets the requirements" (ledger-mode)) (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 () - (interactive) +(defun ledger-schedule-upcoming (file look-backward look-forward) + "Generate upcoming transaction + +FILE is the file containing the scheduled transaction, +default to `ledger-schedule-file'. +LOOK-BACKWARD is the number of day in the past to look at +default to `ledger-schedule-look-backward' +LOOK-FORWARD is the number of day in the futur to look at +default to `ledger-schedule-look-forward' + +Use a prefix arg to change the default value" + (interactive (if current-prefix-arg + (list (read-file-name "Schedule File: " () ledger-schedule-file t) + (read-number "Look backward: " ledger-schedule-look-backward) + (read-number "Look forward: " ledger-schedule-look-forward)) + (list ledger-schedule-file ledger-schedule-look-backward ledger-schedule-look-forward))) (ledger-schedule-create-auto-buffer - (ledger-schedule-scan-transactions ledger-schedule-file) - ledger-schedule-look-backward - ledger-schedule-look-forward - (current-buffer))) + (ledger-schedule-scan-transactions file) + look-backward + look-forward + (current-buffer)) + (pop-to-buffer ledger-schedule-buffer-name)) (provide 'ledger-schedule) diff --git a/lisp/ledger-sort.el b/lisp/ledger-sort.el index c5a41952..d337cc4c 100644 --- a/lisp/ledger-sort.el +++ b/lisp/ledger-sort.el @@ -1,6 +1,6 @@ ;;; ledger-xact.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. @@ -49,7 +49,7 @@ (save-excursion (goto-char (point-min)) (if (ledger-sort-find-start) - (delete-region (match-beginning 0) (match-end 0)))) + (delete-region (match-beginning 0) (match-end 0)))) (beginning-of-line) (insert "\n; Ledger-mode: Start sort\n\n")) @@ -58,7 +58,7 @@ (save-excursion (goto-char (point-min)) (if (ledger-sort-find-end) - (delete-region (match-beginning 0) (match-end 0)))) + (delete-region (match-beginning 0) (match-end 0)))) (beginning-of-line) (insert "\n; Ledger-mode: End sort\n\n")) @@ -69,57 +69,57 @@ (defun ledger-sort-region (beg end) "Sort the region from BEG to END in chronological order." (interactive "r") ;; load beg and end from point and mark - ;; automagically + ;; automagically (let ((new-beg beg) - (new-end end) - point-delta - (bounds (ledger-find-xact-extents (point))) - target-xact) - - (setq point-delta (- (point) (car bounds))) - (setq target-xact (buffer-substring (car bounds) (cadr bounds))) - (setq inhibit-modification-hooks t) + (new-end end) + point-delta + (bounds (ledger-find-xact-extents (point))) + target-xact) + + (setq point-delta (- (point) (car bounds))) + (setq target-xact (buffer-substring (car bounds) (cadr bounds))) + (setq inhibit-modification-hooks t) (save-excursion (save-restriction - (goto-char beg) - (ledger-next-record-function) ;; make sure point is at the - ;; beginning of a xact - (setq new-beg (point)) - (goto-char end) - (ledger-next-record-function) ;; make sure end of region is at - ;; the beginning of next record - ;; after the region - (setq new-end (point)) - (narrow-to-region new-beg new-end) - (goto-char new-beg) - - (let ((inhibit-field-text-motion t)) - (sort-subr - nil - 'ledger-next-record-function - 'ledger-end-record-function - 'ledger-sort-startkey)))) - - (goto-char (point-min)) - (re-search-forward (regexp-quote target-xact)) - (goto-char (+ (match-beginning 0) point-delta)) + (goto-char beg) + (ledger-next-record-function) ;; make sure point is at the + ;; beginning of a xact + (setq new-beg (point)) + (goto-char end) + (ledger-next-record-function) ;; make sure end of region is at + ;; the beginning of next record + ;; after the region + (setq new-end (point)) + (narrow-to-region new-beg new-end) + (goto-char new-beg) + + (let ((inhibit-field-text-motion t)) + (sort-subr + nil + 'ledger-next-record-function + 'ledger-end-record-function + 'ledger-sort-startkey)))) + + (goto-char (point-min)) + (re-search-forward (regexp-quote target-xact)) + (goto-char (+ (match-beginning 0) point-delta)) (setq inhibit-modification-hooks nil))) (defun ledger-sort-buffer () "Sort the entire buffer." (interactive) (let (sort-start - sort-end) - (save-excursion - (goto-char (point-min)) - (setq sort-start (ledger-sort-find-start) - sort-end (ledger-sort-find-end))) + sort-end) + (save-excursion + (goto-char (point-min)) + (setq sort-start (ledger-sort-find-start) + sort-end (ledger-sort-find-end))) (ledger-sort-region (if sort-start - sort-start - (point-min)) - (if sort-end - sort-end - (point-max))))) + sort-start + (point-min)) + (if sort-end + sort-end + (point-max))))) (provide 'ledger-sort) diff --git a/lisp/ledger-state.el b/lisp/ledger-state.el index 121e97ca..fffaab14 100644 --- a/lisp/ledger-state.el +++ b/lisp/ledger-state.el @@ -1,6 +1,6 @@ ;;; ledger-state.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: diff --git a/lisp/ledger-test.el b/lisp/ledger-test.el index a275ae7f..f74c5428 100644 --- a/lisp/ledger-test.el +++ b/lisp/ledger-test.el @@ -1,6 +1,6 @@ ;;; ledger-test.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. (defgroup ledger-test nil "Definitions for the Ledger testing framework" diff --git a/lisp/ledger-texi.el b/lisp/ledger-texi.el index 68880550..c9e438c0 100644 --- a/lisp/ledger-texi.el +++ b/lisp/ledger-texi.el @@ -1,6 +1,6 @@ ;;; ledger-texi.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. (defgroup ledger-texi nil "Options for working on Ledger texi documentation" diff --git a/lisp/ledger-xact.el b/lisp/ledger-xact.el index 25413e43..35b0d62c 100644 --- a/lisp/ledger-xact.el +++ b/lisp/ledger-xact.el @@ -1,6 +1,6 @@ ;;; ledger-xact.el --- Helper code for use with the "ledger" command-line tool -;; Copyright (C) 2003-2013 John Wiegley (johnw AT gnu DOT org) +;; Copyright (C) 2003-2014 John Wiegley (johnw AT gnu DOT org) ;; This file is not part of GNU Emacs. @@ -16,8 +16,8 @@ ;; ;; You should have received a copy of the GNU General Public License ;; along with GNU Emacs; see the file COPYING. If not, write to the -;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -;; MA 02111-1307, USA. +;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +;; MA 02110-1301 USA. ;;; Commentary: @@ -36,7 +36,8 @@ :group 'ledger :safe t) -(defvar highlight-overlay (list)) +(defvar ledger-xact-highlight-overlay (list)) +(make-variable-buffer-local 'ledger-xact-highlight-overlay) (defun ledger-find-xact-extents (pos) "Return point for beginning of xact and and of xact containing position. @@ -46,28 +47,28 @@ within the transaction." (save-excursion (goto-char pos) (list (progn - (backward-paragraph) - (if (/= (point) (point-min)) - (forward-line)) - (line-beginning-position)) - (progn - (forward-paragraph) - (line-beginning-position))))) + (backward-paragraph) + (if (/= (point) (point-min)) + (forward-line)) + (line-beginning-position)) + (progn + (forward-paragraph) + (line-beginning-position))))) (defun ledger-highlight-xact-under-point () "Move the highlight overlay to the current transaction." (if ledger-highlight-xact-under-point (let ((exts (ledger-find-xact-extents (point))) - (ovl highlight-overlay)) - (if (not highlight-overlay) - (setq ovl - (setq highlight-overlay - (make-overlay (car exts) - (cadr exts) - (current-buffer) t nil))) - (move-overlay ovl (car exts) (cadr exts))) - (overlay-put ovl 'face 'ledger-font-xact-highlight-face) - (overlay-put ovl 'priority 100)))) + (ovl ledger-xact-highlight-overlay)) + (if (not ledger-xact-highlight-overlay) + (setq ovl + (setq ledger-xact-highlight-overlay + (make-overlay (car exts) + (cadr exts) + (current-buffer) t nil))) + (move-overlay ovl (car exts) (cadr exts))) + (overlay-put ovl 'face 'ledger-font-xact-highlight-face) + (overlay-put ovl 'priority 100)))) (defun ledger-xact-payee () "Return the payee of the transaction containing point or nil." @@ -77,7 +78,7 @@ within the transaction." (let ((context-info (ledger-context-other-line i))) (if (eq (ledger-context-line-type context-info) 'xact) (ledger-context-field-value context-info 'payee) - nil)))) + nil)))) (defun ledger-time-less-p (t1 t2) "Say whether time value T1 is less than time value T2." @@ -93,7 +94,7 @@ MOMENT is an encoded date" (function (lambda (start date mark desc) (if (ledger-time-less-p moment date) - (throw 'found t))))))) + (throw 'found t))))))) (defun ledger-xact-iterate-transactions (callback) "Iterate through each transaction call CALLBACK for each." @@ -105,19 +106,19 @@ MOMENT is an encoded date" (let ((found-y-p (match-string 2))) (if found-y-p (setq current-year (string-to-number found-y-p)) ;; a Y directive was found - (let ((start (match-beginning 0)) - (year (match-string 4)) - (month (string-to-number (match-string 5))) - (day (string-to-number (match-string 6))) - (mark (match-string 7)) - (code (match-string 8)) - (desc (match-string 9))) - (if (and year (> (length year) 0)) - (setq year (string-to-number year))) - (funcall callback start - (encode-time 0 0 0 day month - (or year current-year)) - mark desc))))) + (let ((start (match-beginning 0)) + (year (match-string 4)) + (month (string-to-number (match-string 5))) + (day (string-to-number (match-string 6))) + (mark (match-string 7)) + (code (match-string 8)) + (desc (match-string 9))) + (if (and year (> (length year) 0)) + (setq year (string-to-number year))) + (funcall callback start + (encode-time 0 0 0 day month + (or year current-year)) + mark desc))))) (forward-line)))) (defsubst ledger-goto-line (line-number) @@ -128,29 +129,30 @@ MOMENT is an encoded date" (defun ledger-year-and-month () (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) "Ask for a new DATE and copy the transaction under point to that date. Leave point on the first amount." (interactive (list - (read-string "Copy to date: " (ledger-year-and-month) - 'ledger-minibuffer-history))) + (ledger-read-date "Copy to date: "))) (let* ((here (point)) - (extents (ledger-find-xact-extents (point))) - (transaction (buffer-substring-no-properties (car extents) (cadr extents))) - encoded-date) + (extents (ledger-find-xact-extents (point))) + (transaction (buffer-substring-no-properties (car extents) (cadr extents))) + encoded-date) (if (string-match ledger-iso-date-regexp date) - (setq encoded-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 2 date))))) + (setq encoded-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 2 date))))) (ledger-xact-find-slot encoded-date) (insert transaction "\n") (backward-paragraph 2) (re-search-forward ledger-iso-date-regexp) (replace-match date) - (ledger-next-amount))) + (ledger-next-amount) + (if (re-search-forward "[-0-9]") + (goto-char (match-beginning 0))))) (defun ledger-delete-current-transaction (pos) "Delete the transaction surrounging point." @@ -164,7 +166,9 @@ If INSERT-AT-POINT is non-nil insert the transaction there, otherwise call `ledger-xact-find-slot' to insert it at the correct chronological place in the buffer." (interactive (list - (read-string "Transaction: " (ledger-year-and-month)))) + ;; Note: This isn't "just" the date - it can contain + ;; other text too + (ledger-read-date "Transaction: "))) (let* ((args (with-temp-buffer (insert transaction-text) (eshell-parse-arguments (point-min) (point-max)))) @@ -179,20 +183,20 @@ correct chronological place in the buffer." (string-to-number (match-string 2 date))))) (ledger-xact-find-slot date))) (if (> (length args) 1) - (save-excursion - (insert - (with-temp-buffer - (setq exit-code - (apply #'ledger-exec-ledger ledger-buf (current-buffer) "xact" - (mapcar 'eval args))) - (goto-char (point-min)) - (if (looking-at "Error: ") - (error (concat "Error in ledger-add-transaction: " (buffer-string))) - (buffer-string))) - "\n")) - (progn - (insert (car args) " \n\n") - (end-of-line -1))))) + (save-excursion + (insert + (with-temp-buffer + (setq exit-code + (apply #'ledger-exec-ledger ledger-buf (current-buffer) "xact" + (mapcar 'eval args))) + (goto-char (point-min)) + (if (looking-at "Error: ") + (error (concat "Error in ledger-add-transaction: " (buffer-string))) + (buffer-string))) + "\n")) + (progn + (insert (car args) " \n\n") + (end-of-line -1))))) (provide 'ledger-xact) |