diff options
Diffstat (limited to 'src/lib.lisp')
-rw-r--r-- | src/lib.lisp | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/src/lib.lisp b/src/lib.lisp new file mode 100644 index 0000000..20f75ea --- /dev/null +++ b/src/lib.lisp @@ -0,0 +1,117 @@ +;;;; main.lisp -- oneliners.cli entrypoint + +(defpackage oneliners.cli + (:use :cl) + (:local-nicknames (#:api #:oneliners.api-client))) +(in-package :oneliners.cli) + +;;; CLI OPTIONS + +;; (opts:define-opts +;; (:name :add +;; :description "Intaractively add a oneliner to the a wiki." +;; :long "add") +;; (:name :tags +;; :description "A comma separated list of tags to filter search results." +;; :short #\t +;; :long "tags" +;; :arg-parser #'identity +;; :meta-var "'T1, T2, ...'") +;; (:name :limit +;; :description "An integer. The maximum number of results to return." +;; :short #\l +;; :long "limit" +;; :meta-var "N" +;; :default 10 +;; :arg-parser #'parse-integer) +;; (:name :edit +;; :description "An integer, a result number. Interactively edit af command." +;; :long "edit" +;; :meta-var "RESULT" +;; :arg-parser #'parse-integer) +;; (:name :not-flagged +;; :description "Filter flagged oneliners from the search results" +;; :long "not-flagged")) + +(defparameter +help-suffix+ + "Unless RESULT is an integer, search for oneliners that involve each command in COMMANDS. +E.g. + # search for oneliners involving both 'find' and 'grep' + ol find grep + +Otherwise, when RESULT is an integer, run the oneliner with index RESULT from the most +recent search command, and supply ARGS to that oneliner, if provided. +E.g. + # run the third result from the last search with arguments foo and bar + ol 3 foo bar") + +;; (defun help-text () +;; (opts:describe :prefix "Oneliners Wiki Command Line Tool" +;; :args "[[RESULT ARGS | COMMANDS]" +;; :usage-of "ol" +;; :suffix +help-suffix+)) + +;;; CONFIG AND RESULTS FILE LOCATIONS + +(defun config-file () + (merge-pathnames ".config/oneliners.config" (user-homedir-pathname) )) + +(defun last-search-file () + (merge-pathnames ".last_oneliners_search" (user-homedir-pathname))) + +;;; RUNNING COMMANDS + +(defun parent-process-name () + "Prints the name of the parent process of the current process." + (let ((ppidfile (format nil "/proc/~a/status" (osicat-posix:getppid)))) + (first (last + (ppcre:split "\\s" + (with-open-file (input ppidfile) + (read-line input))))))) + +(defmacro wait-until ((&key (timeout 1) (poll-every 0.01)) &body check) + "Run CHECK every POLL-EVERY seconds until either TIMEOUT seconds +have passed or CHECK returns non-nil." + (let ((clockvar (gensym)) + (var (gensym))) + `(loop + for ,clockvar from 0 by ,poll-every to ,timeout + for ,var = (progn ,@check) + when ,var + return ,var + do (sleep ,poll-every)))) + +(defun run-with-shell + (command + &key + (shell-name (parent-process-name)) + (await-output-p 0.8) + (output-stream *standard-output*)) + "run COMMAND, a string, in a fresh shell environment, initialized +with SHELL-NAME. The output from the command read line by line and is +printed to OUTPUT-STREAM. " + (let ((shell + (uiop:launch-program shell-name :input :stream :output :stream))) + (symbol-macrolet ((shell-input (uiop:process-info-input shell)) + (shell-output (uiop:process-info-output shell))) + (write-line command shell-input) + (finish-output shell-input) + (when await-output-p + (wait-until (:timeout await-output-p :poll-every 0.005) + (listen shell-output)) + (loop while (listen shell-output) + do (princ (read-line shell-output) output-stream) + (terpri output-stream)))))) + +;;; main + +;; (defun main () +;; (handler-case +;; (multiple-value-bind (options free-args) (opts:get-opts) +;; (print (list :options options :free-args free-args)) +;; (terpri) +;; (uiop:quit)) +;; (unix-opts:unknown-option (err) +;; (declare (ignore err)) +;; (princ (help-text)) +;; (terpri)))) |