Browse Source

Added basic CLI interface.

Simon Watson 1 year ago
parent
commit
185eef4fe5
2 changed files with 59 additions and 21 deletions
  1. 2 1
      README.md
  2. 57 20
      fin-lisp.lisp

+ 2 - 1
README.md

@@ -14,8 +14,9 @@ in this version.
  - Generic expense handling
  - Encryption/decryption of old records
  - Upload/download support like perl version
+ - Basic interactive mode, basic CLI mode
 
 - TODO
- - Non interactive CLI Interface
  - Clean up messy/inefficient stuff
  - More robust error reporting
+ - Confirmation when changing encryption key

+ 57 - 20
fin-lisp.lisp

@@ -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)