Skip to content

Commit

Permalink
Terminal can be launched with a specified command
Browse files Browse the repository at this point in the history
Added option :command to API and --command command line.

- screenshot :play/--play option is now optional
- Adapted sample play scripts to run /bin/bash as part
  of setup. On my system I run zsh with powerlevel10k and
  my fancy prompts were getting into README screenshots.
- On macOS and Linux :command defaults to $SHELL else
  /bin/bash
- Included support to default :command to powershell if on
  Windows. This gets us past launch, but there
  are still be many issues on Windows.
  Contributes to phronmophobic#29
- See README and docstrings for details on usage

Closes phronmophobic#3
  • Loading branch information
lread committed Dec 5, 2021
1 parent d1c8eb6 commit fc08852
Show file tree
Hide file tree
Showing 16 changed files with 130 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This change

## [Unreleased]
### Changed
- Can now specify the launch command [#3](https://github.com/phronmophobic/membrane.term/issues/3)
- Document public API [#28](https://github.com/phronmophobic/membrane.term/issues/28)
- **Breaking** `screenshot` `:play` option was file, is now string (command line is unaffected, `--play` still references a file) [#26](https://github.com/phronmophobic/membrane.term/issues/28)

Expand Down
48 changes: 44 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -75,6 +78,7 @@ Given play script `play-msgcat.sh`:
<!-- copied from doc/examples/play-msgcat.sh -->
```bash
# override prompt to something doc-friendly
/bin/bash # could alternatively use --command
export PS1="$ "
# print out some colors
clear
Expand All @@ -91,10 +95,11 @@ Membrane.term passes the script to the terminal character by character, then wri
<!-- generated by script/regen-screenshots.sh -->
![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)\
Expand All @@ -112,6 +117,7 @@ Given play script `play-deep-diff.sh`:
<!-- copied from doc/examples/play-deep-diff.sh -->
```bash
# our setup
/bin/bash # could alternatively use --command
export PS1="$ "
cd
mkdir -p target/term-screenshot
Expand All @@ -135,6 +141,40 @@ Produces `deep-diff.jpg`:
<!-- generated by script/regen-screenshots.sh -->
![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-msgcat-command-example](doc/images/screenshot-msgcat-command.png)
Or, for a contrived example, let's pretend you want to play some text in `vi` and take a screenshot.
Given file `an-ode-to-clojure.txt`:
```
iRoses are red
Violets are blue
Clojure is fun
And so are you
```

Let's run:
```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).
Expand Down
1 change: 1 addition & 0 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -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"}
Expand Down
4 changes: 4 additions & 0 deletions doc/examples/an-ode-to-clojure.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
iRoses are red
Violets are blue
Clojure is fun
And so are you
1 change: 1 addition & 0 deletions doc/examples/play-deep-diff.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/bin/bash -l
export PS1="$ "
cd
mkdir -p target/term-screenshot
Expand Down
1 change: 1 addition & 0 deletions doc/examples/play-msgcat.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/bin/bash -l
# override prompt to something doc-friendly
export PS1="$ "
# print out some colors
Expand Down
Binary file modified doc/images/screenshot-deep-diff.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/screenshot-msgcat-command.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/screenshot-msgcat-font.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/screenshot-msgcat-scheme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified doc/images/screenshot-msgcat.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/images/screenshot-vi-command.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
<artifactId>clojure</artifactId>
<version>1.10.3</version>
</dependency>
<dependency>
<groupId>babashka</groupId>
<artifactId>process</artifactId>
<version>0.0.2</version>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>data.xml</artifactId>
Expand Down
14 changes: 13 additions & 1 deletion script/regen-screenshots.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#/usr/bin/env bash
#!/usr/bin/env bash

set -eou pipefail

Expand Down Expand Up @@ -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 10 \
--out doc/images/screenshot-vi-command.png
58 changes: 45 additions & 13 deletions src/com/phronemophobic/membrane/term.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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"}))]
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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: value of 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]`.
Expand Down Expand Up @@ -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 []
Expand All @@ -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: value of 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`)
Expand Down Expand Up @@ -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")
Expand All @@ -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"}))
19 changes: 15 additions & 4 deletions src/com/phronemophobic/membrane/term/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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=<cols>] [--height=<rows>] \\
membrane.term run-term [--command=<cmdline>] \\
[--width=<cols>] [--height=<rows>] \\
[--color-scheme=<path>] [--font-family=<font>] [--font-size=<points>] [--toolkit=<toolkit>]
membrane.term screenshot --play=<path> [--width=<cols>] [--height=<rows>] \\
membrane.term screenshot [--command=<cmdline>] [--play=<path>] \\
[--width=<cols>] [--height=<rows>] \\
[--color-scheme=<path>] [--font-family=<font>] [--font-size=<points>]\\
[--out=<file>] [--line-delay=<ms>] [--final-delay=<ms>] [--toolkit=<toolkit>]
membrane.term --help
Common Options:
-c, --command=<cmdline> 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=<cols> Width in characters [default: 90]
-h, --height=<rows> Height in characters [default: 30]
--color-scheme=<path> Local path or url to iTerm .itermcolors scheme file, uses internal scheme by default.
Expand Down Expand Up @@ -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")
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit fc08852

Please sign in to comment.