JSPM

  • Created
  • Published
  • Downloads 12
  • Score
    100M100P100Q59644F
  • License MIT

A simple rendering engine for rich text terminal output with its own markup language.

Package Exports

  • ansie
  • ansie/index.ts

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ansie) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Ansie

A library used to render a simplified html-like declarative language to rich terminal text.

For example,

<bold>Title</bold>
<color fg="gray">Subtitle goes here</color>
A description using the default text will appear here.  But you can also include
<underline style="single"><italics>nested</italics></underline> values.

The library contains three components:

  1. Parser - this is used to convert a string to an Abstract Syntax Tree. You probably won't need to use this as it represents an incremental state
  2. Compiler - Converts the abstract syntax tree to renderer terminal text. You can use this if you want to just pass in markup to get your terminal string.
  3. Composer - A convenient set of methods to build markup through a functional syntax. You can use this if you want a nicer, functional way of building your markup.

Installation

bun add ansie

or

npm install ansie

Usage as CLI

⚠️ This is a very early release so the CLI and the markup may change

You can access the functionality in ansie through a CLI as in:

> ansie -m "<bold>This is bold</bold>"

This will output:

This is bold

Usage as API

⚠️ This is a very early release so the API and the markup may change

import { compile } from 'ansie';
console.log(compile('<bold>This is bold</bold>'));

// Output: "\u001b[1mThis is bold\u001b[21m"
import { Composer } from 'ansie';
console.log(Composer.start().bold('This is bold').end());
// Output: "\u001b[1mThis is bold\u001b[21m"

Ansie Markup

The markup language follows XML rules in that it uses a declarative tag-based system of angle brackets and attributes. The supported tags available today are:

  1. <color name="[see colors below]"></color>
  2. <bold></bold>
  3. <italics></italics>
  4. <underline style="[single|double]"></underline>

Additionally you can have regular text that is not enclosed in a tag.

Tags can be nested and will render the way you would expect. So, for example,

<color name="red">This is red but <color name="blue"> this is blue </color> and this is red again </color>

Underline Table

Underline Styles
single
double

Color Table

Color Names
black
red
green
yellow
blue
magenta
cyan
white
gray
brightred
brightgreen
brightyellow
brightblue
brightmagenta
brightcyan
brightwhite
brightgray

Composition

The library includes a Composer that allows for easy composition through a programmatic interface. This is not required to use Ansie. For some people it's a little easier to use an imperative approach for building views. Here's an exmaple of how to build markup programmatically:

const markup = compose([
    .bold('Title')
    .br()
    .underline('single', 'Subtitle')
    .br()
    .text('This is some text that is not formatted')
    .color('red', undefined, 'Some red text')
]).toString()

console.log(markup);
console.log(compile(markup))

// Line 1: <bold>Title</bold><br/><underline type="single">Subtitle</underline><br/>This is some text that is not formatted<color fg="red">Some red text</color>
// Line 2: \x1b[1mTitle\x1b[22m\n\x1b[4mSubtitle\x1b[24m\nThis is some text that is not formatted\x1b[31mSome red text\x1b[39;49m

Convenience Functions

Function Params Description
bold Child Nodes Contained items are surrounded with <bold>
underline type, Child Nodes Contained items are surrounded with <underline>
italics Child Nodes Contained items are surrounded with <italics>
br None Inserts a <br/>
text None Inserts text as-is (but will replace :emoji:)
color fg, bg, Child Nodes Contained items are surrounded with <color>
list bullet, Child Nodes Adds a bulleted list item for each item in the passed array of nodes
bundle Sibling Nodes Outputs a set of sibling nodes - useful when passing to other functions that need a single node
raw Valid Markup Allows you to combine raw markup with composed items from above

Some of these nodes accept children because they add some formatting to a finite set of contained items. For these you will pass in the children as an array to the function, after the other properties that customize the styling.

For example, the color function takes a foreground, background and an array of children:

console.log(color('white', 'red', 'This text will be colored white with a red background'))

// <color fg="white" bg="red">This text will be colored white with a red background</color>

You can create lists with the list method which takes a bullet style followed by a list of items to prepend the bullet to.

console.log(list('* ', ['Item 1', 'Item 2', 'Item 3']))

// * Item 1<br/>* Item 2<br/>* Item 3<br/>

You can also create more complex output using bundles which will take arbitrary array of nodes and render them in order.

console.log(bundle(['Property: ', bold('Bold Value')]))

// Property: <bold>Bold Value</bold>
console.log(bundle(['Property: ', raw('<bold>Bold Text</bold>')]))

// Property: <bold>Bold Text</bold>

Using these you can create relatively complex compositions imperatively.

Developing

This package is developed using bun to make the building and packaging of Typescript easier. If you have an interest in making this npm compatible please submit a PR.

To install dependencies:

bun install

To update the parser if you made changes to the grammar:

bun run parser:generate

If you added new tests to test-strings.ts you will need to generate a new fixtures.json file which you can do by running:

bun run test:record

Updating the Grammar

The parser code in this context is generated from a grammar file (terminal-markup.peggy) using the peggy library. If you want to update the parser, you would need to modify the grammar file and then re-run the generate.ts script to create a new parser. Here are the steps:

  1. Navigate to the terminal-markup.peggy file in your project directory.
  2. Make the necessary changes to the grammar. This could involve adding new rules, modifying existing ones, or fixing bugs.
  3. Run the generate.ts script to generate a new parser. You can do this by running bun parser:generate
  4. The updated parser will be written to generated-parser.js.
  5. Any new grammar that added or fixed remember to add a test to test/fixtures.json