Skip to content

phronmophobic/membrane.term

Repository files navigation

membrane.term

cljdoc clojurians slack clojars

A simple terminal emulator in clojure. Built with membrane.

Rationale

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

Status

Pre 1.0 release. APIs and behavior are subject to change.

Installation

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"}}}

Command Line Usage

For usage help run:

clj -M:membrane.term --help

Run an interactive GUI terminal

clj -M:membrane.term run-term

A demo of the types of things you can do:

run-term-demo

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)

Run a headless terminal and take a screenshot

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:

play-msgcat-example

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 like lein 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:

play-deep-diff-example

Color Schemes

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:

play-msgcat-scheme-example

Fonts

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:

play-msgcat-font-example

Toolkits

You can specify a toolkit. Available options are "java2d" (the default) and "skia".

Java2d

The java2d toolkit will use swing for windowing, graphics, and events.

Skia

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

Discuss

Questions? Comments? Connect with us on clojurians slack in #membrane-term (join here)

License

Copyright © 2021 Adrian Smith

Distributed under the Eclipse Public License version 1.0.

About

A terminal emulator in pure clojure

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published