;; Reconcile mode (defvar ledger-buf nil) (defvar ledger-acct nil) (defun ledger-display-balance () (let ((buffer ledger-buf) (account ledger-acct)) (with-temp-buffer (let ((exit-code (ledger-run-ledger buffer "-C" "balance" account))) (if (/= 0 exit-code) (message "Error determining cleared balance") (goto-char (1- (point-max))) (goto-char (line-beginning-position)) (delete-horizontal-space) (message "Cleared balance = %s" (buffer-substring-no-properties (point) (line-end-position)))))))) (defun ledger-reconcile-toggle () (interactive) (let ((where (get-text-property (point) 'where)) (account ledger-acct) (inhibit-read-only t) cleared) (when (or (equal (car where) "") (equal (car where) "/dev/stdin")) (with-current-buffer ledger-buf (goto-char (cdr where)) (setq cleared (ledger-toggle-current 'pending))) (if cleared (add-text-properties (line-beginning-position) (line-end-position) (list 'face 'bold)) (remove-text-properties (line-beginning-position) (line-end-position) (list 'face)))) (forward-line))) (defun ledger-reconcile-refresh () (interactive) (let ((inhibit-read-only t) (line (count-lines (point-min) (point)))) (erase-buffer) (ledger-do-reconcile) (set-buffer-modified-p t) (goto-char (point-min)) (forward-line line))) (defun ledger-reconcile-refresh-after-save () (let ((buf (get-buffer "*Reconcile*"))) (if buf (with-current-buffer buf (ledger-reconcile-refresh) (set-buffer-modified-p nil))))) (defun ledger-reconcile-add () (interactive) (with-current-buffer ledger-buf (call-interactively #'ledger-add-entry)) (ledger-reconcile-refresh)) (defun ledger-reconcile-delete () (interactive) (let ((where (get-text-property (point) 'where))) (when (or (equal (car where) "") (equal (car where) "/dev/stdin")) (with-current-buffer ledger-buf (goto-char (cdr where)) (ledger-delete-current-entry)) (let ((inhibit-read-only t)) (goto-char (line-beginning-position)) (delete-region (point) (1+ (line-end-position))) (set-buffer-modified-p t))))) (defun ledger-reconcile-visit () (interactive) (let ((where (get-text-property (point) 'where))) (when (or (equal (car where) "") (equal (car where) "/dev/stdin")) (switch-to-buffer-other-window ledger-buf) (goto-char (cdr where))))) (defun ledger-reconcile-save () (interactive) (with-current-buffer ledger-buf (save-buffer)) (set-buffer-modified-p nil) (ledger-display-balance)) (defun ledger-reconcile-quit () (interactive) (kill-buffer (current-buffer))) (defun ledger-reconcile-finish () (interactive) (save-excursion (goto-char (point-min)) (while (not (eobp)) (let ((where (get-text-property (point) 'where)) (face (get-text-property (point) 'face))) (if (and (eq face 'bold) (or (equal (car where) "") (equal (car where) "/dev/stdin"))) (with-current-buffer ledger-buf (goto-char (cdr where)) (ledger-toggle-current 'cleared)))) (forward-line 1))) (ledger-reconcile-save)) (defun ledger-do-reconcile () (let* ((buf ledger-buf) (account ledger-acct) (items (with-current-buffer (apply #'ledger-exec-ledger buf nil "emacs" account "--uncleared" '("--real")) (goto-char (point-min)) (unless (eobp) (unless (looking-at "(") (error (buffer-string))) (read (current-buffer)))))) (dolist (item items) (let ((index 1)) (dolist (xact (nthcdr 5 item)) (let ((beg (point)) (where (with-current-buffer buf (cons (nth 0 item) (if ledger-clear-whole-entries (save-excursion (goto-line (nth 1 item)) (point-marker)) (save-excursion (goto-line (nth 0 xact)) (point-marker))))))) (insert (format "%s %-30s %-25s %15s\n" (format-time-string "%m/%d" (nth 2 item)) (nth 4 item) (nth 1 xact) (nth 2 xact))) (if (nth 3 xact) (set-text-properties beg (1- (point)) (list 'face 'bold 'where where)) (set-text-properties beg (1- (point)) (list 'where where)))) (setq index (1+ index))))) (goto-char (point-min)) (set-buffer-modified-p nil) (toggle-read-only t))) (defun ledger-reconcile (account) (interactive "sAccount to reconcile: ") (let ((buf (current-buffer)) (rbuf (get-buffer "*Reconcile*"))) (if rbuf (kill-buffer rbuf)) (add-hook 'after-save-hook 'ledger-reconcile-refresh-after-save) (with-current-buffer (pop-to-buffer (get-buffer-create "*Reconcile*")) (ledger-reconcile-mode) (set (make-local-variable 'ledger-buf) buf) (set (make-local-variable 'ledger-acct) account) (ledger-do-reconcile)))) (defvar ledger-reconcile-mode-abbrev-table) (define-derived-mode ledger-reconcile-mode text-mode "Reconcile" "A mode for reconciling ledger entries." (let ((map (make-sparse-keymap))) (define-key map [(control ?m)] 'ledger-reconcile-visit) (define-key map [return] 'ledger-reconcile-visit) (define-key map [(control ?c) (control ?c)] 'ledger-reconcile-finish) (define-key map [(control ?x) (control ?s)] 'ledger-reconcile-save) (define-key map [(control ?l)] 'ledger-reconcile-refresh) (define-key map [? ] 'ledger-reconcile-toggle) (define-key map [?a] 'ledger-reconcile-add) (define-key map [?d] 'ledger-reconcile-delete) (define-key map [?n] 'next-line) (define-key map [?p] 'previous-line) (define-key map [?s] 'ledger-reconcile-save) (define-key map [?q] 'ledger-reconcile-quit) (use-local-map map)))