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