summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ledger.cc2
-rw-r--r--ledger.el146
-rw-r--r--reports.cc30
3 files changed, 108 insertions, 70 deletions
diff --git a/ledger.cc b/ledger.cc
index 4883c3cb..08edc278 100644
--- a/ledger.cc
+++ b/ledger.cc
@@ -63,7 +63,7 @@ void transaction::print(std::ostream& out, bool display_quantity,
void entry::print(std::ostream& out, bool shortcut) const
{
char buf[32];
- std::strftime(buf, 31, "%Y.%m.%d ", std::localtime(&date));
+ std::strftime(buf, 31, "%Y/%m/%d ", std::localtime(&date));
out << buf;
if (cleared)
diff --git a/ledger.el b/ledger.el
index 095138eb..5994345a 100644
--- a/ledger.el
+++ b/ledger.el
@@ -37,16 +37,66 @@
(defvar ledger-version "1.1"
"The version of ledger.el currently loaded")
+(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 "%m.%d " (current-time)))))
- (let ((args (mapcar 'shell-quote-argument (split-string entry))))
- (shell-command
- (concat "ledger entry "
- (mapconcat 'identity args " ")) t)
- (delete-char 5)
- (exchange-point-and-mark)))
+ (list (read-string "Entry: " (format-time-string "%m/%d "))))
+ (let ((args (mapcar 'shell-quote-argument (split-string entry)))
+ date entry)
+ (with-temp-buffer
+ (shell-command
+ (concat "ledger entry "
+ (mapconcat 'identity args " ")) t)
+ (setq date (buffer-substring (point) (+ (point) 10)))
+ (setq entry (buffer-substring (+ (point) 5) (point-max))))
+ (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)
+ (insert entry)))
+
+(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)
@@ -64,57 +114,37 @@
(define-derived-mode ledger-mode text-mode "Ledger"
"A mode for editing ledger data files."
- (setq comment-start ";" comment-end nil)
+ (setq comment-start ";" comment-end nil
+ indent-tabs-mode nil)
(let ((map (current-local-map)))
- (define-key map [(control ?c) (control ?n)] 'ledger-add-entry)
- (define-key map [(control ?c) (control ?c)]
- 'ledger-toggle-current)))
-
-(defun ledger-parse-entries (account)
- (let* ((now (current-time))
- (current-year (nth 5 (decode-time now)))
- (then now)
- entries)
- ;; `then' is 45 days ago
- (setq then (time-subtract then (seconds-to-time (* 45 24 60 60))))
- (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))
- total when)
- (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)))
- (setq when (encode-time 0 0 0 day month
- (or year current-year)))
- (when (or (not mark) (time-less-p then when))
- (forward-line)
- (setq total 0.0)
- (while (looking-at
- (concat "\\s-+\\([A-Za-z_].+?\\)\\(\\s-*$\\| \\s-*"
- "\\([^0-9]+\\)\\s-*\\([0-9.]+\\)\\)"))
- (let ((acct (match-string 1))
- (amt (match-string 4)))
- (if amt
- (setq amt (string-to-number amt)
- total (+ total amt)))
- (if (string= account acct)
- (setq entries
- (cons (list (copy-marker start)
- mark when desc (or amt total))
- entries))))
- (forward-line)))))))
- (forward-line))
+ (define-key map [(control ?c) (control ?a)] 'ledger-add-entry)
+ (define-key map [(control ?c) (control ?c)] 'ledger-toggle-current)))
+
+(defun ledger-parse-entries (account &optional all-p)
+ ;; `then' is 45 days ago
+ (let ((then (time-subtract (current-time)
+ (seconds-to-time (* 45 24 60 60))))
+ total entries)
+ (ledger-iterate-entries
+ (function
+ (lambda (start date mark desc)
+ (when (or all-p (not mark) (time-less-p then date))
+ (forward-line)
+ (setq total 0.0)
+ (while (looking-at
+ (concat "\\s-+\\([A-Za-z_].+?\\)\\(\\s-*$\\| \\s-*"
+ "\\([^0-9]+\\)\\s-*\\([0-9.]+\\)\\)"))
+ (let ((acct (match-string 1))
+ (amt (match-string 4)))
+ (if 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))))))
(nreverse entries)))
(define-derived-mode ledger-reconcile-mode text-mode "Reconcile"
diff --git a/reports.cc b/reports.cc
index 7add7379..de8ea6b1 100644
--- a/reports.cc
+++ b/reports.cc
@@ -369,7 +369,7 @@ void add_new_entry(int index, int argc, char **argv)
assert(index < argc);
if (! parse_date(argv[index++], &added.date)) {
- std::cerr << "Error: Bad add date: " << argv[index - 1]
+ std::cerr << "Error: Bad entry date: " << argv[index - 1]
<< std::endl;
std::exit(1);
}
@@ -377,7 +377,7 @@ void add_new_entry(int index, int argc, char **argv)
added.cleared = show_cleared;
if (index == argc) {
- std::cerr << "Error: Too few arguments to 'add'." << std::endl;
+ std::cerr << "Error: Too few arguments to 'entry'." << std::endl;
std::exit(1);
}
@@ -396,7 +396,7 @@ void add_new_entry(int index, int argc, char **argv)
added.desc = matching ? matching->desc : regexps.front().pattern;
if (index == argc) {
- std::cerr << "Error: Too few arguments to 'add'." << std::endl;
+ std::cerr << "Error: Too few arguments to 'entry'." << std::endl;
std::exit(1);
}
@@ -437,11 +437,13 @@ void add_new_entry(int index, int argc, char **argv)
mask acct_regex(argv[index++]);
account * acct = NULL;
+ commodity * cmdty = NULL;
for (std::list<transaction *>::iterator x = matching->xacts.begin();
x != matching->xacts.end();
x++) {
if (acct_regex.match((*x)->acct->as_str())) {
acct = (*x)->acct;
+ cmdty = (*x)->cost->commdty();
break;
}
}
@@ -458,16 +460,18 @@ void add_new_entry(int index, int argc, char **argv)
}
if (index == argc) {
- std::cerr << "Error: Too few arguments to 'add'." << std::endl;
+ std::cerr << "Error: Too few arguments to 'entry'." << std::endl;
std::exit(1);
}
xact->cost = create_amount(argv[index++]);
+ if (! xact->cost->commdty())
+ xact->cost->set_commdty(cmdty);
added.xacts.push_back(xact);
}
- if ((index + 1) < argc && std::string(argv[index]) == "-from")
+ if ((index + 1) < argc && std::string(argv[index]) == "-from") {
if (account * acct = main_ledger->re_find_account(argv[++index])) {
transaction * xact = new transaction();
xact->acct = acct;
@@ -475,15 +479,21 @@ void add_new_entry(int index, int argc, char **argv)
added.xacts.push_back(xact);
}
+ } else {
+ transaction * xact = new transaction();
+ xact->acct = matching->xacts.back()->acct;
+ xact->cost = NULL;
+ added.xacts.push_back(xact);
+ }
}
if (added.finalize())
added.print(std::cout);
}
-// Print out the entire ledger that was read in, sorted by date.
-// This can be used to "wash" ugly ledger files. It's written here,
-// instead of ledger.cc, in order to access the static globals above.
+// Print out the entire ledger that was read in. This can be used to
+// "wash" ugly ledger files. It's written here, instead of ledger.cc,
+// in order to access the static globals above.
void book::print(std::ostream& out, regexps_map& regexps,
bool shortcut) const
@@ -491,9 +501,7 @@ void book::print(std::ostream& out, regexps_map& regexps,
for (entries_list_const_iterator i = entries.begin();
i != entries.end();
i++) {
- if ((! show_cleared && (*i)->cleared) ||
- ! matches_date_range(*i) ||
- ! (*i)->matches(regexps))
+ if (! matches_date_range(*i) || ! (*i)->matches(regexps))
continue;
(*i)->print(out, shortcut);