npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

magic-symbols

v1.3.1

Published

Inline color syntax and parsing for ANSI/Xterm256.

Downloads

21

Readme

magic-symbols

Table of Contents

magic-symbols is a color syntax and parser for ANSI and Xterm256 colors, created with MU* and similar text games in mind. The syntax is inspired by and adapted from the implementation used by the Evennia MUD library.

Installation

npm install magic-symbols

Usage

magic-symbols implements two main functions: parse and strip.

const { parse, strip } = require("magic-symbols");

const coloredString = "|rhello world";

parse(coloredString); // "\u001b[31mhello world"

strip(coloredString); // "hello world"

parse(coloredString, false); // (Parsed in ANSI-only mode)

// Escape sequences with '||'

const escapedString = "||rhello world";

parse(escapedString); // "|rhello world"

strip(escapedString); // "hello world"

Syntax

Note: See the Custom Syntax section for information on customizing the parser syntax.

ANSI Colors

Setting ANSI colors inline is easiest with the |{letter} notation. The color's brightness depends on the case of the letter:

Uppercased letters are automatically un-highlighted.

  • |X Un-Highlighted Black (Note - This is often invisible on termimals.)
  • |R Un-Highlighted Red
  • |G Un-Highlighted Green
  • |Y Un-Highlighted Yellow
  • |B Un-Highlighted Blue
  • |M Un-Highlighted Magenta
  • |C Un-Highlighted Cyan
  • |W Un-Highlighted White

Lowercased letters are automatically highlighted.

  • |x Highlighted Black
  • |r Highlighted Red
  • |g Highlighted Green
  • |y Highlighted Yellow
  • |b Highlighted Blue
  • |m Highlighted Magenta
  • |c Highlighted Cyan
  • |w Highlighted White

