MarkupString.Ansi 2.27.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package MarkupString.Ansi --version 2.27.1
                    
NuGet\Install-Package MarkupString.Ansi -Version 2.27.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MarkupString.Ansi" Version="2.27.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MarkupString.Ansi" Version="2.27.1" />
                    
Directory.Packages.props
<PackageReference Include="MarkupString.Ansi" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MarkupString.Ansi --version 2.27.1
                    
#r "nuget: MarkupString.Ansi, 2.27.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MarkupString.Ansi@2.27.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MarkupString.Ansi&version=2.27.1
                    
Install as a Cake Addin
#tool nuget:?package=MarkupString.Ansi&version=2.27.1
                    
Install as a Cake Tool

MarkupString.Ansi

Terminal styling for MarkupString: colours (the 16 standard ones, xterm-256 and truecolor), bold/faint/italic/underline/overline/strike/blink/invert, and links — either a URL or a command for the client to send.

One AnsiMarkup layer per span; a run's stack of layers folds into a single SGR sequence for the terminal, one <span> for HTML, or the nearest equivalent in the other formats. Transitions are written as diffs, so nested spans do not restate what is already in effect.

dotnet add package MarkupString.Ansi

Usage

using MarkupString;
using MarkupString.Ansi;
using MarkupString.Html;

MarkupRegistry.Default = MarkupRegistry.Empty.WithAnsi().WithHtml();

var text = MarkupText.Concat(
  MarkupText.Plain("Hello, "),
  MarkupText.Wrap(AnsiCodeParser.Parse("hr"), "world"));

text.Render(MarkupFormat.Ansi);   // Hello, \e[1;31mworld\e[0m
text.Render(MarkupFormat.Html);   // Hello, <span style="color: #ff5555">world</span>

var json = MarkupTextSerializer.Serialize(text);
var back = MarkupTextSerializer.Deserialize(json);

AnsiCodeParser.Parse takes MUSH ansi() syntax — hr, /R, +xterm200, #ff5555, <255 0 0> — and AnsiMarkup.Create(...) builds the same thing from named arguments. AnsiCodeWriter.Write(style) goes the other way, from a style to the codes that produce it.

Formats

WithAnsi() registers emitters for Ansi, Html, Pueblo, Mxp, BBCode and Markdown. Plain needs none: the body passes through. For Markdown it also draws a layout from its tree — a table as a pipe table, lists as lists — so a page made with BlockLayout can be stored in a wiki. See Markdown.

A command link (linkKind: LinkKind.Command) is written in each client's own dialect: <A XCH_CMD> for Pueblo, <SEND HREF> for MXP, an ms-cmd-link anchor carrying xch_cmd for HTML, and the bare text for a terminal. Pueblo and MXP are different dialects, and each client prints the other's tags as text.

An MXP client reads tags only on a line opened in secure mode. The core package's MarkupRegistry.WithMxpSecureLines() opens every line of Mxp output with ESC[1z. Use it on the registry that renders for an MXP connection, and leave it off the one used for tests, logs and previews.

A client that cannot show every colour gets its own registry: MarkupRegistry.Default.WithAnsiOutput(AnsiColorDepth.Xterm256) writes each colour as the nearest one the 256-colour palette has, Standard as the nearest of the sixteen, Attributes with no colour at all, and None with no SGR. It covers Ansi, Pueblo and Mxp. Pass hyperlinks: false for a terminal that prints OSC 8 instead of reading it.

WithAnsiOutput(new AnsiOutputOptions(depth, features) { Pictures = source }) describes one client fully. TerminalFeatures says what its terminal reads beyond colour:

Feature Written as
Hyperlinks a URL link as OSC 8 (ESC ] 8 ; ; url ST)
CommandLinks a command link as MSLP (ESC ] 68 ; 1 ; SEND ; command BEL, then the underlined text)
KittyGraphics a picture through the Kitty graphics protocol, with Unicode placeholders
InlineImages a picture as an iTerm2 inline image (ESC ] 1337 ; File=…)
Sixel a picture as sixel graphics
BlockArt a picture as coloured ▀/▄ half blocks, plain text any UTF-8 colour terminal shows
MovingPictures a moving picture played, through Kitty frames or an iTerm2 GIF, rather than its first frame

Pictures are drawn into the cells a Figure reserves when it is laid out for such a reader (LayoutContext.Pictures, which answers the cells a picture takes). Each row is marked with the figure's ImageMarkup, its Row saying which row of the picture it is, over the figure's text art, so a box, a flex row or a table around it lines up whichever way it ends up drawn. The pixels come from the host's ITerminalPictureSource: this package neither fetches nor decodes a file. Without the pixels, or without the feature, the row is its art.

  • Kitty sends the picture once per connection (a=T,U=1, a PNG in 4096-byte chunks, q=2 so nothing comes back as input) and writes each cell as U+10EEEE with row and column diacritics, the image id as a truecolor foreground. Placeholders are text: they wrap, scroll and are erased like it. MarkTransmitted is how the source says whether the terminal already has it. A moving picture (a TerminalPicture made from TerminalPictureFrames) sends its later frames after the first (a=f,X=1, each with its duration as z), sets the first frame's duration, and starts it looping (a=a,s=3,v=1); the terminal plays it with nothing more sent. Only a client with MovingPictures is sent the frames.
  • iTerm2 and sixel are pixels over the screen. A moving picture is sent to iTerm2, given MovingPictures, as a looping GIF. On the picture's first row the cursor makes room below (ESC D per row), comes back up, and draws the picture between ESC 7 and ESC 8; every row then steps over its cells with CSI n C, so no text is written over it. Sixel is the cells' size in pixels (CellWidth × CellHeight, 10 × 20 unless the host knows better; 0, which a terminal reports when it does not know, counts as unknown).
  • Half blocks letterbox the picture into two pixels a cell, at the client's colour depth. A client with no colour (Attributes or None) is sent the text art instead.

