Skip to content

Instantly share code, notes, and snippets.

@aels
Created April 8, 2022 14:10
Show Gist options
  • Save aels/551c531a46f2b359ea3fa74129592934 to your computer and use it in GitHub Desktop.
Save aels/551c531a46f2b359ea3fa74129592934 to your computer and use it in GitHub Desktop.
/**@license
* __ _____ ________ __
* / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / /
* __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ /
* / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__
* \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/
* \/ /____/
* http://terminal.jcubic.pl
*
* This is example of how to create custom formatter for jQuery Terminal
*
* Copyright (c) 2014-2021 Jakub Jankiewicz <https://jcubic.pl/me>
* Released under the MIT license
*
* Includes: node-ansiparser, MIT license, Copyright (c) 2014 Joerg Breitbart
*
* Last Update in jQuery Terminal 2.23.0
*
*/
/* global define */
(function(factory) {
var root;
if (typeof window !== 'undefined') {
root = window;
} else if (typeof self !== 'undefined') {
root = self;
} else if (typeof global !== 'undefined') {
root = global;
} else {
throw new Error('Unknow context');
}
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
// istanbul ignore next
define(['jquery', 'jquery.terminal'], factory);
} else if (typeof module === 'object' && module.exports) {
// Node/CommonJS
module.exports = function(root, jQuery) {
if (jQuery === undefined) {
// require('jQuery') returns a factory that requires window to
// build a jQuery instance, we normalize how we use modules
// that require this pattern but the window provided is a noop
// if it's defined (how jquery works)
if (typeof window !== 'undefined') {
jQuery = require('jquery');
} else {
jQuery = require('jquery')(root);
}
}
if (!jQuery.fn.terminal) {
if (typeof window !== 'undefined') {
require('jquery.terminal');
} else {
require('jquery.terminal')(jQuery);
}
}
factory(jQuery);
return jQuery;
};
} else {
// Browser
// istanbul ignore next
factory(root.jQuery);
}
})(function($) {
var DEBUG = true;
/* eslint-disable */
/* istanbul ignore next */
function warn(str) {
if ('warn' in console) {
console.warn(str);
}
}
// node-ansiparser
// The MIT License (MIT)
// Copyright (c) 2014 Joerg Breitbart
/* istanbul ignore next */
var AnsiParser = (function () {
'use strict';
/**
* range function for numbers [a, .., b-1]
*
* @param {number} a
* @param {number} b
* @return {Array}
*/
function r(a, b) {
var c = b - a;
var arr = new Array(c);
while (c--)
arr[c] = --b;
return arr;
}
/**
* Add a transition to the transition table.
*
* @param table - table to add transition
* @param {number} inp - input character code
* @param {number} state - current state
* @param {number=} action - action to be taken
* @param {number=} next - next state
*/
function add(table, inp, state, action, next) {
table[state<<8|inp] = ((action | 0) << 4) | ((next === undefined) ? state : next);
}
/**
* Add multiple transitions to the transition table.
*
* @param table - table to add transition
* @param {Array} inps - array of input character codes
* @param {number} state - current state
* @param {number=} action - action to be taken
* @param {number=} next - next state
*/
function add_list(table, inps, state, action, next) {
for (var i=0; i<inps.length; i++)
add(table, inps[i], state, action, next);
}
/** global definition of printables and executables */
var PRINTABLES = r(0x20, 0x7f);
var EXECUTABLES = r(0x00, 0x18);
EXECUTABLES.push(0x19);
EXECUTABLES.push(0x1E);
EXECUTABLES.concat(r(0x1c, 0x20));
/* meaning of state and action indices
var STATES = [
'GROUND',
'ESCAPE',
'ESCAPE_INTERMEDIATE',
'CSI_ENTRY',
'CSI_PARAM',
'CSI_INTERMEDIATE',
'CSI_IGNORE',
'SOS_PM_APC_STRING',
'OSC_STRING',
'DCS_ENTRY',
'DCS_PARAM',
'DCS_IGNORE',
'DCS_INTERMEDIATE',
'DCS_PASSTHROUGH'
];
var ACTIONS = [
'ignore',
'error',
'print',
'execute',
'osc_start',
'osc_put',
'osc_end',
'csi_dispatch',
'param',
'collect',
'esc_dispatch',
'clear',
'dcs_hook',
'dcs_put',
'dcs_unhook'
];
*/
/**
* create the standard transition table - used by all parser instances
*
* table[state << 8 | character code] = action << 4 | next state
*
* - states are indices of STATES (0 to 13)
* - control character codes defined from 0 to 159 (C0 and C1)
* - actions are indices of ACTIONS (0 to 14)
* - any higher character than 159 is handled by the 'error' action
*/
var TRANSITION_TABLE = (function() {
var t = new Uint8Array(4095);
// table with default transition [any] --> [error, GROUND]
for (var state=0; state<14; ++state) {
for (var code=0; code<160; ++code) {
t[state<<8|code] = 16;
}
}
// apply transitions
// printables
add_list(t, PRINTABLES, 0, 2);
// global anywhere rules
for (state=0; state<14; ++state) {
add_list(t, [0x18, 0x1a, 0x99, 0x9a], state, 3, 0);
add_list(t, r(0x80, 0x90), state, 3, 0);
add_list(t, r(0x90, 0x98), state, 3, 0);
add(t, 0x9c, state, 0, 0); // ST as terminator
add(t, 0x1b, state, 11, 1); // ESC
add(t, 0x9d, state, 4, 8); // OSC
add_list(t, [0x98, 0x9e, 0x9f], state, 0, 7);
add(t, 0x9b, state, 11, 3); // CSI
add(t, 0x90, state, 11, 9); // DCS
}
// rules for executables and 7f
add_list(t, EXECUTABLES, 0, 3);
add_list(t, EXECUTABLES, 1, 3);
add(t, 0x7f, 1);
add_list(t, EXECUTABLES, 8);
add_list(t, EXECUTABLES, 3, 3);
add(t, 0x7f, 3);
add_list(t, EXECUTABLES, 4, 3);
add(t, 0x7f, 4);
add_list(t, EXECUTABLES, 6, 3);
add_list(t, EXECUTABLES, 5, 3);
add(t, 0x7f, 5);
add_list(t, EXECUTABLES, 2, 3);
add(t, 0x7f, 2);
// osc
add(t, 0x5d, 1, 4, 8);
add_list(t, PRINTABLES, 8, 5);
add(t, 0x7f, 8, 5);
add_list(t, [0x9c, 0x1b, 0x18, 0x1a, 0x07], 8, 6, 0);
add_list(t, r(0x1c, 0x20), 8, 0);
// sos/pm/apc does nothing
add_list(t, [0x58, 0x5e, 0x5f], 1, 0, 7);
add_list(t, PRINTABLES, 7);
add_list(t, EXECUTABLES, 7);
add(t, 0x9c, 7, 0, 0);
// csi entries
add(t, 0x5b, 1, 11, 3);
add_list(t, r(0x40, 0x7f), 3, 7, 0);
add_list(t, r(0x30, 0x3a), 3, 8, 4);
add(t, 0x3b, 3, 8, 4);
add_list(t, [0x3c, 0x3d, 0x3e, 0x3f], 3, 9, 4);
add_list(t, r(0x30, 0x3a), 4, 8);
add(t, 0x3b, 4, 8);
add_list(t, r(0x40, 0x7f), 4, 7, 0);
add_list(t, [0x3a, 0x3c, 0x3d, 0x3e, 0x3f], 4, 0, 6);
add_list(t, r(0x20, 0x40), 6);
add(t, 0x7f, 6);
add_list(t, r(0x40, 0x7f), 6, 0, 0);
add(t, 0x3a, 3, 0, 6);
add_list(t, r(0x20, 0x30), 3, 9, 5);
add_list(t, r(0x20, 0x30), 5, 9);
add_list(t, r(0x30, 0x40), 5, 0, 6);
add_list(t, r(0x40, 0x7f), 5, 7, 0);
add_list(t, r(0x20, 0x30), 4, 9, 5);
// esc_intermediate
add_list(t, r(0x20, 0x30), 1, 9, 2);
add_list(t, r(0x20, 0x30), 2, 9);
add_list(t, r(0x30, 0x7f), 2, 10, 0);
add_list(t, r(0x30, 0x50), 1, 10, 0);
add_list(t, [0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x59, 0x5a, 0x5c], 1, 10, 0);
add_list(t, r(0x60, 0x7f), 1, 10, 0);
// dcs entry
add(t, 0x50, 1, 11, 9);
add_list(t, EXECUTABLES, 9);
add(t, 0x7f, 9);
add_list(t, r(0x1c, 0x20), 9);
add_list(t, r(0x20, 0x30), 9, 9, 12);
add(t, 0x3a, 9, 0, 11);
add_list(t, r(0x30, 0x3a), 9, 8, 10);
add(t, 0x3b, 9, 8, 10);
add_list(t, [0x3c, 0x3d, 0x3e, 0x3f], 9, 9, 10);
add_list(t, EXECUTABLES, 11);
add_list(t, r(0x20, 0x80), 11);
add_list(t, r(0x1c, 0x20), 11);
add_list(t, EXECUTABLES, 10);
add(t, 0x7f, 10);
add_list(t, r(0x1c, 0x20), 10);
add_list(t, r(0x30, 0x3a), 10, 8);
add(t, 0x3b, 10, 8);
add_list(t, [0x3a, 0x3c, 0x3d, 0x3e, 0x3f], 10, 0, 11);
add_list(t, r(0x20, 0x30), 10, 9, 12);
add_list(t, EXECUTABLES, 12);
add(t, 0x7f, 12);
add_list(t, r(0x1c, 0x20), 12);
add_list(t, r(0x20, 0x30), 12, 9);
add_list(t, r(0x30, 0x40), 12, 0, 11);
add_list(t, r(0x40, 0x7f), 12, 12, 13);
add_list(t, r(0x40, 0x7f), 10, 12, 13);
add_list(t, r(0x40, 0x7f), 9, 12, 13);
add_list(t, EXECUTABLES, 13, 13);
add_list(t, PRINTABLES, 13, 13);
add(t, 0x7f, 13);
add_list(t, [0x1b, 0x9c], 13, 14, 0);
return t;
})();
/**
* AnsiParser - Parser for ANSI terminal escape sequences.
*
* @param {Object=} terminal emulation object
* @constructor
*/
function AnsiParser(terminal) {
this.initial_state = 0; // 'GROUND' is default
this.current_state = this.initial_state|0;
// clone global transition table
this.transitions = new Uint8Array(4095);
this.transitions.set(TRANSITION_TABLE);
// global non pushable buffers for multiple parse invocations
this.osc = '';
this.params = [0];
this.collected = '';
// back reference to terminal
this.term = terminal || {};
var instructions = ['inst_p', 'inst_o', 'inst_x', 'inst_c',
'inst_e', 'inst_H', 'inst_P', 'inst_U', 'inst_E'];
for (var i=0; i<instructions.length; ++i)
if (!(instructions[i] in this.term))
this.term[instructions[i]] = function() {};
}
/**
* Reset the parser.
*/
AnsiParser.prototype.reset = function() {
this.current_state = this.initial_state|0;
this.osc = '';
this.params = [0];
this.collected = '';
};
/**
* Parse string s.
* @param {string} s
*/
AnsiParser.prototype.parse = function(s) {
var code = 0,
transition = 0,
error = false,
current_state = this.current_state|0;
// local buffers
var printed = -1;
var dcs = -1;
var osc = this.osc;
var collected = this.collected;
var params = this.params;
// process input string
for (var i=0, l=s.length|0; i<l; ++i) {
code = s.charCodeAt(i)|0;
// shortcut for most chars (print action)
if (current_state===0 && code>0x1f && code<0x80) {
printed = (printed + 1) ? printed|0: i|0;
continue;
}
transition = ((code < 0xa0) ? (this.transitions[(current_state<<8|code)|0])|0 : 16)|0;
switch ((transition >> 4)|0) {
case 2: // print
printed = (printed + 1) ? printed|0: i|0;
break;
case 3: // execute
if (printed + 1) {
this.term.inst_p(s.substring(printed, i));
printed = -1;
}
this.term.inst_x(String.fromCharCode(code));
break;
case 0: // ignore
// handle leftover print and dcs chars
if (printed + 1) {
this.term.inst_p(s.substring(printed, i));
printed = -1;
} else if (dcs + 1) {
this.term.inst_P(s.substring(dcs, i));
dcs = -1;
}
break;
case 1: // error
// handle unicode chars in write buffers w'o state change
if (code > 0x9f) {
switch (current_state) {
case 0: // GROUND -> add char to print string
printed = (!(printed+1)) ? i|0 : printed|0;
break;
case 8: // OSC_STRING -> add char to osc string
osc += String.fromCharCode(code);
transition = (transition | 8)|0;
break;
case 6: // CSI_IGNORE -> ignore char
transition = (transition | 6)|0;
break;
case 11: // DCS_IGNORE -> ignore char
transition = (transition | 11)|0;
break;
case 13: // DCS_PASSTHROUGH -> add char to dcs
if (!(dcs + 1))
dcs = i|0;
transition = (transition | 13)|0;
break;
default: // real error
error = true;
}
} else { // real error
error = true;
}
if (error) {
if (this.term.inst_E(
{
pos: i, // position in parse string
character: String.fromCharCode(code), // wrong character
state: current_state, // in state
print: printed, // print buffer
dcs: dcs, // dcs buffer
osc: osc, // osc buffer
collect: collected, // collect buffer
params: params // params buffer
})) {
return;
}
error = false;
}
break;
case 7: // csi_dispatch
this.term.inst_c(collected, params, String.fromCharCode(code));
break;
case 8: // param
if (code === 0x3b)
params.push(0);
else
params[params.length-1] = (params[params.length-1] * 10 + code - 48)|0;
break;
case 9: // collect
collected += String.fromCharCode(code);
break;
case 10: // esc_dispatch
this.term.inst_e(collected, String.fromCharCode(code));
break;
case 11: // clear
if (printed + 1) {
this.term.inst_p(s.substring(printed, i));
printed = -1;
}
osc = '';
params = [0];
collected = '';
dcs = -1;
break;
case 12: // dcs_hook
this.term.inst_H(collected, params, String.fromCharCode(code));
break;
case 13: // dcs_put
if (!(dcs + 1))
dcs = i|0;
break;
case 14: // dcs_unhook
if (dcs + 1) {
this.term.inst_P(s.substring(dcs, i));
}
this.term.inst_U();
if (code === 0x1b)
transition = (transition | 1)|0;
osc = '';
params = [0];
collected = '';
dcs = -1;
break;
case 4: // osc_start
if (~printed) {
this.term.inst_p(s.substring(printed, i));
printed = -1;
}
osc = '';
break;
case 5: // osc_put
osc += s.charAt(i);
break;
case 6: // osc_end
if (osc && code !== 0x18 && code !== 0x1a)
this.term.inst_o(osc);
if (code === 0x1b)
transition = (transition | 1)|0;
osc = '';
params = [0];
collected = '';
dcs = -1;
break;
}
current_state = (transition & 15)|0;
}
// push leftover pushable buffers to terminal
if (!current_state && (printed + 1)) {
this.term.inst_p(s.substring(printed));
} else if (current_state===13 && (dcs + 1)) {
this.term.inst_P(s.substring(dcs));
}
// save non pushable buffers
this.osc = osc;
this.collected = collected;
this.params = params;
// save state
this.current_state = current_state|0;
};
return AnsiParser;
})();
/* eslint-enable */
// ---------------------------------------------------------------------
$.terminal.AnsiParser = AnsiParser;
// ---------------------------------------------------------------------
// we match characters and html entities because command line escape brackets
// echo don't, when writing formatter always process html entitites so it work
// for cmd plugin as well for echo
var chr = '[^\\x08]|[\\r\\n]{2}|&[^;]+;';
var backspace_re = new RegExp('^(' + chr + ')?\\x08');
var overtyping_re = new RegExp('^(?:(' + chr + ')?\\x08(_|\\1)|' +
'(_)\\x08(' + chr + '))');
var new_line_re = /^(\r\n|\n\r|\r|\n)/;
var clear_line_re = /[^\r\n]+\r\x1B\[K/g;
// ---------------------------------------------------------------------
function length(string) {
return $.terminal.length(string);
}
// ---------------------------------------------------------------------
function get_settings(options) {
var unixFormatting = {
escapeBrackets: false,
ansiParser: {},
position: 0,
ansiArt: false
};
if (options) {
if (options.unixFormatting) {
unixFormatting = $.extend({
escapeBrackets: false,
ansiParser: {},
ansiArt: false
}, unixFormatting, options.unixFormatting);
}
if ('position' in options) {
unixFormatting.position = options.position;
}
if ('unixFormattingEscapeBrackets' in options) {
unixFormatting.escapeBrackets = options.unixFormattingEscapeBrackets;
}
if ('ansiParser' in options) {
unixFormatting.ansiParser = $.extend(
unixFormatting.ansiParser,
options.ansiParser
);
}
}
return unixFormatting;
}
// ---------------------------------------------------------------------
// :: Replace overtyping (from man) formatting with terminal formatting
// ---------------------------------------------------------------------
$.terminal.overtyping = function overtyping(string, options) {
string = $.terminal.unescape_brackets(string);
var settings = get_settings(options);
var removed_chars = [];
var new_position;
var char_count = 0;
var backspaces = [];
function replace(string, position) {
var result = '';
var push = 0;
var start;
char_count = 0;
function correct_position(start, match, rep_string) {
// logic taken from $.terminal.tracking_replace
if (start < position) {
var last_index = start + length(match);
if (last_index < position) {
// It's after the replacement, move it
new_position = Math.max(
0,
new_position +
length(rep_string) -
length(match)
);
} else {
// It's *in* the replacement, put it just after
new_position += length(rep_string) - (position - start);
}
}
}
for (var i = 0; i < string.length; ++i) {
var partial = string.substring(i);
var match = partial.match(backspace_re);
var removed_char = removed_chars[0];
if (match) {
// we remove backspace and character or html entity before it
// but we keep it in removed array so we can put it back
// when we have caritage return or line feed
if (match[1]) {
start = i - match[1].length + push;
removed_chars.push({
index: start,
string: match[1],
overtyping: partial.match(overtyping_re)
});
correct_position(start, match[0], '', 1);
}
if (char_count < 0) {
char_count = 0;
}
backspaces = backspaces.map(function(b) {
return b - 1;
});
backspaces.push(start);
return result + partial.replace(backspace_re, '');
} else if (partial.match(new_line_re)) {
// if newline we need to add at the end all characters
// removed by backspace but only if there are no more
// other characters than backspaces added between
// backspaces and newline
if (removed_chars.length) {
var chars = removed_chars;
removed_chars = [];
chars.reverse().forEach(function(char) {
if (i > char.index) {
if (--char_count <= 0) {
correct_position(char.index, '', char.string, 2);
result += char.string;
}
} else {
removed_chars.unshift(char);
}
});
}
var m = partial.match(new_line_re);
result += m[1];
i += m[1].length - 1;
} else {
if (backspaces.length) {
var backspace = backspaces[0];
if (i === backspace) {
backspaces.shift();
}
if (i >= backspace) {
char_count++;
}
}
if (removed_chars.length) {
// if we are in index of removed character we check if the
// character is the same it will be bold or if removed char
// or char at index is underscore then it will
// be terminal formatting with underscore
if (i > removed_char.index && removed_char.overtyping) {
removed_chars.shift();
correct_position(removed_char.index, '', removed_char.string);
// if we add special character we need to correct
// next push to removed_char array
push++;
// we use special characters instead of terminal
// formatting so it's easier to proccess when removing
// backspaces
if (removed_char.string === string[i]) {
result += string[i] + '\uFFF1';
continue;
} else if (removed_char.string === '_' ||
string[i] === '_') {
var chr;
if (removed_char.string === '_') {
chr = string[i];
} else {
chr = removed_char.string;
}
result += chr + '\uFFF2';
continue;
}
}
}
result += string[i];
}
}
return result;
}
var break_next = false;
// loop until not more backspaces
new_position = settings.position;
// we need to clear line \x1b[K in overtyping because it need to be before
// overtyping and from_ansi need to be called after so it escape stuff
// between Escape Code and cmd will have escaped formatting typed by user
var rep = $.terminal.tracking_replace(string, clear_line_re, '', new_position);
string = rep[0];
new_position = rep[1];
while (string.match(/\x08/) || removed_chars.length) {
string = replace(string, new_position);
if (break_next) {
break;
}
if (!string.match(/\x08/)) {
// we break the loop so if removed_chars still chave items
// we don't have infite loop
break_next = true;
}
}
function format(string, chr, style) {
var re = new RegExp('((:?.' + chr + ')+)', 'g');
return string.replace(re, function(_, string) {
var re = new RegExp(chr, 'g');
return '[[' + style + ']' + string.replace(re, '') + ']';
});
}
// replace special characters with terminal formatting
string = format(string, '\uFFF1', 'b;#fff;');
string = format(string, '\uFFF2', 'u;;');
if (settings.escapeBrackets) {
string = $.terminal.escape_brackets(string);
}
if (options && typeof options.position === 'number') {
return [string, new_position];
}
return string;
};
var CHARSETS = {};
// taken from xterm.js MIT License
// see https://github.com/xtermjs/xterm.js for more details
CHARSETS['0'] = {
'`': '\u25c6', // '◆'
'a': '\u2592', // '▒'
'b': '\u2409', // (HT)
'c': '\u240c', // (FF)
'd': '\u240d', // (CR)
'e': '\u240a', // (LF)
'f': '\u00b0', // '°'
'g': '\u00b1', // '±'
'h': '\u2424', // (NL)
'i': '\u240b', // (VT)
'j': '\u2518', // '┘'
'k': '\u2510', // '┐'
'l': '\u250c', // '┌'
'm': '\u2514', // '└'
'n': '\u253c', // '┼'
'o': '\u23ba', // '⎺'
'p': '\u23bb', // '⎻'
'q': '\u2500', // '─'
'r': '\u23bc', // '⎼'
's': '\u23bd', // '⎽'
't': '\u251c', // '├'
'u': '\u2524', // '┤'
'v': '\u2534', // '┴'
'w': '\u252c', // '┬'
'x': '\u2502', // '│'
'y': '\u2264', // '≤'
'z': '\u2265', // '≥'
'{': '\u03c0', // 'π'
'|': '\u2260', // '≠'
'}': '\u00a3', // '£'
'~': '\u00b7' // '·'
};
/**
* British character set
* ESC (A
* Reference: http://vt100.net/docs/vt220-rm/table2-5.html
*/
CHARSETS['A'] = {
'#': '£'
};
/**
* United States character set
* ESC (B
*/
CHARSETS['B'] = null;
/**
* Dutch character set
* ESC (4
* Reference: http://vt100.net/docs/vt220-rm/table2-6.html
*/
CHARSETS['4'] = {
'#': '£',
'@': '¾',
'[': 'ij',
'\\': '½',
']': '|',
'{': '¨',
'|': 'f',
'}': '¼',
'~': '´'
};
/**
* Finnish character set
* ESC (C or ESC (5
* Reference: http://vt100.net/docs/vt220-rm/table2-7.html
*/
CHARSETS['C'] = CHARSETS['5'] = {
'[': 'Ä',
'\\': 'Ö',
']': 'Å',
'^': 'Ü',
'`': 'é',
'{': 'ä',
'|': 'ö',
'}': 'å',
'~': 'ü'
};
/**
* French character set
* ESC (R
* Reference: http://vt100.net/docs/vt220-rm/table2-8.html
*/
CHARSETS['R'] = {
'#': '£',
'@': 'à',
'[': '°',
'\\': 'ç',
']': '§',
'{': 'é',
'|': 'ù',
'}': 'è',
'~': '¨'
};
/**
* French Canadian character set
* ESC (Q
* Reference: http://vt100.net/docs/vt220-rm/table2-9.html
*/
CHARSETS['Q'] = {
'@': 'à',
'[': 'â',
'\\': 'ç',
']': 'ê',
'^': 'î',
'`': 'ô',
'{': 'é',
'|': 'ù',
'}': 'è',
'~': 'û'
};
/**
* German character set
* ESC (K
* Reference: http://vt100.net/docs/vt220-rm/table2-10.html
*/
CHARSETS['K'] = {
'@': '§',
'[': 'Ä',
'\\': 'Ö',
']': 'Ü',
'{': 'ä',
'|': 'ö',
'}': 'ü',
'~': 'ß'
};
/**
* Italian character set
* ESC (Y
* Reference: http://vt100.net/docs/vt220-rm/table2-11.html
*/
CHARSETS['Y'] = {
'#': '£',
'@': '§',
'[': '°',
'\\': 'ç',
']': 'é',
'`': 'ù',
'{': 'à',
'|': 'ò',
'}': 'è',
'~': 'ì'
};
/**
* Norwegian/Danish character set
* ESC (E or ESC (6
* Reference: http://vt100.net/docs/vt220-rm/table2-12.html
*/
CHARSETS['E'] =
CHARSETS['6'] = {
'@': 'Ä',
'[': 'Æ',
'\\': 'Ø',
']': 'Å',
'^': 'Ü',
'`': 'ä',
'{': 'æ',
'|': 'ø',
'}': 'å',
'~': 'ü'
};
/**
* Spanish character set
* ESC (Z
* Reference: http://vt100.net/docs/vt220-rm/table2-13.html
*/
CHARSETS['Z'] = {
'#': '£',
'@': '§',
'[': '¡',
'\\': 'Ñ',
']': '¿',
'{': '°',
'|': 'ñ',
'}': 'ç'
};
/**
* Swedish character set
* ESC (H or ESC (7
* Reference: http://vt100.net/docs/vt220-rm/table2-14.html
*/
CHARSETS['H'] =
CHARSETS['7'] = {
'@': 'É',
'[': 'Ä',
'\\': 'Ö',
']': 'Å',
'^': 'Ü',
'`': 'é',
'{': 'ä',
'|': 'ö',
'}': 'å',
'~': 'ü'
};
/**
* Swiss character set
* ESC (=
* Reference: http://vt100.net/docs/vt220-rm/table2-15.html
*/
CHARSETS['='] = {
'#': 'ù',
'@': 'à',
'[': 'é',
'\\': 'ç',
']': 'ê',
'^': 'î',
'_': 'è',
'`': 'ô',
'{': 'ä',
'|': 'ö',
'}': 'ü',
'~': 'û'
};
// ---------------------------------------------------------------------
// :: Html colors taken from ANSI formatting in Linux Terminal
// ---------------------------------------------------------------------
$.terminal.ansi_colors = {
normal: {
black: '#000',
red: '#A00',
green: '#008400',
yellow: '#A50',
blue: '#00A',
magenta: '#A0A',
cyan: '#0AA',
white: '#AAA'
},
faited: {
black: '#000',
red: '#640000',
green: '#006100',
yellow: '#737300',
blue: '#000087',
magenta: '#650065',
cyan: '#008787',
white: '#818181'
},
bold: {
black: '#555',
red: '#F55',
green: '#44D544',
yellow: '#FF5',
blue: '#55F',
magenta: '#F5F',
cyan: '#5FF',
white: '#FFF'
},
// XTerm 8-bit pallete
palette: [
'#000000', '#AA0000', '#00AA00', '#AA5500', '#0000AA', '#AA00AA',
'#00AAAA', '#AAAAAA', '#555555', '#FF5555', '#55FF55', '#FFFF55',
'#5555FF', '#FF55FF', '#55FFFF', '#FFFFFF', '#000000', '#00005F',
'#000087', '#0000AF', '#0000D7', '#0000FF', '#005F00', '#005F5F',
'#005F87', '#005FAF', '#005FD7', '#005FFF', '#008700', '#00875F',
'#008787', '#0087AF', '#0087D7', '#0087FF', '#00AF00', '#00AF5F',
'#00AF87', '#00AFAF', '#00AFD7', '#00AFFF', '#00D700', '#00D75F',
'#00D787', '#00D7AF', '#00D7D7', '#00D7FF', '#00FF00', '#00FF5F',
'#00FF87', '#00FFAF', '#00FFD7', '#00FFFF', '#5F0000', '#5F005F',
'#5F0087', '#5F00AF', '#5F00D7', '#5F00FF', '#5F5F00', '#5F5F5F',
'#5F5F87', '#5F5FAF', '#5F5FD7', '#5F5FFF', '#5F8700', '#5F875F',
'#5F8787', '#5F87AF', '#5F87D7', '#5F87FF', '#5FAF00', '#5FAF5F',
'#5FAF87', '#5FAFAF', '#5FAFD7', '#5FAFFF', '#5FD700', '#5FD75F',
'#5FD787', '#5FD7AF', '#5FD7D7', '#5FD7FF', '#5FFF00', '#5FFF5F',
'#5FFF87', '#5FFFAF', '#5FFFD7', '#5FFFFF', '#870000', '#87005F',
'#870087', '#8700AF', '#8700D7', '#8700FF', '#875F00', '#875F5F',
'#875F87', '#875FAF', '#875FD7', '#875FFF', '#878700', '#87875F',
'#878787', '#8787AF', '#8787D7', '#8787FF', '#87AF00', '#87AF5F',
'#87AF87', '#87AFAF', '#87AFD7', '#87AFFF', '#87D700', '#87D75F',
'#87D787', '#87D7AF', '#87D7D7', '#87D7FF', '#87FF00', '#87FF5F',
'#87FF87', '#87FFAF', '#87FFD7', '#87FFFF', '#AF0000', '#AF005F',
'#AF0087', '#AF00AF', '#AF00D7', '#AF00FF', '#AF5F00', '#AF5F5F',
'#AF5F87', '#AF5FAF', '#AF5FD7', '#AF5FFF', '#AF8700', '#AF875F',
'#AF8787', '#AF87AF', '#AF87D7', '#AF87FF', '#AFAF00', '#AFAF5F',
'#AFAF87', '#AFAFAF', '#AFAFD7', '#AFAFFF', '#AFD700', '#AFD75F',
'#AFD787', '#AFD7AF', '#AFD7D7', '#AFD7FF', '#AFFF00', '#AFFF5F',
'#AFFF87', '#AFFFAF', '#AFFFD7', '#AFFFFF', '#D70000', '#D7005F',
'#D70087', '#D700AF', '#D700D7', '#D700FF', '#D75F00', '#D75F5F',
'#D75F87', '#D75FAF', '#D75FD7', '#D75FFF', '#D78700', '#D7875F',
'#D78787', '#D787AF', '#D787D7', '#D787FF', '#D7AF00', '#D7AF5F',
'#D7AF87', '#D7AFAF', '#D7AFD7', '#D7AFFF', '#D7D700', '#D7D75F',
'#D7D787', '#D7D7AF', '#D7D7D7', '#D7D7FF', '#D7FF00', '#D7FF5F',
'#D7FF87', '#D7FFAF', '#D7FFD7', '#D7FFFF', '#FF0000', '#FF005F',
'#FF0087', '#FF00AF', '#FF00D7', '#FF00FF', '#FF5F00', '#FF5F5F',
'#FF5F87', '#FF5FAF', '#FF5FD7', '#FF5FFF', '#FF8700', '#FF875F',
'#FF8787', '#FF87AF', '#FF87D7', '#FF87FF', '#FFAF00', '#FFAF5F',
'#FFAF87', '#FFAFAF', '#FFAFD7', '#FFAFFF', '#FFD700', '#FFD75F',
'#FFD787', '#FFD7AF', '#FFD7D7', '#FFD7FF', '#FFFF00', '#FFFF5F',
'#FFFF87', '#FFFFAF', '#FFFFD7', '#FFFFFF', '#080808', '#121212',
'#1C1C1C', '#262626', '#303030', '#3A3A3A', '#444444', '#4E4E4E',
'#585858', '#626262', '#6C6C6C', '#767676', '#808080', '#8A8A8A',
'#949494', '#9E9E9E', '#A8A8A8', '#B2B2B2', '#BCBCBC', '#C6C6C6',
'#D0D0D0', '#DADADA', '#E4E4E4', '#EEEEEE'
]
};
// ---------------------------------------------------------------------
// :: Replace ANSI formatting with terminal formatting
// ---------------------------------------------------------------------
$.terminal.from_ansi = (function() {
var color_list = {
30: 'black',
31: 'red',
32: 'green',
33: 'yellow',
34: 'blue',
35: 'magenta',
36: 'cyan',
37: 'white',
39: 'inherit' // default color
};
var background_list = {
40: 'black',
41: 'red',
42: 'green',
43: 'yellow',
44: 'blue',
45: 'magenta',
46: 'cyan',
47: 'white',
49: 'transparent' // default background
};
function format_ansi(controls, state, ansi_art) {
var num;
var styles = [];
var output_color;
var output_background;
var _process_true_color = -1;
var _ex_color = false;
var _ex_background = false;
var _process_8bit = false;
var palette = $.terminal.ansi_colors.palette;
function set_styles(num) {
switch (num) {
case 0:
Object.keys(state).forEach(function(key) {
delete state[key];
});
state.blink = false;
state.bold = false;
state.faited = false;
break;
case 1:
styles.push('b');
state.bold = true;
state.faited = false;
break;
case 4:
styles.push('u');
break;
case 3:
styles.push('i');
break;
case 5:
if (_ex_color || _ex_background) {
_process_8bit = true;
} else {
state.blink = true;
}
break;
case 38:
_ex_color = true;
break;
case 48:
_ex_background = true;
break;
case 2:
if (_ex_color || _ex_background) {
_process_true_color = 0;
} else {
state.faited = true;
state.bold = false;
}
break;
case 7:
state.reverse = true;
break;
default:
if (color_list[num]) {
output_color = color_list[num];
}
if (background_list[num]) {
output_background = background_list[num];
}
}
}
// -----------------------------------------------------------------
function process_true_color() {
if (_ex_color) {
if (!output_color) {
output_color = '#';
}
if (output_color.length < 7) {
output_color += ('0' + num.toString(16)).slice(-2);
}
}
if (_ex_background) {
if (!output_background) {
output_background = '#';
}
if (output_background.length < 7) {
output_background += ('0' + num.toString(16)).slice(-2);
}
}
if (_process_true_color === 2) {
_process_true_color = -1;
} else {
_process_true_color++;
}
}
// -----------------------------------------------------------------
function should__process_8bit() {
return _process_8bit && ((_ex_background && !output_background) ||
(_ex_color && !output_color));
}
// -----------------------------------------------------------------
function process_8bit() {
if (_ex_color && palette[num] && !output_color) {
output_color = palette[num];
}
if (_ex_background && palette[num] && !output_background) {
output_background = palette[num];
}
_process_8bit = false;
}
// -----------------------------------------------------------------
for (var i in controls) {
if (controls.hasOwnProperty(i)) {
num = parseInt(controls[i], 10);
if (_process_true_color > -1) {
process_true_color();
} else if (should__process_8bit()) {
process_8bit();
} else {
set_styles(num);
}
}
}
if (state.reverse) {
if (output_color || output_background) {
var tmp = output_background;
output_background = output_color;
output_color = tmp;
} else {
output_color = 'black';
output_background = 'white';
}
}
output_color = output_color || state.color;
output_background = output_background || state.background;
var colors, color, background;
if (state.bold) {
colors = $.terminal.ansi_colors.bold;
} else if (state.faited) {
colors = $.terminal.ansi_colors.faited;
} else {
colors = $.terminal.ansi_colors.normal;
}
if (typeof output_color !== 'undefined') {
if (output_color.match(/^#/)) {
color = output_color;
} else if (output_color === 'inherit') {
color = output_color;
} else {
color = colors[output_color];
}
state.color = output_color;
} else {
color = colors['white'];
}
if (typeof output_background !== 'undefined') {
if (output_background.match(/^#/)) { // already 8bit color #460
background = output_background;
} else if (output_background === 'transparent') {
background = output_background;
} else if (state.blink && ansi_art) {
background = $.terminal.ansi_colors.bold[output_background];
} else {
// background is not changed by bold flag
background = $.terminal.ansi_colors.normal[output_background];
}
state.background = output_background;
} else if (state.blink && ansi_art) {
background = $.terminal.ansi_colors.bold['black'];
}
var ret = [styles.join(''), color, background];
if (state.blink && !ansi_art) {
ret.push('terminal-blink');
}
return ret;
}
// -------------------------------------------------------------------------------
return function from_ansi(input, options) {
options = options || {};
var settings = get_settings(options);
var ansi_art = settings.ansiArt;
// if there are SAUCE record if something after end of file
input = input.replace(/\x1A.*/, '');
input = input.replace(/\r?\n?\x1b\[A\x1b\[[0-9]+C/g, '');
input = $.terminal.unescape_brackets(input);
var code, inside, format, charset, saved_cursor;
var print = function print(s) {
var s_len = s.length;
if (settings.escapeBrackets) {
s = $.terminal.escape_formatting(s);
}
if (charset) {
s = s.split('').map(function(chr) {
return charset[chr] || chr;
}).join('');
}
if (format) {
// this will always need to be escaped
if (s.match(/\\$|[[\]]/) &&
!settings.escapeBrackets &&
!$.terminal.have_formatting(s)) {
s = $.terminal.escape_formatting(s);
}
s = format + s + ']';
}
var line = this.result[this.cursor.y];
var len, after, before, line_len;
if (!line) {
if (this.cursor.x > 0) {
var space = new Array(this.cursor.x + 1).join(' ');
this.result[this.cursor.y] = space + s;
} else {
this.result[this.cursor.y] = s;
}
} else {
var stripped = $.terminal.strip(line);
line_len = $.terminal.unescape_brackets(stripped).length;
if (this.cursor.x === 0) {
after = $.terminal.substring(line, s_len);
this.result[this.cursor.y] = s + after;
} else if (line_len < this.cursor.x) {
len = this.cursor.x - (line_len - 1);
this.result[this.cursor.y] += new Array(len).join(' ') + s;
} else if (line_len === this.cursor.x) {
this.result[this.cursor.y] += s;
} else {
before = $.terminal.substring(line, 0, this.cursor.x);
after = $.terminal.substring(line, this.cursor.x + s_len);
this.result[this.cursor.y] = before + s + after;
}
}
this.cursor.x += s_len;
};
var use_CR = !!input.match(/\x0D/);
var term = $.terminal.active();
var ROWS = term && term.rows() || 1000;
var COLS = term && term.cols() || 80;
// correction to CP 437
// ref: https://unix.stackexchange.com/a/611513/1806
// https://unix.stackexchange.com/a/611344/1806
var cp_437_control = {
0x00: ' ',
0x01: '☺',
0x02: '☻',
0x03: '♥',
0x07: '•',
0x08: '█',
0x0F: '*',
0x10: '█',
0x11: '◄',
0x12: '↕',
0x14: '¶',
0x15: '§',
0x16: '▬',
0x17: '↨',
0x18: '↑',
0x19: '↓',
0x1E: '▲'
};
var characters = 'qwertyuiopasdfghjklzxcvbnm';
var parser_events = {
cursor: {x: 0, y: 0},
result: [],
state: {},
inst_p: print,
inst_x: function(flag) {
var code = flag.charCodeAt(0);
if (code === 13) {
this.cursor.x = 0;
} else if (code === 10) {
this.cursor.y++;
if (!use_CR) {
this.cursor.x = 0;
}
} else if (code === 9) {
print.call(this, '\t');
} else if (ansi_art && code in cp_437_control) {
// eslint-disable-next-line no-console
console.log({code: '0x' + code.toString(16)});
print.call(this, cp_437_control[code]);
} else if (DEBUG) {
var mod = code % characters.length;
var char = characters[mod];
// eslint-disable-next-line no-console
console.log({code: code, char: char});
print.call(this, char);
}
if (!this.result[this.cursor.y]) {
this.result[this.cursor.y] = '';
}
},
inst_e: function(collected, flag) {
if (collected === '(') {
if (flag in CHARSETS) {
charset = CHARSETS[flag];
}
}
},
inst_E: function(data) {
/* eslint-disable no-console */
console.log(data);
/* eslint-enable no-console */
},
inst_c: function(collected, params, flag) {
var value = params[0] === 0 ? 1 : params[0];
switch (flag) {
case 's':
saved_cursor = Object.assign({}, this.cursor);
break;
case 'u':
this.cursor = saved_cursor;
break;
case 'A': // UP
this.cursor.y -= value;
break;
case 'B': // Down
this.cursor.y += value;
break;
case 'C': // Forward
this.cursor.x += value;
break;
case 'D': // Backward
this.cursor.x -= value;
break;
case 'E': // Cursor Next Line
this.cursor.x = 0;
this.cursor.y += value;
break;
case 'F': // Cursor Previous Line
this.cursor.x = 0;
this.cursor.y -= value;
break;
case 'H':
// -1 since CUP is 1-based
this.cursor.y = Math.min(params[0] || 1, ROWS) - 1;
this.cursor.x = Math.min(params[1] || 1, COLS) - 1;
break;
case 'm':
code = format_ansi(params, this.state, ansi_art);
var empty = params.length === 1 && params[0] === 0;
if (inside) {
if (empty) {
inside = false;
format = null;
} else {
format = '[[' + code.join(';') + ']';
}
} else if (empty) {
format = null;
} else {
format = '[[' + code.join(';') + ']';
inside = true;
}
break;
}
if (this.cursor.x < 0) {
this.cursor.x = 0;
}
if (this.cursor.y < 0) {
this.cursor.y = 0;
}
}
};
// extra parser options not used by unix_formatting
Object.keys(settings.ansiParser).forEach(function(name) {
var original = parser_events[name];
var fn = settings.ansiParser[name];
parser_events[name] = original ? function() {
if (fn.apply(parser_events, arguments) !== false) {
return original.apply(parser_events, arguments);
}
} : function() {
return fn.apply(parser_events, arguments);
};
settings.ansiParser[name] = parser_events[name];
});
var parser = new AnsiParser(parser_events);
parser.parse(input);
var output = parser_events.result.join('\n');
if (input !== output) {
return output;
}
if (typeof options !== 'undefined' && typeof options.position === 'number') {
return [input, options.position];
}
return input;
};
})();
$.terminal.from_ansi.__no_warn__ = true;
$.terminal.defaults.formatters.unshift($.terminal.from_ansi);
$.terminal.defaults.formatters.unshift($.terminal.overtyping);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment