diff --git a/core/ansi_escape_parser.js b/core/ansi_escape_parser.js index 083bedde..107a5ff1 100644 --- a/core/ansi_escape_parser.js +++ b/core/ansi_escape_parser.js @@ -1,24 +1,27 @@ /* jslint node: true */ 'use strict'; -var events = require('events'); -var util = require('util'); var miscUtil = require('./misc_util.js'); var ansi = require('./ansi_term.js'); +var events = require('events'); +var util = require('util'); +var _ = require('lodash'); + exports.ANSIEscapeParser = ANSIEscapeParser; +var CR = 0x0d; +var LF = 0x0a; function ANSIEscapeParser(options) { var self = this; events.EventEmitter.call(this); - this.column = 1; - this.row = 1; - this.style = 0x00; - //this.style = { 0 : true }; - this.scrollBack = 0; + this.column = 1; + this.row = 1; + this.scrollBack = 0; + this.graphicRendition = { styles : [] }; options = miscUtil.valueWithDefault(options, { mciReplaceChar : '', @@ -71,23 +74,11 @@ function ANSIEscapeParser(options) { self.emit('clear screen'); }; - self.resetColor = function() { - //self.fgColor = 7; - //self.bgColor = 0; - self.fgColor = 39; - self.bgColor = 49; - //self.style = { 0 : true }; - //delete self.style; - self.style = 0; - }; - self.rowUpdated = function() { self.emit('row update', self.row + self.scrollBack); }; function literal(text) { - var CR = 0x0d; - var LF = 0x0a; var charCode; var len = text.length; @@ -127,14 +118,14 @@ function ANSIEscapeParser(options) { function getProcessedMCI(mci) { if(self.mciReplaceChar.length > 0) { - var eraseColor = ansi.sgr(self.eraseColor.style, self.eraseColor.fgColor, self.eraseColor.bgColor); - return eraseColor + new Array(mci.length + 1).join(self.mciReplaceChar); + return ansi.getSGRFromGraphicRendition(self.graphicRendition) + new Array(mci.length + 1).join(self.mciReplaceChar); } else { return mci; } } function parseMCI(buffer) { + // :TODO: move this to "constants" seciton @ top var mciRe = /\%([A-Z]{2})([0-9]{1,2})?(?:\(([0-9A-Z,]+)\))*/g; var pos = 0; var match; @@ -165,19 +156,16 @@ function ANSIEscapeParser(options) { if(self.lastMciCode !== fullMciCode) { self.lastMciCode = fullMciCode; - - self.eraseColor = { - flags : self.style, - fgColor : self.fgColor, - bgColor : self.bgColor, - }; + + self.graphicRenditionForErase = _.clone(self.graphicRendition, true); } self.emit('mci', mciCode, id, args); if(self.mciReplaceChar.length > 0) { - self.emit('chunk', ansi.sgr(self.eraseColor.style, self.eraseColor.fgColor, self.eraseColor.bgColor)); + //self.emit('chunk', ansi.sgr(self.eraseColor.style, self.eraseColor.fgColor, self.eraseColor.bgColor)); + self.emit('chunk', ansi.getSGRFromGraphicRendition(self.graphicRenditionForErase)); literal(new Array(match[0].length + 1).join(self.mciReplaceChar)); } else { literal(match[0]); @@ -197,6 +185,7 @@ function ANSIEscapeParser(options) { self.parse = function(buffer, savedRe) { // :TODO: ensure this conforms to ANSI-BBS / CTerm / bansi.txt for movement/etc. + // :TODO: move this to "constants" section @ top var re = /(?:\x1b\x5b)([\?=;0-9]*?)([ABCDHJKfhlmnpsu])/g; var pos = 0; var match; @@ -282,46 +271,28 @@ function ANSIEscapeParser(options) { // set graphic rendition case 'm' : - // :TODO: reset state here for new system + self.graphicRendition = { styles : [ 0 ] }; // reset + //self.graphicRendition.styles = [ 0 ]; + for(i = 0, len = args.length; i < len; ++i) { arg = args[i]; - // :TODO: finish this system - // * style is map of styleName -> boolean - // * Change all fg/bg/etc -> self.state.color { fg, bg, style{} } - // * Change all refs to use this new system - // * When passing color -> sgr, iterate enabled styles -> additional params - // * view.getANSIColor() will need updated - // * art.js will need updated - /* if(ANSIEscapeParser.foregroundColors[arg]) { - self.fgColor = arg;//ANSIEscapeParser.foregroundColors[arg]; + self.graphicRendition.fg = arg; } else if(ANSIEscapeParser.backgroundColors[arg]) { - self.bgColor = arg;//ANSIEscapeParser.backgroundColors[arg]; + self.graphicRendition.bg = arg; } else if(39 === arg) { - delete self.fgColor; + delete self.graphicRendition.fg; } else if(49 === arg) { - delete self.bgColor; + delete self.graphicRendition.bg; } else if(ANSIEscapeParser.styles[arg]) { - self.style = arg; + self.graphicRendition.styles.push(arg); + } else if(22 === arg) { + // :TODO: remove bold. } - - */ - - if(arg >= 30 && arg <= 37) { - self.fgColor = arg; - } else if(arg >= 40 && arg <= 47) { - self.bgColor = arg; - } else { - self.style |= arg; - - if(0 === arg) { - self.resetColor(); - //self.style = 0; - } - } - } + + console.log(self.graphicRendition) break; // erase display/screen @@ -333,8 +304,6 @@ function ANSIEscapeParser(options) { break; } } - - this.resetColor(); } util.inherits(ANSIEscapeParser, events.EventEmitter); @@ -364,12 +333,13 @@ ANSIEscapeParser.backgroundColors = { }; Object.freeze(ANSIEscapeParser.backgroundColors); +// :TODO: ensure these all align with that of ansi_term.js ANSIEscapeParser.styles = { 0 : 'default', 1 : 'bright', 2 : 'dim', - 5 : 'slow blink', - 6 : 'fast blink', + 5 : 'slowBlink', + 6 : 'fastBlink', 7 : 'negative', 8 : 'concealed', 22 : 'normal', diff --git a/core/ansi_term.js b/core/ansi_term.js index b4f20a77..fc7b00f1 100644 --- a/core/ansi_term.js +++ b/core/ansi_term.js @@ -19,6 +19,7 @@ var _ = require('lodash'); exports.getFGColorValue = getFGColorValue; exports.getBGColorValue = getBGColorValue; exports.sgr = sgr; +exports.getSGRFromGraphicRendition = getSGRFromGraphicRendition; exports.clearScreen = clearScreen; exports.resetScreen = resetScreen; exports.normal = normal; @@ -323,6 +324,21 @@ function sgr() { return ESC_CSI + result + 'm'; } +// +// Converts a Graphic Rendition object used elsewhere +// to a ANSI SGR sequence +// +function getSGRFromGraphicRendition(graphicRendition) { + var sgrSeq = graphicRendition.styles.slice(0); // start out with styles + if(graphicRendition.fg) { + sgrSeq.push(graphicRendition.fg); + } + if(graphicRendition.bg) { + sgrSeq.push(graphicRendition.bg); + } + return sgr(sgrSeq); +} + /////////////////////////////////////////////////////////////////////////////// // Shortcuts for common functions /////////////////////////////////////////////////////////////////////////////// diff --git a/core/art.js b/core/art.js index 14e10cf1..1df6c06d 100644 --- a/core/art.js +++ b/core/art.js @@ -456,22 +456,29 @@ function display(options, cb) { var mapItem = mciCode + id; // :TODO: Avoid mutiple [] lookups here if(mci[mapItem]) { + mci[mapItem].focusGraphicRendition = parser.graphicRendition; + + /* mci[mapItem].focusColor = { fg : parser.fgColor, bg : parser.bgColor, flags : parser.style, }; + */ mci[mapItem].focusArgs = args; } else { mci[mapItem] = { - args : args, + args : args, + /* color : { fg : parser.fgColor, bg : parser.bgColor, flags : parser.style, }, - code : mciCode, - id : parseInt(id, 10), + */ + graphicRendition : parser.graphicRendition, + code : mciCode, + id : parseInt(id, 10), }; mciPosQueue.push(mapItem); diff --git a/core/edit_text_view.js b/core/edit_text_view.js index 146693ea..a98ff1c7 100644 --- a/core/edit_text_view.js +++ b/core/edit_text_view.js @@ -23,8 +23,7 @@ function EditTextView(options) { this.cursorPos = { x : 0 }; this.clientBackspace = function() { - this.client.term.write( - '\b' + this.getANSIColor(this.getColor()) + this.fillChar + '\b' + this.getANSIColor(this.getFocusColor())); + this.client.term.write('\b' + this.getSGR() + this.fillChar + '\b' + this.getFocusSGR()); }; } diff --git a/core/mci_view_factory.js b/core/mci_view_factory.js index 8a21edb0..e34b58cc 100644 --- a/core/mci_view_factory.js +++ b/core/mci_view_factory.js @@ -56,11 +56,15 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { var view; var options = { - client : this.client, - id : mci.id, - color : mci.color, - focusColor : mci.focusColor, - position : { x : mci.position[0], y : mci.position[1] }, + client : this.client, + id : mci.id, + color : mci.color, + focusColor : mci.focusColor, + + graphicRendition : mci.graphicRendition, + focusGraphicRendition : mci.focusGraphicRendition, + + position : { x : mci.position[0], y : mci.position[1] }, }; function setOption(pos, name) { diff --git a/core/spinner_menu_view.js b/core/spinner_menu_view.js index 8965ef8e..41c0e3b9 100644 --- a/core/spinner_menu_view.js +++ b/core/spinner_menu_view.js @@ -38,7 +38,7 @@ function SpinnerMenuView(options) { } this.client.term.write(ansi.goto(this.position.x, this.position.y)); - this.client.term.write(self.getANSIColor(this.hasFocus ? self.getFocusColor() : self.getColor())); + this.client.term.write(self.hasFocus ? self.getFocusSGR() : self.getSGR()); var text = strUtil.stylizeString(item.text, item.focused ? self.focusTextStyle : self.textStyle); diff --git a/core/text_view.js b/core/text_view.js index 10628537..c08e939e 100644 --- a/core/text_view.js +++ b/core/text_view.js @@ -51,14 +51,18 @@ function TextView(options) { // this is the text but too long // text but too long if(this.horizScroll) { - textToDraw = textToDraw.substr(textToDraw.length - this.dimens.width, textToDraw.length);//0, this.dimens.width);//textToDraw.length - (this.dimens.width + 1)); + textToDraw = textToDraw.substr(textToDraw.length - this.dimens.width, textToDraw.length); } } - var textAnsiColor = this.getANSIColor(this.hasFocus ? this.getFocusColor() : this.getColor()); - var fillAnsiColor = this.getANSIColor(this.getColor()); - - this.client.term.write(strUtil.pad(textToDraw, this.dimens.width + 1, this.fillChar, this.justify, textAnsiColor, fillAnsiColor)); + this.client.term.write(strUtil.pad( + textToDraw, + this.dimens.width + 1, + this.fillChar, + this.justify, + this.hasFocus ? this.getFocusSGR() : this.getSGR(), + this.getSGR() // :TODO: use extended style color if avail + )); }; this.setText(options.text || ''); @@ -76,8 +80,15 @@ TextView.prototype.setFocus = function(focused) { TextView.super_.prototype.setFocus.call(this, focused); this.redraw(); + + console.log('---') + console.log(this.graphicRendition) + console.log(this.focusGraphicRendition) + console.log('---') + + // position & SGR for cursor this.client.term.write(ansi.goto(this.position.x, this.position.y + this.text.length)); - this.client.term.write(this.getANSIColor(this.getFocusColor())); + this.client.term.write(this.getFocusSGR()); }; TextView.prototype.getData = function() { diff --git a/core/toggle_menu_view.js b/core/toggle_menu_view.js index c055d5f0..a01f3331 100644 --- a/core/toggle_menu_view.js +++ b/core/toggle_menu_view.js @@ -37,7 +37,7 @@ ToggleMenuView.prototype.redraw = function() { this.cachePositions(); - this.client.term.write(this.getANSIColor(this.hasFocus ? this.getFocusColor() : this.getColor())); + this.client.term.write(this.hasFocus ? this.getFocusSGR() : this.getSGR()); assert(this.items.length === 2); for(var i = 0; i < 2; i++) { @@ -47,13 +47,13 @@ ToggleMenuView.prototype.redraw = function() { if(1 === i) { //console.log(this.styleColor1) - var sepColor = this.getANSIColor(this.styleColor1 || this.getColor()); - console.log(sepColor.substr(1)) - //sepColor = '\u001b[0m\u001b[1;30m'; + //var sepColor = this.getANSIColor(this.styleColor1 || this.getColor()); + //console.log(sepColor.substr(1)) + var sepColor = '\u001b[0m\u001b[1;30m'; // :TODO: FIX ME!!! this.client.term.write(sepColor + ' / '); } - this.client.term.write(this.getANSIColor(i === this.focusedItemIndex ? this.getFocusColor() : this.getColor())); + this.client.term.write(i === this.focusedItemIndex ? this.getFocusSGR() : this.getSGR()); this.client.term.write(text); } }; diff --git a/core/vertical_menu_view.js b/core/vertical_menu_view.js index 1a87995f..924f2749 100644 --- a/core/vertical_menu_view.js +++ b/core/vertical_menu_view.js @@ -76,8 +76,7 @@ function VerticalMenuView(options) { } self.client.term.write(ansi.goto(item.xPosition, self.position.y)); - this.client.term.write(self.getANSIColor( - index === self.focusedItemIndex ? self.getFocusColor() : self.getColor())); + this.client.term.write(index === self.focusedItemIndex ? this.getFocusSGR() : this.getSGR()); var text = strUtil.stylizeString(item.text, item.focused ? self.focusTextStyle : self.textStyle); diff --git a/core/view.js b/core/view.js index b73b26c6..09b641a5 100644 --- a/core/view.js +++ b/core/view.js @@ -64,8 +64,8 @@ function View(options) { this.dimens.width = options.dimens.width; } - this.color = options.color || { flags : 0, fg : 7, bg : 0 }; - this.focusColor = options.focusColor || this.color; + this.graphicRendition = options.graphicRendition || { fg : 7, bg : 0, styles : [ 0 ] }; + this.focusGraphicRendition = options.focusGraphicRendition || this.graphicRendition; if(options.styleColor1) { this.styleColor1 = options.styleColor1; @@ -134,6 +134,7 @@ View.prototype.setPosition = function(pos) { 'Y position ' + this.position.y + ' out of terminal range ' + this.client.term.termWidth); }; +/* View.prototype.setColor = function(color, bgColor, flags) { if(_.isObject(color)) { assert(_.has(color, 'fg')); @@ -164,14 +165,23 @@ View.prototype.setColor = function(color, bgColor, flags) { this.color.bg = ansi.getBGColorValue(this.color.bg); } }; +*/ -View.prototype.getColor = function() { - return this.color; -}; +View.prototype.getGraphicRendition = function() { + return this.graphicRendition; +} -View.prototype.getFocusColor = function() { - return this.focusColor; -}; +View.prototype.getFocusGraphicRendition = function() { + return this.focusGraphicRendition; +} + +View.prototype.getSGR = function() { + return ansi.getSGRFromGraphicRendition(this.getGraphicRendition()); +} + +View.prototype.getFocusSGR = function() { + return ansi.getSGRFromGraphicRendition(this.getFocusGraphicRendition()); +} View.prototype.redraw = function() { this.client.term.write(ansi.goto(this.position.x, this.position.y));