A Library to Convert Ansi Escapes (Terminal Formatting/Color Codes) to HTML

A library to convert ANSI escapes (terminal formatting/color codes) to HTML

There seems to be an HTML::FromANSI Perl module.

Converting ANSI escape sequences to HTML using PHP

I don't know of any such library in PHP. But if you have a consistent input with limited colors, you can accomplish it using a simple str_replace():

$dictionary = array(
'ESC[01;34' => '<span style="color:blue">',
'ESC[01;31' => '<span style="color:red">',
'ESC[00m' => '</span>' ,
);
$htmlString = str_replace(array_keys($dictionary), $dictionary, $shellString);

How can I convert the output of `git diff --color-words` to HTML?

This question asks about converting ANSI escape sequences into HTML color directives, and the accepted answer is a link to the Perl module HTML::FromANSI, in CPAN.

How to use the ANSI Escape code for outputting colored text on Console

I'm afraid you forgot the ESC character:

#include <cstdio>

int main()
{
printf("%c[%dmHELLO!\n", 0x1B, 32);
}

Unfortunately it will only work on consoles that support ANSI escape sequences (like a linux console using bash, or old Windows consoles that used ansi.sys)

QTextEdit and colored bash-like output emulation

Finally, I found the approach (it is understood, that QTextEdit::setReadOnly(true)):

