diff --git a/README.md b/README.md index ef3e743..0238e91 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Some reasons to use **membrane.term**: Pre 1.0 release. APIs and behavior are subject to change. - +macOS and Linux are the current focus, Windows support is pre-alpha. ## Installation Membrane.term works on macOS and Linux operating systems. @@ -60,6 +60,9 @@ A demo of the types of things you can do: ![run-term-demo](doc/images/run-term-demo.gif?raw=true) You can also optional specify: +- [`-c, --command`](#command) Command to launch with, defaults to: + - macOS & Linux: `$SHELL` else `/bin/bash` + - Windows: `powershell` - `-w, --width` width of the terminal window in character columns (default: 90) - `-h, --height` height of the terminal window in character rows (default: 30) - [`--color-scheme`](#color-schemes) choose a different color scheme @@ -75,6 +78,7 @@ Given play script `play-msgcat.sh`: ```bash # override prompt to something doc-friendly +/bin/bash # could alternatively use --command export PS1="$ " # print out some colors clear @@ -91,10 +95,11 @@ Membrane.term passes the script to the terminal character by character, then wri ![play-msgcat-example](doc/images/screenshot-msgcat.png) -You must specify: -- `-p, --play` script to play - You can also optionally specify: +- [`-c, --command`](#command) Command to launch with, defaults to: + - macOS & Linux: `$SHELL` else `/bin/bash` + - Windows: `powershell` +- `-p, --play` script to play in the terminal - `-w, --width` width of the terminal window in character columns (default: 90) - `-h, --height` height of the terminal window in character columns (default: 30) - `-o, --out` filename of the image file to generate (default: terminal.png)\ @@ -112,6 +117,7 @@ Given play script `play-deep-diff.sh`: ```bash # our setup +/bin/bash # could alternatively use --command export PS1="$ " cd mkdir -p target/term-screenshot @@ -135,6 +141,30 @@ Produces `deep-diff.jpg`: ![play-deep-diff-example](doc/images/screenshot-deep-diff.png) + +## Command + +By default, `membrane.term` will attempt to launch with your OS shell. + +Use the `--command` option to launch with a different program. + +Let's suppose your favorite process monitor is [htop](https://htop.dev/) and that just want to run that: +```bash +clj -M:membrane.term run-term --command "htop --tree --delay 10" +``` + +Sometimes you are interested in taking a screenshot of only the output of a command: +```bash +clj -M:membrane.term screenshot --command "msgcat --color=test" --width 80 --height 21 +``` +![screenshot-vi-command-example](doc/images/screenshot-msgcat-command.png) + +Or, for a contrived example, you want to play some text in `vi` and take a screenshot: +```bash +clj -M:membrane.term screenshot --command "vi" --play "an-ode-to-clojure.txt" --width 40 --height 10 +``` +![screenshot-vi-command-example](doc/images/screenshot-vi-command.png) + ## Color Schemes There are boatloads of terminal color schemes available at [iTerm2-Color-Schemes](https://github.com/mbadolato/iTerm2-Color-Schemes). diff --git a/deps.edn b/deps.edn index b38d6fe..4126009 100644 --- a/deps.edn +++ b/deps.edn @@ -1,5 +1,6 @@ {:paths ["src" "resources"] :deps {org.clojure/clojure {:mvn/version "1.10.3"} + babashka/process {:mvn/version "0.0.2"} org.clojure/data.xml {:mvn/version "0.2.0-alpha6"} org.clojure/data.zip {:mvn/version "1.0.0"} dev.nubank/docopt {:mvn/version "0.6.1-fix7"} diff --git a/doc/examples/an-ode-to-clojure.txt b/doc/examples/an-ode-to-clojure.txt new file mode 100644 index 0000000..ed7da54 --- /dev/null +++ b/doc/examples/an-ode-to-clojure.txt @@ -0,0 +1,4 @@ +iRoses are red +Violets are blue +Clojure is fun +And so are you diff --git a/doc/examples/play-deep-diff.sh b/doc/examples/play-deep-diff.sh index c537225..0c3b298 100644 --- a/doc/examples/play-deep-diff.sh +++ b/doc/examples/play-deep-diff.sh @@ -1,3 +1,4 @@ +/bin/bash -l export PS1="$ " cd mkdir -p target/term-screenshot diff --git a/doc/examples/play-msgcat.sh b/doc/examples/play-msgcat.sh index d7b5869..742d90e 100644 --- a/doc/examples/play-msgcat.sh +++ b/doc/examples/play-msgcat.sh @@ -1,3 +1,4 @@ +/bin/bash -l # override prompt to something doc-friendly export PS1="$ " # print out some colors diff --git a/doc/images/screenshot-deep-diff.png b/doc/images/screenshot-deep-diff.png index 696836e..4d5a4fe 100644 Binary files a/doc/images/screenshot-deep-diff.png and b/doc/images/screenshot-deep-diff.png differ diff --git a/doc/images/screenshot-msgcat-command.png b/doc/images/screenshot-msgcat-command.png new file mode 100644 index 0000000..13d0d5a Binary files /dev/null and b/doc/images/screenshot-msgcat-command.png differ diff --git a/doc/images/screenshot-msgcat-font.png b/doc/images/screenshot-msgcat-font.png index 23f7038..4eb7439 100644 Binary files a/doc/images/screenshot-msgcat-font.png and b/doc/images/screenshot-msgcat-font.png differ diff --git a/doc/images/screenshot-msgcat-scheme.png b/doc/images/screenshot-msgcat-scheme.png index 7ad20d5..c03a60e 100644 Binary files a/doc/images/screenshot-msgcat-scheme.png and b/doc/images/screenshot-msgcat-scheme.png differ diff --git a/doc/images/screenshot-msgcat.png b/doc/images/screenshot-msgcat.png index 9764088..43c6d68 100644 Binary files a/doc/images/screenshot-msgcat.png and b/doc/images/screenshot-msgcat.png differ diff --git a/doc/images/screenshot-vi-command.png b/doc/images/screenshot-vi-command.png new file mode 100644 index 0000000..2b1e643 Binary files /dev/null and b/doc/images/screenshot-vi-command.png differ diff --git a/script/regen-screenshots.sh b/script/regen-screenshots.sh index 153d128..60852ee 100755 --- a/script/regen-screenshots.sh +++ b/script/regen-screenshots.sh @@ -31,3 +31,15 @@ clj -M:membrane.term screenshot \ --font-family "NovaMono" \ --font-size 16 \ --out doc/images/screenshot-msgcat-font.png + +echo "- launch msgcat as command -" +clj -M:membrane.term screenshot \ + --command 'msgcat --color=test' \ + --width 80 --height 22 \ + --out doc/images/screenshot-msgcat-command.png + +echo "- launch with vi and play some text -" +clj -M:membrane.term screenshot \ + --command "vi" --play "doc/examples/an-ode-to-clojure.txt" \ + --width 40 --height 20 \ + --out doc/images/screenshot-vi-command.png diff --git a/src/com/phronemophobic/membrane/term.clj b/src/com/phronemophobic/membrane/term.clj index 67903a8..660172c 100644 --- a/src/com/phronemophobic/membrane/term.clj +++ b/src/com/phronemophobic/membrane/term.clj @@ -7,8 +7,13 @@ (:import [com.pty4j PtyProcess WinSize])) -(defn- start-pty [] - (let [cmd (into-array String ["/bin/bash" "-l"]) +(def ^:private windows? + (-> (System/getProperty "os.name") + (string/lower-case) + (string/includes? "win"))) + +(defn- start-pty [cmd] + (let [cmd (into-array String cmd) pty (PtyProcess/exec ^"[Ljava.lang.String;" cmd ^java.util.Map (merge (into {} (System/getenv)) {"TERM" "xterm-256color"}))] @@ -278,9 +283,9 @@ nil) view))) -(defn- run-pty-process [width height term-state] +(defn- run-pty-process [cmd width height term-state] (let [^PtyProcess - pty (doto ^PtyProcess (start-pty) + pty (doto ^PtyProcess (start-pty cmd) (.setWinSize (WinSize. width height)))] (future (try @@ -316,6 +321,12 @@ (defn- load-default-toolkit [] @(requiring-resolve 'membrane.java2d/toolkit)) +(defn- default-cmd [] + [(if windows? + "powershell" + (or (System/getenv "SHELL") + "/bin/bash"))]) + (def default-color-scheme "Default color-scheme used in [[default-run-term-opts]] and [[default-screenshot-opts]]" {:white [1 1 1] @@ -352,8 +363,15 @@ "Launch an interactive membrane.term terminal. Terminal exits when explicitly closed by user. Accepts optional `opts` map: - - `:width` Window width in characters (default: `90`) - - `:height` Window height in characters (default: `30`) + - `:command` The command to run, typically, but not necessarily, a shell. + - Examples: + - `[\"/bin/bash\" \"--login\"]` + - `[\"top\"]` + - Defaults: + - macOS and linux: SHELL environment value, else `\"/bin/bash\"` + - Windows: `powershell` + - `:width` Window width in characters (default: `90`) + - `:height` Window height in characters (default: `30`) - `:color-scheme` Map for terminal colors (defaults to an internal scheme) Colors are specified per membrane convention, vectors of `[red green blue]` or `[red green blue alpha]` with values from `0` - `1` inclusive. Example: `[0.14 0.74 0.14 0.50]`. @@ -381,16 +399,17 @@ - Usable examples from membrane library: `membrane.java2d/toolkit`, `membrane.skia/toolkit`" ([] (run-term {})) - ([{:keys [width height color-scheme font-family font-size toolkit] :as opts}] + ([{:keys [command width height color-scheme font-family font-size toolkit] :as opts}] (let [opts (merge default-run-term-opts opts) - {:keys [width height color-scheme font-family font-size toolkit]} opts + {:keys [command width height color-scheme font-family font-size toolkit]} opts + command (or command (default-cmd)) term-state (atom {:vt (vt/make-vt width height)}) toolkit (if toolkit toolkit (load-default-toolkit)) font (load-terminal-font toolkit font-family font-size)] (swap! term-state assoc - :pty (run-pty-process width height term-state)) + :pty (run-pty-process command width height term-state)) (tk/run-sync toolkit (fn [] @@ -414,7 +433,14 @@ Terminal is not displayed and automatically exits after screenshot is written. Requires `opts` map: - - `:play` Script string to play in terminal (**required**) + - `:command` The command to run, typically, but not necessarily, a shell. + - Examples: + - `[\"/bin/bash\" \"--login\"]` + - `[\"top\"]` + - Defaults: + - macOS and linux: SHELL environment value, else `\"/bin/bash\"` + - Windows: `powershell` + - `:play` Optional script string to play in terminal - `:out` Filename for screenshot image (default: `\"terminal.png\"`) - `:line-delay` Delay in milliseconds to wait after each line in `:play` script is sent to terminal (default: `1000`) - `:final-delay` Delay in milliseconds to wait after all lines in `:play` script are sent to terminal (default: `10000`) @@ -446,16 +472,18 @@ - `IToolkitRunSync` - `IToolkitSaveImage` - Usable examples from membrane library: `membrane.java2d/toolkit`, `membrane.skia/toolkit`" - [{:keys [play out line-delay final-delay width height color-scheme font-family font-size toolkit] :as opts}] + [{:keys [play command out line-delay final-delay width height color-scheme font-family font-size toolkit] :as opts}] (let [opts (merge default-screenshot-opts opts) - {:keys [play width height out line-delay final-delay color-scheme font-family font-size toolkit]} opts + {:keys [play command width height out line-delay final-delay color-scheme font-family font-size toolkit]} opts + command (or command (default-cmd)) + play (or play "") term-state (atom {:vt (vt/make-vt width height)}) toolkit (if toolkit toolkit (load-default-toolkit)) font (load-terminal-font toolkit font-family font-size)] (swap! term-state assoc - :pty (run-pty-process width height term-state)) + :pty (run-pty-process command width height term-state)) (doseq [line (string/split-lines play)] (send-input (:pty @term-state) line) (send-input (:pty @term-state) "\n") @@ -473,6 +501,10 @@ (.close (.getOutputStream pty))))) (comment + (run-term {:cmd ["ls" "-l"]}) + (run-term {:cmd ["top"]}) + (run-term {:font-family "MesloLGS NF" :font-size 14 :width 200} ) + (screenshot {:play "ls -l" :out "x.png"}) (screenshot {:play "ls -l\n" :out "y.png"}) (screenshot {:play "export PS1='$ '\nclear\nmsgcat --color=test | head -11" :out "z.png"})) diff --git a/src/com/phronemophobic/membrane/term/main.clj b/src/com/phronemophobic/membrane/term/main.clj index 3901212..43cc9d9 100644 --- a/src/com/phronemophobic/membrane/term/main.clj +++ b/src/com/phronemophobic/membrane/term/main.clj @@ -5,20 +5,26 @@ [membrane.ui :as ui] [membrane.toolkit :as tk] [com.phronemophobic.membrane.term.color-scheme :as color-scheme] - [docopt.core :as docopt])) + [docopt.core :as docopt] + [babashka.process :as process])) (def docopt-usage "membrane.term Usage: - membrane.term run-term [--width=] [--height=] \\ + membrane.term run-term [--command=] \\ + [--width=] [--height=] \\ [--color-scheme=] [--font-family=] [--font-size=] [--toolkit=] - membrane.term screenshot --play= [--width=] [--height=] \\ + membrane.term screenshot [--command=] [--play=] \\ + [--width=] [--height=] \\ [--color-scheme=] [--font-family=] [--font-size=]\\ [--out=] [--line-delay=] [--final-delay=] [--toolkit=] membrane.term --help Common Options: + -c, --command= Command to launch with, typically but not necessary a shell. + Default: on macOS and Linux defaults to $SHELL else /bin/bash + on Windows powershell -w, --width= Width in characters [default: 90] -h, --height= Height in characters [default: 30] --color-scheme= Local path or url to iTerm .itermcolors scheme file, uses internal scheme by default. @@ -110,6 +116,10 @@ Replace membrane.term with your appropriate Clojure tools CLI launch sequence. F (catch Throwable e {:error (ex-message e)}))) +(defn parse-command [v] + (when v + (process/tokenize (str v)))) + (defn- validate-font [args] (let [font-family (get args "--font-family") font-size (get args "--font-size") @@ -151,7 +161,8 @@ Replace membrane.term with your appropriate Clojure tools CLI launch sequence. F (defn -main [& args] (docopt/docopt (undo-line-continuations docopt-usage) args (fn result-fn [arg-map] - (let [arg-map (validate-args arg-map {"--width" (int-parser-validator 1) + (let [arg-map (validate-args arg-map {"--command" parse-command + "--width" (int-parser-validator 1) "--height" (int-parser-validator 1) "--play" parse-play-script "--color-scheme" parse-color-scheme