Each encoding (the PNG, the Kitty transmission, the sixels, the half-block rows) is made once per picture and size and kept with the TerminalPicture, for as long as the host keeps the picture: every other connection shown it at that size is sent a copy. So a host should hand out one TerminalPicture per picture rather than a new one per render.

None of these is sent on a guess: a MUD client that is not a terminal emulator may print them.

Terminals by name

TerminalProfile names the terminals this package knows and what each can be sent. A host identifies the client's terminal from what it reports (TerminalProfile.Identify("kitty(0.35.2)"), a telnet terminal type or an XTVERSION reply) or from the player (TerminalProfile.Find("wezterm")), and sends it only what the player turned on:

var options = AnsiOutputOptions.For(TerminalProfile.WezTerm, chosenByPlayer) with { Pictures = source };
Terminal Links Kitty (placeholders) iTerm2 images Sixel Moving pictures
kitty yes yes Kitty frames
Ghostty yes yes
WezTerm yes yes yes GIF
iTerm2 yes yes, in parts past 1 MiB yes GIF
Konsole yes yes yes
foot yes yes
xterm yes (-ti vt340)
Windows Terminal yes yes
mintty yes yes yes
VS Code yes yes (with images on) yes
Contour yes yes
Rio yes yes yes yes
mlterm yes yes
Alacritty, VTE, tmux yes

Every one draws half blocks. A cell is empty where the terminal lacks the feature or it could not be confirmed: several terminals read Kitty graphics without the Unicode placeholders this package writes (WezTerm, Konsole, Contour, VS Code), Ghostty does not yet animate them in a release, and iTerm2's own Kitty support is unannounced, so it is drawn for with its own protocol. Windows Terminal and Alacritty do not answer XTVERSION, so only a player can name them.

Reading terminal output

DecoderRegistry.Empty.WithVt().WithPictures() reads SGR, the C0 controls, OSC links, titles and palette, terminal queries, and Kitty, iTerm2 and sixel pictures into MarkupText lines. DisplayRegistry.Core.WithAnsi() resolves them for a web page or a cell grid. See Decoding and Display.

Styling the HTML output

The HTML-family emitters write ms-* classes for the attributes with a fixed rendering (bold, italic, underline, strike, overline, faint, blink, invert, and command links) and inline style for colours, which are open-ended. AnsiCss.Fixed is the stylesheet for those classes — include it once per page, or copy its rules into your own sheet.

Extension points

  • IAnsiStyleSource — implement it on your own IMarkup and this package's fold picks the style up, so a layer of yours can contribute bold or a colour without its own emitter per format.
  • IMarkupEmitter / IMarkupSetEmitter / IMarkupCodec — replace any of this package's registrations by adding yours to the registry afterwards.

AOT and trimming

IsAotCompatible; no reflection, no dynamic code. Registration is an explicit WithAnsi() call, so nothing depends on a type surviving the trimmer by name.

Licence

Apache-2.0. Source, guides and issues: SharpMUSH/MarkupString.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on MarkupString.Ansi:

Package Downloads
MarkupString.Html

Raw HTML tag markup for MarkupString — an anchor, a pre, a span — rendered as itself in the HTML, Pueblo and MXP formats and folded into terminal styling elsewhere, with checked construction and tag policies for untrusted input.

MarkupString.Mxp

MXP for MarkupString: writes the shared vocabulary — sounds, music, pictures, panes, gauges, status, variables, link expiry, relocation, login prompts — as MXP tags, holding each to what the client said it supports.

SharpMUSH.Library

SharpMUSH plugin contract surface (interim). External SharpMUSH plugins reference this package to write [SharpPlugin] : PluginBase entry types with [SharpCommand]/[SharpFunction] members. Aligned to PluginContractVersion 4.0.0.

MarkupString.Extensions.DependencyInjection

Microsoft.Extensions.DependencyInjection setup for MarkupString: AddMarkupString() registers the markup, decoder and display registries, a shared picture cache, a decoder factory and the link policy, configured in code or bound from configuration.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.31.3 0 11/15/2026
2.31.2 198 11/15/2026
2.31.1 187 11/15/2026
2.31.0 1,535 11/13/2026
2.30.0 338 11/12/2026
2.29.1 121 11/11/2026
2.29.0 110 11/11/2026
2.28.1 136 11/11/2026
2.28.0 1,589 11/10/2026
2.27.3 625 11/9/2026
2.27.2 365 11/7/2026
2.27.1 187 11/7/2026
2.27.0 149 11/7/2026
2.26.0 133 11/7/2026
2.25.0 1,757 11/3/2026
2.24.2 1,645 10/29/2026
2.24.1 122 10/29/2026
2.24.0 379 10/28/2026
2.23.1 826 10/27/2026
2.23.0 1,090 10/24/2026
Loading failed