Created
November 19, 2013 10:09
-
-
Save walling/7543151 to your computer and use it in GitHub Desktop.
Convert terminal output including ANSI escape sequences to HTML. Only handles simple cases!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
var defaultColors = [ '#000', '#D00', '#00CF12', '#C2CB00', '#3100CA', | |
'#E100C6', '#00CBCB', '#C7C7C7', '#686868', '#FF5959', '#00FF6B', | |
'#FAFF5C', '#775AFF', '#FF47FE', '#0FF', '#FFF' ]; | |
function term2html(text, options) { | |
options = options || {}; | |
var colors = options.colors || defaultColors; | |
// EL – Erase in Line: CSI n K. | |
// Erases part of the line. If n is zero (or missing), clear from cursor to | |
// the end of the line. If n is one, clear from cursor to beginning of the | |
// line. If n is two, clear entire line. Cursor position does not change. | |
text = text.replace(/^.*\u001B\[[12]K/mg, ''); | |
// CHA – Cursor Horizontal Absolute: CSI n G. | |
// Moves the cursor to column n. | |
text = text.replace(/^(.*)\u001B\[(\d+)G/mg, function(_, text, n) { | |
return text.slice(0, n); | |
}); | |
// SGR – Select Graphic Rendition: CSI n m. | |
// Sets SGR parameters, including text color. After CSI can be zero or more | |
// parameters separated with ;. With no parameters, CSI m is treated as | |
// CSI 0 m (reset / normal), which is typical of most of the ANSI escape | |
// sequences. | |
var state = { | |
bg: -1, | |
fg: -1, | |
bold: false, | |
underline: false, | |
negative: false | |
}; | |
text = text.replace(/\u001B\[([\d;]+)m([^\u001B]+)/g, function(_, n, text) { | |
// Update state according to SGR codes. | |
n.split(';').forEach(function(code) { | |
code = code | 0; | |
if (code === 0) { | |
state.bg = -1; | |
state.fg = -1; | |
state.bold = false; | |
state.underline = false; | |
state.negative = false; | |
} else if (code === 1) { | |
state.bold = true; | |
} else if (code === 4) { | |
state.underline = true; | |
} else if (code === 7) { | |
state.negative = true; | |
} else if (code === 21) { | |
state.bold = false; | |
} else if (code === 24) { | |
state.underline = false; | |
} else if (code === 27) { | |
state.negative = false; | |
} else if (code >= 30 && code <= 37) { | |
state.fg = code - 30; | |
} else if (code === 39) { | |
state.fg = -1; | |
} else if (code >= 40 && code <= 47) { | |
state.bg = code - 40; | |
} else if (code === 49) { | |
state.bg = -1; | |
} else if (code >= 90 && code <= 97) { | |
state.fg = code - 90 + 8; | |
} else if (code >= 100 && code <= 107) { | |
state.bg = code - 100 + 8; | |
} | |
}); | |
// Convert color codes to CSS colors. | |
var bold = state.bold * 8; | |
var fg, bg; | |
if (state.negative) { | |
fg = state.bg | bold; | |
bg = state.fg; | |
} else { | |
fg = state.fg | bold; | |
bg = state.bg; | |
} | |
fg = colors[fg] || ''; | |
bg = colors[bg] || ''; | |
// Create style element. | |
var style = ''; | |
if (bg) { | |
style += 'background-color:' + bg + ';'; | |
} | |
if (fg) { | |
style += 'color:' + fg + ';'; | |
} | |
if (bold) { | |
style += 'font-weight:bold;'; | |
} | |
if (state.underline) { | |
style += 'text-decoration:underline'; | |
} | |
var html = text. | |
replace(/&/g, '&'). | |
replace(/</g, '<'). | |
replace(/>/g, '>'); | |
// Return HTML for this section of formatted text. | |
if (style) { | |
return '<span style="' + style + '">' + html + '</span>'; | |
} else { | |
return html; | |
} | |
}); | |
return text.replace(/\u001B\[.*?[A-Za-z]/g, ''); | |
} | |
module.exports = term2html; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
+1