diff options
author | John Wiegley <johnw@newartisans.com> | 2004-07-29 17:25:28 -0400 |
---|---|---|
committer | John Wiegley <johnw@newartisans.com> | 2004-07-29 17:25:28 -0400 |
commit | abae9138e9b7746a23d66d56673e10343a9cec11 (patch) | |
tree | 69d2275d589618f266ad7ed5a5d182171fe49d28 | |
parent | 358e3329b3b981bcd7ddf8a03192dec9378fbcab (diff) | |
download | fork-ledger-abae9138e9b7746a23d66d56673e10343a9cec11.tar.gz fork-ledger-abae9138e9b7746a23d66d56673e10343a9cec11.tar.bz2 fork-ledger-abae9138e9b7746a23d66d56673e10343a9cec11.zip |
added missing files
-rw-r--r-- | ledger.el | 301 | ||||
-rw-r--r-- | scripts/README | 5 | ||||
-rwxr-xr-x | scripts/bal | 26 | ||||
-rwxr-xr-x | scripts/confirm.py | 40 | ||||
-rwxr-xr-x | scripts/entry | 16 | ||||
-rwxr-xr-x | scripts/getquote | 16 | ||||
-rwxr-xr-x | scripts/mean | 27 | ||||
-rwxr-xr-x | scripts/profit | 2 | ||||
-rwxr-xr-x | scripts/reg | 14 | ||||
-rwxr-xr-x | scripts/report | 17 | ||||
-rwxr-xr-x | scripts/spending | 8 | ||||
-rwxr-xr-x | scripts/stripreg | 16 | ||||
-rwxr-xr-x | scripts/test | 14 | ||||
-rwxr-xr-x | scripts/version | 5 | ||||
-rwxr-xr-x | scripts/worth | 2 |
15 files changed, 509 insertions, 0 deletions
diff --git a/ledger.el b/ledger.el new file mode 100644 index 00000000..bd4d10c7 --- /dev/null +++ b/ledger.el @@ -0,0 +1,301 @@ +;;; ledger.el --- Helper code for using my "ledger" command-line tool + +;; Copyright (C) 2004 John Wiegley (johnw AT gnu DOT org) + +;; Emacs Lisp Archive Entry +;; Filename: ledger.el +;; Version: 1.1 +;; Date: Thu 02-Apr-2004 +;; Keywords: data +;; Author: John Wiegley (johnw AT gnu DOT org) +;; Maintainer: John Wiegley (johnw AT gnu DOT org) +;; Description: Helper code for using my "ledger" command-line tool +;; URL: http://www.newartisans.com/johnw/emacs.html +;; Compatibility: Emacs21 + +;; This file is not part of GNU Emacs. + +;; This is free software; you can redistribute it and/or modify it under +;; the terms of the GNU General Public License as published by the Free +;; Software Foundation; either version 2, or (at your option) any later +;; version. +;; +;; This is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +;; FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +;; for more details. +;; +;; 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. + +;;; Commentary: + +;; This code is only meaningful if you are using "ledger". + +(defvar ledger-version "1.1" + "The version of ledger.el currently loaded") + +(defgroup ledger nil + "Interface to the Ledger command-line accounting program." + :group 'data) + +(defcustom ledger-binary-path (executable-find "ledger") + "Path to the ledger executable." + :type 'file + :group 'ledger) + +(defcustom ledger-data-file (getenv "LEDGER") + "Path to the ledger data file." + :type 'file + :group 'ledger) + +(defvar bold 'bold) + +(defvar ledger-font-lock-keywords + '(("^[0-9./]+\\s-+\\(?:([^)]+)\\s-+\\)?\\([^*].+\\)" 1 bold) + ("^\\s-+.+?\\( \\|\t\\|\\s-+$\\)" . font-lock-keyword-face)) + "Default expressions to highlight in Ledger mode.") + +(defun ledger-iterate-entries (callback) + (goto-char (point-min)) + (let* ((now (current-time)) + (current-year (nth 5 (decode-time now)))) + (while (not (eobp)) + (when (looking-at + (concat "\\(Y\\s-+\\([0-9]+\\)\\|" + "\\([0-9]\\{4\\}+\\)?[./]?" + "\\([0-9]+\\)[./]\\([0-9]+\\)\\s-+" + "\\(\\*\\s-+\\)?\\(.+\\)\\)")) + (let ((found (match-string 2))) + (if found + (setq current-year (string-to-number found)) + (let ((start (match-beginning 0)) + (year (match-string 3)) + (month (string-to-number (match-string 4))) + (day (string-to-number (match-string 5))) + (mark (match-string 6)) + (desc (match-string 7))) + (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)))) + +(defun ledger-find-slot (moment) + (catch 'found + (ledger-iterate-entries + (function + (lambda (start date mark desc) + (if (time-less-p moment date) + (throw 'found t))))))) + +(defun ledger-add-entry (entry) + (interactive + (list (read-string "Entry: " (format-time-string "%Y/%m/%d ")))) + (let* ((args (mapcar 'shell-quote-argument (split-string entry))) + (date (car args)) + (insert-year t) exit-code) + (if (string-match "\\([0-9]+\\)/\\([0-9]+\\)/\\([0-9]+\\)" date) + (setq date (encode-time 0 0 0 (string-to-int (match-string 3 date)) + (string-to-int (match-string 2 date)) + (string-to-int (match-string 1 date))))) + (ledger-find-slot date) + (save-excursion + (if (re-search-backward "^Y " nil t) + (setq insert-year nil))) + (save-excursion + (insert + (with-temp-buffer + (setq exit-code (apply 'ledger-run-ledger "entry" args)) + (if (= 0 exit-code) + (if insert-year + (buffer-string) + (buffer-substring 5 (point-max))) + (concat (if insert-year entry + (substring entry 5)) "\n\n"))))))) + +(defun ledger-expand-entry () + (interactive) + (ledger-add-entry (prog1 + (buffer-substring (line-beginning-position) + (line-end-position)) + (delete-region (line-beginning-position) + (1+ (line-end-position)))))) + +(defun ledger-toggle-current () + (interactive) + (let (clear) + (save-excursion + (when (or (looking-at "^[0-9]") + (re-search-backward "^[0-9]" nil t)) + (skip-chars-forward "0-9./") + (delete-horizontal-space) + (if (equal ?\* (char-after)) + (delete-char 1) + (insert " * ") + (setq clear t)))) + clear)) + +(defun ledger-print-result (command) + (interactive "sLedger command: ") + (shell-command (format "%s -f %s %s" ledger-binary-path + buffer-file-name command))) + +(define-derived-mode ledger-mode text-mode "Ledger" + "A mode for editing ledger data files." + (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))) + (let ((map (current-local-map))) + (define-key map [(control ?c) (control ?a)] 'ledger-add-entry) + (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current) + (define-key map [(control ?c) (control ?p)] 'ledger-print-result) + (define-key map [(control ?c) (control ?r)] 'ledger-reconcile))) + +(defun ledger-parse-entries (account &optional all-p after-date) + (let (total entries) + (ledger-iterate-entries + (function + (lambda (start date mark desc) + (when (and (or all-p (not mark)) + (time-less-p after-date date)) + (forward-line) + (setq total 0.0) + (while (looking-at + (concat "\\s-+\\([A-Za-z_].+?\\)\\(\\s-*$\\| \\s-*" + "\\([^0-9]+\\)\\s-*\\([0-9,.]+\\)\\)?" + "\\(\\s-+;.+\\)?$")) + (let ((acct (match-string 1)) + (amt (match-string 4))) + (when amt + (while (string-match "," amt) + (setq amt (replace-match "" nil nil amt))) + (setq amt (string-to-number amt) + total (+ total amt))) + (if (string= account acct) + (setq entries + (cons (list (copy-marker start) + mark date desc (or amt total)) + entries)))) + (forward-line)))))) + entries)) + +(defvar ledger-reconcile-text "Reconcile") + +(define-derived-mode ledger-reconcile-mode text-mode 'ledger-reconcile-text + "A mode for reconciling ledger entries." + (let ((map (make-sparse-keymap))) + (define-key map [? ] 'ledger-reconcile-toggle) + (define-key map [?q] + (function + (lambda () + (interactive) + (kill-buffer (current-buffer))))) + (use-local-map map))) + +(add-to-list 'minor-mode-alist + '(ledger-reconcile-mode ledger-reconcile-text)) + +(defvar ledger-buf nil) +(defvar ledger-acct nil) + +(defun ledger-update-balance-display () + (let ((account ledger-acct)) + (with-temp-buffer + (let ((exit-code (ledger-run-ledger "-C" "balance" account))) + (if (/= 0 exit-code) + (setq ledger-reconcile-text "Reconcile [ERR]") + (goto-char (point-min)) + (delete-horizontal-space) + (skip-syntax-forward "^ ") + (setq ledger-reconcile-text + (concat "Reconcile [" + (buffer-substring-no-properties (point-min) (point)) + "]")))))) + (force-mode-line-update)) + +(defun ledger-reconcile-toggle () + (interactive) + (let ((where (get-text-property (point) 'where)) + (account ledger-acct) + cleared) + (with-current-buffer ledger-buf + (goto-char where) + (setq cleared (ledger-toggle-current)) + (save-buffer)) + (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) + (ledger-update-balance-display))) + +(defun ledger-reconcile (account &optional days) + (interactive "sAccount to reconcile: \nnBack how far (default 30 days): ") + (let* ((then (time-subtract (current-time) + (seconds-to-time (* (or days 30) 24 60 60)))) + (items (save-excursion + (goto-char (point-min)) + (ledger-parse-entries account t then))) + (buf (current-buffer))) + (with-current-buffer + (pop-to-buffer (generate-new-buffer "*Reconcile*")) + (ledger-reconcile-mode) + (set (make-local-variable 'ledger-buf) buf) + (set (make-local-variable 'ledger-acct) account) + (ledger-update-balance-display) + (dolist (item items) + (let ((beg (point))) + (insert (format "%s %-30s %8.2f\n" + (format-time-string "%Y/%m/%d" (nth 2 item)) + (nth 3 item) (nth 4 item))) + (if (nth 1 item) + (set-text-properties beg (1- (point)) + (list 'face 'bold + 'where (nth 0 item))) + (set-text-properties beg (1- (point)) + (list 'where (nth 0 item))))) + (goto-char (point-min)))))) + +(defun ledger-align-dollars (&optional column) + (interactive "p") + (if (= column 1) + (setq column 48)) + (while (search-forward "$" nil t) + (backward-char) + (let ((col (current-column)) + (beg (point)) + target-col len) + (skip-chars-forward "-$0-9,.") + (setq len (- (point) beg)) + (setq target-col (- column len)) + (if (< col target-col) + (progn + (goto-char beg) + (insert (make-string (- target-col col) ? ))) + (move-to-column target-col) + (if (looking-back " ") + (delete-char (- col target-col)) + (skip-chars-forward "^ \t") + (delete-horizontal-space) + (insert " "))) + (forward-line)))) + +(defun ledger-run-ledger (&rest args) + "run ledger with supplied arguments" + (apply 'call-process ledger-binary-path nil t nil + (append (list "-f" ledger-data-file) args))) + +(provide 'ledger) + +;;; ledger.el ends here diff --git a/scripts/README b/scripts/README new file mode 100644 index 00000000..7221f95f --- /dev/null +++ b/scripts/README @@ -0,0 +1,5 @@ +This scripts are provided just in the way of giving ideas. They +probably all need to be modified to suit your particular environment. +Beware! + +John diff --git a/scripts/bal b/scripts/bal new file mode 100755 index 00000000..a6d97ab9 --- /dev/null +++ b/scripts/bal @@ -0,0 +1,26 @@ +#!/bin/sh + +switch="" +current="-c" +limit="-l \$50" + +if [ "$1" = "-C" -o "$1" = "-U" -o "$1" = "-P" ]; then + switch="$1" + shift +elif [ "$1" = "-b" -o "$1" = "-e" ]; then + current="$1 $2" + shift 2 +fi + +accts="$@" +if [ -z "$accts" ]; then + accts="-Equity -Income -Expenses" + if [ ! "$switch" = "-P" ]; then + accts="$accts -Savings -Retirement" + fi +else + limit="" + negonly="" +fi + +ledger $current $limit $negonly -s $switch balance $accts diff --git a/scripts/confirm.py b/scripts/confirm.py new file mode 100755 index 00000000..c3fe70ab --- /dev/null +++ b/scripts/confirm.py @@ -0,0 +1,40 @@ +#!/usr/bin/python + +# This script confirms what ledger tells you. + +import sys +import os +import re + +def clean(num): + return float(re.sub("(\s+|\$|,)","",num)) + +running_total = 0.0 +index = 1 +last_line = "" + +for line in os.popen("./ledger %s reg %s" % (sys.argv[1], sys.argv[2])): + value = clean(line[55:67]) + total = clean(line[68:80]) + + running_total += value + if abs(running_total - total) > 0.001: + print "! discrepancy of %.2f (%.2f - %.2f) at line %d:" % \ + (running_total - total, running_total, total, index) + print line, + running_total = total + + index += 1 + last_line = line + +balance_total = 0.0 + +for line in os.popen("./ledger %s bal %s" % (sys.argv[1], sys.argv[2])): + balance_total = clean(line[:20]) + +if abs(balance_total - running_total) > 0.001: + print + print "! discrepancy of %.2f (%.2f - %.2f) between register and balance" % \ + (balance_total - running_total, balance_total, running_total) + print last_line, + print line, diff --git a/scripts/entry b/scripts/entry new file mode 100755 index 00000000..28daf8c8 --- /dev/null +++ b/scripts/entry @@ -0,0 +1,16 @@ +#!/bin/sh + +if [ -z "$LEDGER" -o ! -r $LEDGER ]; then + echo Please set your LEDGER environment variable. +fi + +line=`wc -l $LEDGER | awk '{print $1}'` + +if ledger entry "$@" > /tmp/entry; then + cat /tmp/entry >> $LEDGER +else + echo "$@" >> $LEDGER +fi +rm /tmp/entry + +vi +$line $LEDGER diff --git a/scripts/getquote b/scripts/getquote new file mode 100755 index 00000000..cf8c8abd --- /dev/null +++ b/scripts/getquote @@ -0,0 +1,16 @@ +#!/usr/bin/perl + +exit 0 if $ARGV[0] eq "\$"; + +use Finance::Quote; + +$q = Finance::Quote->new; + +$q->timeout(60); +$q->require_labels(qw/price/); + +%quotes = $q->fetch("nasdaq", $ARGV[0]); + +if ($quotes{$ARGV[0], "price"}) { + print "\$", $quotes{$ARGV[0], "price"}, "\n"; +} diff --git a/scripts/mean b/scripts/mean new file mode 100755 index 00000000..3c6f779a --- /dev/null +++ b/scripts/mean @@ -0,0 +1,27 @@ +#!/usr/bin/perl + +$last = $ARGV[-1]; +splice(@ARGV, -1); + +open(PIPE, "ledger -MG @ARGV register $last |") || die; +@values = (); +while (<PIPE>) { + ($date, $value) = split; + push @values, $value; +} +close(PIPE); + +@values = sort @values; +splice(@values, 0, 1); +splice(@values, -1); + +$value = 0.0; +for $item (@values) { + $value += $item; +} + +if (@values) { + printf("%.2f\n", $value / @values); +} else { + die "There are no values to average!\n"; +} diff --git a/scripts/profit b/scripts/profit new file mode 100755 index 00000000..26f112d1 --- /dev/null +++ b/scripts/profit @@ -0,0 +1,2 @@ +#!/bin/sh +ledger "$@" balance ^Income$ ^Expenses$ diff --git a/scripts/reg b/scripts/reg new file mode 100755 index 00000000..75ac364e --- /dev/null +++ b/scripts/reg @@ -0,0 +1,14 @@ +#!/bin/sh + +switch="-U" +current="-c" + +if [ "$1" = "-C" -o "$1" = "-U" -o "$1" = "-P" -o "$1" = "-M" ]; then + switch="$1" + shift +elif [ "$1" = "-b" -o "$1" = "-e" ]; then + current="$1 $2" + shift 2 +fi + +ledger $current -s $switch register "$@" diff --git a/scripts/report b/scripts/report new file mode 100755 index 00000000..c548792c --- /dev/null +++ b/scripts/report @@ -0,0 +1,17 @@ +#!/bin/sh + +args=("$@") +last=${args[`expr ${#args} - 3`]} + +cd /tmp +ledger "$@" | stripreg > $last + +gnuplot <<EOF +set terminal png +set output "report.png" +set xdata time +set timefmt "%Y/%m/%d" +plot "$1" using 1:2 with linespoints +EOF + +open report.png diff --git a/scripts/spending b/scripts/spending new file mode 100755 index 00000000..895c4170 --- /dev/null +++ b/scripts/spending @@ -0,0 +1,8 @@ +#!/bin/sh +ledger "$@" balance \ + Expenses:Food \ + Expenses:Movies \ + Expenses:Auto:Gas \ + Expenses:Tips \ + Expenses:Health \ + Expenses:Supplies diff --git a/scripts/stripreg b/scripts/stripreg new file mode 100755 index 00000000..c974e646 --- /dev/null +++ b/scripts/stripreg @@ -0,0 +1,16 @@ +#!/usr/bin/python + +import sys +import re + +print_total = 0 + +def clean(num): + return float(re.sub("(\s+|\$|,)","",num)) + +for line in sys.stdin: + print line[:10], + if print_total: + print clean(line[68:80]) + else: + print clean(line[55:67]) diff --git a/scripts/test b/scripts/test new file mode 100755 index 00000000..7b17a1b2 --- /dev/null +++ b/scripts/test @@ -0,0 +1,14 @@ +#!/bin/sh + +for test in \ + "-O nrl:checking" \ + "-B 401" \ + "-V 401" \ + "-G 401" \ + "-B retire" \ + "-V retire" \ + "-G retire" +do + echo testing: $test + python confirm.py $test +done diff --git a/scripts/version b/scripts/version new file mode 100755 index 00000000..75cb06da --- /dev/null +++ b/scripts/version @@ -0,0 +1,5 @@ +#!/bin/sh + +cat ledger.cc | \ + grep "^const std::string version" | \ + sed 's/const std::string version = "\([0-9.A-Za-z]*\)";/\1/' diff --git a/scripts/worth b/scripts/worth new file mode 100755 index 00000000..58b20440 --- /dev/null +++ b/scripts/worth @@ -0,0 +1,2 @@ +#!/bin/sh +ledger "$@" balance ^Assets$ ^Liabilities$ |