From f116178dcf8b450c76400e2a0fbd2991f2c227b4 Mon Sep 17 00:00:00 2001 From: Colin Okay Date: Fri, 5 Aug 2022 08:58:35 -0500 Subject: [wip] [refactor] [add] subcommands. --- app/app.lisp | 23 +++++++++++++- app/clip.lisp | 17 +++++++++++ app/draft.lisp | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ app/run.lisp | 22 ++++++++++--- app/search.lisp | 14 ++++++++- app/show.lisp | 16 ++++++++++ app/util.lisp | 11 +++++++ lib/client.lisp | 92 +++++++++++++++++++++---------------------------------- 8 files changed, 226 insertions(+), 64 deletions(-) create mode 100644 app/clip.lisp create mode 100644 app/draft.lisp create mode 100644 app/show.lisp create mode 100644 app/util.lisp diff --git a/app/app.lisp b/app/app.lisp index a4ff596..5af7006 100644 --- a/app/app.lisp +++ b/app/app.lisp @@ -28,7 +28,28 @@ (defun toplevel/subcommands () "Returns a list of the subcommands for the top level command" (list - (search/command))) + (search/command) + (run/command) + (clip/command) + (show/command) + (draft/command) + )) + + +;; ol delete + +;; ol account login +;; ol account logout +;; ol account signature +;; ol account password +;; ol account whois +;; ol invite new +;; ol invite redeem + +;; ol account use ;; for switchign servers + +;; new edit delete publish trash drafts flag unflag lockated unlock +;; redeem login logout password signature whois (defun toplevel/handler (cmd) "Prints usage statement and then exits" diff --git a/app/clip.lisp b/app/clip.lisp new file mode 100644 index 0000000..922cacc --- /dev/null +++ b/app/clip.lisp @@ -0,0 +1,17 @@ +;;;; clip.lisp + +(in-package :oneliners.cli.app) + +(defun clip/handler (cmd) + (a:if-let (args (cli:command-arguments cmd)) + (ol::run-item + (parse-identifier (first args)) (rest args) + :force-clip t) + (cli:print-usage-and-exit cmd t))) + +(defun clip/command () + (cli:make-command + :name "clip" + :usage " [ARG ...]" + :description "attempt to copy the oneliner to the clipboard" + :handler #'clip/handler)) diff --git a/app/draft.lisp b/app/draft.lisp new file mode 100644 index 0000000..ea71e49 --- /dev/null +++ b/app/draft.lisp @@ -0,0 +1,95 @@ +;;;; draft.lisp + +(in-package :oneliners.cli.app) + +(defun draft/new/handler (cmd) + (ol:add-new-oneliner)) + +(defun draft/new/command () + (cli:make-command + :name "new" + :description "interactively draft a new oneliner" + :handler #'draft/new/handler)) + + +(defun draft/publish/handler (cmd) + (a:if-let (name (first (cli:command-arguments cmd))) + (ol::publish-draft name) + (cli:print-usage-and-exit cmd t))) + +(defun draft/publish/command () + (cli:make-command + :name "publish" + :usage "" + :description "publish draft to the server" + :handler #'draft/publish/handler)) + +(defun draft/test/handler (cmd) + (a:if-let (args (cli:command-arguments cmd)) + (ol:run-item (first args) (rest args) + :verbose (cli:getopt cmd :verbose) + :confirm (cli:getopt cmd :confirm) + :timeout (cli:getopt cmd :timeout) + :draftp t) + (cli:print-usage-and-exit cmd t))) + +(defun draft/test/command () + (cli:make-command + :name "test" + :usage " [ARG ...]" + :description "runs a draft oneliner, same options as `ol run`" + :options (run/options) + :handler #'draft/new/handler)) + +(defun draft/edit/handler (cmd) + (a:if-let (name (first (cli:command-arguments cmd))) + (ol:edit-item name t) + (cli:print-usage-and-exit cmd t))) + +(defun draft/edit/command () + (cli:make-command + :name "edit" + :usage "" + :description "interactively edits a draft" + :handler #'draft/edit/handler)) + +(defun draft/trash/handler (cmd) + (a:if-let (name (first (cli:command-arguments cmd))) + (ol::drop-draft name) + (cli:print-usage-and-exit cmd t))) + +(defun draft/trash/command () + (cli:make-command + :name "trash" + :usage "" + :description "trash a draft" + :handler #'draft/trash/handler)) + +(defun draft/list/handler (cmd) + (declare (ignore cmd)) + (ol::print-drafts)) + +(defun draft/list/command () + (cli:make-command + :name "list" + :description "list drafted oneliners" + :handler #'draft/list/handler)) + +(defun draft/subcommands () + (list + (draft/new/command) + (draft/publish/command) + (draft/test/command) + (draft/edit/command) + (draft/trash/command) + (draft/list/command))) + +(defun draft/handler (cmd) + (cli:print-usage-and-exit cmd t)) + +(defun draft/command () + (cli:make-command + :name "draft" + :description "draft, test, and publish new oneliners" + :handler #'draft/command + :sub-commands (draft/subcommands))) diff --git a/app/run.lisp b/app/run.lisp index 2591927..987ecad 100644 --- a/app/run.lisp +++ b/app/run.lisp @@ -24,13 +24,27 @@ :key :confirm :description "prompts the user for confirmation before running the command"))) -(defun run/handler (cmd)) +(defun run/handler (cmd) + (a:if-let (args (cli:command-arguments cmd)) + (ol::run-item + (first args) (rest args) + :verbose (cli:getopt cmd :verbose) + :confirm (cli:getopt cmd :confirm) + :timeout (cli:getopt cmd :timeout)) + (cli:print-usage-and-exit cmd t))) (defparameter +run/examples+ - '(())) - + '(("Run a hypothetical command called echo-stuff with positional arguments" . + "ol run echo-stuff one two three") + ("Run a hypothetical command with id 341 with a timeout and confirmation" . + "ol run -c -t 10 341"))) (defun run/command () (cli:make-command :name "run" - :description "")) + :usage " [ARG ...]" + :description "run the identified oneliner with any arguments it might take" + :options (run/options) + :handler #'run/handler + :examples +run/examples+)) + diff --git a/app/search.lisp b/app/search.lisp index 015a749..afc8f84 100644 --- a/app/search.lisp +++ b/app/search.lisp @@ -29,7 +29,19 @@ :short-name #\n :long-name "newest" :description "the newest matching oneliners are returned" - :key :newest))) + :key :newest) + + ;; TODO + ;; (cli:make-option + ;; :flag + ;; :short-name #\c + ;; :long-name "cache" + ;; :description "restrict search to what is already in the local cache" + ;; :env-vars '("OL_CACHE_ONLY") + ;; :key :cache) + + + )) (defun search/handler (cmd) "Handler function for the search command. " diff --git a/app/show.lisp b/app/show.lisp new file mode 100644 index 0000000..1ed3493 --- /dev/null +++ b/app/show.lisp @@ -0,0 +1,16 @@ +;;;; show.lisp + +(in-package :oneliners.cli.app) + +(defun show/handler (cmd) + (a:if-let (ident + (parse-identifier (first (cli:command-arguments cmd)))) + (ol:print-item-explanation ident) + (cli:print-usage-and-exit cmd t))) + +(defun show/command () + (cli:make-command + :name "show" + :usage "" + :description "show detailed information about a oneliner" + :handelr #'show/handler )) diff --git a/app/util.lisp b/app/util.lisp new file mode 100644 index 0000000..d9d5ea2 --- /dev/null +++ b/app/util.lisp @@ -0,0 +1,11 @@ +;;;; utils.lisp + +(in-package :oneliners.cli.app) + +(defun parse-identifier (str) + "If STR holds digits representing an integer, parse them. otherwise + return the string. Oneliner identifiers may be names or ID + numbers. Returns NIL in the case that STR is NIL" + (when str + (or (parse-integer str :junk-allowed t) + str))) diff --git a/lib/client.lisp b/lib/client.lisp index b39e0ac..e3f304e 100644 --- a/lib/client.lisp +++ b/lib/client.lisp @@ -125,7 +125,7 @@ running the body. If such a oneliner can be found." (format t "Attempting to run:~%") (princ oneliner) (princ #\newline)) - ;; substitute positional args + (when (or (not confirm) (y-or-n-p "Proceed?")) (handle-run-oneliner oneliner (or force-clip (equalp runstyle "manual"))))))) @@ -141,11 +141,7 @@ running the body. If such a oneliner can be found." (defun add-new-oneliner () (api-token) ;; fails with error if not set. ;; read each field required to make a onelienr in from a prompt. - (let* ((oneliner-string - (prompt "Oneliner: " - :expect 'valid-oneliner-string-p - :retry-text "Oneliners must contain at least one command: ")) - (name + (let* ((name (string-trim '(#\space #\newline #\tab #\linefeed) (prompt "Name (leave blank for none): " @@ -153,13 +149,16 @@ running the body. If such a oneliner can be found." :retry-text "Must begin with a letter contain only letters, numbers, - and _."))) (draft-name - (unless (y-or-n-p "Upload immediately instead of keeping a draft?") - (if (plusp (length name)) - name - (prompt "No name was provided, name this draft: " - :expect 'valid-oneliner-name-p - :retry-text "Must begin with a letter contain only letters, numbers, - and _.")))) + (if (plusp (length name)) + name + (prompt "No name was provided, name this draft: " + :expect 'valid-oneliner-name-p + :retry-text "Must begin with a letter contain only letters, numbers, - and _."))) + (oneliner-string + (prompt "Oneliner: " + :expect 'valid-oneliner-string-p + :retry-text "Oneliners must contain at least one command: ")) (init-tags (parse-oneliner-tags oneliner-string)) @@ -191,32 +190,16 @@ running the body. If such a oneliner can be found." :brief brief :explanation explanation :runstyle runstyle))) - (if draft-name - ;; if this is a draft, save it to disk. - (progn - (put-draft draft-name local) - (format t "Saved draft ~a~%Do `ol --draft run ~a` to test~%" - draft-name - draft-name)) - ;; otherwise, format the oneliner as json and make a request - ;; to create a new oneliner in the wiki - (api:request-with - (:body (oneliner-to-json-body local) - :content-type "application/json") - (api:post--oneliner :token (api-token)) ;TODO: update api to return the instance created. - (format t "Added Oneliner~%")))))) + (progn + (put-draft draft-name local) + (format t "Saved draft ~a~%" draft-name))))) ;;; EDITING ONELINERS (defun edit-item (ident &optional draftp) - (api-token) ;; fails with error if not set. + ;;(unless draftp (api-token)) ;; fails with error if not set. (let ((ol (if draftp (fetch-draft ident) (the-oneliner ident)))) - (let* ((oneliner-string - (prompt "Oneliner: " - :expect 'valid-oneliner-string-p - :retry-text "Oneliners must contain at least one command: " - :prefill (oneliner-oneliner ol))) - (name + (let* ((name (string-trim '(#\space #\newline #\tab #\linefeed) (prompt "Name (leave blank for none): " @@ -225,12 +208,16 @@ running the body. If such a oneliner can be found." :prefill (or (oneliner-name ol) "")))) (draft-name - (unless (y-or-n-p "Upload edits immediately instead of keeping a draft?") - (if (plusp (length name)) - name - (prompt "No name was provided, name this draft: " - :expect 'valid-oneliner-name-p - :retry-text "Must begin with a letter contain only letters, numbers, - and _.")))) + (if (plusp (length name)) + name + (prompt "No name was provided, name this draft: " + :expect 'valid-oneliner-name-p + :retry-text "Must begin with a letter contain only letters, numbers, - and _."))) + (oneliner-string + (prompt "Oneliner: " + :expect 'valid-oneliner-string-p + :retry-text "Oneliners must contain at least one command: " + :prefill (oneliner-oneliner ol))) (brief (prompt "Brief Description: " :expect 'valid-brief-description-p @@ -271,31 +258,20 @@ running the body. If such a oneliner can be found." :brief brief :explanation explanation :runstyle runstyle))) - (if draft-name - (progn - (put-draft draft-name local) - (format t "Saved draft ~a~%Do `ol --draft run ~a` to test~%" - draft-name - draft-name)) - (api:request-with - (:body (oneliner-to-json-body local) - :content-type "application/json") - (let ((updated - (jonathan:parse - (api:patch--oneliner-entry-edit (oneliner-id ol) :token (api-token))))) - (merge-oneliners (list updated))) - - (format t "Edits accepted~%"))))))) + (progn + (put-draft draft-name local) + (format t "Saved draft ~a~%" draft-name)))))) -;;TODO: need to sync cache here. (defun publish-draft (name) (when-draft (ol name) (api:request-with (:body (oneliner-to-json-body ol) :content-type "application/json") - (if (oneliner-id ol) - (api:patch--oneliner-entry-edit (oneliner-id ol) :token (api-token)) - (api:post--oneliner :token (api-token))) + (let ((updated + (if (oneliner-id ol) + (api:patch--oneliner-entry-edit (oneliner-id ol) :token (api-token)) + (api:post--oneliner :token (api-token))))) + (merge-oneliners (list updated))) ;; if that worked, no http error occured, so this next part will run (drop-draft name) (format t "Draft ~a published and removed from drafts.~%" name)))) -- cgit v1.2.3