diff --git a/static-files/clog-terminal/unix_formatting.js b/static-files/clog-terminal/unix_formatting.js new file mode 100644 index 0000000..14a2458 --- /dev/null +++ b/static-files/clog-terminal/unix_formatting.js @@ -0,0 +1,1432 @@ +/**@license + * __ _____ ________ __ + * / // _ /__ __ _____ ___ __ _/__ ___/__ ___ ______ __ __ __ ___ / / + * __ / // // // // // _ // _// // / / // _ // _// // // \/ // _ \/ / + * / / // // // // // ___// / / // / / // ___// / / / / // // /\ // // / /__ + * \___//____ \\___//____//_/ _\_ / /_//____//_/ /_/ /_//_//_/ /_/ \__\_\___/ + * \/ /____/ + * http://terminal.jcubic.pl + * + * This is example of how to create custom formatter for jQuery Terminal + * + * Copyright (c) 2014-2023 Jakub Jankiewicz + * 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 [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; i0x1f && 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) { + $.extend(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 = 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 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 prev_code; + 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 (prev_code !== 13) { + 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] = ''; + } + prev_code = code; + }, + 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]; + if (typeof fn === 'function') { + 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); +}); diff --git a/tutorial/03-tutorial.lisp b/tutorial/03-tutorial.lisp index 941b2c4..a3cd607 100644 --- a/tutorial/03-tutorial.lisp +++ b/tutorial/03-tutorial.lisp @@ -26,7 +26,7 @@ ;;; This means that appropriate precautions to thread protect data should be taken ;;; and that events do not wait for previous event handlers to complete. To change ;;; this behavior just add at start of event WITH-SYNC-EVENT and then all events -;;; will be serialized like in "traditional" GUIs to that event, events using +;;; will be serialized like in "traditional" GUIs so that event, events using ;;; WITH-SYNC-EVENT will be on same queue of incoming events and syncronized. ;;; But... notice what happens once syncing is on the next event doesn't hit until ;;; SLEEP returns. diff --git a/tutorial/04-tutorial.lisp b/tutorial/04-tutorial.lisp index 7e5b09e..fe3c8fa 100644 --- a/tutorial/04-tutorial.lisp +++ b/tutorial/04-tutorial.lisp @@ -10,7 +10,7 @@ (defun on-new-window (body) "On-new-window handler." (setf (title (html-document body)) "Tutorial 04") - ;; The same handler #'my-on-click is set on both targets + ;; The same handler my-on-click is set on both targets (set-on-click (create-section body :h1 :content "Hello World! (click me!)") 'my-on-click) (set-on-click (create-section body :h3 :content "Click me too!")