To set the background color in ANSI, use the |[{letter} notation, using the same colors as with foregrounds.

  • |[X Un-Highlighted Black Background
  • |[R Un-Highlighted Red Background
  • |[G Un-Highlighted Green Background
  • |[Y Un-Highlighted Yellow Background
  • |[B Un-Highlighted Blue Background
  • |[M Un-Highlighted Magenta Background
  • |[C Un-Highlighted Cyan Background
  • |[W Un-Highlighted White Background

Note that by default, normal ANSI does not allow for highlighted background colors. We "fake" these colors by relying on the Xterm256 implementation, but if the parser is run in ANSI-only mode these will fall back to the un-highlighted versions above.

  • |[x Highlighted Black Background
  • |[r Highlighted Red Background
  • |[g Highlighted Green Background
  • |[y Highlighted Yellow Background
  • |[b Highlighted Blue Background
  • |[m Highlighted Magenta Background
  • |[c Highlighted Cyan Background
  • |[w Highlighted White Background

If we want to handle colors and highlighting manually, we can use the '|!{letter} syntax.

  • |!X Black
  • |!R Red
  • |!G Green
  • |!Y Yellow
  • |!B Blue
  • |!M Magenta
  • |!C Cyan
  • |!W White

To control the colors' brightness, we can use the 'highlight' and 'unhighlight' tags:

  • |h Highlight
  • |H Un-Highlight

We can reset all color information with the 'reset' tag.

  • |n Reset / Normal

Text can also be underlined with the 'underline' tag:

  • |u Underline

Xterm256

Xterm256 tags come in two main flavors: a 6x6x6 color cube, and a range of grayscale values. (It also defines the 16 original ANSI colors, but we handle those with the above ANSI syntax).

Rather than with letters, we select Xterm colors with the |RGB notation, where R, G, and B are each integers between 0 and 5, and determine the intensity of each color.

(Examples)

  • |500 - Bright Red
  • |505 - Bright Magenta
  • |444 - Light Gray

To set these colors as backgrounds, we use the background notation |[RGB.

(Examples)

  • |[500 - Bright Red Background
  • |[505 - Bright Magenta Background
  • |[444 - Light Gray Background

We can also select between 26 different grayscale values using the notation |={letter}, where the letter can be any lowercase letter from a to z.

(Examples)

  • |=a Black (darkest value)
  • |=m Gray (medium value)
  • |=z White (lightest value)

We can of course set the background to these colors with the |[={letter} notation:

(Examples)

  • |[=a Black Background (darkest value)
  • |[=m Gray Background (medium value)
  • |[=z White Background (lightest value)

Advanced Syntax

Recall Symbols

When parsing a string, magic-symbols will always "remember" the last 9 color symbols it processed. It is possible to refer to these symbols via the "recall symbol", which is |<d by default, where d is any integer on the [1-9] interval. For example, |<1 will resolve to whichever symbol was used one step before the "current" symbol. Likewise, |<5 will resolve to the symbol used 5 steps before the current symbol. (Note that if the process hasn't seen (d+1) symbols yet, the recall symbol will be ignored.)

// A simple example that resolves to the "previous" color symbol.
// We want the text in the middle to be blue, before "reverting" to red.
const coloredString = "|r(this is red) |b(this is blue) |<1(this is also red)";
const resolvesTo = "|r(this is red) |b(this is blue) |r(this is also red)";

parse(coloredString) === parse(resolvesTo); // true

In most cases it would be better to simply write the explicit color code, but in certain cases (such as string concatenation), we might know that we want to repeat a color, but not which color.

This feature is fairly dumb, and will always resolve to the symbol used exactly d steps ago (including resolved recall symbols), whether or not that symbol makes sense in the current position. Additionally, the symbol's behavior of resolving to an empty string (when there is insufficient history for it) can cause side effects if used carelessly.

Custom Syntax

magic-symbols additionally exposes a setSyntax method that allows the user to specify the character sequences that mark the start of a particular color tag. There are seven such sequences in total, and each of them must be defined in the syntax definition object. Any missing symbol will be replaced with the default |-based equivalent.

While the sequences are not required to be related to one another, note that the parser will replace the escape_symbol with the unescape_symbol. Therefore, it is usually simplest to have every sequence begin with some common leading character, and use two of that character for your escape (e.g. using || to escape | ).

Note: To reset the syntax to default, simply pass in an empty object ( setSyntax({}) ).

const { parse, setSyntax } = require("magic-symbols");

// Example
// Set the syntax to one based on the '~' character.

setSyntax({
  // Foreground Symbol ( Default: "|" )
  foreground_symbol: "~",

  // Foreground Grayscale Symbol ( Default: "|=" )
  foreground_grayscale_symbol: "~-",

  // Background Symbol: ( Default: "|[" )
  background_symbol: "~:",

  // Background Grayscale Symbol ( Default: "|[=" )
  background_grayscale_symbol: "~:-",

  // No Hilite Symbol ( Default: "|!" )
  no_hilite_symbol: "~+",

  // Escape Symbol ( Default: "||" )
  escape_symbol: "~~",

  // Unescape Symbol ( Default: "|" )
  unescape_symbol: "~",

  // Recall Symbol ( Default: "|<")
  recall_symbol: "~<",
});

// 'parse' and 'strip' are updated automatically to use
// the new syntax

const coloredString = "~rhello world";
parse(coloredString); // "\u001b[31mhello world"
strip(coloredString); // "hello world"

Xterm256 Aliases

If a particular Xterm256 color code is commonly used, it may be useful to define a shorthand code for it. For instance, you may wish to map |534 and |[534 (pink) to |p and |[p respectively. To acheive this, the setSyntax method also accepts an xtermAliases object to specify (alias -> code) pairings.

Note that there are some limitations and side-effects to keep in mind when defining aliases.

  • Aliases may not overwrite existing color codes. This includes Xterm256 Grayscale and basic ANSI colors such as |r.
  • Xterm256 codes and aliases will be parsed before ANSI codes. Therefore it is possible to define codes like |bg for blue-green, and the alias will take priority over |b.
  • Longer aliases will be considered before shorter ones. For example, |sa will be consdered before |s, if both are defined. However, keep in mind...
  • Defining multiple codes with common prefixes can lead to unexpected behavior. For example, suppose both |s and |sa were defined as separate aliases. Because the longer code is parsed first, the text |salmond will be parsed as lmond, even if this is not the preferred behavior.

In general, it is safest to stick to single-character codes that are distinct from the default ANSI codes. That is, try to avoid codes starting with: x, r, g, y, b, m, c, w, or their uppercased variants. If defining a multi-letter code, make sure that no other code is a prefix for it, and that it won't accidentally occur when a shorter code is placed before plain text, like in the 'almond' example. (One way to avoid this might be to add a terminating symbol like ; or - to the custom code; see below for an example.)

const { parse, setSyntax } = require("magic-symbols");

// Example
// Add three "new" color codes to let us use
// pink, sea-green, and orange more easily.

setSyntax({
  // ... custom token syntax ...

  xtermAliases: {
    // Pink
    p: "543",

    // Sea Green (Note: See above for warning about multi-letter codes)
    "sg;": "141",

    // Orange
    o: "410",
  },
});

// 'parse' and 'strip' are updated automatically to use
// the new syntax

const coloredString = "|phello world";
parse(coloredString); // "\u001b[38;5;218mhello world"