--- 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)))