From 549ef5c52e209b066e77dba233d4a04d9cb18d72 Mon Sep 17 00:00:00 2001
From: deuce <>
Date: Sun, 8 Nov 2015 06:15:44 +0000
Subject: [PATCH] Move Attribute into separate file in dorkit dir. Start ANSI
 detection "stuff" Add ^A parser. Implement the various *print*() functions
 here rather than per-mode code.

---
 exec/load/dorkit.js | 341 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 294 insertions(+), 47 deletions(-)

diff --git a/exec/load/dorkit.js b/exec/load/dorkit.js
index 9c7ec3eaae..8cb7acbea7 100644
--- a/exec/load/dorkit.js
+++ b/exec/load/dorkit.js
@@ -1,38 +1,9 @@
-function Attribute(value) {
-	if (typeof(value) == 'object' && value.constructor === Attribute)
-		this.value = value.value;
-	else
-		this.value = value;
-}
-
-Attribute.prototype = {
-	// TODO: High intensity background, not blink
-	get blink() {
-		return (this.value & 0x80) ? true : false;
-	},
-	set blink(val) {
-		if (val)
-			this.value |= 0x80;
-		else
-			this.value &= ~0x80;
-	},
-
-	get bg() {
-		return (this.value >> 4) & 0x07;
-	},
-	set bg(val) {
-		this.value &= 0x8f;
-		this.value |= ((val << 4) & 0x70);
-	},
-
-	get fg() {
-		return this.value & 0x0f;
-	},
-	set fg(val) {
-		this.value &= 0xf0;
-		this.value |= val & 0x0f;
-	}
-}
+js.load_path_list.unshift(js.exec_dir+"/dorkit/");
+if (js.global.system !== undefined)
+	js.load_path_list.unshift(system.exec_dir+"/dorkit/");
+log("Load path: "+js.load_path_list.join(", "));
+load("attribute.js");
+load("graphic.js");
 
 var dk = {
 	key:{
@@ -169,7 +140,6 @@ var dk = {
 		/* End of ASCII */
 	},
 
-
 	console:{
 		x:1,					// Current column (1-based)
 		y:1,					// Current row (1-based)
@@ -178,20 +148,266 @@ var dk = {
 		charset:'cp437',		// Supported character set
 		local:true,				// True if writes should go to the local screen
 		remote:true,			// True if writes should go to the remote terminal
-		rows:24,				// Rows in users terminal
+		rows:undefined,			// Rows in users terminal
+		cols:undefined,			// Columns in users terminal
+
+		/*
+		 * Returns a string with ^A codes converted to ANSI or stripped
+		 * as appropriate.
+		 */
+		parse_ctrla:function(txt, orig_attr) {
+			var ret='';
+			var i;
+			var curr_attr;
+			var next_attr;
+
+			if (orig_attr !== undefined)
+				curr_attr = new Attribute(orig_attr);
+			next_attr = new Attribute(curr_attr);
+
+			function attr_str() {
+				var ansi_str;
+
+				if (curr_attr === undefined || curr_attr.value != next_attr.value) {
+					ansi_str = next_attr.ansi(curr_attr);
+					curr_attr.value = next_attr.value;
+					return ansi_str;
+				}
+				return '';
+			}
+
+			for (i=0; i<txt.length; i++) {
+				if (txt.charCodeAt(i)==1) {
+					i++;
+					switch(txt.substr(i, 1)) {
+						case '\1':
+							ret += attr_str()+'\1';
+							break;
+						case 'K':
+							next_attr.fg = Attribute.BLACK;
+							break;
+						case 'R':
+							next_attr.fg = Attribute.RED;
+							break;
+						case 'G':
+							next_attr.fg = Attribute.GREEN;
+							break;
+						case 'Y':
+							next_attr.fg = Attribute.YELLOW;
+							break;
+						case 'B':
+							next_attr.fg = Attribute.BLUE;
+							break;
+						case 'M':
+							next_attr.fg = Attribute.MAGENTA;
+							break;
+						case 'C':
+							next_attr.fg = Attribute.CYAN;
+							break;
+						case 'W':
+							next_attr.fg = Attribute.WHITE;
+							break;
+						case '0':
+							next_attr.bg = Attribute.BLACK;
+							break;
+						case '1':
+							next_attr.bg = Attribute.RED;
+							break;
+						case '2':
+							next_attr.bg = Attribute.GREEN;
+							break;
+						case '3':
+							next_attr.bg = Attribute.YELLOW;
+							break;
+						case '4':
+							next_attr.bg = Attribute.BLUE;
+							break;
+						case '5':
+							next_attr.bg = Attribute.MAGENTA;
+							break;
+						case '6':
+							next_attr.bg = Attribute.CYAN;
+							break;
+						case '7':
+							next_attr.bg = Attribute.WHITE;
+							break;
+						case 'H':
+							next_attr.bright = true;
+							break;
+						case 'I':
+							next_attr.blink = true;
+							break;
+						case 'N':
+							next_attr.value = 7;
+							break;
+						case '-':
+							if (next_attr.blink || next_attr.bright || next_attr.bg !== Attribute.BLACK)
+								next_attr.value = 7;
+							break;
+						case '_':
+							if (next_attr.blink || next_attr.bg !== Attribute.BLACK)
+								next_attr.value = 7;
+							break;
+						default:
+							break;
+					}
+				}
+				else {
+					ret += attr_str()+txt.substr(i, 1);
+				}
+			}
+			return ret;
+
+			return txt.replace(/\1([\x00-\xff])/g, function(unused, code) {
+				switch(code) {
+					case '\1':
+						return '\1';
+					case 'K':
+						curr_attr.fg = Attribute.BLACK;
+						break;
+				}
+			});
+			/* ToDo: Expand \1D, \1T, \1<, \1Z */
+			/* ToDo: "Expand" (ie: remove from string when appropriate) per-level/per-flag stuff */
+			/* ToDo: Strip ANSI (I betcha @-codes can slap it in there) */
+			while(p<txt.length) {
+				ch=txt[p++];
+				switch(ch) {
+					case '\1':		/* CTRL-A code */
+						ch=txt[p++].toUpperCase();
+						switch(ch) {
+							case '\1':	/* A "real" ^A code */
+								this.data[x][y].ch=ch;
+								this.data[x][y].attr=curattr;
+								x++;
+								if(x>=this.width) {
+									x=0;
+									y++;
+									log("next char: [" + txt[p] + "]");
+									if(txt[p] == '\r') p++;
+									if(txt[p] == '\n') p++;
+								}
+								break;
+							case 'K':	/* Black */
+								curattr=(curattr)&0xf8;
+								break;
+							case 'R':	/* Red */
+								curattr=((curattr)&0xf8)|this.defs.RED;
+								break;
+							case 'G':	/* Green */
+								curattr=((curattr)&0xf8)|this.defs.GREEN;
+								break;
+							case 'Y':	/* Yellow */
+								curattr=((curattr)&0xf8)|this.defs.BROWN;
+								break;
+							case 'B':	/* Blue */
+								curattr=((curattr)&0xf8)|this.defs.BLUE;
+								break;
+							case 'M':	/* Magenta */
+								curattr=((curattr)&0xf8)|this.defs.MAGENTA;
+								break;
+							case 'C':	/* Cyan */
+								curattr=((curattr)&0xf8)|this.defs.CYAN;
+								break;
+							case 'W':	/* White */
+								curattr=((curattr)&0xf8)|this.defs.LIGHTGRAY;
+								break;
+							case '0':	/* Black */
+								curattr=(curattr)&0x8f;
+								break;
+							case '1':	/* Red */
+								curattr=((curattr)&0x8f)|(this.defs.RED<<4);
+								break;
+							case '2':	/* Green */
+								curattr=((curattr)&0x8f)|(this.defs.GREEN<<4);
+								break;
+							case '3':	/* Yellow */
+								curattr=((curattr)&0x8f)|(this.defs.BROWN<<4);
+								break;
+							case '4':	/* Blue */
+								curattr=((curattr)&0x8f)|(this.defs.BLUE<<4);
+								break;
+							case '5':	/* Magenta */
+								curattr=((curattr)&0x8f)|(this.defs.MAGENTA<<4);
+								break;
+							case '6':	/* Cyan */
+								curattr=((curattr)&0x8f)|(this.defs.CYAN<<4);
+								break;
+							case '7':	/* White */
+								curattr=((curattr)&0x8f)|(this.defs.LIGHTGRAY<<4);
+								break;
+							case 'H':	/* High Intensity */
+								curattr|=this.defs.HIGH;
+								break;
+							case 'I':	/* Blink */
+								curattr|=this.defs.BLINK;
+								break;
+							case 'N':	/* Normal (ToDo: Does this do ESC[0?) */
+								curattr=7;
+								break;
+							case '-':	/* Normal if High, Blink, or BG */
+								if(curattr & 0xf8)
+									curattr=7;
+								break;
+							case '_':	/* Normal if blink/background */
+								if(curattr & 0xf0)
+									curattr=7;
+								break;
+							case '[':	/* CR */
+								x=0;
+								break;
+							case ']':	/* LF */
+								y++;
+								break;
+							default:	/* Other stuff... specifically, check for right movement */
+								if(ch.charCodeAt(0)>127) {
+									x+=ch.charCodeAt(0)-127;
+									if(x>=this.width)
+										x=this.width-1;
+								}
+						}
+						break;
+					case '\7':		/* Beep */
+						break;
+					case '\r':
+						x=0;
+						break;
+					case '\n':
+						y++;
+						break;
+					default:
+						this.data[x][y]=new this.Cell(ch,curattr);
+						x++;
+						if(x>=this.width) {
+							x=0;
+							y++;
+							if(txt[p] == '\r') p++;
+							if(txt[p] == '\n') p++;
+						}
+				}
+			}
+		},
 
 		/*
 		 * Clears the current screen to black and moves to location 1,1
 		 * sets the current attribute to 7
 		 */
 		clear:function() {
+			if (this.local)
+				this.local_io.clear();
+			if (this.remote)
+				this.remote_io.clear();
 		},
 
 		/*
 		 * Clears to end of line.
-		 * Not available witout ANSI (???)
+		 * Not available without ANSI (???)
 		 */
 		cleareol:function() {
+			if (this.local)
+				this.local_io.cleareol();
+			if (this.remote)
+				this.remote_io.cleareol();
 		},
 
 		/*
@@ -200,6 +416,10 @@ var dk = {
 		 * Not available without ANSI
 		 */
 		gotoxy:function(x,y) {
+			if (this.local)
+				this.local_io.gotoxy(x,y);
+			if (this.remote)
+				this.remote_io.gotoxy(x,y);
 		},
 
 		/*
@@ -209,28 +429,35 @@ var dk = {
 		getblock:function(sx,sy,ex,ey) {
 		},
 
-		/*
-		 * Writes a string with a "\r\n" appended.
-		 */
-		println:function(line) {
-		},
-
 		/*
 		 * Writes a string unmodified.
 		 */
 		print:function(string) {
+			if (this.local)
+				this.local_io.print(string);
+			if (this.remote)
+				this.remote_io.print(string);
 		},
 
 		/*
-		 * Writes a string after parsing ^A codes and appends a "\r\n".
+		 * Writes a string with a "\r\n" appended.
 		 */
-		aprintln:function(line) {
+		println:function(line) {
+			this.print(line+'\r\n');
 		},
 
 		/*
 		 * Writes a string after parsing ^A codes.
 		 */
 		aprint:function(string) {
+			this.println(this.parse_ctrla(line));
+		},
+
+		/*
+		 * Writes a string after parsing ^A codes and appends a "\r\n".
+		 */
+		aprintln:function(line) {
+			this.println(this.parse_ctrla(line));
 		},
 
 		/*
@@ -239,6 +466,11 @@ var dk = {
 		 * true when the entire ANSI sequence is available.
 		 */
 		waitkey:function(timeout) {
+			var q = new Queue("dorkit_input");
+			// TODO: Parse ANSI here!
+			if (q.poll(timeout) === false)
+				return false;
+			return true;
 		},
 
 		/*
@@ -246,12 +478,17 @@ var dk = {
 		 * Returns undefined if there is no key pressed.
 		 */
 		getkey:function() {
+			var q = new Queue("dorkit_input");
+			// TODO: Parse ANSI here!
+			return q.read();
 		},
 
 		/*
 		 * Returns a single byte... ANSI is not parsed.
 		 */
 		getbyte:function() {
+			var q = new Queue("dorkit_input");
+			return q.read();
 		},
 	},
 	connection:{
@@ -319,6 +556,16 @@ var dk = {
 		record_locking:undefined
 	},
 
+	detect_ansi:function() {
+		this.console.remote_io.print("\x1b[s" +	// Save cursor position.
+						"\x1b[255B" +	// Locate as far down as possible
+						"\x1b[255C" +	// Locate as far right as possible
+						"\b "+			// Print something (some terminals apparently need this)
+						"\x1b[6n" +		// Get cursor position
+						"\x1b[u"		// Restore cursor position
+		);
+	},
+
 	parse_dropfile:function(path) {
 		var f = new File(path);
 		var df;
@@ -409,7 +656,7 @@ var dk = {
 	}
 };
 
-js.load_path_list.unshift(js.exec_dir+"/jsdoor/");
+load("local_console.js");
 
 switch(dk.system.mode) {
 	case 'sbbs':
-- 
GitLab