diff options
-rw-r--r-- | config.h | 5 | ||||
-rw-r--r-- | st.c | 318 |
2 files changed, 178 insertions, 145 deletions
@@ -31,10 +31,6 @@ static Key key[] = { | |||
31 | { XK_End, "\033[4~" }, | 31 | { XK_End, "\033[4~" }, |
32 | { XK_Prior, "\033[5~" }, | 32 | { XK_Prior, "\033[5~" }, |
33 | { XK_Next, "\033[6~" }, | 33 | { XK_Next, "\033[6~" }, |
34 | { XK_Left, "\033[D" }, | ||
35 | { XK_Right, "\033[C" }, | ||
36 | { XK_Up, "\033[A" }, | ||
37 | { XK_Down, "\033[B" }, | ||
38 | }; | 34 | }; |
39 | 35 | ||
40 | static char gfx[] = { | 36 | static char gfx[] = { |
@@ -70,4 +66,5 @@ static char gfx[] = { | |||
70 | ['l'] = '+', | 66 | ['l'] = '+', |
71 | ['k'] = '+', | 67 | ['k'] = '+', |
72 | ['x'] = '|', | 68 | ['x'] = '|', |
69 | [255] = 0, | ||
73 | }; | 70 | }; |
@@ -23,10 +23,10 @@ | |||
23 | #define TNAME "xterm" | 23 | #define TNAME "xterm" |
24 | 24 | ||
25 | /* Arbitrary sizes */ | 25 | /* Arbitrary sizes */ |
26 | #define TITLESIZ 256 | 26 | #define ESC_TITLE_SIZ 256 |
27 | #define ESCSIZ 256 | 27 | #define ESC_BUF_SIZ 256 |
28 | #define ESCARGSIZ 16 | 28 | #define ESC_ARG_SIZ 16 |
29 | #define MAXDRAWBUF 1024 | 29 | #define DRAW_BUF_SIZ 1024 |
30 | 30 | ||
31 | #define SERRNO strerror(errno) | 31 | #define SERRNO strerror(errno) |
32 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) | 32 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
@@ -38,21 +38,19 @@ | |||
38 | #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) | 38 | #define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || (a).bg != (b).bg) |
39 | 39 | ||
40 | /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */ | 40 | /* Attribute, Cursor, Character state, Terminal mode, Screen draw mode */ |
41 | enum { ATnone=0 , ATreverse=1 , ATunderline=2, ATbold=4, ATgfx=8 }; | 41 | enum { ATTR_NULL=0 , ATTR_REVERSE=1 , ATTR_UNDERLINE=2, ATTR_BOLD=4, ATTR_GFX=8 }; |
42 | enum { CSup, CSdown, CSright, CSleft, CShide, CSdraw, CSsave, CSload }; | 42 | enum { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_HIDE, CURSOR_DRAW, CURSOR_SAVE, CURSOR_LOAD }; |
43 | enum { CRset=1, CRupdate=2 }; | 43 | enum { GLYPH_SET=1, GLYPH_DIRTY=2 }; |
44 | enum { TMwrap=1, TMinsert=2 }; | 44 | enum { MODE_WRAP=1, MODE_INSERT=2, MODE_APPKEYPAD=4 }; |
45 | enum { ESCin=1, ESCcsi=2, ESCosc=4, ESCtitle=8, ESCcharset=16 }; | 45 | enum { ESC_START=1, ESC_CSI=2, ESC_OSC=4, ESC_TITLE=8, ESC_ALTCHARSET=16 }; |
46 | enum { SCupdate, SCredraw }; | 46 | enum { SCREEN_UPDATE, SCREEN_REDRAW }; |
47 | |||
48 | typedef int Color; | ||
49 | 47 | ||
50 | typedef struct { | 48 | typedef struct { |
51 | char c; /* character code */ | 49 | char c; /* character code */ |
52 | char mode; /* attribute flags */ | 50 | char mode; /* attribute flags */ |
53 | Color fg; /* foreground */ | 51 | int fg; /* foreground */ |
54 | Color bg; /* background */ | 52 | int bg; /* background */ |
55 | char state; /* state flag */ | 53 | char state; /* state flags */ |
56 | } Glyph; | 54 | } Glyph; |
57 | 55 | ||
58 | typedef Glyph* Line; | 56 | typedef Glyph* Line; |
@@ -67,11 +65,11 @@ typedef struct { | |||
67 | /* CSI Escape sequence structs */ | 65 | /* CSI Escape sequence structs */ |
68 | /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */ | 66 | /* ESC '[' [[ [<priv>] <arg> [;]] <mode>] */ |
69 | typedef struct { | 67 | typedef struct { |
70 | char buf[ESCSIZ]; /* raw string */ | 68 | char buf[ESC_BUF_SIZ]; /* raw string */ |
71 | int len; /* raw string length */ | 69 | int len; /* raw string length */ |
72 | char priv; | 70 | char priv; |
73 | int arg[ESCARGSIZ]; | 71 | int arg[ESC_ARG_SIZ]; |
74 | int narg; /* nb of args */ | 72 | int narg; /* nb of args */ |
75 | char mode; | 73 | char mode; |
76 | } CSIEscape; | 74 | } CSIEscape; |
77 | 75 | ||
@@ -83,9 +81,9 @@ typedef struct { | |||
83 | TCursor c; /* cursor */ | 81 | TCursor c; /* cursor */ |
84 | int top; /* top scroll limit */ | 82 | int top; /* top scroll limit */ |
85 | int bot; /* bottom scroll limit */ | 83 | int bot; /* bottom scroll limit */ |
86 | int mode; /* terminal mode */ | 84 | int mode; /* terminal mode flags */ |
87 | int esc; | 85 | int esc; /* escape state flags */ |
88 | char title[TITLESIZ]; | 86 | char title[ESC_TITLE_SIZ]; |
89 | int titlelen; | 87 | int titlelen; |
90 | } Term; | 88 | } Term; |
91 | 89 | ||
@@ -102,7 +100,7 @@ typedef struct { | |||
102 | 100 | ||
103 | typedef struct { | 101 | typedef struct { |
104 | KeySym k; | 102 | KeySym k; |
105 | char s[ESCSIZ]; | 103 | char s[ESC_BUF_SIZ]; |
106 | } Key; | 104 | } Key; |
107 | 105 | ||
108 | #include "config.h" | 106 | #include "config.h" |
@@ -126,8 +124,8 @@ static void csiparse(void); | |||
126 | static void csireset(void); | 124 | static void csireset(void); |
127 | 125 | ||
128 | static void tclearregion(int, int, int, int); | 126 | static void tclearregion(int, int, int, int); |
129 | static void tcpos(int); | ||
130 | static void tcursor(int); | 127 | static void tcursor(int); |
128 | static void tmovecursor(int); | ||
131 | static void tdeletechar(int); | 129 | static void tdeletechar(int); |
132 | static void tdeleteline(int); | 130 | static void tdeleteline(int); |
133 | static void tinsertblank(int); | 131 | static void tinsertblank(int); |
@@ -187,7 +185,7 @@ tdump(void) { | |||
187 | putchar('#'); | 185 | putchar('#'); |
188 | else { | 186 | else { |
189 | c = term.line[row][col]; | 187 | c = term.line[row][col]; |
190 | putchar(c.state & CRset ? c.c : '.'); | 188 | putchar(c.state & GLYPH_SET ? c.c : '.'); |
191 | } | 189 | } |
192 | } | 190 | } |
193 | putchar('\n'); | 191 | putchar('\n'); |
@@ -218,7 +216,7 @@ xbell(void) { /* visual bell */ | |||
218 | XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); | 216 | XSetForeground(xw.dis, dc.gc, dc.col[BellCol]); |
219 | XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); | 217 | XFillRectangles(xw.dis, xw.win, dc.gc, &r, 1); |
220 | /* usleep(30000); */ | 218 | /* usleep(30000); */ |
221 | draw(SCredraw); | 219 | draw(SCREEN_REDRAW); |
222 | } | 220 | } |
223 | 221 | ||
224 | void | 222 | void |
@@ -281,13 +279,10 @@ ttyread(void) { | |||
281 | char buf[BUFSIZ] = {0}; | 279 | char buf[BUFSIZ] = {0}; |
282 | int ret; | 280 | int ret; |
283 | 281 | ||
284 | switch(ret = read(cmdfd, buf, BUFSIZ)) { | 282 | if((ret = read(cmdfd, buf, BUFSIZ)) < 0) |
285 | case -1: | ||
286 | die("Couldn't read from shell: %s\n", SERRNO); | 283 | die("Couldn't read from shell: %s\n", SERRNO); |
287 | break; | 284 | else |
288 | default: | ||
289 | tputs(buf, ret); | 285 | tputs(buf, ret); |
290 | } | ||
291 | } | 286 | } |
292 | 287 | ||
293 | void | 288 | void |
@@ -308,14 +303,13 @@ ttyresize(int x, int y) { | |||
308 | } | 303 | } |
309 | 304 | ||
310 | void | 305 | void |
311 | tcpos(int mode) { | 306 | tcursor(int mode) { |
312 | static int x = 0; | 307 | static TCursor c; |
313 | static int y = 0; | 308 | |
314 | 309 | if(mode == CURSOR_SAVE) | |
315 | if(mode == CSsave) | 310 | c = term.c; |
316 | x = term.c.x, y = term.c.y; | 311 | else if(mode == CURSOR_LOAD) |
317 | else if(mode == CSload) | 312 | term.c = c, tmoveto(c.x, c.y); |
318 | tmoveto(x, y); | ||
319 | } | 313 | } |
320 | 314 | ||
321 | void | 315 | void |
@@ -323,9 +317,9 @@ tnew(int col, int row) { /* screen size */ | |||
323 | term.row = row, term.col = col; | 317 | term.row = row, term.col = col; |
324 | term.top = 0, term.bot = term.row - 1; | 318 | term.top = 0, term.bot = term.row - 1; |
325 | /* mode */ | 319 | /* mode */ |
326 | term.mode = TMwrap; | 320 | term.mode = MODE_WRAP; |
327 | /* cursor */ | 321 | /* cursor */ |
328 | term.c.attr.mode = ATnone; | 322 | term.c.attr.mode = ATTR_NULL; |
329 | term.c.attr.fg = DefaultFG; | 323 | term.c.attr.fg = DefaultFG; |
330 | term.c.attr.bg = DefaultBG; | 324 | term.c.attr.bg = DefaultBG; |
331 | term.c.x = term.c.y = 0; | 325 | term.c.x = term.c.y = 0; |
@@ -370,7 +364,7 @@ csiparse(void) { | |||
370 | escseq.arg[escseq.narg] *= 10; | 364 | escseq.arg[escseq.narg] *= 10; |
371 | escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */; | 365 | escseq.arg[escseq.narg] += *p++ - '0'/*, noarg = 0 */; |
372 | } | 366 | } |
373 | if(*p == ';' && escseq.narg+1 < ESCARGSIZ) | 367 | if(*p == ';' && escseq.narg+1 < ESC_ARG_SIZ) |
374 | escseq.narg++, p++; | 368 | escseq.narg++, p++; |
375 | else { | 369 | else { |
376 | escseq.mode = *p; | 370 | escseq.mode = *p; |
@@ -387,27 +381,27 @@ tmoveto(int x, int y) { | |||
387 | } | 381 | } |
388 | 382 | ||
389 | void | 383 | void |
390 | tcursor(int dir) { | 384 | tmovecursor(int dir) { |
391 | int xf = term.c.x, yf = term.c.y; | 385 | int xf = term.c.x, yf = term.c.y; |
392 | 386 | ||
393 | switch(dir) { | 387 | switch(dir) { |
394 | case CSup: | 388 | case CURSOR_UP: |
395 | yf--; | 389 | yf--; |
396 | break; | 390 | break; |
397 | case CSdown: | 391 | case CURSOR_DOWN: |
398 | yf++; | 392 | yf++; |
399 | break; | 393 | break; |
400 | case CSleft: | 394 | case CURSOR_LEFT: |
401 | xf--; | 395 | xf--; |
402 | if(term.mode & TMwrap && xf < 0) { | 396 | if(term.mode & MODE_WRAP && xf < 0) { |
403 | xf = term.col-1, yf--; | 397 | xf = term.col-1, yf--; |
404 | if(yf < term.top) | 398 | if(yf < term.top) |
405 | yf = term.top, xf = 0; | 399 | yf = term.top, xf = 0; |
406 | } | 400 | } |
407 | break; | 401 | break; |
408 | case CSright: | 402 | case CURSOR_RIGHT: |
409 | xf++; | 403 | xf++; |
410 | if(term.mode & TMwrap && xf >= term.col) { | 404 | if(term.mode & MODE_WRAP && xf >= term.col) { |
411 | xf = 0, yf++; | 405 | xf = 0, yf++; |
412 | if(yf > term.bot) | 406 | if(yf > term.bot) |
413 | yf = term.bot, tscroll(); | 407 | yf = term.bot, tscroll(); |
@@ -421,7 +415,7 @@ void | |||
421 | tsetchar(char c) { | 415 | tsetchar(char c) { |
422 | term.line[term.c.y][term.c.x] = term.c.attr; | 416 | term.line[term.c.y][term.c.x] = term.c.attr; |
423 | term.line[term.c.y][term.c.x].c = c; | 417 | term.line[term.c.y][term.c.x].c = c; |
424 | term.line[term.c.y][term.c.x].state |= CRset | CRupdate; | 418 | term.line[term.c.y][term.c.x].state |= GLYPH_SET | GLYPH_DIRTY; |
425 | } | 419 | } |
426 | 420 | ||
427 | void | 421 | void |
@@ -477,7 +471,7 @@ tsetlinestate(int n, int state) { | |||
477 | } | 471 | } |
478 | 472 | ||
479 | void | 473 | void |
480 | tinsertblankline (int n) { | 474 | tinsertblankline(int n) { |
481 | int i; | 475 | int i; |
482 | Line blank; | 476 | Line blank; |
483 | int bot = term.bot; | 477 | int bot = term.bot; |
@@ -497,8 +491,8 @@ tinsertblankline (int n) { | |||
497 | term.line[i-n] = blank; | 491 | term.line[i-n] = blank; |
498 | /* blank it */ | 492 | /* blank it */ |
499 | memset(blank, 0, term.col * sizeof(Glyph)); | 493 | memset(blank, 0, term.col * sizeof(Glyph)); |
500 | tsetlinestate(i, CRupdate); | 494 | tsetlinestate(i, GLYPH_DIRTY); |
501 | tsetlinestate(i-n, CRupdate); | 495 | tsetlinestate(i-n, GLYPH_DIRTY); |
502 | } | 496 | } |
503 | } | 497 | } |
504 | 498 | ||
@@ -523,8 +517,8 @@ tdeleteline(int n) { | |||
523 | term.line[i+n] = blank; | 517 | term.line[i+n] = blank; |
524 | /* blank it */ | 518 | /* blank it */ |
525 | memset(blank, 0, term.col * sizeof(Glyph)); | 519 | memset(blank, 0, term.col * sizeof(Glyph)); |
526 | tsetlinestate(i, CRupdate); | 520 | tsetlinestate(i, GLYPH_DIRTY); |
527 | tsetlinestate(i-n, CRupdate); | 521 | tsetlinestate(i-n, GLYPH_DIRTY); |
528 | } | 522 | } |
529 | } | 523 | } |
530 | 524 | ||
@@ -535,30 +529,30 @@ tsetattr(int *attr, int l) { | |||
535 | for(i = 0; i < l; i++) { | 529 | for(i = 0; i < l; i++) { |
536 | switch(attr[i]) { | 530 | switch(attr[i]) { |
537 | case 0: | 531 | case 0: |
538 | term.c.attr.mode &= ~(ATreverse | ATunderline | ATbold); | 532 | term.c.attr.mode &= ~(ATTR_REVERSE | ATTR_UNDERLINE | ATTR_BOLD); |
539 | term.c.attr.fg = DefaultFG; | 533 | term.c.attr.fg = DefaultFG; |
540 | term.c.attr.bg = DefaultBG; | 534 | term.c.attr.bg = DefaultBG; |
541 | break; | 535 | break; |
542 | case 1: | 536 | case 1: |
543 | term.c.attr.mode |= ATbold; | 537 | term.c.attr.mode |= ATTR_BOLD; |
544 | break; | 538 | break; |
545 | case 4: | 539 | case 4: |
546 | term.c.attr.mode |= ATunderline; | 540 | term.c.attr.mode |= ATTR_UNDERLINE; |
547 | break; | 541 | break; |
548 | case 7: | 542 | case 7: |
549 | term.c.attr.mode |= ATreverse; | 543 | term.c.attr.mode |= ATTR_REVERSE; |
550 | break; | 544 | break; |
551 | case 8: | 545 | case 8: |
552 | term.c.hidden = CShide; | 546 | term.c.hidden = CURSOR_HIDE; |
553 | break; | 547 | break; |
554 | case 22: | 548 | case 22: |
555 | term.c.attr.mode &= ~ATbold; | 549 | term.c.attr.mode &= ~ATTR_BOLD; |
556 | break; | 550 | break; |
557 | case 24: | 551 | case 24: |
558 | term.c.attr.mode &= ~ATunderline; | 552 | term.c.attr.mode &= ~ATTR_UNDERLINE; |
559 | break; | 553 | break; |
560 | case 27: | 554 | case 27: |
561 | term.c.attr.mode &= ~ATreverse; | 555 | term.c.attr.mode &= ~ATTR_REVERSE; |
562 | break; | 556 | break; |
563 | case 39: | 557 | case 39: |
564 | term.c.attr.fg = DefaultFG; | 558 | term.c.attr.fg = DefaultFG; |
@@ -593,57 +587,56 @@ tsetscroll(int t, int b) { | |||
593 | 587 | ||
594 | void | 588 | void |
595 | csihandle(void) { | 589 | csihandle(void) { |
596 | if(escseq.priv) | ||
597 | csidump(); | ||
598 | switch(escseq.mode) { | 590 | switch(escseq.mode) { |
599 | unknown: | ||
600 | default: | 591 | default: |
601 | fprintf(stderr, "erresc: unknown sequence\n"); | 592 | unknown: |
593 | printf("erresc: unknown sequence -- "); | ||
602 | csidump(); | 594 | csidump(); |
603 | /* die(""); */ | 595 | /* die(""); */ |
604 | break; | 596 | break; |
605 | case '@': /* Insert <n> blank char */ | 597 | case '@': /* ICH -- Insert <n> blank char */ |
606 | DEFAULT(escseq.arg[0], 1); | 598 | DEFAULT(escseq.arg[0], 1); |
607 | tinsertblank(escseq.arg[0]); | 599 | tinsertblank(escseq.arg[0]); |
608 | break; | 600 | break; |
609 | case 'A': /* Cursor <n> Up */ | 601 | case 'A': /* CUU -- Cursor <n> Up */ |
610 | case 'e': | 602 | case 'e': |
611 | DEFAULT(escseq.arg[0], 1); | 603 | DEFAULT(escseq.arg[0], 1); |
612 | tmoveto(term.c.x, term.c.y-escseq.arg[0]); | 604 | tmoveto(term.c.x, term.c.y-escseq.arg[0]); |
613 | break; | 605 | break; |
614 | case 'B': /* Cursor <n> Down */ | 606 | case 'B': /* CUD -- Cursor <n> Down */ |
615 | DEFAULT(escseq.arg[0], 1); | 607 | DEFAULT(escseq.arg[0], 1); |
616 | tmoveto(term.c.x, term.c.y+escseq.arg[0]); | 608 | tmoveto(term.c.x, term.c.y+escseq.arg[0]); |
617 | break; | 609 | break; |
618 | case 'C': /* Cursor <n> Forward */ | 610 | case 'C': /* CUF -- Cursor <n> Forward */ |
619 | case 'a': | 611 | case 'a': |
620 | DEFAULT(escseq.arg[0], 1); | 612 | DEFAULT(escseq.arg[0], 1); |
621 | tmoveto(term.c.x+escseq.arg[0], term.c.y); | 613 | tmoveto(term.c.x+escseq.arg[0], term.c.y); |
622 | break; | 614 | break; |
623 | case 'D': /* Cursor <n> Backward */ | 615 | case 'D': /* CUB -- Cursor <n> Backward */ |
624 | DEFAULT(escseq.arg[0], 1); | 616 | DEFAULT(escseq.arg[0], 1); |
625 | tmoveto(term.c.x-escseq.arg[0], term.c.y); | 617 | tmoveto(term.c.x-escseq.arg[0], term.c.y); |
626 | break; | 618 | break; |
627 | case 'E': /* Cursor <n> Down and first col */ | 619 | case 'E': /* CNL -- Cursor <n> Down and first col */ |
628 | DEFAULT(escseq.arg[0], 1); | 620 | DEFAULT(escseq.arg[0], 1); |
629 | tmoveto(0, term.c.y+escseq.arg[0]); | 621 | tmoveto(0, term.c.y+escseq.arg[0]); |
630 | break; | 622 | break; |
631 | case 'F': /* Cursor <n> Up and first col */ | 623 | case 'F': /* CPL -- Cursor <n> Up and first col */ |
632 | DEFAULT(escseq.arg[0], 1); | 624 | DEFAULT(escseq.arg[0], 1); |
633 | tmoveto(0, term.c.y-escseq.arg[0]); | 625 | tmoveto(0, term.c.y-escseq.arg[0]); |
634 | break; | 626 | break; |
635 | case 'G': /* Move to <col> */ | 627 | case 'G': /* CHA -- Move to <col> */ |
636 | case '`': | 628 | case '`': /* XXX: HPA -- same? */ |
637 | DEFAULT(escseq.arg[0], 1); | 629 | DEFAULT(escseq.arg[0], 1); |
638 | tmoveto(escseq.arg[0]-1, term.c.y); | 630 | tmoveto(escseq.arg[0]-1, term.c.y); |
639 | break; | 631 | break; |
640 | case 'H': /* Move to <row> <col> */ | 632 | case 'H': /* CUP -- Move to <row> <col> */ |
641 | case 'f': | 633 | case 'f': /* XXX: HVP -- same? */ |
642 | DEFAULT(escseq.arg[0], 1); | 634 | DEFAULT(escseq.arg[0], 1); |
643 | DEFAULT(escseq.arg[1], 1); | 635 | DEFAULT(escseq.arg[1], 1); |
644 | tmoveto(escseq.arg[1]-1, escseq.arg[0]-1); | 636 | tmoveto(escseq.arg[1]-1, escseq.arg[0]-1); |
645 | break; | 637 | break; |
646 | case 'J': /* Clear screen */ | 638 | /* XXX: (CSI n I) CHT -- Cursor Forward Tabulation <n> tab stops */ |
639 | case 'J': /* ED -- Clear screen */ | ||
647 | switch(escseq.arg[0]) { | 640 | switch(escseq.arg[0]) { |
648 | case 0: /* below */ | 641 | case 0: /* below */ |
649 | tclearregion(term.c.x, term.c.y, term.col-1, term.row-1); | 642 | tclearregion(term.c.x, term.c.y, term.col-1, term.row-1); |
@@ -653,10 +646,13 @@ csihandle(void) { | |||
653 | break; | 646 | break; |
654 | case 2: /* all */ | 647 | case 2: /* all */ |
655 | tclearregion(0, 0, term.col-1, term.row-1); | 648 | tclearregion(0, 0, term.col-1, term.row-1); |
656 | break; | 649 | break; |
650 | case 3: /* XXX: erase saved lines (xterm) */ | ||
651 | default: | ||
652 | goto unknown; | ||
657 | } | 653 | } |
658 | break; | 654 | break; |
659 | case 'K': /* Clear line */ | 655 | case 'K': /* EL -- Clear line */ |
660 | switch(escseq.arg[0]) { | 656 | switch(escseq.arg[0]) { |
661 | case 0: /* right */ | 657 | case 0: /* right */ |
662 | tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); | 658 | tclearregion(term.c.x, term.c.y, term.col-1, term.c.y); |
@@ -669,54 +665,77 @@ csihandle(void) { | |||
669 | break; | 665 | break; |
670 | } | 666 | } |
671 | break; | 667 | break; |
672 | case 'S': | 668 | case 'S': /* XXX: SU -- Scroll <n> line up (faked) */ |
673 | case 'L': /* Insert <n> blank lines */ | 669 | case 'L': /* IL -- Insert <n> blank lines */ |
674 | DEFAULT(escseq.arg[0], 1); | 670 | DEFAULT(escseq.arg[0], 1); |
675 | tinsertblankline(escseq.arg[0]); | 671 | tinsertblankline(escseq.arg[0]); |
676 | break; | 672 | break; |
677 | case 'l': | 673 | case 'l': /* RM -- Reset Mode */ |
678 | if(escseq.priv) { | 674 | if(escseq.priv) { |
679 | switch(escseq.arg[0]) { | 675 | switch(escseq.arg[0]) { |
676 | case 1: | ||
677 | term.mode &= ~MODE_APPKEYPAD; | ||
678 | break; | ||
680 | case 7: | 679 | case 7: |
681 | term.mode &= ~TMwrap; | 680 | term.mode &= ~MODE_WRAP; |
681 | break; | ||
682 | case 12: /* att610 -- Stop blinking cursor (IGNORED) */ | ||
682 | break; | 683 | break; |
683 | case 25: | 684 | case 25: |
684 | term.c.hidden = 1; | 685 | term.c.hidden = 1; |
685 | break; | 686 | break; |
687 | case 1048: /* XXX: no alt. screen to erase/save */ | ||
688 | case 1049: | ||
689 | tcursor(CURSOR_LOAD); | ||
690 | tclearregion(0, 0, term.col-1, term.row-1); | ||
691 | break; | ||
692 | default: | ||
693 | goto unknown; | ||
686 | } | 694 | } |
687 | } | 695 | } else goto unknown; |
688 | break; | 696 | break; |
689 | case 'M': /* Delete <n> lines */ | 697 | case 'M': /* DL -- Delete <n> lines */ |
690 | DEFAULT(escseq.arg[0], 1); | 698 | DEFAULT(escseq.arg[0], 1); |
691 | tdeleteline(escseq.arg[0]); | 699 | tdeleteline(escseq.arg[0]); |
692 | break; | 700 | break; |
693 | case 'X': | 701 | case 'X': /* ECH -- Erase <n> char XXX: same? */ |
694 | case 'P': /* Delete <n> char */ | 702 | case 'P': /* DCH -- Delete <n> char */ |
695 | DEFAULT(escseq.arg[0], 1); | 703 | DEFAULT(escseq.arg[0], 1); |
696 | tdeletechar(escseq.arg[0]); | 704 | tdeletechar(escseq.arg[0]); |
697 | break; | 705 | break; |
698 | case 'd': /* Move to <row> */ | 706 | /* XXX: (CSI n Z) CBT -- Cursor Backward Tabulation <n> tab stops */ |
707 | case 'd': /* VPA -- Move to <row> */ | ||
699 | DEFAULT(escseq.arg[0], 1); | 708 | DEFAULT(escseq.arg[0], 1); |
700 | tmoveto(term.c.x, escseq.arg[0]-1); | 709 | tmoveto(term.c.x, escseq.arg[0]-1); |
701 | break; | 710 | break; |
702 | case 'h': /* Set terminal mode */ | 711 | case 'h': /* SM -- Set terminal mode */ |
703 | if(escseq.priv) | 712 | if(escseq.priv) { |
704 | switch(escseq.arg[0]) { | 713 | switch(escseq.arg[0]) { |
714 | case 1: | ||
715 | term.mode |= MODE_APPKEYPAD; | ||
716 | break; | ||
705 | case 7: | 717 | case 7: |
706 | term.mode |= TMwrap; | 718 | term.mode |= MODE_WRAP; |
719 | break; | ||
720 | case 12: /* att610 -- Start blinking cursor (IGNORED) */ | ||
707 | break; | 721 | break; |
708 | case 25: | 722 | case 25: |
709 | term.c.hidden = 0; | 723 | term.c.hidden = 0; |
710 | break; | 724 | break; |
711 | case 1034: | 725 | case 1048: |
712 | /* XXX: Interpret "meta" key, sets eighth bit. */ | 726 | case 1049: /* XXX: no alt. screen to erase/save */ |
727 | tcursor(CURSOR_SAVE); | ||
728 | tclearregion(0, 0, term.col-1, term.row-1); | ||
713 | break; | 729 | break; |
730 | default: | ||
731 | goto unknown; | ||
714 | } | 732 | } |
733 | } else goto unknown; | ||
715 | break; | 734 | break; |
716 | case 'm': /* Terminal attribute (color) */ | 735 | case 'm': /* SGR -- Terminal attribute (color) */ |
717 | tsetattr(escseq.arg, escseq.narg); | 736 | tsetattr(escseq.arg, escseq.narg); |
718 | break; | 737 | break; |
719 | case 'r': | 738 | case 'r': /* DECSTBM -- Set Scrolling Region */ |
720 | if(escseq.priv) | 739 | if(escseq.priv) |
721 | goto unknown; | 740 | goto unknown; |
722 | else { | 741 | else { |
@@ -725,11 +744,11 @@ csihandle(void) { | |||
725 | tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1); | 744 | tsetscroll(escseq.arg[0]-1, escseq.arg[1]-1); |
726 | } | 745 | } |
727 | break; | 746 | break; |
728 | case 's': /* Save cursor position */ | 747 | case 's': /* DECSC -- Save cursor position (ANSI.SYS) */ |
729 | tcpos(CSsave); | 748 | tcursor(CURSOR_SAVE); |
730 | break; | 749 | break; |
731 | case 'u': /* Load cursor position */ | 750 | case 'u': /* DECRC -- Restore cursor position (ANSI.SYS) */ |
732 | tcpos(CSload); | 751 | tcursor(CURSOR_LOAD); |
733 | break; | 752 | break; |
734 | } | 753 | } |
735 | } | 754 | } |
@@ -759,70 +778,82 @@ tputtab(void) { | |||
759 | space--; | 778 | space--; |
760 | 779 | ||
761 | for(; space > 0; space--) | 780 | for(; space > 0; space--) |
762 | tcursor(CSright); | 781 | tmovecursor(CURSOR_RIGHT); |
763 | } | 782 | } |
764 | 783 | ||
765 | void | 784 | void |
766 | tputc(char c) { | 785 | tputc(char c) { |
767 | #if 0 | 786 | /* dump(c); */ |
768 | dump(c); | 787 | if(term.esc & ESC_START) { |
769 | #endif | 788 | if(term.esc & ESC_CSI) { |
770 | if(term.esc & ESCin) { | ||
771 | if(term.esc & ESCcsi) { | ||
772 | escseq.buf[escseq.len++] = c; | 789 | escseq.buf[escseq.len++] = c; |
773 | if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESCSIZ) { | 790 | if(BETWEEN(c, 0x40, 0x7E) || escseq.len >= ESC_BUF_SIZ) { |
774 | term.esc = 0; | 791 | term.esc = 0; |
775 | csiparse(), csihandle(); | 792 | csiparse(), csihandle(); |
776 | } | 793 | } |
777 | } else if (term.esc & ESCosc) { | 794 | } else if(term.esc & ESC_OSC) { |
778 | if(c == ';') { | 795 | if(c == ';') { |
779 | term.titlelen = 0; | 796 | term.titlelen = 0; |
780 | term.esc = ESCin | ESCtitle; | 797 | term.esc = ESC_START | ESC_TITLE; |
781 | } | 798 | } |
782 | } else if(term.esc & ESCtitle) { | 799 | } else if(term.esc & ESC_TITLE) { |
783 | if(c == '\a' || term.titlelen+1 >= TITLESIZ) { | 800 | if(c == '\a' || term.titlelen+1 >= ESC_TITLE_SIZ) { |
784 | term.esc = 0; | 801 | term.esc = 0; |
785 | term.title[term.titlelen] = '\0'; | 802 | term.title[term.titlelen] = '\0'; |
786 | XStoreName(xw.dis, xw.win, term.title); | 803 | XStoreName(xw.dis, xw.win, term.title); |
787 | } else { | 804 | } else { |
788 | term.title[term.titlelen++] = c; | 805 | term.title[term.titlelen++] = c; |
789 | } | 806 | } |
790 | } else if(term.esc & ESCcharset) { | 807 | } else if(term.esc & ESC_ALTCHARSET) { |
791 | printf("ESC ( %c\n", c); | ||
792 | switch(c) { | 808 | switch(c) { |
793 | case '0': /* Line drawing crap */ | 809 | case '0': /* Line drawing crap */ |
794 | term.c.attr.mode |= ATgfx; | 810 | term.c.attr.mode |= ATTR_GFX; |
795 | break; | 811 | break; |
796 | case 'B': /* Back to regular text */ | 812 | case 'B': /* Back to regular text */ |
797 | term.c.attr.mode &= ~ATgfx; | 813 | term.c.attr.mode &= ~ATTR_GFX; |
798 | break; | 814 | break; |
815 | default: | ||
816 | printf("esc unhandled charset: ESC ( %c\n", c); | ||
799 | } | 817 | } |
800 | term.esc = 0; | 818 | term.esc = 0; |
801 | } else { | 819 | } else { |
802 | switch(c) { | 820 | switch(c) { |
803 | case '[': | 821 | case '[': |
804 | term.esc |= ESCcsi; | 822 | term.esc |= ESC_CSI; |
805 | break; | 823 | break; |
806 | case ']': | 824 | case ']': |
807 | term.esc |= ESCosc; | 825 | term.esc |= ESC_OSC; |
808 | break; | 826 | break; |
809 | case '(': | 827 | case '(': |
810 | term.esc |= ESCcharset; | 828 | term.esc |= ESC_ALTCHARSET; |
811 | break; | 829 | break; |
812 | case 'A': | 830 | case 'A': |
813 | tmoveto(term.c.x, term.c.y-1); | 831 | tmoveto(term.c.x, term.c.y-1); |
832 | term.esc = 0; | ||
814 | break; | 833 | break; |
815 | case 'B': | 834 | case 'B': |
816 | tmoveto(term.c.x, term.c.y+1); | 835 | tmoveto(term.c.x, term.c.y+1); |
836 | term.esc = 0; | ||
817 | break; | 837 | break; |
818 | case 'C': | 838 | case 'C': |
819 | tmoveto(term.c.x+1, term.c.y); | 839 | tmoveto(term.c.x+1, term.c.y); |
840 | term.esc = 0; | ||
820 | break; | 841 | break; |
821 | case 'D': | 842 | case 'D': |
822 | tmoveto(term.c.x-1, term.c.y); | 843 | tmoveto(term.c.x-1, term.c.y); |
844 | term.esc = 0; | ||
845 | break; | ||
846 | case '=': /* DECPAM */ | ||
847 | term.mode |= MODE_APPKEYPAD; | ||
848 | term.esc = 0; | ||
849 | break; | ||
850 | case '>': /* DECPNM */ | ||
851 | term.mode &= ~MODE_APPKEYPAD; | ||
852 | term.esc = 0; | ||
823 | break; | 853 | break; |
824 | default: | 854 | default: |
825 | fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.'); | 855 | fprintf(stderr, "erresc: unknown sequence ESC %02X '%c'\n", c, isprint(c)?c:'.'); |
856 | term.esc = 0; | ||
826 | } | 857 | } |
827 | } | 858 | } |
828 | } else { | 859 | } else { |
@@ -831,7 +862,7 @@ tputc(char c) { | |||
831 | tputtab(); | 862 | tputtab(); |
832 | break; | 863 | break; |
833 | case '\b': | 864 | case '\b': |
834 | tcursor(CSleft); | 865 | tmovecursor(CURSOR_LEFT); |
835 | break; | 866 | break; |
836 | case '\r': | 867 | case '\r': |
837 | tmoveto(0, term.c.y); | 868 | tmoveto(0, term.c.y); |
@@ -844,11 +875,11 @@ tputc(char c) { | |||
844 | break; | 875 | break; |
845 | case '\033': | 876 | case '\033': |
846 | csireset(); | 877 | csireset(); |
847 | term.esc = ESCin; | 878 | term.esc = ESC_START; |
848 | break; | 879 | break; |
849 | default: | 880 | default: |
850 | tsetchar(c); | 881 | tsetchar(c); |
851 | tcursor(CSright); | 882 | tmovecursor(CURSOR_RIGHT); |
852 | break; | 883 | break; |
853 | } | 884 | } |
854 | } | 885 | } |
@@ -917,7 +948,7 @@ xscroll(void) { | |||
917 | int dsty = term.top * xw.ch; | 948 | int dsty = term.top * xw.ch; |
918 | int height = (term.bot-term.top) * xw.ch; | 949 | int height = (term.bot-term.top) * xw.ch; |
919 | 950 | ||
920 | xcursor(CShide); | 951 | xcursor(CURSOR_HIDE); |
921 | XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dsty); | 952 | XCopyArea(xw.dis, xw.win, xw.win, dc.gc, 0, srcy, xw.w, height, 0, dsty); |
922 | xclear(0, term.bot, term.col-1, term.bot); | 953 | xclear(0, term.bot, term.col-1, term.bot); |
923 | } | 954 | } |
@@ -950,7 +981,7 @@ xinit(void) { | |||
950 | 981 | ||
951 | term.c.attr.fg = DefaultFG; | 982 | term.c.attr.fg = DefaultFG; |
952 | term.c.attr.bg = DefaultBG; | 983 | term.c.attr.bg = DefaultBG; |
953 | term.c.attr.mode = ATnone; | 984 | term.c.attr.mode = ATTR_NULL; |
954 | /* windows */ | 985 | /* windows */ |
955 | xw.h = term.row * xw.ch; | 986 | xw.h = term.row * xw.ch; |
956 | xw.w = term.col * xw.cw; | 987 | xw.w = term.col * xw.cw; |
@@ -977,12 +1008,12 @@ xinit(void) { | |||
977 | } | 1008 | } |
978 | 1009 | ||
979 | void | 1010 | void |
980 | xdraws (char *s, Glyph base, int x, int y, int len) { | 1011 | xdraws(char *s, Glyph base, int x, int y, int len) { |
981 | unsigned long xfg, xbg; | 1012 | unsigned long xfg, xbg; |
982 | int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw; | 1013 | int winx = x*xw.cw, winy = y*xw.ch + dc.font->ascent, width = len*xw.cw; |
983 | int i; | 1014 | int i; |
984 | 1015 | ||
985 | if(base.mode & ATreverse) | 1016 | if(base.mode & ATTR_REVERSE) |
986 | xfg = dc.col[base.bg], xbg = dc.col[base.fg]; | 1017 | xfg = dc.col[base.bg], xbg = dc.col[base.fg]; |
987 | else | 1018 | else |
988 | xfg = dc.col[base.fg], xbg = dc.col[base.bg]; | 1019 | xfg = dc.col[base.fg], xbg = dc.col[base.bg]; |
@@ -990,15 +1021,13 @@ xdraws (char *s, Glyph base, int x, int y, int len) { | |||
990 | XSetBackground(xw.dis, dc.gc, xbg); | 1021 | XSetBackground(xw.dis, dc.gc, xbg); |
991 | XSetForeground(xw.dis, dc.gc, xfg); | 1022 | XSetForeground(xw.dis, dc.gc, xfg); |
992 | 1023 | ||
993 | if(base.mode & ATgfx) { | 1024 | if(base.mode & ATTR_GFX) |
994 | |||
995 | for(i = 0; i < len; i++) | 1025 | for(i = 0; i < len; i++) |
996 | s[i] = gfx[s[i]]; | 1026 | s[i] = gfx[s[i]]; |
997 | } | ||
998 | 1027 | ||
999 | XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len); | 1028 | XDrawImageString(xw.dis, xw.win, dc.gc, winx, winy, s, len); |
1000 | 1029 | ||
1001 | if(base.mode & ATunderline) | 1030 | if(base.mode & ATTR_UNDERLINE) |
1002 | XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1); | 1031 | XDrawLine(xw.dis, xw.win, dc.gc, winx, winy+1, winx+width-1, winy+1); |
1003 | } | 1032 | } |
1004 | 1033 | ||
@@ -1008,7 +1037,7 @@ xdrawc(int x, int y, Glyph g) { | |||
1008 | unsigned long xfg, xbg; | 1037 | unsigned long xfg, xbg; |
1009 | 1038 | ||
1010 | /* reverse video */ | 1039 | /* reverse video */ |
1011 | if(g.mode & ATreverse) | 1040 | if(g.mode & ATTR_REVERSE) |
1012 | xfg = dc.col[g.bg], xbg = dc.col[g.fg]; | 1041 | xfg = dc.col[g.bg], xbg = dc.col[g.fg]; |
1013 | else | 1042 | else |
1014 | xfg = dc.col[g.fg], xbg = dc.col[g.bg]; | 1043 | xfg = dc.col[g.fg], xbg = dc.col[g.bg]; |
@@ -1022,20 +1051,20 @@ void | |||
1022 | xcursor(int mode) { | 1051 | xcursor(int mode) { |
1023 | static int oldx = 0; | 1052 | static int oldx = 0; |
1024 | static int oldy = 0; | 1053 | static int oldy = 0; |
1025 | Glyph g = {' ', ATnone, DefaultBG, DefaultCS, 0}; | 1054 | Glyph g = {' ', ATTR_NULL, DefaultBG, DefaultCS, 0}; |
1026 | 1055 | ||
1027 | LIMIT(oldx, 0, term.col-1); | 1056 | LIMIT(oldx, 0, term.col-1); |
1028 | LIMIT(oldy, 0, term.row-1); | 1057 | LIMIT(oldy, 0, term.row-1); |
1029 | 1058 | ||
1030 | if(term.line[term.c.y][term.c.x].state & CRset) | 1059 | if(term.line[term.c.y][term.c.x].state & GLYPH_SET) |
1031 | g.c = term.line[term.c.y][term.c.x].c; | 1060 | g.c = term.line[term.c.y][term.c.x].c; |
1032 | /* remove the old cursor */ | 1061 | /* remove the old cursor */ |
1033 | if(term.line[oldy][oldx].state & CRset) | 1062 | if(term.line[oldy][oldx].state & GLYPH_SET) |
1034 | xdrawc(oldx, oldy, term.line[oldy][oldx]); | 1063 | xdrawc(oldx, oldy, term.line[oldy][oldx]); |
1035 | else | 1064 | else |
1036 | xclear(oldx, oldy, oldx, oldy); | 1065 | xclear(oldx, oldy, oldx, oldy); |
1037 | /* draw the new one */ | 1066 | /* draw the new one */ |
1038 | if(mode == CSdraw) { | 1067 | if(mode == CURSOR_DRAW) { |
1039 | xdrawc(term.c.x, term.c.y, g); | 1068 | xdrawc(term.c.x, term.c.y, g); |
1040 | oldx = term.c.x, oldy = term.c.y; | 1069 | oldx = term.c.x, oldy = term.c.y; |
1041 | } | 1070 | } |
@@ -1045,14 +1074,14 @@ void | |||
1045 | draw(int redraw_all) { | 1074 | draw(int redraw_all) { |
1046 | int i, x, y, ox; | 1075 | int i, x, y, ox; |
1047 | Glyph base, new; | 1076 | Glyph base, new; |
1048 | char buf[MAXDRAWBUF]; | 1077 | char buf[DRAW_BUF_SIZ]; |
1049 | 1078 | ||
1050 | for(y = 0; y < term.row; y++) { | 1079 | for(y = 0; y < term.row; y++) { |
1051 | base = term.line[y][0]; | 1080 | base = term.line[y][0]; |
1052 | i = ox = 0; | 1081 | i = ox = 0; |
1053 | for(x = 0; x < term.col; x++) { | 1082 | for(x = 0; x < term.col; x++) { |
1054 | new = term.line[y][x]; | 1083 | new = term.line[y][x]; |
1055 | if(!ATTRCMP(base, new) && i < MAXDRAWBUF) | 1084 | if(!ATTRCMP(base, new) && i < DRAW_BUF_SIZ) |
1056 | buf[i++] = new.c; | 1085 | buf[i++] = new.c; |
1057 | else { | 1086 | else { |
1058 | xdraws(buf, base, ox, y, i); | 1087 | xdraws(buf, base, ox, y, i); |
@@ -1065,12 +1094,12 @@ draw(int redraw_all) { | |||
1065 | xdraws(buf, base, ox, y, i); | 1094 | xdraws(buf, base, ox, y, i); |
1066 | } | 1095 | } |
1067 | if(!term.c.hidden) | 1096 | if(!term.c.hidden) |
1068 | xcursor(CSdraw); | 1097 | xcursor(CURSOR_DRAW); |
1069 | } | 1098 | } |
1070 | 1099 | ||
1071 | void | 1100 | void |
1072 | expose(XEvent *ev) { | 1101 | expose(XEvent *ev) { |
1073 | draw(SCredraw); | 1102 | draw(SCREEN_REDRAW); |
1074 | } | 1103 | } |
1075 | 1104 | ||
1076 | char* | 1105 | char* |
@@ -1105,6 +1134,13 @@ kpress(XEvent *ev) { | |||
1105 | ttywrite(buf, len); | 1134 | ttywrite(buf, len); |
1106 | } else | 1135 | } else |
1107 | switch(ksym) { | 1136 | switch(ksym) { |
1137 | case XK_Up: | ||
1138 | case XK_Down: | ||
1139 | case XK_Left: | ||
1140 | case XK_Right: | ||
1141 | sprintf(buf, "\033%c%c", term.mode & MODE_APPKEYPAD ? 'O' : '[', "DACB"[ksym - XK_Left]); | ||
1142 | ttywrite(buf, 3); | ||
1143 | break; | ||
1108 | case XK_Insert: | 1144 | case XK_Insert: |
1109 | if(shift) | 1145 | if(shift) |
1110 | /* XXX: paste X clipboard */; | 1146 | /* XXX: paste X clipboard */; |
@@ -1126,7 +1162,7 @@ resize(XEvent *e) { | |||
1126 | ttyresize(col, row); | 1162 | ttyresize(col, row); |
1127 | xw.w = e->xconfigure.width; | 1163 | xw.w = e->xconfigure.width; |
1128 | xw.h = e->xconfigure.height; | 1164 | xw.h = e->xconfigure.height; |
1129 | draw(SCredraw); | 1165 | draw(SCREEN_REDRAW); |
1130 | } | 1166 | } |
1131 | } | 1167 | } |
1132 | 1168 | ||
@@ -1151,7 +1187,7 @@ run(void) { | |||
1151 | } | 1187 | } |
1152 | if(FD_ISSET(cmdfd, &rfd)) { | 1188 | if(FD_ISSET(cmdfd, &rfd)) { |
1153 | ttyread(); | 1189 | ttyread(); |
1154 | draw(SCupdate); | 1190 | draw(SCREEN_UPDATE); |
1155 | } | 1191 | } |
1156 | while(XPending(xw.dis)) { | 1192 | while(XPending(xw.dis)) { |
1157 | XNextEvent(xw.dis, &ev); | 1193 | XNextEvent(xw.dis, &ev); |