summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2004-07-29 17:25:28 -0400
committerJohn Wiegley <johnw@newartisans.com>2004-07-29 17:25:28 -0400
commitabae9138e9b7746a23d66d56673e10343a9cec11 (patch)
tree69d2275d589618f266ad7ed5a5d182171fe49d28
parent358e3329b3b981bcd7ddf8a03192dec9378fbcab (diff)
downloadfork-ledger-abae9138e9b7746a23d66d56673e10343a9cec11.tar.gz
fork-ledger-abae9138e9b7746a23d66d56673e10343a9cec11.tar.bz2
fork-ledger-abae9138e9b7746a23d66d56673e10343a9cec11.zip
added missing files
-rw-r--r--ledger.el301
-rw-r--r--scripts/README5
-rwxr-xr-xscripts/bal26
-rwxr-xr-xscripts/confirm.py40
-rwxr-xr-xscripts/entry16
-rwxr-xr-xscripts/getquote16
-rwxr-xr-xscripts/mean27
-rwxr-xr-xscripts/profit2
-rwxr-xr-xscripts/reg14
-rwxr-xr-xscripts/report17
-rwxr-xr-xscripts/spending8
-rwxr-xr-xscripts/stripreg16
-rwxr-xr-xscripts/test14
-rwxr-xr-xscripts/version5
-rwxr-xr-xscripts/worth2
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$