Skip to content

Commit

Permalink
Merge pull request #34 from lread/lread-docstrings
Browse files Browse the repository at this point in the history
Refine for cljdoc/codox
  • Loading branch information
phronmophobic authored Dec 2, 2021
2 parents 06f4fe6 + 7cfb8ac commit f6d59d7
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 87 deletions.
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"}]]}
195 changes: 131 additions & 64 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,12 +313,11 @@
: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
"Colors are specified a per membrane convention:
vectors of [red green blue] or [red green blue alpha] with values from 0 - 1 inclusive"
"Default color-scheme used in [[default-run-term-opts]] and [[default-screenshot-opts]]"
{:white [1 1 1]
:black [0 0 0]
:red [0.76 0.21 0.13]
Expand All @@ -340,67 +339,135 @@
: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
:height 30
:font-family :monospace
:font-size 12
:toolkit nil
:color-scheme default-color-scheme})

(def default-run-term-opts "Default options used for [[run-term]]" default-common-opts)

(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`)
- `: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
- `: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 (default: `membrane.toolkit/java2d`)
- An object that must satisfy the following
[`membrane.toolkit`](https://github.com/phronmophobic/membrane/blob/master/src/membrane/toolkit.clj) interfaces:
- `IToolkit`
- `IToolkitLogicalFontFontFamily`
- `IToolkitFontExists`
- `IToolkitFontMetrics`
- `IToolkitFontAdvanceX`
- `IToolkitFontLineHeight`
- `IToolkitRunSync`
- Usable examples from membrane library: `membrane.java2d/toolkit`, `membrane.skia/toolkit`"
([]
(run-term {}))
([opts]
(let [opts (merge default-common-opts opts)
([{:keys [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
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))
(tk/run-sync
toolkit
(fn []
(let [{:keys [pty vt]} @term-state]
(term-events pty
(term-view color-scheme font vt))))
{:window-title "membrane.term"
:window-start-width (* width (:membrane.term/cell-width font))
:window-start-height (+ window-padding-height (* height (:membrane.term/cell-height font)))})

(let [^PtyProcess pty (:pty @term-state)]
(.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 "."))
(tk/run-sync
toolkit
(fn []
(let [{:keys [pty vt]} @term-state]
(term-events pty
(term-view color-scheme font vt))))
{:window-title "membrane.term"
:window-start-width (* width (:membrane.term/cell-width font))
:window-start-height (+ window-padding-height (* height (:membrane.term/cell-height font)))})

(let [^PtyProcess pty (:pty @term-state)]
(.close (.getInputStream pty))
(.close (.getOutputStream pty))))))

(def default-screenshot-opts "Default options used for [[screenshot]]" (merge default-common-opts {:line-delay 1e3
:final-delay 10e3
:out "terminal.png"}))

(defn screenshot
"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:
- `: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`)
- `: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]`.
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
- `: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 (default: `membrane.toolkit/java2d`)
- An object that must satisfy the following
[`membrane.toolkit`](https://github.com/phronmophobic/membrane/blob/master/src/membrane/toolkit.clj) interfaces:
- `IToolkit`
- `IToolkitLogicalFontFontFamily`
- `IToolkitFontExists`
- `IToolkitFontMetrics`
- `IToolkitFontAdvanceX`
- `IToolkitFontLineHeight`
- `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}]
(let [opts (merge default-screenshot-opts 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

0 comments on commit f6d59d7

Please sign in to comment.