// based on information: http://en.m.wikipedia.org/wiki/ANSI_escape_code http://misc.flogisoft.com/bash/tip_colors_and_formatting http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
void MainWindow::parseEscapeSequence(int attribute, QListIterator< QString > & i, QTextCharFormat & textCharFormat, QTextCharFormat const & defaultTextCharFormat)
{
switch (attribute) {
case 0 : { // Normal/Default (reset all attributes)
textCharFormat = defaultTextCharFormat;
break;
}
case 1 : { // Bold/Bright (bold or increased intensity)
textCharFormat.setFontWeight(QFont::Bold);
break;
}
case 2 : { // Dim/Faint (decreased intensity)
textCharFormat.setFontWeight(QFont::Light);
break;
}
case 3 : { // Italicized (italic on)
textCharFormat.setFontItalic(true);
break;
}
case 4 : { // Underscore (single underlined)
textCharFormat.setUnderlineStyle(QTextCharFormat::SingleUnderline);
textCharFormat.setFontUnderline(true);
break;
}
case 5 : { // Blink (slow, appears as Bold)
textCharFormat.setFontWeight(QFont::Bold);
break;
}
case 6 : { // Blink (rapid, appears as very Bold)
textCharFormat.setFontWeight(QFont::Black);
break;
}
case 7 : { // Reverse/Inverse (swap foreground and background)
QBrush foregroundBrush = textCharFormat.foreground();
textCharFormat.setForeground(textCharFormat.background());
textCharFormat.setBackground(foregroundBrush);
break;
}
case 8 : { // Concealed/Hidden/Invisible (usefull for passwords)
textCharFormat.setForeground(textCharFormat.background());
break;
}
case 9 : { // Crossed-out characters
textCharFormat.setFontStrikeOut(true);
break;
}
case 10 : { // Primary (default) font
textCharFormat.setFont(defaultTextCharFormat.font());
break;
}
case 11 ... 19 : {
QFontDatabase fontDatabase;
QString fontFamily = textCharFormat.fontFamily();
QStringList fontStyles = fontDatabase.styles(fontFamily);
int fontStyleIndex = attribute - 11;
if (fontStyleIndex < fontStyles.length()) {
textCharFormat.setFont(fontDatabase.font(fontFamily, fontStyles.at(fontStyleIndex), textCharFormat.font().pointSize()));
}
break;
}
case 20 : { // Fraktur (unsupported)
break;
}
case 21 : { // Set Bold off
textCharFormat.setFontWeight(QFont::Normal);
break;
}
case 22 : { // Set Dim off
textCharFormat.setFontWeight(QFont::Normal);
break;
}
case 23 : { // Unset italic and unset fraktur
textCharFormat.setFontItalic(false);
break;
}
case 24 : { // Unset underlining
textCharFormat.setUnderlineStyle(QTextCharFormat::NoUnderline);
textCharFormat.setFontUnderline(false);
break;
}
case 25 : { // Unset Blink/Bold
textCharFormat.setFontWeight(QFont::Normal);
break;
}
case 26 : { // Reserved
break;
}
case 27 : { // Positive (non-inverted)
QBrush backgroundBrush = textCharFormat.background();
textCharFormat.setBackground(textCharFormat.foreground());
textCharFormat.setForeground(backgroundBrush);
break;
}
case 28 : {
textCharFormat.setForeground(defaultTextCharFormat.foreground());
textCharFormat.setBackground(defaultTextCharFormat.background());
break;
}
case 29 : {
textCharFormat.setUnderlineStyle(QTextCharFormat::NoUnderline);
textCharFormat.setFontUnderline(false);
break;
}
case 30 ... 37 : {
int colorIndex = attribute - 30;
QColor color;
if (QFont::Normal < textCharFormat.fontWeight()) {
switch (colorIndex) {
case 0 : {
color = Qt::darkGray;
break;
}
case 1 : {
color = Qt::red;
break;
}
case 2 : {
color = Qt::green;
break;
}
case 3 : {
color = Qt::yellow;
break;
}
case 4 : {
color = Qt::blue;
break;
}
case 5 : {
color = Qt::magenta;
break;
}
case 6 : {
color = Qt::cyan;
break;
}
case 7 : {
color = Qt::white;
break;
}
default : {
Q_ASSERT(false);
}
}
} else {
switch (colorIndex) {
case 0 : {
color = Qt::black;
break;
}
case 1 : {
color = Qt::darkRed;
break;
}
case 2 : {
color = Qt::darkGreen;
break;
}
case 3 : {
color = Qt::darkYellow;
break;
}
case 4 : {
color = Qt::darkBlue;
break;
}
case 5 : {
color = Qt::darkMagenta;
break;
}
case 6 : {
color = Qt::darkCyan;
break;
}
case 7 : {
color = Qt::lightGray;
break;
}
default : {
Q_ASSERT(false);
}
}
}
textCharFormat.setForeground(color);
break;
}
case 38 : {
if (i.hasNext()) {
bool ok = false;
int selector = i.next().toInt(&ok);
Q_ASSERT(ok);
QColor color;
switch (selector) {
case 2 : {
if (!i.hasNext()) {
break;
}
int red = i.next().toInt(&ok);
Q_ASSERT(ok);
if (!i.hasNext()) {
break;
}
int green = i.next().toInt(&ok);
Q_ASSERT(ok);
if (!i.hasNext()) {
break;
}
int blue = i.next().toInt(&ok);
Q_ASSERT(ok);
color.setRgb(red, green, blue);
break;
}
case 5 : {
if (!i.hasNext()) {
break;
}
int index = i.next().toInt(&ok);
Q_ASSERT(ok);
switch (index) {
case 0x00 ... 0x07 : { // 0x00-0x07: standard colors (as in ESC [ 30..37 m)
return parseEscapeSequence(index - 0x00 + 30, i, textCharFormat, defaultTextCharFormat);
}
case 0x08 ... 0x0F : { // 0x08-0x0F: high intensity colors (as in ESC [ 90..97 m)
return parseEscapeSequence(index - 0x08 + 90, i, textCharFormat, defaultTextCharFormat);
}
case 0x10 ... 0xE7 : { // 0x10-0xE7: 6*6*6=216 colors: 16 + 36*r + 6*g + b (0≤r,g,b≤5)
index -= 0x10;
int red = index % 6;
index /= 6;
int green = index % 6;
index /= 6;
int blue = index % 6;
index /= 6;
Q_ASSERT(index == 0);
color.setRgb(red, green, blue);
break;
}
case 0xE8 ... 0xFF : { // 0xE8-0xFF: grayscale from black to white in 24 steps
qreal intensity = qreal(index - 0xE8) / (0xFF - 0xE8);
color.setRgbF(intensity, intensity, intensity);
break;
}
}
textCharFormat.setForeground(color);
break;
}
default : {
break;
}
}
}
break;
}
case 39 : {
textCharFormat.setForeground(defaultTextCharFormat.foreground());
break;
}
case 40 ... 47 : {
int colorIndex = attribute - 40;
QColor color;
switch (colorIndex) {
case 0 : {
color = Qt::darkGray;
break;
}
case 1 : {
color = Qt::red;
break;
}
case 2 : {
color = Qt::green;
break;
}
case 3 : {
color = Qt::yellow;
break;
}
case 4 : {
color = Qt::blue;
break;
}
case 5 : {
color = Qt::magenta;
break;
}
case 6 : {
color = Qt::cyan;
break;
}
case 7 : {
color = Qt::white;
break;
}
default : {
Q_ASSERT(false);
}
}
textCharFormat.setBackground(color);
break;
}
case 48 : {
if (i.hasNext()) {
bool ok = false;
int selector = i.next().toInt(&ok);
Q_ASSERT(ok);
QColor color;
switch (selector) {
case 2 : {
if (!i.hasNext()) {
break;
}
int red = i.next().toInt(&ok);
Q_ASSERT(ok);
if (!i.hasNext()) {
break;
}
int green = i.next().toInt(&ok);
Q_ASSERT(ok);
if (!i.hasNext()) {
break;
}
int blue = i.next().toInt(&ok);
Q_ASSERT(ok);
color.setRgb(red, green, blue);
break;
}
case 5 : {
if (!i.hasNext()) {
break;
}
int index = i.next().toInt(&ok);
Q_ASSERT(ok);
switch (index) {
case 0x00 ... 0x07 : { // 0x00-0x07: standard colors (as in ESC [ 40..47 m)
return parseEscapeSequence(index - 0x00 + 40, i, textCharFormat, defaultTextCharFormat);
}
case 0x08 ... 0x0F : { // 0x08-0x0F: high intensity colors (as in ESC [ 100..107 m)
return parseEscapeSequence(index - 0x08 + 100, i, textCharFormat, defaultTextCharFormat);
}
case 0x10 ... 0xE7 : { // 0x10-0xE7: 6*6*6=216 colors: 16 + 36*r + 6*g + b (0≤r,g,b≤5)
index -= 0x10;
int red = index % 6;
index /= 6;
int green = index % 6;
index /= 6;
int blue = index % 6;
index /= 6;
Q_ASSERT(index == 0);
color.setRgb(red, green, blue);
break;
}
case 0xE8 ... 0xFF : { // 0xE8-0xFF: grayscale from black to white in 24 steps
qreal intensity = qreal(index - 0xE8) / (0xFF - 0xE8);
color.setRgbF(intensity, intensity, intensity);
break;
}
}
textCharFormat.setBackground(color);
break;
}
default : {
break;
}
}
}
break;
}
case 49 : {
textCharFormat.setBackground(defaultTextCharFormat.background());
break;
}
case 90 ... 97 : {
int colorIndex = attribute - 90;
QColor color;
switch (colorIndex) {
case 0 : {
color = Qt::darkGray;
break;
}
case 1 : {
color = Qt::red;
break;
}
case 2 : {
color = Qt::green;
break;
}
case 3 : {
color = Qt::yellow;
break;
}
case 4 : {
color = Qt::blue;
break;
}
case 5 : {
color = Qt::magenta;
break;
}
case 6 : {
color = Qt::cyan;
break;
}
case 7 : {
color = Qt::white;
break;
}
default : {
Q_ASSERT(false);
}
}
color.setRedF(color.redF() * 0.8);
color.setGreenF(color.greenF() * 0.8);
color.setBlueF(color.blueF() * 0.8);
textCharFormat.setForeground(color);
break;
}
case 100 ... 107 : {
int colorIndex = attribute - 100;
QColor color;
switch (colorIndex) {
case 0 : {
color = Qt::darkGray;
break;
}
case 1 : {
color = Qt::red;
break;
}
case 2 : {
color = Qt::green;
break;
}
case 3 : {
color = Qt::yellow;
break;
}
case 4 : {
color = Qt::blue;
break;
}
case 5 : {
color = Qt::magenta;
break;
}
case 6 : {
color = Qt::cyan;
break;
}
case 7 : {
color = Qt::white;
break;
}
default : {
Q_ASSERT(false);
}
}
color.setRedF(color.redF() * 0.8);
color.setGreenF(color.greenF() * 0.8);
color.setBlueF(color.blueF() * 0.8);
textCharFormat.setBackground(color);
break;
}
default : {
break;
}
}
}

