A simple terminal emulator in clojure. Built with membrane.
I thought it would be fun. There's not much code. All of the ANSI parsing work is done by asciinema/vt. membrane.term
is just small UI on top.
Some reasons to use membrane.term:
- If you need to programmatically control, inspect, drive, or manipulate a terminal
- If you want to learn more about how terminal emulators work
- If you'd like to embed a terminal somewhere. There's not really a guide for embedding, but if you file an issue, I can provide some tips
- If you'd like to capture terminal screenshots for documentation
Pre 1.0 release. APIs and behavior are subject to change.
Membrane.term works on macOS and Linux operating systems.
To invoke via clj -M:membrane.term
add the following alias to your deps.edn
:
{:aliases
{:membrane.term
{:replace-deps
{com.phronemophobic/membrane.term {:git/url "https://github.com/phronmophobic/membrane.term.git"
:git/sha "7b973adc4910729042736d8a84e5fce4f4f43722"}
;; the next 2 optional deps appease pty4j which does some logging
;; change nop to simple if you'd actually like to see the log lines
org.slf4j/log4j-over-slf4j {:mvn/version "1.7.32"}
org.slf4j/slf4j-nop {:mvn/version "1.7.32"}}
:main-opts ["-m" "com.phronemophobic.membrane.term.main"]}}
:mvn/repos
;; pty4j is currently only available from the jetbrains maven repo
{"jetbrains-intellij-dependencies" {:url "https://packages.jetbrains.team/maven/p/ij/intellij-dependencies"}}}
For usage help run:
clj -M:membrane.term --help
clj -M:membrane.term run-term
A demo of the types of things you can do:
You can also optional specify:
-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
choose a different color scheme--font-family
choose an OS installed font (default: monospace)--font-size
specify font point size (default: 12)--toolkit
specify the toolkit (default: java2d)
Play a script in a headless terminal and write an image to terminal.png.
Given play script play-msgcat.sh
:
# override prompt to something doc-friendly
export PS1="$ "
# print out some colors
clear
msgcat --color=test | head -11
If we run:
clj -M:membrane.term screenshot --play play-msgcat.sh --height 14
Membrane.term passes the script to the terminal character by character, then writes a screenshot to terminal.png
:
You must specify:
-p, --play
script to play
You can also optionally specify:
-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)
Image format determined by filename extension, supported extensions are.png
,.webp
,.jpeg
and.jpg
.--color-scheme
choose a different color scheme--font-family
choose an OS installed font (default: monospace)--font-size
specify font point size (default: 12)--toolkit
specify the toolkit (default: java2d)--line-delay
if your play script runs a command likelein repl
, the underlying program might not be ready to accept input immediately.
You can specify a delay in ms to wait after each line is played to the terminal (default: 1000)--final-delay
after the last line of your play script is run, you might need to wait for it to generate all of its output.
You can specify a delay in ms to wait after the entire script has been played to the terminal (default: 10000)
Given play script play-deep-diff.sh
:
# our setup
export PS1="$ "
cd
mkdir -p target/term-screenshot
cd target/term-screenshot
echo '{:deps {lambdaisland/deep-diff2 {:mvn/version "2.0.108"}}}' > deps.edn
# we clear to wipe setup output
clear
clojure
(require '[lambdaisland.deep-diff2 :as ddiff])
(ddiff/pretty-print (ddiff/diff {:a 1 :b 2} {:a 1 :c 3}))
Let's increase the line delay to give the Clojure REPL a chance to start up before feeding it input. We'll also reduce the final delay, we just don't need 10 seconds for this one:
clj -M:membrane.term screenshot --play play-deep-diff.sh \
--width 80 --height 9 \
--final-delay 1000 --line-delay 3000 \
--out deep-diff.jpg
Produces deep-diff.jpg
:
There are boatloads of terminal color schemes available at iTerm2-Color-Schemes.
Review what you might like from their screenshots, then find the corresponding .itermcolors
file under their schemes directory.
Use the --color-scheme
option to specify an .itermcolors
file, either from a copy you have downloaded:
clj -M:membrane.term run-term --width 90 --height 30 \
---color-scheme "Builtin Solarized Dark.itermcolors"
...or directly from the raw GitHub URL:
clj -M:membrane.term screenshot --play play-msgcat.sh --height 14 \
--color-scheme "https://raw.githubusercontent.com/mbadolato/iTerm2-Color-Schemes/master/schemes/Builtin%20Solarized%20Dark.itermcolors"
The screenshot command produces terminal.png
:
You can specify a font family and size. The font must be OS installed and is assumed to be monospace.
Let's pretend that, for whatever reason, you've fallen in love with the Nova Mono font, and have installed it on your system.
To use this font in an interactive membrane.term terminal, specify its installed name. Here we've opted for a point size of 16:
clj -M:membrane.term run-term --font-family "NovaMono" --font-size 16
The same options are available for screenshots:
clj -M:membrane.term screenshot --play play-msgcat.sh --height 14 \
--font-family "NovaMono" --font-size 16
produces terminal.png
:
You can specify a toolkit. Available options are "java2d" (the default) and "skia".
The java2d toolkit will use swing for windowing, graphics, and events.
The skia toolkit will use skia for graphics and glfw for windowing and events. Using the skia toolkit requires the following extra dependency:
M1 mac:
com.phronemophobic.membrane/skialib-macosx-aarch64 {:mvn/version "0.9.31.0-beta"}
Non-M1 mac:
com.phronemophobic.membrane/skialib-macosx-x86-64 {:mvn/version "0.9.31.0-beta"}
Linux
com.phronemophobic.membrane/skialib-linux-x86-64 {:mvn/version "0.9.31.0-beta"}
If running from the membrane.term
project, you can use the :skia
alias to add the dependency:
clojure -M:membrane.term:skia run-term --toolkit skia
Questions? Comments? Connect with us on clojurians slack in #membrane-term (join here)
Copyright © 2021 Adrian Smith
Distributed under the Eclipse Public License version 1.0.