aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Okay <okay@toyful.space>2022-02-22 13:46:35 -0600
committerColin Okay <okay@toyful.space>2022-02-22 13:46:35 -0600
commit2f977d630fad6918fe0039d22ec13d90b89a94a0 (patch)
tree396c1ec26b621d8345166c078a9c2648cc231f6d
parentd6dee4eb2906b1a845488065066fae7ef6906338 (diff)
prompt with validation and retry
-rw-r--r--src/lib.lisp55
1 files changed, 43 insertions, 12 deletions
diff --git a/src/lib.lisp b/src/lib.lisp
index 0ea4cda..858675f 100644
--- a/src/lib.lisp
+++ b/src/lib.lisp
@@ -91,9 +91,24 @@ the directories that appear in the value of that variable."
(defun tags-from-oneliner (oneliner)
(remove-if-not #'executable-on-system-p (ppcre:split " +" oneliner)))
-(defun prompt (prompt &key (out-stream *standard-output*) (in-stream *standard-input*))
- (princ prompt out-stream) (force-output out-stream)
- (read-line in-stream))
+(defun prompt (prompt
+ &key
+ (out-stream *standard-output*)
+ (in-stream *standard-input*)
+ (expect (constantly t))
+ retry-text)
+
+ (loop
+ with to-prompt = prompt
+ with should-retry-p = t
+ while should-retry-p
+ for line = (progn
+ (princ to-prompt out-stream) (force-output out-stream)
+ (setf to-prompt (or retry-text prompt))
+ (read-line in-stream))
+ when (funcall expect line)
+ do (setf should-retry-p nil)
+ finally (return line)))
(defun cached-result (&optional n)
(when (uiop:file-exists-p (last-search-file))
@@ -158,8 +173,10 @@ the directories that appear in the value of that variable."
(format t "Copied oneliner to clipboard~%"))
(progn
(ensure-config)
- (format t "Attempting to run: ~%")
- (princ ol) (terpri)
+ (format t "Attempting to run:~%")
+ (princ ol)
+ (princ #\newline)
+ (princ #\newline)
(run-with-shell ol :shell-name (or (get-shell) "bash")))))
@@ -188,27 +205,41 @@ the directories that appear in the value of that variable."
(handle-run-oneliner oneliner (or force-clip (equalp runstyle "manual")))))))
+(defun valid-oneliner-string-p (string)
+ (and (not (find #\newline string))
+ (tags-from-oneliner string)))
+
+(defun valid-brief-description-p (string)
+ (<= (length string) 72))
+
+(defun valid-runstyle-p (string)
+ (member string '("auto" "manual") :test 'equalp))
(defun add-new-oneliner ()
(ensure-config)
(assert (api-token) () "Cannot add a oneliner without an api token.")
(let* ((oneliner
- (prompt "Oneliner: "))
+ (prompt "Oneliner: "
+ :expect 'valid-oneliner-string-p
+ :retry-text "Oneliners must contain at least one command: "))
(init-tags
(tags-from-oneliner oneliner))
(brief
- (prompt "Brief Description: "))
+ (prompt "Brief Description: "
+ :expect 'valid-brief-description-p
+ :retry-text "Too long. Must be <= 72 characters: "))
(tags
(append init-tags
(ppcre:split " +"
(prompt (format nil "Tags in addition to ~{~a ~} ?" init-tags)))))
+ (runstyle
+ (string-upcase
+ (prompt "Runstyle (auto or manual): "
+ :expect 'valid-runstyle-p
+ :retry-text "Must be (auto or manual): ")))
(explanation
(when (y-or-n-p "Provide an explanation?")
- (string-from-editor)))
- (runstyle
- (if (y-or-n-p "Does this oneliner invoke a GUI, a TUI, or will it require user input?")
- "MANUAL"
- "AUTO")))
+ (string-from-editor))))
(api:request-with
(:host (host)
:body (jonathan:to-json