void MainWindow::setTextTermFormatting(QTextEdit * textEdit, QString const & text)
{
QTextDocument * document = textEdit->document();
QRegExp const escapeSequenceExpression(R"(\x1B\[([\d;]+)m)");
QTextCursor cursor(document);
QTextCharFormat const defaultTextCharFormat = cursor.charFormat();
cursor.beginEditBlock();
int offset = escapeSequenceExpression.indexIn(text);
cursor.insertText(text.mid(0, offset));
QTextCharFormat textCharFormat = defaultTextCharFormat;
while (!(offset < 0)) {
int previousOffset = offset + escapeSequenceExpression.matchedLength();
QStringList capturedTexts = escapeSequenceExpression.capturedTexts().back().split(';');
QListIterator< QString > i(capturedTexts);
while (i.hasNext()) {
bool ok = false;
int attribute = i.next().toInt(&ok);
Q_ASSERT(ok);
parseEscapeSequence(attribute, i, textCharFormat, defaultTextCharFormat);
}
offset = escapeSequenceExpression.indexIn(text, previousOffset);
if (offset < 0) {
cursor.insertText(text.mid(previousOffset), textCharFormat);
} else {
cursor.insertText(text.mid(previousOffset, offset - previousOffset), textCharFormat);
}
}
cursor.setCharFormat(defaultTextCharFormat);
cursor.endEditBlock();
//cursor.movePosition(QTextCursor::Start);
textEdit->setTextCursor(cursor);
}

