src/shell.lisp @ f0254c404ef4

Move `sh` and friends from CACL into this repo
author Steve Losh <steve@stevelosh.com>
date Thu, 03 Oct 2019 17:26:22 -0400
parents (none)
children a85855efde4a
(in-package :losh.shell)

(defun sh (command &key input output (wait t))
  "Run `command`, piping `input` to it, optionally returning its output.

  `command` must be either a string (the program), or a list of the program and
  its arguments.

  `wait` must be a boolean.  If true, this function will block until the command
  completes.  If false, it will return immediately and allow the program to run
  asynchronously.

  `input` must be a character input stream, a string, or `nil`.  If non-`nil`
  its contents will be sent to the program as its standard input.

  `output` must be one of `:string`, `:stream`, or `nil`.  `:string` cannot be
  used if `:wait` is `nil`.

  "
  (ctypecase command
    (string (setf command (list command)))
    ((cons string list)))
  (ctypecase input
    (string (setf input (make-string-input-stream input)))
    (stream)
    (null))
  (let ((result (funcall (if wait #'uiop:run-program #'uiop:launch-program)
                         command
                         :output (when output
                                   (if wait
                                     (ccase output
                                       (:string :string)
                                       (:stream :string)) ; hack because uiop doesn't support this
                                     (ccase output
                                       (:string (error "`output` cannot be `:string` when not `wait`ing."))
                                       (:stream :stream))))
                         :input input)))
    (ecase output
      ((nil) (values))
      (:stream (if wait
                 (make-string-input-stream result)
                 (uiop:process-info-output result)))
      (:string result))))


(defun pbcopy (object)
  "`pbcopy` the `aesthetic-string` of `object`."
  (sh "pbcopy" :input (format nil "~A" object) :wait nil)
  (values))

(defun pbpaste ()
  "`pbpaste` the current clipboard as a string."
  (values (sh "pbpaste" :output :string)))