https://github.com/lambdaisland/ansi
Parse ANSI color escape sequences to Hiccup syntax
https://github.com/lambdaisland/ansi
Last synced: 6 months ago
JSON representation
Parse ANSI color escape sequences to Hiccup syntax
- Host: GitHub
- URL: https://github.com/lambdaisland/ansi
- Owner: lambdaisland
- License: mpl-2.0
- Created: 2018-04-18T16:54:04.000Z (over 7 years ago)
- Default Branch: main
- Last Pushed: 2022-04-27T14:14:00.000Z (over 3 years ago)
- Last Synced: 2025-06-16T11:29:52.304Z (7 months ago)
- Language: Clojure
- Size: 46.9 KB
- Stars: 33
- Watchers: 5
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# lambdaisland/ansi
[](https://circleci.com/gh/lambdaisland/ansi) [](https://cljdoc.org/d/lambdaisland/ansi) [](https://clojars.org/lambdaisland/ansi) [](https://codecov.io/gh/lambdaisland/ansi)
Parse ANSI color codes, optionally convert to Hiccup.
## Features
- Clojure and ClojureScript support (cljc)
- parses color codes and bold, including 8-bit and 24-bit (rgb) colors
- Fine-grained building blocks, convert to Hiccup or a format of your choice
## Usage
Colors in your terminal work by embedding "escape codes" in the text. This
library contains utilities for parsing and transforming these escape codes.
Terminals are stateful, you can set a property like foreground, background, or
bold, and it will stay that way until it gets changes or unset (reset).
The starting point for dealing with a textual stream is `token-stream`. It takes
a string as input, and returns a sequence of "tokens", either plain text, or a
map of properties that are being set at that point in the stream.
``` clojure
(require '[lambdaisland.ansi :as ansi])
(ansi/token-stream "Hello,\033[1;30;45m world!")
;;=> ["Hello," {:bold true, :foreground [:rgb 0 0 0], :background [:rgb 205 0 205]} " world!"]
```
To convert this to a different format, you need to know which styles apply to
which piece of text, this is what the `apply-props` stateful transducer is for.
It keeps track of the "terminal state", and returns pairs of style information
and text.
``` clojure
(def text "\033[1m here \033[45m we \033[31m go! \033[0m done.")
(sequence ansi/apply-props (ansi/token-stream text))
;;=>
([{:bold true} " here "]
[{:bold true
:background [:rgb 205 0 205]} " we "]
[{:bold true
:background [:rgb 205 0 205]
:foreground [:rgb 205 0 0]} " go! "]
[{} " done."])
```
Now you have all the information available to convert this into Hiccup, you can
convert a single one of these pairs with `chunk->hiccup`.
``` clojure
(ansi/chunk->hiccup [{:bold true, :foreground [:rgb 100 200 0]} "so far..."])
;;=> [:span {:style {:color "rgb(100,200,0)", :font-weight "bold"}} "so far..."]
```
There's a convenience function to do this in one go, `text->hiccup`
``` clojure
(ansi/text->hiccup text)
;;=>
([:span {:style {:font-weight "bold"}} " here "]
[:span {:style {:background-color "rgb(205,0,205)", :font-weight "bold"}}
" we "]
[:span {:style {:color "rgb(205,0,0)",
:background-color "rgb(205,0,205)",
:font-weight "bold"}}
" go! "]
[:span {} " done."])
```
If you deal with streaming text, then you need to incrementally apply these
state changes, carrying over the old state whenever you receive more input.
In this case the `hiccup-xform` might be useful.
``` clojure
(require '[clojure.core.async :as async])
(def channel (chan 1 ansi/hiccup-xform))
(async/go-loop [hiccup-el (async/! channel "\033[1mhello,\033[35mworld!"))
(async/go (async/>! channel " life is \033[0mgreat!"))
```
## License
© Arne Brasseur 2018
Available under the terms of the Mozilla Public License Version 2.0, see LICENSE.txt