User can create new category on the CLI

This commit is contained in:
Logan Hunt 2022-05-31 23:23:58 -07:00
parent 10d7a20a79
commit a76bfbf944
Signed by untrusted user who does not match committer: simponic
GPG Key ID: 52B3774857EB24B1
5 changed files with 70 additions and 57 deletions

View File

@ -24,12 +24,16 @@
(if start (if start
(floor (* 100 (local-time:timestamp-difference end start)))))) (floor (* 100 (local-time:timestamp-difference end start))))))
(defun format-elapsed-time (run-split) (defun run-split-format-elapsed-time (run-split)
(let ((elapsed (run-split-elapsed-time run-split))) (let ((elapsed (run-split-elapsed-time run-split)))
(if elapsed (if elapsed
(format-time (make-time-alist elapsed)) (format-time (make-time-alist elapsed))
"-"))) "-")))
;;(defun best-split (category-split)
;; (mito:select-dao 'run-split
;; (sxql:order-by (:- V
;; Returns stuff like PB, best of each split, etc. ;; Returns stuff like PB, best of each split, etc.
(defun run-statistics (category) (defun run-statistics (category)
`((asdf . 1))) `((asdf . 1)))

View File

@ -1,25 +1,24 @@
(asdf:defsystem "lispruns" (asdf:defsystem "lispruns"
:description "A speedrun timer using n-curses written in lisp" :description "A speedrun timer using n-curses written in lisp"
:version "0.1" :version "0.1"
:author "Simponic" :author "Simponic"
:depends-on (:unix-opts :depends-on (:mito
:mito :sxql
:sxql :cl-ppcre
:cl-ppcre :croatoan
:croatoan :local-time)
:local-time) :components ((:file "util") ;; Miscellaneous helpers
:components ((:file "util") ;; Miscellaneous helpers (:file "config") ;; For importing category configuration files
(:file "config") ;; For importing category configuration files (:file "digits") ;; Lisp file with cool ascii digits
(:file "digits") ;; Lisp file with cool ascii digits (:file "text" :depends-on ("digits")) ;; Helper functions for performing figlet-like actions and such
(:file "text" :depends-on ("digits")) ;; Helper functions for performing figlet-like actions and such (:file "time") ;; Custom time forms
(:file "time") ;; Custom time forms (:file "ui" :depends-on ("util" "text" "time")) ;; Functions to draw the UI
(:file "ui" :depends-on ("util" "text" "time")) ;; Functions to draw the UI (:file "speedrun" :depends-on ("util")) ;; The actual timer logic
(:file "speedrun" :depends-on ("util")) ;; The actual timer logic (:file "database/category") ;; Category DAO
(:file "database/category") ;; Category DAO (:file "database/run") ;; Run DAO
(:file "database/run") ;; Run DAO (:file "main" :depends-on ("database/category"
(:file "main" :depends-on ("database/category" "database/run"
"database/run" "util"
"util" "config"
"config" "ui"
"ui" "speedrun"))))
"speedrun"))))

View File

@ -20,7 +20,7 @@
(if (ignore-errors (funcall validator input)) (if (ignore-errors (funcall validator input))
input input
(progn (progn
(format t "E: Invalid input. Try again.") (format t "E: Invalid input. Try again.~%")
(get-input prompt validator))))) (get-input prompt validator)))))
;; Options is an alist with the prompt string as the car and the value as the cdr ;; Options is an alist with the prompt string as the car and the value as the cdr
@ -53,6 +53,29 @@
(progn (format t "E: Could not find option that matched query.~%") (progn (format t "E: Could not find option that matched query.~%")
(select-option options))))))) (select-option options)))))))
(defun user-create-new-category ()
(let* ((name (get-input "Category Name (e.g. \"SM64\"): " 'empty-p))
(percentage (get-input "Percentage (e.g. \"16 Star\"): " 'empty-p))
(category (mito:insert-dao (make-instance 'category :name name :percentage percentage)))
(splits (do ((spliti 1 (1+ spliti))
(inputs '() (push (get-input (format nil "Split Name [~a]~a: " spliti (if (<= spliti 1) " (blank when done adding)" ""))) inputs)))
((equal (car inputs) "")
(mapcar (lambda
(category-split-name)
(mito:insert-dao
(make-instance 'category-split
:name category-split-name
:category category)))
(reverse (cdr inputs)))))))))
(defun with-selected-category (f)
(let* ((categories (mito:select-dao 'category))
(category-alist (mapcar (lambda (category) `(,(format nil "~a - ~a" (category-name category) (category-percentage category)) . ,category)) categories)))
(if categories
(funcall f (select-option category-alist))
(format t "E: There are no categories. Try creating one or importing one"))))
(defun main () (defun main ()
(let ((choice (select-option '(("Help" . HELP) (let ((choice (select-option '(("Help" . HELP)
("Import a category" . IMPORT-CATEGORY) ("Import a category" . IMPORT-CATEGORY)
@ -62,6 +85,7 @@
("Exit" . EXIT))))) ("Exit" . EXIT)))))
(case choice (case choice
('HELP ('HELP
(format t "~%")
(mapcar #'(lambda (x) (format t "~a~%" x)) *lispruns-logo*)) (mapcar #'(lambda (x) (format t "~a~%" x)) *lispruns-logo*))
('IMPORT-CATEGORY ('IMPORT-CATEGORY
(import-category (get-input (import-category (get-input
@ -69,25 +93,9 @@
(uiop/os:getcwd)) (uiop/os:getcwd))
'probe-file))) 'probe-file)))
('NEW-CATEGORY ('NEW-CATEGORY
(let* ((name (get-input "Category Name (e.g. \"SM64\"): " 'not-empty-string)) (user-create-new-category))
(percentage (get-input "Percentage (e.g. \"16 Star\"): " 'not-empty-string))
(category (mito:insert-dao (make-instance 'category :name name :percentage percentage)))
(splits (do ((spliti 1 (1+ spliti))
(inputs '() (push (get-input (format nil "Split [~a]: " spliti)) inputs)))
((equal (car inputs) "")
(mapcar (lambda
(category-split-name)
(mito:insert-dao
(make-instance 'category-split
:name category-split-name
:category category)))
(reverse (cdr inputs)))))))))
('START-SPEEDRUN ('START-SPEEDRUN
(let* ((categories (mito:select-dao 'category)) (with-selected-category 'speedrun-ui))
(category-alist (mapcar (lambda (category) `(,(format nil "~a - ~a" (category-name category) (category-percentage category)) . ,category)) categories)))
(if categories
(speedrun-ui (select-option category-alist))
(format t "E: There are no categories. Try creating one or importing one"))))
('EXIT ('EXIT
(quit)))) (quit))))
(format t "~%") (format t "~%")

24
ui.lisp
View File

@ -18,6 +18,12 @@
(inc yi)) (inc yi))
slices))) slices)))
;; Formats a category split and a run split for the splits window
(defun make-split-line (csplit speedrun-split)
`((,(category-split-name csplit) . ,(/ 4 12))
("" . ,(/ 1 12))
(,(run-split-format-elapsed-time speedrun-split) . ,(/ 3 12))))
;; Creates a window with the total time and statistics ;; Creates a window with the total time and statistics
(defun timer-window (speedrun pos width height) (defun timer-window (speedrun pos width height)
(let* ((timerglet (lispglet (format-time (make-time-alist (speedrun-elapsed speedrun))))) (let* ((timerglet (lispglet (format-time (make-time-alist (speedrun-elapsed speedrun)))))
@ -82,6 +88,7 @@
(subseq elements (car elements-to-draw-subseq) (cadr elements-to-draw-subseq)))) (subseq elements (car elements-to-draw-subseq) (cadr elements-to-draw-subseq))))
highlight-menu)) highlight-menu))
;; The big bad monolithic UI loop
(defun speedrun-ui (category) (defun speedrun-ui (category)
(croatoan:with-screen (scr :input-blocking nil :input-echoing nil :cursor-visible nil :enable-colors t :input-buffering nil :input-blocking nil) (croatoan:with-screen (scr :input-blocking nil :input-echoing nil :cursor-visible nil :enable-colors t :input-buffering nil :input-blocking nil)
(setf (croatoan:background scr) (make-instance 'croatoan:complex-char :color-pair (cdr (assoc 'main *colors*)))) (setf (croatoan:background scr) (make-instance 'croatoan:complex-char :color-pair (cdr (assoc 'main *colors*))))
@ -90,7 +97,9 @@
(state 'TITLE) (state 'TITLE)
(redraws '(title-instance)) (redraws '(title-instance))
(speedrun (make-speedrun category)) (speedrun (make-speedrun category))
(csplits (category-splits category))) (csplits (category-splits category))
;; TODO
(pbs ()))
(flet ((render () (flet ((render ()
(case state (case state
('TITLE ('TITLE
@ -124,16 +133,8 @@
:current-element-index (speedrun-current-split-index speedrun) :current-element-index (speedrun-current-split-index speedrun)
:height splits-height :height splits-height
:width max-width :width max-width
:elements (mapcar (lambda (csplit speedrun-split) ;; Todo: add personal bests to elements
`( :elements (mapcar 'make-split-line csplits (speedrun-splits speedrun))))
(,(category-split-name csplit) . ,(/ 4 12))
("" . ,(/ 1 12))
(,(format-elapsed-time speedrun-split) . ,(/ 3 12))
))
csplits
(speedrun-splits speedrun))))
;; :elements (mapcar #'category-split-name csplits)))
;; :elements `((("FIRST SPLIT IS EPIC" . ,(/ 4 12)) ("" . ,(/ 1 12)) ("10:10:00.22" . ,(/ 3 12)) ("" . ,(/ 1 12)) ("20:00.00" . ,(/ 3 12))))))
(splits-instance (highlight-list-window split-list `(0 ,centered-x))) (splits-instance (highlight-list-window split-list `(0 ,centered-x)))
(timer-instance (timer-window speedrun `(,splits-height ,centered-x) max-width timer-height))) (timer-instance (timer-window speedrun `(,splits-height ,centered-x) max-width timer-height)))
(croatoan:refresh splits-instance) (croatoan:refresh splits-instance)
@ -143,6 +144,7 @@
(if (zerop (mod frame 30)) (if (zerop (mod frame 30))
(inc scroll)) (inc scroll))
(sleep (/ 1 60)))) (sleep (/ 1 60))))
(croatoan:event-case (scr event) (croatoan:event-case (scr event)
(#\q (return-from croatoan:event-case)) (#\q (return-from croatoan:event-case))
(#\space (#\space

View File

@ -10,5 +10,5 @@
(defun max-length (lists) (defun max-length (lists)
(reduce (lambda (a x) (max a x)) (mapcar #'length lists))) (reduce (lambda (a x) (max a x)) (mapcar #'length lists)))
(defun not-empty-string (str) (defun empty-p (s)
(not (zerop (length str)))) (not (zerop (length s))))