summaryrefslogtreecommitdiff
path: root/lisp
diff options
context:
space:
mode:
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ledger-fontify.el20
-rw-r--r--lisp/ledger-schedule.el180
-rw-r--r--lisp/ledger-state.el6
3 files changed, 86 insertions, 120 deletions
diff --git a/lisp/ledger-fontify.el b/lisp/ledger-fontify.el
index 309cbc3b..caf7690a 100644
--- a/lisp/ledger-fontify.el
+++ b/lisp/ledger-fontify.el
@@ -82,7 +82,7 @@ Fontify the first line of an xact"
(let ((state nil))
(re-search-forward ledger-xact-start-regex)
(ledger-fontify-set-face (list (match-beginning 1) (match-end 1)) 'ledger-font-posting-date-face)
- (save-match-data (setq state (ledger-state-from-string (s-trim (match-string 5)))))
+ (save-match-data (setq state (ledger-state-from-string (match-string 5))))
(ledger-fontify-set-face (list (match-beginning 7) (match-end 7))
(cond ((eq state 'pending)
'ledger-font-payee-pending-face)
@@ -113,7 +113,7 @@ Fontify the first line of an xact"
;; that took to figure out
(re-search-forward " \\([*!]\\) " end t)
(if (match-string 1)
- (setq state (ledger-state-from-string (s-trim (match-string 1))))))
+ (setq state (ledger-state-from-string (match-string 1)))))
(beginning-of-line)
(re-search-forward "[[:graph:]]\\([ \t][ \t]\\)" end 'end) ;; find the end of the account, or end of line
@@ -191,20 +191,4 @@ Fontify the first line of an xact"
(defun ledger-fontify-set-face (extents face)
(put-text-property (car extents) (cadr extents) 'face face))
-
-(defun s-trim-left (s)
- "Remove whitespace at the beginning of S."
- (if (string-match "\\`[ \t\n\r]+" s)
- (replace-match "" t t s)
- s))
-
-(defun s-trim-right (s)
- "Remove whitespace at the end of S."
- (if (string-match "[ \t\n\r]+\\'" s)
- (replace-match "" t t s)
- s))
-
-(defun s-trim (s)
- "Remove whitespace at the beginning and end of S."
- (s-trim-left (s-trim-right s)))
;;; ledger-fontify.el ends here
diff --git a/lisp/ledger-schedule.el b/lisp/ledger-schedule.el
index 9c41c63d..a5e7decb 100644
--- a/lisp/ledger-schedule.el
+++ b/lisp/ledger-schedule.el
@@ -74,6 +74,15 @@ If year is nil, assume it is not a leap year"
(nth (1- month) '(31 28 31 30 31 30 31 31 30 31 30 31)))
(error "Month out of range, MONTH=%S" month)))
+(defun ledger-schedule-encode-day-of-week ( day-string)
+ "return the numerical day of week corresponding to DAY-STRING"
+ (cond ((string= day-string "Su") 7)
+ ((string= day-string "Mo") 1)
+ ((string= day-string "Tu") 2)
+ ((string= day-string "We") 3)
+ ((string= day-string "Th") 4)
+ ((string= day-string "Fr") 5)
+ ((string= day-string "Sa") 6)))
;; Macros to handle date expressions
(defun ledger-schedule-constrain-day-in-month (count day-of-week)
@@ -111,9 +120,9 @@ COUNT 0) means EVERY day-of-week (eg. every Saturday)"
(defun ledger-schedule-constrain-every-count-day (day-of-week skip start-date)
"Return a form that is true for every DAY skipping SKIP, starting on START.
For example every second Friday, regardless of month."
- (let ((start-day (nth 6 (decode-time (eval start-date)))))
+ (let ((start-day (nth 6 (decode-time start-date))))
(if (eq start-day day-of-week) ;; good, can proceed
- `(zerop (mod (- (time-to-days date) ,(time-to-days (eval start-date))) ,(* skip 7)))
+ `(zerop (mod (- (time-to-days date) ,(time-to-days start-date)) ,(* skip 7)))
(error "START-DATE day of week doesn't match DAY-OF-WEEK"))))
(defun ledger-schedule-constrain-date-range (month1 day1 month2 day2)
@@ -131,10 +140,11 @@ For example every second Friday, regardless of month."
(defun ledger-schedule-is-holiday (date)
- "Return true if DATE is a holiday.")
+ "Return true if DATE is a holiday."
+ nil)
(defun ledger-schedule-scan-transactions (schedule-file)
- "Scans AUTO_FILE and returns a list of transactions with date predicates.
+ "Scans SCHEDULE-FILE and returns a list of transactions with date predicates.
The car of each item is a function of date that returns true if
the transaction should be logged for that day."
(interactive "fFile name: ")
@@ -159,51 +169,8 @@ the transaction should be logged for that day."
(setq xact-list (cons transaction xact-list))))
xact-list)))
-(defun ledger-schedule-replace-brackets ()
- "Replace all brackets with parens"
- (goto-char (point-min))
- (while (search-forward "]" nil t)
- (replace-match ")" nil t))
- (goto-char (point-min))
- (while (search-forward "[" nil t)
- (replace-match "(" nil t)))
-
-(defvar ledger-schedule-descriptor-regex
- (concat "\\(20[0-9][0-9]\\|[\*]\\)[/\\-]" ;; Year slot
- "\\([\*EO]\\|[01][0-9]\\)[/\\-]" ;; Month slot
- "\\([\*]\\|\\([0-3][0-9]\\)\\|"
- "\\([0-5]"
- "\\(\\(Su\\)\\|"
- "\\(Mo\\)\\|"
- "\\(Tu\\)\\|"
- "\\(We\\)\\|"
- "\\(Th\\)\\|"
- "\\(Fr\\)\\|"
- "\\(Sa\\)\\)\\)\\)"))
-
(defun ledger-schedule-read-descriptor-tree (descriptor-string)
- "Take a date DESCRIPTOR-STRING and return a function of date that
-returns true if the date meets the requirements"
- (with-temp-buffer
- ;; copy the descriptor string into a temp buffer for manipulation
- (let (pos)
- ;; Replace brackets with parens
- (insert descriptor-string)
- (ledger-schedule-replace-brackets)
-
- (goto-char (point-max))
- ;; double quote all the descriptors for string processing later
- (while (re-search-backward ledger-schedule-descriptor-regex nil t) ;; Day slot
- (goto-char
- (match-end 0))
- (insert ?\")
- (goto-char (match-beginning 0))
- (insert "\"" )))
-
- ;; read the descriptor string into a lisp object the transform the
- ;; string descriptor into usable things
- (ledger-schedule-transform-auto-tree
- (read (buffer-substring-no-properties (point-min) (point-max))))))
+ (ledger-schedule-transform-auto-tree (split-string (substring descriptor-string 1 (string-match "]" descriptor-string)) " ")))
(defun ledger-schedule-transform-auto-tree (descriptor-string-list)
"Takes a lisp list of date descriptor strings, TREE, and returns a string with a lambda function of date."
@@ -221,67 +188,82 @@ returns true if the date meets the requirements"
(push (ledger-schedule-compile-constraints newcar) result)) )
(setq descriptor-string-list (cdr descriptor-string-list)))
- ;; tie up all the clauses in a big or and lambda, and return
+ ;; tie up all the clauses in a big or lambda, and return
;; the lambda function as list to be executed by funcall
`(lambda (date)
,(nconc (list 'or) (nreverse result) descriptor-string-list)))))
(defun ledger-schedule-compile-constraints (descriptor-string)
"Return a list with the year, month and day fields split"
- (let ((fields (split-string descriptor-string "[/\\-]" t))
- constrain-year constrain-month constrain-day)
- (setq constrain-year (ledger-schedule-constrain-year (nth 0 fields)))
- (setq constrain-month (ledger-schedule-constrain-month (nth 1 fields)))
- (setq constrain-day (ledger-schedule-constrain-day (nth 2 fields)))
-
- (list 'and constrain-year constrain-month constrain-day)))
-
-(defun ledger-schedule-constrain-year (str)
- (let ((year-match t))
- (cond ((string= str "*")
- year-match)
- ((/= 0 (setq year-match (string-to-number str)))
- `(eq (nth 5 (decode-time date)) ,year-match))
- (t
- (error "Improperly specified year constraint: %s" str)))))
-
-(defun ledger-schedule-constrain-month (str)
-
- (let ((month-match t))
- (cond ((string= str "*")
- month-match) ;; always match
- ((/= 0 (setq month-match (string-to-number str)))
- (if (between month-match 1 12) ;; no month specified, assume 31 days.
- `(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: %s" str)))))
-
-(defun ledger-schedule-constrain-day (str)
- (let ((day-match t))
- (cond ((string= str "*")
- t)
- ((/= 0 (setq day-match (string-to-number str)))
- `(eq (nth 3 (decode-time date)) ,day-match))
- (t
- (error "Improperly specified day constraint: %s" str)))))
-
-(defun ledger-schedule-parse-date-descriptor (descriptor)
- "Parse the date descriptor, return the evaluator"
- (ledger-schedule-compile-constraints descriptor))
+ (let ((fields (split-string descriptor-string "[/\\-]" t)))
+ (if (string-match "[A-Za-z]" descriptor-string)
+ (ledger-schedule-constrain-day (nth 0 fields) (nth 1 fields) (nth 2 fields))
+ (list 'and
+ (ledger-schedule-constrain-day (nth 0 fields) (nth 1 fields) (nth 2 fields))
+ (ledger-schedule-constrain-year (nth 0 fields) (nth 1 fields) (nth 2 fields))
+ (ledger-schedule-constrain-month (nth 0 fields) (nth 1 fields) (nth 2 fields))))))
+
+(defun ledger-schedule-constrain-year (year-desc month-desc day-desc)
+ (cond ((string= year-desc "*") t)
+ ((/= 0 (string-to-number year-desc))
+ `(memq (nth 5 (decode-time date)) ',(mapcar 'string-to-number (split-string year-desc ","))))
+ (t
+ (error "Improperly specified year constraint: %s %s %s" year-desc month-desc day-desc))))
+
+(defun ledger-schedule-constrain-month (year-desc month-desc day-desc)
+ (cond ((string= month-desc "*")
+ t) ;; always match
+ ((string= month-desc "E") ;; Even
+ `(evenp (nth 4 (decode-time date))))
+ ((string= month-desc "O") ;; Odd
+ `(oddp (nth 4 (decode-time date))))
+ ((/= 0 (string-to-number month-desc)) ;; Starts with number
+ `(memq (nth 4 (decode-time date)) ',(mapcar 'string-to-number (split-string month-desc ","))))
+ (t
+ (error "Improperly specified month constraint: %s %s %s" year-desc month-desc day-desc))))
+
+(defun ledger-schedule-constrain-day (year-desc month-desc day-desc)
+ (cond ((string= day-desc "*")
+ t)
+ ((string-match "[A-Za-z]" day-desc) ;; There is something other than digits and commas
+ (ledger-schedule-parse-complex-date year-desc month-desc day-desc))
+ ((/= 0 (string-to-number day-desc))
+ `(memq (nth 3 (decode-time date)) ',(mapcar 'string-to-number (split-string day-desc ","))))
+ (t
+ (error "Improperly specified day constraint: %s %s %s" year-desc month-desc day-desc))))
+
+
+
+(defun ledger-schedule-parse-complex-date (year-desc month-desc day-desc)
+ (let ((years (mapcar 'string-to-number (split-string year-desc ",")))
+ (months (mapcar 'string-to-number (split-string month-desc ",")))
+ (day-parts (split-string day-desc "+"))
+ (every-nth (string-match "+" day-desc)))
+ (if every-nth
+ (let ((base-day (string-to-number (car day-parts)))
+ (increment (string-to-number (substring (cadr day-parts) 0
+ (string-match "[A-Za-z]" (cadr day-parts)))))
+ (day-of-week (ledger-schedule-encode-day-of-week
+ (substring (cadr day-parts) (string-match "[A-Za-z]" (cadr day-parts))))))
+ (ledger-schedule-constrain-every-count-day day-of-week increment (encode-time 0 0 0 base-day (car months) (car years))))
+ (let ((count (string-to-number (substring (car day-parts) 0 1)))
+ (day-of-week (ledger-schedule-encode-day-of-week
+ (substring (car day-parts) (string-match "[A-Za-z]" (car day-parts))))))
+ (ledger-schedule-constrain-day-in-month count day-of-week)))))
(defun ledger-schedule-list-upcoming-xacts (candidate-items early horizon)
- "Search CANDIDATE-ITEMS for xacts that occur within the period today - EARLY to today + HORIZON"
- (let ((start-date (time-subtract (current-time) (days-to-time early)))
- test-date items)
- (loop for day from 0 to (+ early horizon) by 1 do
- (setq test-date (time-add start-date (days-to-time day)))
- (dolist (candidate candidate-items items)
- (if (funcall (car candidate) test-date)
- (setq items (append items (list (list test-date (cadr candidate))))))))
- items))
+ "Search CANDIDATE-ITEMS for xacts that occur within the period today - EARLY to today + HORIZON"
+ (let ((start-date (time-subtract (current-time) (days-to-time early)))
+ test-date items)
+ (loop for day from 0 to (+ early horizon) by 1 do
+ (setq test-date (time-add start-date (days-to-time day)))
+ (dolist (candidate candidate-items items)
+ (if (funcall (car candidate) test-date)
+ (setq items (append items (list (list test-date (cadr candidate))))))))
+ items))
(defun ledger-schedule-already-entered (candidate buffer)
+ "return TRUE if CANDIDATE is already in BUFFER"
(let ((target-date (format-time-string date-format (car candidate)))
(target-payee (cadr candidate)))
nil))
diff --git a/lisp/ledger-state.el b/lisp/ledger-state.el
index 8822570d..b2574b10 100644
--- a/lisp/ledger-state.el
+++ b/lisp/ledger-state.el
@@ -68,9 +68,9 @@
(defun ledger-state-from-string (state-string)
"Get state from STATE-CHAR."
- (cond ((string= state-string "!") 'pending)
- ((string= state-string "*") 'cleared)
- ((string= state-string ";") 'comment)
+ (cond ((string-match "\\!" state-string) 'pending)
+ ((string-match "\\*" state-string) 'cleared)
+ ((string-match ";" state-string) 'comment)
(t nil)))
(defun ledger-toggle-current-posting (&optional style)