Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refine for cljdoc/codox #34

Merged
merged 11 commits into from
Dec 2, 2021
21 changes: 3 additions & 18 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,7 @@ All notable changes to this project will be documented in this file. This change

## [Unreleased]
### Changed
- Add a new arity to `make-widget-async` to provide a different widget shape.
- Document public API [#28](https://github.com/phronmophobic/membrane.term/issues/28)

## [0.1.1] - 2021-10-21
### Changed
- Documentation on how to make the widgets.

### Removed
- `make-widget-sync` - we're all async, all the time.

### Fixed
- Fixed widget maker to keep working when daylight savings switches over.

## 0.1.0 - 2021-10-21
### Added
- Files from the new template.
- Widget maker public API - `make-widget-sync`.

[Unreleased]: https://github.com/com.phronemophobic.membrane/term/compare/0.1.1...HEAD
[0.1.1]: https://github.com/com.phronemophobic.membrane/term/compare/0.1.0...0.1.1
## [0.9.0] - 2021-11-30
- Initial release to clojars
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# membrane.term

[![cljdoc](https://cljdoc.org/badge/com.phronemophobic/membrane.term)](https://cljdoc.org/d/com.phronemophobic/membrane.term)
[![clojurians slack](https://img.shields.io/badge/slack-join_chat-brightgreen.svg)](https://clojurians.slack.com/archives/C02KE09HMHV)
[![clojars](https://img.shields.io/clojars/v/com.phronemophobic/membrane.term.svg)](https://clojars.org/com.phronemophobic/membrane.term)

A simple terminal emulator in clojure.

## Rationale
Expand All @@ -12,6 +16,11 @@ Some reasons to use **membrane.term**:
- 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.
Expand Down
3 changes: 3 additions & 0 deletions doc/cljdoc.edn
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{:cljdoc.doc/tree [["Readme" {:file "README.md"}]
["Changelog" {:file "CHANGELOG.md"}]
["Developer Notes" {:file "doc/dev.md"}]]}
129 changes: 79 additions & 50 deletions src/com/phronemophobic/membrane/term.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@
(:import [com.pty4j PtyProcess WinSize]))


(defn start-pty []
(defn- start-pty []
(let [cmd (into-array String ["/bin/bash" "-l"])
pty (PtyProcess/exec ^"[Ljava.lang.String;" cmd
^java.util.Map (merge (into {} (System/getenv))
{"TERM" "xterm-256color"}))]
pty))

(def blank-cell [32 {}])
(defn blank-cell? [cell]
(def ^:private blank-cell [32 {}])
(defn- blank-cell? [cell]
(= cell blank-cell))

(defn vt-color->term-color
(defn- vt-color->term-color
[color-scheme vt-color]
(if (vector? vt-color)
(let [[r g b] vt-color]
Expand Down Expand Up @@ -101,7 +101,7 @@
:italic
:upright)))))

(defn term-line [color-scheme {:keys [:membrane.term/cell-width :membrane.term/cell-height] :as font} line]
(defn- term-line [color-scheme {:keys [:membrane.term/cell-width :membrane.term/cell-height] :as font} line]
(into []
(comp
(map-indexed vector)
Expand All @@ -125,10 +125,10 @@
foreground))))))
line))

(def term-line-memo (memoize term-line))
(def window-padding-height 8)
(def ^:private term-line-memo (memoize term-line))
(def ^:private window-padding-height 8)

(defn term-view [color-scheme {:keys [:membrane.term/cell-width :membrane.term/cell-height] :as font} vt]
(defn- term-view [color-scheme {:keys [:membrane.term/cell-width :membrane.term/cell-height] :as font} vt]
(let [screen (:screen vt)
cursor (let [{:keys [x y visible]} (:cursor screen)]
(when visible
Expand All @@ -153,14 +153,14 @@
(-> vt :screen :lines))
cursor))))

(defn writec-bytes [out bytes]
(defn- writec-bytes [out bytes]
(.write ^java.io.OutputStream out (byte-array bytes)))

(defn send-input [pty s]
(defn- send-input [pty s]
(let [out (.getOutputStream ^PtyProcess pty)]
(writec-bytes out (.getBytes ^String s))))

(def meta-shift-map
(def ^:private meta-shift-map
{
\` \~
\1 \!
Expand All @@ -187,7 +187,7 @@
\. \>
\/ \?})

(defn term-events [pty view]
(defn- term-events [pty view]
(let [out (.getOutputStream ^PtyProcess pty)]
(ui/on
:key-event
Expand Down Expand Up @@ -278,7 +278,7 @@
nil)
view)))

(defn run-pty-process [width height term-state]
(defn- run-pty-process [width height term-state]
(let [^PtyProcess
pty (doto ^PtyProcess (start-pty)
(.setWinSize (WinSize. width height)))]
Expand Down Expand Up @@ -313,10 +313,10 @@
:cell-height (tk/font-line-height toolkit term-font)
:descent-gap (- descent-offset baseline-offset)})))))

(defn load-default-toolkit []
(defn- load-default-toolkit []
@(requiring-resolve 'membrane.java2d/toolkit))

(def default-color-scheme
(def ^:private default-color-scheme
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like it would be useful to make public.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, good observation. I shall make it so.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to leave this one private and expose run-term and screenshots opts instead.
They both include default-color-scheme.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tend to lean more on the open side for these types of things, especially if they're just data. What's the reason for not making this public?

Copy link
Contributor Author

@lread lread Dec 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My thinking:

  • we are covered because it is included in both default-run-term-opts and default-screenshot-opts
  • it is added to cljdoc docs, and thought it might be superfluous.

But... can easily expose it if that makes more sense to you. I have no strong feeling on the matter. If it will be useful to you or others, let's expose it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phronmophobic lemme know your choice on this one, and I shall make it so.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, it makes sense to expose it!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good sir! It is done.

"Colors are specified a per membrane convention:
vectors of [red green blue] or [red green blue alpha] with values from 0 - 1 inclusive"
{:white [1 1 1]
Expand All @@ -340,14 +340,34 @@
:background [1 1 1]
:foreground [0 0 0]})

(def default-common-opts {:width 90
:height 30
:font-family :monospace
:font-size 12
:toolkit nil
:color-scheme default-color-scheme})
(def ^:private default-common-opts {:width 90
phronmophobic marked this conversation as resolved.
Show resolved Hide resolved
:height 30
:font-family :monospace
:font-size 12
:toolkit nil
:color-scheme default-color-scheme})

(defn run-term
"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`)
- `:font-family` OS installed font family name. Example: `\"Courier New\"`.
Use `:monospace` for default monospace (default: `:monospace`)
- `:font-size` Font point size (default: `12`)
- `:toolkit` Graphics toolkit, specify `\"java2d\"` or `\"skia\"` (default: `\"java2d\"`)
phronmophobic marked this conversation as resolved.
Show resolved Hide resolved
- `: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]`.
A color value must be specified for all of:
- ANSI colors
- `:white` `:black` `:red` `:green` `:yellow` `:blue` `:magenta` `cyan`
- `:bright-white` `:bright-black` `:bright-red` `:bright-green` `:bright-yellow` `:bright-blue` `:bright-magenta` `:bright-cyan`
- `:cursor` - Background color for cursor
- `:cursor-text` - Foreground color for cursor text
- `:background` - Default background color
- `:foreground` - Default text color"
([]
(run-term {}))
([opts]
Expand All @@ -374,33 +394,42 @@
(.close (.getInputStream pty))
(.close (.getOutputStream pty))))))


(defn screenshot
([opts]
(let [opts (merge default-common-opts
{:line-delay 1e3
:final-delay 10e3
:out "terminal.png"}
opts)
{:keys [play width height out line-delay final-delay color-scheme font-family font-size toolkit]} opts
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))
(doseq [line (string/split-lines (slurp play))]
(send-input (:pty @term-state) line)
(send-input (:pty @term-state) "\n")
(Thread/sleep line-delay))

(Thread/sleep final-delay)
(tk/save-image toolkit
out
(ui/fill-bordered (:background color-scheme) 5
(term-view color-scheme font (:vt @term-state))))
(println (str "Wrote screenshot to " out "."))

(let [^PtyProcess pty (:pty @term-state)]
(.close (.getInputStream pty))
(.close (.getOutputStream pty))))))
"Take a screenshot after playing a script line by line in a membrane.term terminal.
Terminal is not displayed and automatically exits after screenshot is written.

Requires `opts` map which accepts all options documented in [[run-term]] and:
phronmophobic marked this conversation as resolved.
Show resolved Hide resolved
- `:play` Path to script to play in terminal (**required**)
- `: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`)"
[opts]
(let [opts (merge default-common-opts
{:line-delay 1e3
:final-delay 10e3
:out "terminal.png"}
opts)
{:keys [play width height out line-delay final-delay color-scheme font-family font-size toolkit]} opts
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))
(doseq [line (string/split-lines (slurp play))]
(send-input (:pty @term-state) line)
(send-input (:pty @term-state) "\n")
(Thread/sleep line-delay))

(Thread/sleep final-delay)
(tk/save-image toolkit
out
(ui/fill-bordered (:background color-scheme) 5
(term-view color-scheme font (:vt @term-state))))
(println (str "Wrote screenshot to " out "."))

(let [^PtyProcess pty (:pty @term-state)]
(.close (.getInputStream pty))
(.close (.getOutputStream pty)))))
2 changes: 1 addition & 1 deletion src/com/phronemophobic/membrane/term/color_scheme.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(ns com.phronemophobic.membrane.term.color-scheme
(ns ^:no-doc com.phronemophobic.membrane.term.color-scheme
(:require [clojure.data.xml :as xml]
[clojure.data.zip.xml :as zxml]
[clojure.set :as cset]
Expand Down
5 changes: 1 addition & 4 deletions src/com/phronemophobic/membrane/term/main.clj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(ns com.phronemophobic.membrane.term.main
(ns ^:no-doc com.phronemophobic.membrane.term.main
(:require [clojure.java.io :as io]
[clojure.string :as string]
[com.phronemophobic.membrane.term :as term]
Expand Down Expand Up @@ -37,9 +37,6 @@ Replace membrane.term with your appropriate Clojure tools CLI launch sequence. F
| clojure -M:membrane.term run-term -w 133 -h 60
|")

(defn- parse-string [v]
(str v))

(defn parse-font-family [v]
(if (= "monospace" v)
:monospace
Expand Down