f0254c404ef4

Move `sh` and friends from CACL into this repo
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Thu, 03 Oct 2019 17:26:22 -0400
parents 3b355cd31642
children 19519aba4cb5 a85855efde4a
branches/tags (none)
files DOCUMENTATION.markdown losh.asd make-docs.lisp package.lisp src/shell.lisp

Changes

--- a/DOCUMENTATION.markdown	Thu Oct 03 10:38:04 2019 -0400
+++ b/DOCUMENTATION.markdown	Thu Oct 03 17:26:22 2019 -0400
@@ -2105,6 +2105,43 @@
 
   
 
+## Package `LOSH.SHELL`
+
+Utilities for interacting with external programs.
+
+### `PBCOPY` (function)
+
+    (PBCOPY OBJECT)
+
+`pbcopy` the `aesthetic-string` of `object`.
+
+### `PBPASTE` (function)
+
+    (PBPASTE)
+
+`pbpaste` the current clipboard as a string.
+
+### `SH` (function)
+
+    (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`.
+
+  
+
 ## Package `LOSH.WEIGHTLISTS`
 
 A simple data structure for choosing random items with weighted probabilities.
--- a/losh.asd	Thu Oct 03 10:38:04 2019 -0400
+++ b/losh.asd	Thu Oct 03 17:26:22 2019 -0400
@@ -10,8 +10,8 @@
   :in-order-to ((asdf:test-op (asdf:test-op :losh/test)))
 
   :depends-on (:iterate
-               #+sbcl :sb-sprof
-               )
+               :uiop
+               #+sbcl :sb-sprof)
 
   :serial t
   :components
@@ -31,6 +31,7 @@
                  (:file "io")
                  (:file "lists")
                  (:file "mutation")
+                 (:file "shell")
 
                  ;; 1 ---------------------------------------------------------
                  (:file "arrays" :depends-on ("chili-dogs"))
--- a/make-docs.lisp	Thu Oct 03 10:38:04 2019 -0400
+++ b/make-docs.lisp	Thu Oct 03 17:26:22 2019 -0400
@@ -23,6 +23,7 @@
         "LOSH.QUEUES"
         "LOSH.RANDOM"
         "LOSH.SEQUENCES"
+        "LOSH.SHELL"
         "LOSH.WEIGHTLISTS"
 
         ))
--- a/package.lisp	Thu Oct 03 10:38:04 2019 -0400
+++ b/package.lisp	Thu Oct 03 17:26:22 2019 -0400
@@ -17,7 +17,6 @@
              :collect `(:export ,@(external-symbols parent-package)))))
 
 
-
 (defpackage :losh.chili-dogs
   (:use :cl :iterate :losh.quickutils)
   (:documentation "Gotta go FAST.")
@@ -107,6 +106,14 @@
     :notf
     :callf))
 
+(defpackage :losh.shell
+  (:use :cl :iterate :losh.quickutils)
+  (:documentation "Utilities for interacting with external programs.")
+  (:export
+    :sh
+    :pbcopy
+    :pbpaste))
+
 
 (defpackage :losh.arrays
   (:use :cl :iterate :losh.quickutils
@@ -395,6 +402,7 @@
    :losh.queues
    :losh.random
    :losh.sequences
+   :losh.shell
    :losh.weightlists
 
    )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/shell.lisp	Thu Oct 03 17:26:22 2019 -0400
@@ -0,0 +1,53 @@
+(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)))