Logo  

Home - Old Man Programmer

Displaying webapps/vt100/script//vt100-fb.js

module.exports = {
  terminal : {
  FGMASK	: 15,
  BGMASK	: 240,
  BOLD		: 256,
  UNDERLINE	: 512,
  REVERSE	: 1024,
  BLINK		: 2048,
  
  sc : null,
  m : null, row : null,
  // m: { char : " ", fg : this.fg, bg: this.bg, flags: x };

  rows : 0, cols : 0,
  homeRow: 0, homeCol : 0,
  tmargin: 0, bmargin: 0,
  cx : 0, cy : 0,
  cq : "", cqlen : 0,

  // Attributes:
  fg : 7, bg : 0,
  bold: false, underline: false, blink: false, reverse: false,

  mode : 0,
  // 0 = normal, 1 = escape encountered:
  //   2 = [ encountered, 3 = [? encountered,
  //   4 = ) encountered, 5 = ( encountered

  newrow : function(oldline) {
    var m = [];
    for(var c = 0; c < this.cols; c ++) {
      if (oldline != undefined) {
	m[c] = { char : " ", fg : oldline[c].fg, bg: oldline[c].bg, flags : 0};
      } else {
	m[c] = { char : " ", fg : this.fg, bg: this.bg, flags: 0 };
      }
      this.setColor(m[c], m[c].fg, m[c].bg);
    }
    return m;
  },
  scrollup : function() {
    for(var r = this.tmargin; r < this.bmargin; r++) {
      this.m[r] = this.m[r+1];
    }
    this.m[this.bmargin] = this.newrow();
  },
  scrolldown : function() {
    for(var r = this.bmargin; r > this.tmargin; r--) {
      this.m[r] = this.m[r-1];
    }
    this.m[this.tmargin] = this.newrow();
  },

  tab : function() {
    this.cx = Math.min(this.cols-1, (8*Math.floor((this.cx+8)/8)));
  },
  cr : function() {
    this.cx = 0;
  },
  down : function(lines, scroll) {
    do {
      if (this.cy == this.bmargin) {
	if (scroll) this.scrollup();
      } else this.cy++;
    } while (--lines > 0);
  },
  up : function(lines, scroll) {
    do {
      if (this.cy == this.tmargin) {
	if (scroll) this.scrolldown();
      } else this.cy--;
    } while (--lines > 0);
  },
  left : function(cols) {
    this.cx = Math.max(0, this.cx-(cols?cols:1));
  },
  right : function(cols) {
    this.cx = Math.min(this.cols-1, this.cx + (cols? cols : 1));
  },
  move : function(y, x) {
    this.cy = Math.max(Math.min(this.rows-1,y-1), 0);
    this.cx = Math.max(Math.min(this.cols-1,x-1), 0);
  },
  clrline : function(r, s, e) {
    var m = this.m[r];
    for(var c = s; c <= e; c++) {
      m[c].char = " ";
      this.setColor(m[c], this.fg, this.bg);
    }
  },
  eid : function(n) {
    switch(n) {
      case 0:	// erase cursor to eos
	this.clrline(this.cy, this.cx, this.cols-1);
	for(var r = this.cy+1; r < this.rows; r++)
	  this.clrline(r, 0, this.cols-1);
	break;
      case 1:	// start of screen to cursor
	for(var r = 0; r < this.cy; r++)
	  this.clrline(r, 0, this.cols-1);
	this.clrline(this.cy, 0, this.cx);
	break;
      case 2:	// clear screen
	for(var r = 0; r < this.rows; r++)
	  this.clrline(r, 0, this.cols-1);
    }
  },
  eil : function(n) {
    switch(n) {
      case 0:	// erase cursor to eol
	return this.clrline(this.cy, this.cx, this.cols-1);
      case 1:	// erase from bol to cursor
	return this.clrline(this.cy, 0, this.cx);
      case 2:	// erase entire line
	return this.clrline(this.cy, 0, this.cols-1);
    }
  },

  setMargins : function(t, b) {
    t = Math.min(Math.max(0, t-1), this.rows-2);
    b = Math.min(Math.max(0, b-1), this.rows-1);
    if (t == 0 && b == 0) b = this.rows-1;
    if (t >= b) return;
    this.tmargin = t;
    this.bmargin = b;
    this.move(this.homeRow, this.homeCol);
    return;
  },

  setAttrs : function(pn) {
    var v, l = Math.max(this.cqlen, 1);
    if (this.cqlen == 0) pn[0] = 0;

    while (l-- > 0) {
      switch(v = pn[0]) {
	case 0:
	  this.fg = 7; this.bg = 0;
	  this.bold = this.underline = this.blink = this.reverse = false;
	  break;
	case 1:
	  this.bold = true;
	  break;
	case 4:
	  this.underline = true;
	  break;
	case 5:
	  this.blink = true;
	  break;
	case 7:
	  this.reverse = true;
	  break;
	case 8:
	  this.fg = this.bg;
	  break;
	case 21:
	  this.bold = false;
	  break;
	case 24:
	  this.underline = false;
	  break;
	case 27:
	  this.reverse = false;
	  break;
	case 28:
	  this.fg = 0;
	  break;
	default:
	  if (v >= 30 && v <= 37) this.fg = v-30;
	  else if (v >= 40 && v <= 47) this.bg = v-40;
	  else if (v >= 90 && v <= 97) this.fg = (v-90)+8;
	  else if (v >= 100 && v <= 107) this.bg = (v-100)+8;
	  break;
      }
      pn.shift();
    }
  },

  normal : function(ch) {
    switch(ch) {
      case '\033':
	this.mode = 1;
	return;
      case '\007': return;
      case '\b': return this.left(1);
      case '\t': return this.tab();
      case '\n':
      case '\v':
      case '\f': return this.down(1,true);
      case '\r': return this.cr();
      default:
	if (ch < ' ' || ch == 127) return;
    }
    var m = this.m[this.cy][this.cx];
    m.char = ch;
    if (this.reverse) this.setColor(m,this.colorInverse(this.fg), this.colorInverse(this.bg));
    else this.setColor(m, this.fg, this.bg);
    m.flags = 0;
    if (this.underline) m.flags |= this.UNDERLINE;
    if (this.bold) m.flags |= this.BOLD;

    this.cx++;
    if (this.cx >= this.cols) {
      this.cx = 0;
      if (this.cy+1 >= this.rows) this.scrollup();
      else this.cy++;
    }
  },

  parsecq : function() {
    if (this.cq.length == 0) return [ 0, 0 ];
    var a = [0, 0], s = this.cq.split(";");
    for(var i = 0; i < s.length; i++) {
      a[i] = parseInt(s[i]);
    }
    this.cqlen = s.length;
    this.cq = "";
    return a;
  },

  qmode : function(ch) {
    if (ch >= '0' && ch <='9' || ch == ';') this.cq += ch;
    else {
      this.mode = 0;
      var pn = this.parsecq();
      switch(ch) {
	case 'l':
	  break;
	case 'h':
	  break;
      }
    }
  },

  brac: function(ch) {
    if (ch >= '0' && ch <='9' || ch == ';') this.cq += ch;
    else {
      this.mode = 0;
      var pn = this.parsecq();
      switch(ch) {
	case 'A': // up
	  return this.up(pn[0], false);
	case 'B': // down
	  return this.down(pn[0], false);
	case 'C': // right
	  return this.right(pn[0]);
	case 'D': // left
	  return this.left(pn[0]);
	case 'f':
	case 'H':
	  return this.move(pn[0], pn[1]);
	case 'J':
	  return this.eid(pn[0]);
	case 'K':
	  return this.eil(pn[0]);
	case 'r':
	  return this.setMargins(pn[0], pn[1]);
	case 'm':
	  return this.setAttrs(pn);
	case '?':
	  if (this.cqlen == 0) this.mode = 3;
	  return;
	default:
      }
    }
  },

  escape : function(ch) {
    this.mode = 0;
    switch(ch) {
      case '[': return this.cq = "", this.mode = 2;
      case '(': return this.cq = "", this.mode = 3;
      case ')': return this.cq = "", this.mode = 4;
      case 'c': return this.reset();
      case 'D': return this.down(1,true);
      case 'M': return this.up(1,true);
      case 'E':
	this.cr();
	this.down(1, true);
	return;
      case '7':
	this.sc = { cy : this.cy, cx : this.cx, cset : null };
	return;
      case '8':
	this.cx = this.sc.cx; this.cy = this.sc.cy;
	return;
      default:
    }
  },

  addch : function(ch) {
    switch(this.mode) {
      case 3: return this.qmode(ch);
      case 2: return this.brac(ch);
      case 1: return this.escape(ch);
      case 0:
      default:
	this.normal(ch);
    }
  },

  addstr : function(s) {
    for(var i = 0; i < s.length; i++) {
      this.addch(s[i]);
    }
  },

  reset : function() {
    this.homeRow = this.homeCol = this.cx = this.cy = this.mode = 0;
    this.sc = { cy : 0, cx: 0, charset: null };
    this.tmargin = 0; this.bmargin = this.rows-1;
    this.fg = 7; this.bg = 0;
    this.bold = this.underline = this.blink = this.reverse = false;

    this.m = [];

    for(var r = 0; r < this.rows; r++) {
      this.m[r] = this.newrow();
    }
  },

  dumpstate: function() {
    var rows = [];
    for(var r = 0; r < this.rows; r++) {
      var cdata = "";
      var adata = [];
      for(var c = 0; c < this.cols; c++) {
	var m = this.m[r][c];
	cdata += m.char;
	adata.push(m.fg | m.bg <<4 | m.flags);
      }
      rows.push({c:cdata, a: adata});
    }
    return {
      cx: this.cx, cy: this.cy, sc: this.sc, mode : this.mode, cq: this.cq,
      tmargin: this.tmargin, bmargin: this.bmargin,
      fg: this.fg, bg: this.bg, bold: this.bold, underline: this.underline,
      blink: this.blink, reverse: this.reverse,
      m: rows
    };
  },

  init: function(w, h) {
    this.rows = h;
    this.cols = w;
    this.reset();
  },

  colorInverse : function(color) {
    if (color < 8) return 7-color;
    return 15-color;
  },
  setColor : function(m, f, b) {
    m.fg = f;
    m.bg = b;
  },
  }
};