comparison termemu.js @ 4:ee22eb9ab009

Client: don't assume the terminal is 24x80.
author John "Elwin" Edwards <elwin@sdf.org>
date Mon, 07 May 2012 11:09:14 -0700
parents bd412f63ce0d
children 826a7ced69f8
comparison
equal deleted inserted replaced
3:bfdc775a574f 4:ee22eb9ab009
59 view: null, // The div holding the terminal screen 59 view: null, // The div holding the terminal screen
60 screen: null, // The div representing the active screen area 60 screen: null, // The div representing the active screen area
61 normbuf: null, // The normal screen buffer 61 normbuf: null, // The normal screen buffer
62 altbuf: null, // The alternate screen buffer 62 altbuf: null, // The alternate screen buffer
63 histbuf: null, // The screen history buffer 63 histbuf: null, // The screen history buffer
64 /* Attributes */
65 w: 0, // Screen width
66 h: 0, // Screen height
64 fgColor: "#b2b2b2", // Default color for text 67 fgColor: "#b2b2b2", // Default color for text
65 bgColor: "black", // Default background color 68 bgColor: "black", // Default background color
69 scrT: 0, // top and bottom of scrolling region
70 scrB: 0, // init() will set this properly
66 c: null, // Contains cursor position and text attributes 71 c: null, // Contains cursor position and text attributes
67 offedge: false, // Going off the edge doesn't mean adding a new line 72 offedge: false, // Going off the edge doesn't mean adding a new line
68 clearAttrs: function () { 73 clearAttrs: function () {
69 /* Make sure to reset ALL attribute properties and NOTHING else. */ 74 /* Make sure to reset ALL attribute properties and NOTHING else. */
70 this.c.bold = false; 75 this.c.bold = false;
121 return "#" + colstr + colstr + colstr; 126 return "#" + colstr + colstr + colstr;
122 } 127 }
123 else 128 else
124 return fallback; 129 return fallback;
125 }, 130 },
126 scrT: 0, // top and bottom of scrolling region
127 scrB: 23,
128 // These keyboard-related things don't really belong here. 131 // These keyboard-related things don't really belong here.
129 shift: false, 132 shift: false,
130 shiftp: function () { 133 shiftp: function () {
131 return this.shift; 134 return this.shift;
132 }, 135 },
138 return this.ctrl; 141 return this.ctrl;
139 }, 142 },
140 togglectrl: function () { 143 togglectrl: function () {
141 this.ctrl = !this.ctrl; 144 this.ctrl = !this.ctrl;
142 }, 145 },
143 init: function (divID) { 146 init: function (divID, h, w) {
144 /* Makes a div full of character cells. */ 147 /* Makes a div full of character cells. */
145 if (this.screen != null) 148 if (this.screen != null)
146 return; 149 return;
147 var owrap = document.getElementById(divID); 150 var owrap = document.getElementById(divID);
148 if (!owrap) 151 if (!owrap)
149 return; 152 return;
150 while (owrap.firstChild != null) 153 while (owrap.firstChild != null)
151 owrap.removeChild(owrap.firstChild); 154 owrap.removeChild(owrap.firstChild);
152 this.c = new Cursor(null); 155 this.c = new Cursor(null);
156 /* Set up the sizes. */
157 var tn;
158 tn = Number(h);
159 if (tn > 0 && tn < 256)
160 this.h = tn;
161 else
162 this.h = 24;
163 tn = Number(w);
164 if (tn > 0 && tn < 256)
165 this.w = tn;
166 else
167 this.w = 80;
168 this.scrB = this.h - 1;
153 /* Create the contents of the terminal div */ 169 /* Create the contents of the terminal div */
154 this.inwrap = document.createElement("div"); 170 this.inwrap = document.createElement("div");
155 this.inwrap.id = "inwrap"; 171 this.inwrap.id = "inwrap";
156 owrap.appendChild(this.inwrap); 172 owrap.appendChild(this.inwrap);
157 var termdiv = document.createElement("div"); 173 var termdiv = document.createElement("div");
163 this.histbuf.id = "histbuf"; 179 this.histbuf.id = "histbuf";
164 termdiv.appendChild(this.histbuf); 180 termdiv.appendChild(this.histbuf);
165 this.normbuf = document.createElement("div"); 181 this.normbuf = document.createElement("div");
166 this.normbuf.id = "normbuf"; 182 this.normbuf.id = "normbuf";
167 termdiv.appendChild(this.normbuf); 183 termdiv.appendChild(this.normbuf);
168 for (var row = 0; row < 24; row++) { 184 for (var row = 0; row < this.h; row++) {
169 this.normbuf.appendChild(this.makeRow()); 185 this.normbuf.appendChild(this.makeRow());
170 } 186 }
171 this.altbuf = document.createElement("div"); 187 this.altbuf = document.createElement("div");
172 this.altbuf.id = "altbuf"; 188 this.altbuf.id = "altbuf";
173 termdiv.appendChild(this.altbuf); 189 termdiv.appendChild(this.altbuf);
225 toAltBuf: function () { 241 toAltBuf: function () {
226 if (this.screen == this.altbuf) 242 if (this.screen == this.altbuf)
227 return; 243 return;
228 while (this.altbuf.firstChild != null) 244 while (this.altbuf.firstChild != null)
229 this.altbuf.removeChild(this.altbuf.firstChild); 245 this.altbuf.removeChild(this.altbuf.firstChild);
230 for (var i = 0; i < 24; i++) { 246 for (var i = 0; i < this.h; i++) {
231 this.altbuf.appendChild(this.makeRow()); 247 this.altbuf.appendChild(this.makeRow());
232 } 248 }
233 this.normc = new Cursor(this.c); 249 this.normc = new Cursor(this.c);
234 this.altbuf.style.display = "table-row-group"; 250 this.altbuf.style.display = "table-row-group";
235 this.normbuf.style.display = "none"; 251 this.normbuf.style.display = "none";
264 } 280 }
265 else { 281 else {
266 this.offedge = false; 282 this.offedge = false;
267 if (x < 0) 283 if (x < 0)
268 x = 0; 284 x = 0;
269 else if (x > 79) 285 else if (x >= this.w)
270 x = 79; 286 x = this.w - 1;
271 } 287 }
272 if (y == null) { 288 if (y == null) {
273 if (this.c.y != null) 289 if (this.c.y != null)
274 y = this.c.y; 290 y = this.c.y;
275 else 291 else
276 return; 292 return;
277 } 293 }
278 else if (y < 0) 294 else if (y < 0)
279 y = 0; 295 y = 0;
280 else if (y > 23) 296 else if (y >= this.h)
281 y = 23; 297 y = this.h - 1;
282 /* Un-reverse video the current location. */ 298 /* Un-reverse video the current location. */
283 this.flipCursor(); 299 this.flipCursor();
284 this.c.x = x; 300 this.c.x = x;
285 this.c.y = y; 301 this.c.y = y;
286 /* Reverse-video the new location. */ 302 /* Reverse-video the new location. */
312 this.flipCursor(); 328 this.flipCursor();
313 while (count > 0) { 329 while (count > 0) {
314 var blankrow = this.makeRow(); 330 var blankrow = this.makeRow();
315 /* Careful with the order */ 331 /* Careful with the order */
316 if (lines > 0) { 332 if (lines > 0) {
317 if (this.scrB == 23) 333 if (this.scrB == this.h - 1)
318 this.screen.appendChild(blankrow); 334 this.screen.appendChild(blankrow);
319 else 335 else
320 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB 336 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB
321 + 1]); 337 + 1]);
322 this.historize(this.scrT); 338 this.historize(this.scrT);
332 this.flipCursor(); 348 this.flipCursor();
333 return; 349 return;
334 }, 350 },
335 newline: function (doReturn) { 351 newline: function (doReturn) {
336 if (this.c.y == this.scrB) 352 if (this.c.y == this.scrB)
337 this.scroll(1) 353 this.scroll(1);
338 else if (this.c.y < 23) 354 else if (this.c.y < this.h - 1)
339 this.cmove(this.c.y + 1, null); 355 this.cmove(this.c.y + 1, null);
340 /* If the cursor is at the bottom but outside the scrolling region, 356 /* If the cursor is at the bottom but outside the scrolling region,
341 * nothing can be done. */ 357 * nothing can be done. */
342 if (doReturn) { 358 if (doReturn) {
343 this.cmove(null, 0); 359 this.cmove(null, 0);
348 this.scroll(-1); 364 this.scroll(-1);
349 else if (this.c.y > 0) 365 else if (this.c.y > 0)
350 this.cmove(this.c.y - 1, null); 366 this.cmove(this.c.y - 1, null);
351 }, 367 },
352 advance: function () { 368 advance: function () {
353 if (this.c.x < 79) 369 if (this.c.x < this.w - 1)
354 this.cmove(null, this.c.x + 1); 370 this.cmove(null, this.c.x + 1);
355 else { 371 else {
356 this.offedge = true; 372 this.offedge = true;
357 } 373 }
358 }, 374 },
376 this.c.cset = 'B'; 392 this.c.cset = 'B';
377 this.cmove(0, 0); 393 this.cmove(0, 0);
378 this.saved = null; 394 this.saved = null;
379 this.normc = null; 395 this.normc = null;
380 this.scrT = 0; 396 this.scrT = 0;
381 this.scrB = 23; 397 this.scrB = this.h - 1;
382 while (this.histbuf.firstChild != null) { 398 while (this.histbuf.firstChild != null) {
383 this.histbuf.removeChild(this.histbuf.firstChild); 399 this.histbuf.removeChild(this.histbuf.firstChild);
384 } 400 }
385 for (var i = 0; i < 24; i++) { 401 for (var i = 0; i < this.h; i++) {
386 this.screen.replaceChild(this.makeRow(), this.screen.childNodes[i]); 402 this.screen.replaceChild(this.makeRow(), this.screen.childNodes[i]);
387 } 403 }
388 this.flipCursor(); // make it appear in the new row 404 this.flipCursor(); // make it appear in the new row
389 return; 405 return;
390 }, 406 },
555 this.cmove(null, this.c.x - 1); 571 this.cmove(null, this.c.x - 1);
556 } 572 }
557 else if (codes[i] == 9) { 573 else if (codes[i] == 9) {
558 /* tab */ 574 /* tab */
559 var xnew; 575 var xnew;
560 if (this.c.x < 79) { 576 if (this.c.x < this.w - 1) {
561 xnew = 8 * (Math.floor(this.c.x / 8) + 1); 577 xnew = 8 * (Math.floor(this.c.x / 8) + 1);
562 if (xnew > 79) 578 if (xnew >= this.w)
563 xnew = 79; 579 xnew = this.w - 1;
564 this.cmove(null, xnew); 580 this.cmove(null, xnew);
565 } 581 }
566 else { 582 else {
567 this.offedge = true; 583 this.offedge = true;
568 } 584 }
699 } 715 }
700 if (params[0]) 716 if (params[0])
701 y = params[0] - 1; 717 y = params[0] - 1;
702 if (params[1]) 718 if (params[1])
703 x = params[1] - 1; 719 x = params[1] - 1;
704 if (y > 23) 720 if (y >= this.h)
705 y = 23; 721 y = this.h - 1;
706 if (x > 79) 722 if (x >= this.w)
707 x = 79; 723 x = this.w - 1;
708 debug(0, "Moving to row " + y + ", col " + x); 724 debug(0, "Moving to row " + y + ", col " + x);
709 this.cmove(y, x); 725 this.cmove(y, x);
710 } 726 }
711 else if (c == 73) { 727 else if (c == 73) {
712 /* I - move forward by tabs */ 728 /* I - move forward by tabs */
715 debug(1, "Invalid CSI I sequence: " + comstr); 731 debug(1, "Invalid CSI I sequence: " + comstr);
716 return; 732 return;
717 } 733 }
718 while (count > 0) { 734 while (count > 0) {
719 x = 8 * (Math.floor(x / 8) + 1); 735 x = 8 * (Math.floor(x / 8) + 1);
720 if (x > 79) { 736 if (x >= this.w) {
721 x = 79; 737 x = this.w - 1;
722 break; 738 break;
723 } 739 }
724 count--; 740 count--;
725 } 741 }
726 this.cmove(null, x); 742 this.cmove(null, x);
737 return; 753 return;
738 } 754 }
739 if (!params[0]) { 755 if (!params[0]) {
740 /* Either 0 or not given */ 756 /* Either 0 or not given */
741 start = this.c.y + 1; 757 start = this.c.y + 1;
742 end = 23; 758 end = this.h - 1;
743 cols = 1; 759 cols = 1;
744 } 760 }
745 else if (params[0] == 1) { 761 else if (params[0] == 1) {
746 start = 0; 762 start = 0;
747 end = this.c.y - 1; 763 end = this.c.y - 1;
748 cols = -1; 764 cols = -1;
749 } 765 }
750 else if (params[0] == 2) { 766 else if (params[0] == 2) {
751 start = 0; 767 start = 0;
752 end = 23; 768 end = this.h - 1;
753 cols = 0; 769 cols = 0;
754 } 770 }
755 else { 771 else {
756 debug(1, "Unimplemented parameter in CSI J sequence: " + comstr); 772 debug(1, "Unimplemented parameter in CSI J sequence: " + comstr);
757 return; 773 return;
761 } 777 }
762 if (cols != 0) { 778 if (cols != 0) {
763 /* Otherwise, the whole screen was erased and the active row doesn't 779 /* Otherwise, the whole screen was erased and the active row doesn't
764 * need special treatment. */ 780 * need special treatment. */
765 var cursrow = this.screen.childNodes[this.c.y]; 781 var cursrow = this.screen.childNodes[this.c.y];
766 for (var ncol = this.c.x; ncol >= 0 && ncol < 80; ncol += cols) { 782 for (var ncol = this.c.x; ncol >= 0 && ncol < this.w; ncol += cols) {
767 cursrow.replaceChild(this.makeCell(' '), cursrow.childNodes[ncol]); 783 cursrow.replaceChild(this.makeCell(' '), cursrow.childNodes[ncol]);
768 } 784 }
769 } 785 }
770 this.offedge = false; 786 this.offedge = false;
771 /* Always flip after replacing the active position. */ 787 /* Always flip after replacing the active position. */
788 start = 0; 804 start = 0;
789 end = this.c.x; 805 end = this.c.x;
790 } 806 }
791 else if (params[0] == 2) { 807 else if (params[0] == 2) {
792 start = 0; 808 start = 0;
793 end = 79; 809 end = this.w - 1;
794 } 810 }
795 else { 811 else {
796 start = this.c.x; 812 start = this.c.x;
797 end = 79; 813 end = this.w - 1;
798 } 814 }
799 var rowdiv = this.screen.childNodes[this.c.y]; 815 var rowdiv = this.screen.childNodes[this.c.y];
800 for (var i = start; i <= end; i++) { 816 for (var i = start; i <= end; i++) {
801 rowdiv.replaceChild(this.makeCell(' '), rowdiv.childNodes[i]); 817 rowdiv.replaceChild(this.makeCell(' '), rowdiv.childNodes[i]);
802 } 818 }
822 if (c == 76) { 838 if (c == 76) {
823 this.historize(this.scrB); 839 this.historize(this.scrB);
824 this.screen.insertBefore(blankrow, this.screen.childNodes[this.c.y]); 840 this.screen.insertBefore(blankrow, this.screen.childNodes[this.c.y]);
825 } 841 }
826 else { 842 else {
827 if (this.scrB == 23) 843 if (this.scrB == this.h - 1)
828 this.screen.appendChild(blankrow); 844 this.screen.appendChild(blankrow);
829 else 845 else
830 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB 846 this.screen.insertBefore(blankrow, this.screen.childNodes[this.scrB
831 + 1]); 847 + 1]);
832 this.historize(this.c.y); 848 this.historize(this.c.y);
868 if (prefix || postfix) { 884 if (prefix || postfix) {
869 debug(1, "Invalid CSI sequence: " + comstr); 885 debug(1, "Invalid CSI sequence: " + comstr);
870 return; 886 return;
871 } 887 }
872 var row = this.screen.childNodes[this.c.y]; 888 var row = this.screen.childNodes[this.c.y];
873 for (var i = 0; i < count && this.c.x + i < 80; i++) { 889 for (var i = 0; i < count && this.c.x + i < this.w; i++) {
874 row.replaceChild(this.makeCell(' '), row.childNodes[this.c.x + i]); 890 row.replaceChild(this.makeCell(' '), row.childNodes[this.c.x + i]);
875 } 891 }
876 this.flipCursor(); 892 this.flipCursor();
877 } 893 }
878 else if (c == 90) { 894 else if (c == 90) {
1010 } 1026 }
1011 } 1027 }
1012 else if (c == 114) { 1028 else if (c == 114) {
1013 /* r - set scrolling region */ 1029 /* r - set scrolling region */
1014 var t = 0; 1030 var t = 0;
1015 var b = 23; 1031 var b = this.h - 1;
1016 if (params[0] && params[0] <= 23) 1032 if (params[0] && params[0] <= this.h - 1)
1017 t = params[0] - 1; 1033 t = params[0] - 1;
1018 if (params[1] && params[1] <= 24) 1034 if (params[1] && params[1] <= this.h)
1019 b = params[1] - 1; 1035 b = params[1] - 1;
1020 if (b <= t) 1036 if (b <= t)
1021 return; 1037 return;
1022 this.scrT = t; 1038 this.scrT = t;
1023 this.scrB = b; 1039 this.scrB = b;
1074 return cell; 1090 return cell;
1075 }, 1091 },
1076 makeRow: function() { 1092 makeRow: function() {
1077 var blankrow = document.createElement("div"); 1093 var blankrow = document.createElement("div");
1078 blankrow.className = "termrow"; 1094 blankrow.className = "termrow";
1079 for (var i = 0; i < 80; i++) 1095 for (var i = 0; i < this.w; i++)
1080 blankrow.appendChild(this.makeCell(' ')); 1096 blankrow.appendChild(this.makeCell(' '));
1081 return blankrow; 1097 return blankrow;
1082 } 1098 }
1083 }; 1099 };
1084 1100