diff --git a/IPython/html/static/base/js/utils.js b/IPython/html/static/base/js/utils.js
index c64bd12c2..d8de09737 100644
--- a/IPython/html/static/base/js/utils.js
+++ b/IPython/html/static/base/js/utils.js
@@ -8,7 +8,6 @@
//============================================================================
// Utilities
//============================================================================
-
IPython.namespace('IPython.utils');
IPython.utils = (function (IPython) {
@@ -71,7 +70,7 @@ IPython.utils = (function (IPython) {
separator2, match, lastIndex, lastLength;
str += ""; // Type-convert
- var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined"
+ var compliantExecNpcg = typeof(/()??/.exec("")[1]) === "undefined";
if (!compliantExecNpcg) {
// Doesn't need flags gy, but they don't hurt
separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
@@ -168,23 +167,100 @@ IPython.utils = (function (IPython) {
"36":"ansicyan",
"37":"ansigrey"
};
+
+ function _process_numbers(attrs, numbers) {
+ // process ansi escapes
+ var n = numbers.shift();
+ if (ansi_colormap[n]) {
+ if ( ! attrs["class"] ) {
+ attrs["class"] = ansi_colormap[n];
+ } else {
+ attrs["class"] += " " + ansi_colormap[n];
+ }
+ } else if (n == "38" || n == "48") {
+ // 256-color
+ if (numbers.length < 2) {
+ console.log("Not enough fields for 256-color escapes", numbers);
+ return;
+ }
+
+ var index_or_rgb = numbers.shift();
+ var r,g,b;
+ if (index_or_rgb == "5") {
+ var idx = parseInt(numbers.shift());
+ if (idx < 16) {
+ // indexed color, not supported
+ } else if (idx < 232) {
+ // 216 color 6x6x6
+ idx = idx - 16;
+ b = idx % 6;
+ g = Math.floor(idx / 6) % 6;
+ r = Math.floor(idx / 36) % 6;
+ // convert to rgb
+ r = (r * 51);
+ g = (g * 51);
+ b = (b * 51);
+ } else {
+ // grayscale
+ idx = idx - 231;
+ // it's 1-24 and should *not* include black or white,
+ // so a 26 point scale
+ r = g = b = idx * 256 / 26;
+ }
+ } else if (index_or_rgb == "2") {
+ if (numbers.length > 3) {
+ console.log("Not enough fields for RGB", numbers);
+ return;
+ }
+ // simple rgb
+ r = numbers.shift();
+ g = numbers.shift();
+ b = numbers.shift();
+ } else {
+ console.log("unrecognized control", numbers);
+ return;
+ }
+ if (r !== undefined) {
+ // apply the rgb color
+ var line;
+ if (n == "38") {
+ line = "color: ";
+ } else {
+ line = "background-color: ";
+ }
+ line = line + "rgb(" + r + "," + g + "," + b + ");"
+ if ( !attrs["style"] ) {
+ attrs["style"] = line;
+ } else {
+ attrs["style"] += " " + line;
+ }
+ }
+ }
+ }
function ansispan(str) {
// ansispan function adapted from github.com/mmalecki/ansispan (MIT License)
- Object.keys(ansi_colormap).forEach(function(ansi) {
- var span = '';
-
- //
- // `\033[Xm` == `\033[0;Xm` sets foreground color to `X`.
- //
- str = str.replace(
- new RegExp('\033\\[(0?[01];)?' + ansi + 'm', 'g'), span
- );
+ // regular ansi escapes (using the table above)
+ return str.replace(/\033\[(0?[01]|22|39)?([;\d]+)?m/g, function(match, prefix, pattern) {
+ if (!pattern) {
+ // [(01|22|39|)m close spans
+ return "";
+ }
+ // consume sequence of color escapes
+ var numbers = pattern.match(/\d+/g);
+ var attrs = {};
+ while (numbers.length > 0) {
+ _process_numbers(attrs, numbers);
+ }
+
+ var span = "";
});
-
- str = str.replace(/\033\[(0?[01]|39|22)?m/g, '');
- return str;
- };
+ };
// Transform ANSI color escape codes into HTML tags with css
// classes listed in the above ansi_colormap object. The actual color used