It is not fully tested at the moment, but quite workable. It is exact what I wanted.

Parse ANSI color codes and set the according color attributes for NSAttributedString

You need to approach it differently.
You cannot set attribute ranges and then modify the string in this way. That changes the range of the attribute.
There are lots of ways to do it.
An easier way to do this without getting confused is to first split the string into an array based on the matches.
Then remove the ANSI color prefix from each string in the array and apply the color.
Then join the array into one string.

Another approach would be to first convert the non-attributed string to another format.
It could be HTML or RTF for example. Then all you would be doing is converting the ANSI color tags to a format that the cocoa text system can already handle for you.

How can I syntax highlight the output from the exec() function in PHP?

The question A library to convert ANSI escapes (terminal formatting/color codes) to HTML has an answer to this question.

Solution

aha is a Ansi to HTML Adapter written in C. It's available in an Ubuntu
package and on github theZiz/aha.

My code is then simply:

   exec("$command | aha", $output, $exitCode);
foreach($output as $k => $line) {
if ($line == '1') { continue; }
echo "$line";
}

Description

   aha takes SGR-colored Input and prints W3C conform HTML-Code.
aha reads the Input from a file or stdin and writes HTML-Code to stdout.

There is some nice options:

  • --black , -b: Black Background and white "standard color"
  • --word-wrap , -w: Wrap long lines in the html file. This works with CSS3 supporting browsers as well as many older ones.
  • --no-header , -n: Don't include header into generated HTML, useful for inclusion in full HTML files.


Related Topics



Leave a reply



Submit