|
@@ -25,7 +25,7 @@
|
|
|
;;; Used for pretty printing output
|
|
|
(defconstant +CELL-FORMATS+ '(:left "~vA"
|
|
|
:center "~v:@<~A~>"
|
|
|
- :right "~v@A"))
|
|
|
+ :right "~v@A"))
|
|
|
|
|
|
(defun format-table (stream data &key (column-label (loop for i from 1 to (length (car data))
|
|
|
collect (format nil "COL~D" i)))
|
|
@@ -74,11 +74,29 @@
|
|
|
;;; the user provided a valid key
|
|
|
(defun check-month (month-key)
|
|
|
(if (stringp month-key) month-key
|
|
|
- (return-from check-month NIL))
|
|
|
+ (return-from check-month NIL))
|
|
|
(if (ppcre:scan *old-month-line-regex* month-key) month-key
|
|
|
(if (ppcre:scan *new-month-line-regex* month-key) month-key
|
|
|
(return-from check-month NIL))))
|
|
|
|
|
|
+;; Called like: (add-month '202107)
|
|
|
+(defun add-month (month-key)
|
|
|
+ (if (check-month month-key)
|
|
|
+ (if (not (gethash month-key *records*))
|
|
|
+ (progn
|
|
|
+ (setf (gethash month-key *records*)
|
|
|
+ (make-hash-table :test 'equalp))
|
|
|
+ month-key))))
|
|
|
+
|
|
|
+(defun add-expense-to-month (expense value month)
|
|
|
+ (if (gethash month *records*)
|
|
|
+ (setf (gethash expense (gethash month *records*)) value)
|
|
|
+ (progn
|
|
|
+ (print (concatenate 'string "Adding" month))
|
|
|
+ (if (add-month month)
|
|
|
+ (setf (gethash expense (gethash month *records*)) value)
|
|
|
+ (print (concatenate 'string "Failed to add" month))))))
|
|
|
+
|
|
|
(opts:define-opts
|
|
|
(:name :help
|
|
|
:description "Print help text"
|
|
@@ -89,6 +107,21 @@
|
|
|
:short #\p
|
|
|
:long "print-month"
|
|
|
:arg-parser #'check-month)
|
|
|
+ (:name :add-expense
|
|
|
+ :description "Non interactive interface for recording an expense. Expects expense name as an argument, and requires -v|--value and -m|month"
|
|
|
+ :short #\e
|
|
|
+ :long "add-expense"
|
|
|
+ :arg-parser #'identity)
|
|
|
+ (:name :value
|
|
|
+ :description "Used with -e|--add-expense. Must be an integer."
|
|
|
+ :short #\v
|
|
|
+ :long "value"
|
|
|
+ :arg-parser #'parse-integer)
|
|
|
+ (:name :month
|
|
|
+ :description "Used with -e|--add-expense. Must be a valid month key."
|
|
|
+ :short #\m
|
|
|
+ :long "month"
|
|
|
+ :arg-parser #'check-month)
|
|
|
(:name :interactive-mode
|
|
|
:description "Run in interactive mode"
|
|
|
:short #\i
|
|
@@ -161,12 +194,6 @@
|
|
|
"Get records from remote server"
|
|
|
(setf *records* (yason:parse (decrypt-records key (gethash "content" (download-records))))))
|
|
|
|
|
|
-;; Called like: (add-month '202107)
|
|
|
-(defun add-month (month-key)
|
|
|
- (if (check-month month-key)
|
|
|
- (setf (gethash month-key *records*) (make-hash-table :test 'equalp))
|
|
|
- (return-from add-month NIL)))
|
|
|
-
|
|
|
;;; Taken from practical common lisp
|
|
|
(defun prompt-read (prompt)
|
|
|
(format *query-io* "~a: " prompt)
|
|
@@ -179,13 +206,6 @@
|
|
|
(parse-integer
|
|
|
(prompt-read "Enter expense value"))))
|
|
|
|
|
|
-(defun add-expense-to-month (month)
|
|
|
- (if (gethash month *records*)
|
|
|
- (let ((innerhash (gethash month *records*))
|
|
|
- (exp-l (prompt-for-expense)))
|
|
|
- (setf (gethash (first exp-l) innerhash) (second exp-l)))
|
|
|
- (add-expense-to-month (add-month month))))
|
|
|
-
|
|
|
;;; Given key for *records* hash,
|
|
|
;;; print expenses/values for month
|
|
|
(defun dump-month (month-key)
|
|
@@ -237,7 +257,11 @@
|
|
|
((answer (prompt-read "Select an option")))
|
|
|
(if (string= answer "1")
|
|
|
(generic-handler
|
|
|
- (add-expense-to-month (prompt-read "Enter month"))
|
|
|
+ (let ((month-input (prompt-read "Enter month"))
|
|
|
+ (expense-input (prompt-for-expense)))
|
|
|
+ (add-expense-to-month (first expense-input)
|
|
|
+ (second expense-input)
|
|
|
+ month-input))
|
|
|
"Invalid Input"))
|
|
|
(if (string= answer "2")
|
|
|
(generic-handler
|
|
@@ -256,7 +280,6 @@
|
|
|
(interactive-mode))
|
|
|
|
|
|
(defun display-help ()
|
|
|
- (format t "foo ~%")
|
|
|
(opts:describe
|
|
|
:prefix "fin-lisp.lisp - Basic expense tracker in lisp"
|
|
|
:usage-of "fin-lisp.lisp"
|
|
@@ -267,15 +290,29 @@
|
|
|
(defun main ()
|
|
|
(if (= 1 (length sb-ext:*posix-argv*)) (interactive-mode))
|
|
|
(let ((matches (opts:get-opts)))
|
|
|
- (format t "~a ~%" matches)
|
|
|
+ ;;(format t "~a ~%" matches)
|
|
|
(when-option (matches :help)
|
|
|
(display-help))
|
|
|
(when-option (matches :print-month)
|
|
|
- (let ((key (prompt-read "Enter decryption key: "))
|
|
|
+ (let ((key (prompt-read "Enter decryption key"))
|
|
|
(month-key (destructuring-bind (&key print-month) matches
|
|
|
print-month)))
|
|
|
(get-records key)
|
|
|
- (dump-month-table month-key)))
|
|
|
+ (dump-month-table month-key)
|
|
|
+ (quit)))
|
|
|
+ (when-option (matches :add-expense) ;; This is probably the wrong way to resolve the arguments
|
|
|
+ (when-option (matches :value)
|
|
|
+ (when-option (matches :month)
|
|
|
+ (let ((key (prompt-read "Enter decryption key"))
|
|
|
+ (name-value-month (destructuring-bind (&key add-expense value month) matches
|
|
|
+ (list add-expense value month))))
|
|
|
+ (get-records key)
|
|
|
+ (if (add-expense-to-month
|
|
|
+ (first name-value-month)
|
|
|
+ (second name-value-month)
|
|
|
+ (third name-value-month))
|
|
|
+ (push-records key)
|
|
|
+ (print "Invalid month input"))))))
|
|
|
(when-option (matches :interactive-mode)
|
|
|
(progn
|
|
|
(interactive-mode)
|