cf3fdd18b3f20ab9dca937f4d7786a1097ddbfb3
commit cf3fdd18b3f20ab9dca937f4d7786a1097ddbfb3
Author: Simon Watson <spesk@pm.me>
Date: Wed Feb 2 11:24:18 2022 -0500

Adding basics of CLI

diff --git a/fin-lisp.lisp b/fin-lisp.lisp
index 0ed9ab5..6ac842b 100644
--- a/fin-lisp.lisp
+++ b/fin-lisp.lisp
@@ -1,9 +1,17 @@
(ql:quickload "cl-store")
(ql:quickload "cl-ppcre")
+(ql:quickload "unix-opts")
+
+;;; Features
+;;; - Import records from old .txt format
+;;; - Interactive prompt to manage expenses
+;;; - Generic expense handling
+;;; TODO
+;;; - Non interactive CLI Interface
+;;; - Upload/download support like perl version
+;;; - Should support encryption/decryption of records

;;;; Reimplementation of my bills tracker in Lisp
-(defun reload ()
- (load "~/Repos/fin-lisp/fin-lisp.lisp"))

;;; All records exist in this data structure
;;; nil on start and loaded in from file
@@ -12,6 +20,43 @@
;;; and the value is the monthly expenses hash
(defvar *records* (make-hash-table :test 'equalp))

+(defun file-test (filename)
+ (if (probe-file filename) filename (print "Couldn't find filename")))
+
+;;; Used by "print-month" arg to validate
+;;; the user provided a valid key
+(defun check-month (month-key)
+ (if (stringp month-key) month-key))
+
+(opts:define-opts
+ (:name :help
+ :description "Print help text"
+ :short #\h
+ :long "help")
+ (:name :read
+ :description "Read serialized records file"
+ :short #\r
+ :long "read"
+ :arg-parser #'file-test)
+ (:name :print-month
+ :description "Print records for given month"
+ :short #\p
+ :long "print-month"
+ :arg-parser #'check-month)
+ (:name :interactive-mode
+ :description "Run in interactive mode"
+ :short #\i
+ :long "interactive"))
+
+;; See: https://github.com/libre-man/unix-opts/blob/master/example/example.lisp
+(defmacro when-option ((options opt) &body body)
+ `(let ((it (getf ,options ,opt)))
+ (when it
+ ,@body)))
+
+(defun reload ()
+ (load "~/Repos/fin-lisp/fin-lisp.lisp"))
+
(defun reset-records ()
(setf *records* (make-hash-table :test 'equalp)))

@@ -102,8 +147,7 @@
(defun cls()
(format t "~A[H~@*~A[J" #\escape))

-;; Entry point
-(defun main ()
+(defun interactive-mode ()
(format t "~%")
(format t "Available options:~%")
(format t "1. Enter expense~%")
@@ -135,5 +179,28 @@
(if (string= answer "6")
(generic-handler
(import-records (prompt-read "Enter filename"))
- "Parsing error or invalid filename"))
- (main)))
+ "Parsing error or invalid filename")))
+ (interactive-mode))
+
+(defun display-help ()
+ (format t "foo ~%")
+ (opts:describe
+ :prefix "fin-lisp.lisp - Basic expense tracker in lisp"
+ :usage-of "fin-lisp.lisp"
+ :args "[FREE-ARGS]")
+ (quit))
+
+;; Entry point
+(defun main ()
+ (if (= 1 (length sb-ext:*posix-argv*)) (interactive-mode))
+ (let ((matches (opts:get-opts)))
+ (format t "~a ~%" matches)
+ (when-option (matches :help)
+ (display-help))
+ (when-option (matches :print-month)
+
+ (when-option (matches :interactive-mode)
+ (progn
+ (interactive-mode)
+ (quit)))))
+