terminal: vt102 editing commands
authorCallum Lowcay <callum@callumscode.com>
Fri, 7 Jan 2011 19:47:00 +0000 (19:47 +0000)
committerKristian Høgsberg <krh@bitplanet.net>
Sun, 9 Jan 2011 01:34:17 +0000 (20:34 -0500)
Implement the vt102 editing commands, and insert/replace mode.

Signed-off-by: Callum Lowcay <callum@callumscode.com>
clients/terminal.c

index 60da93a..88864c3 100644 (file)
@@ -62,6 +62,7 @@ static int option_fullscreen;
 #define MODE_AUTOWRAP          0x00000004
 #define MODE_AUTOREPEAT                0x00000008
 #define MODE_LF_NEWLINE                0x00000010
+#define MODE_IRM               0x00000020
 
 union utf8_char {
        unsigned char byte[4];
@@ -394,6 +395,40 @@ terminal_scroll(struct terminal *terminal, int d)
 }
 
 static void
+terminal_shift_line(struct terminal *terminal, int d)
+{
+       union utf8_char *row;
+       struct attr *attr_row, attr;
+       
+       row = terminal_get_row(terminal, terminal->row);
+       attr_row = terminal_get_attr_row(terminal, terminal->row);
+
+       if ((terminal->width + d) <= terminal->column)
+               d = terminal->column + 1 - terminal->width;
+       if ((terminal->column + d) >= terminal->width)
+               d = terminal->width - terminal->column - 1;
+       
+       if (d < 0) {
+               d = 0 - d;
+               memmove(&row[terminal->column],
+                       &row[terminal->column + d],
+                       (terminal->width - terminal->column - d) * sizeof(union utf8_char));
+               attr = attr_row[terminal->width - 1];
+               memmove(&attr_row[terminal->column], &attr_row[terminal->column + d],
+                       (terminal->width - terminal->column - d) * sizeof(struct attr));
+               memset(&row[terminal->width - d], 0, d * sizeof(union utf8_char));
+               attr_init(&attr_row[terminal->width - d], terminal->curr_attr, d);
+       } else {
+               memmove(&row[terminal->column + d], &row[terminal->column],
+                       (terminal->width - terminal->column - d) * sizeof(union utf8_char));
+               memmove(&attr_row[terminal->column + d], &attr_row[terminal->column],
+                       (terminal->width - terminal->column - d) * sizeof(struct attr));
+               memset(&row[terminal->column], 0, d * sizeof(union utf8_char));
+               attr_init(&attr_row[terminal->column], terminal->curr_attr, d);
+       }
+}
+
+static void
 terminal_resize(struct terminal *terminal, int width, int height)
 {
        size_t size;
@@ -724,6 +759,10 @@ handle_term_parameter(struct terminal *terminal, int code, int sr)
                }
        } else {
                switch(code) {
+               case 4:  /* IRM */
+                       if (sr) terminal->mode |=  MODE_IRM;
+                       else    terminal->mode &= ~MODE_IRM;
+                       break;
                case 20: /* LNM */
                        if (sr) terminal->mode |=  MODE_LF_NEWLINE;
                        else    terminal->mode &= ~MODE_LF_NEWLINE;
@@ -763,6 +802,11 @@ handle_escape(struct terminal *terminal)
        }
        
        switch (*p) {
+       case '@':    /* ICH */
+               count = set[0] ? args[0] : 1;
+               if (count == 0) count = 1;
+               terminal_shift_line(terminal, count);
+               break;
        case 'A':    /* CUU */
                count = set[0] ? args[0] : 1;
                if (count == 0) count = 1;
@@ -893,12 +937,59 @@ handle_escape(struct terminal *terminal)
                        attr_init(attr_row, terminal->curr_attr, terminal->width);
                }
                break;
+       case 'L':    /* IL */
+               count = set[0] ? args[0] : 1;
+               if (count == 0) count = 1;
+               if (terminal->row >= terminal->margin_top &&
+                       terminal->row < terminal->margin_bottom)
+               {
+                       top = terminal->margin_top;
+                       terminal->margin_top = terminal->row;
+                       terminal_scroll(terminal, 0 - count);
+                       terminal->margin_top = top;
+               } else if (terminal->row == terminal->margin_bottom) {
+                       memset(terminal_get_row(terminal, terminal->row),
+                              0, terminal->data_pitch);
+                       attr_init(terminal_get_attr_row(terminal, terminal->row),
+                               terminal->curr_attr, terminal->width);
+               }
+               break;
+       case 'M':    /* DL */
+               count = set[0] ? args[0] : 1;
+               if (count == 0) count = 1;
+               if (terminal->row >= terminal->margin_top &&
+                       terminal->row < terminal->margin_bottom)
+               {
+                       top = terminal->margin_top;
+                       terminal->margin_top = terminal->row;
+                       terminal_scroll(terminal, count);
+                       terminal->margin_top = top;
+               } else if (terminal->row == terminal->margin_bottom) {
+                       memset(terminal_get_row(terminal, terminal->row),
+                              0, terminal->data_pitch);
+               }
+               break;
+       case 'P':    /* DCH */
+               count = set[0] ? args[0] : 1;
+               if (count == 0) count = 1;
+               terminal_shift_line(terminal, 0 - count);
+               break;
        case 'S':    /* SU */
                terminal_scroll(terminal, set[0] ? args[0] : 1);
                break;
        case 'T':    /* SD */
                terminal_scroll(terminal, 0 - (set[0] ? args[0] : 1));
                break;
+       case 'X':    /* ECH */
+               count = set[0] ? args[0] : 1;
+               if (count == 0) count = 1;
+               if ((terminal->column + count) > terminal->width)
+                       count = terminal->width - terminal->column;
+               row = terminal_get_row(terminal, terminal->row);
+               attr_row = terminal_get_attr_row(terminal, terminal->row);
+               memset(&row[terminal->column], 0, count * sizeof(union utf8_char));
+               attr_init(&attr_row[terminal->column], terminal->curr_attr, count);
+               break;
        case 'Z':    /* CBT */
                count = set[0] ? args[0] : 1;
                if (count == 0) count = 1;
@@ -923,7 +1014,7 @@ handle_escape(struct terminal *terminal)
                terminal->last_char.byte[0] = 0;
                break;
        case 'c':    /* Primary DA */
-               write(terminal->master, "\e[?1;2c", 7);
+               write(terminal->master, "\e[?6c", 5);
                sleep(1);
                break;
        case 'd':    /* VPA */
@@ -1186,6 +1277,8 @@ handle_special_char(struct terminal *terminal, char c)
        case '\t':
                while (terminal->column < terminal->width) {
                        if (terminal->tab_ruler[terminal->column]) break;
+                       if (terminal->mode & MODE_IRM)
+                               terminal_shift_line(terminal, +1);
                        row[terminal->column].byte[0] = ' ';
                        row[terminal->column].byte[1] = '\0';
                        attr_row[terminal->column] = terminal->curr_attr;
@@ -1259,6 +1352,8 @@ handle_char(struct terminal *terminal, union utf8_char utf8)
        row = terminal_get_row(terminal, terminal->row);
        attr_row = terminal_get_attr_row(terminal, terminal->row);
        
+       if (terminal->mode & MODE_IRM)
+               terminal_shift_line(terminal, +1);
        row[terminal->column] = utf8;
        attr_row[terminal->column++] = terminal->curr_attr;
 
@@ -1508,7 +1603,7 @@ terminal_run(struct terminal *terminal, const char *path)
 
        pid = forkpty(&master, NULL, NULL, NULL);
        if (pid == 0) {
-               setenv("TERM", "vt100", 1);
+               setenv("TERM", "vt102", 1);
                if (execl(path, path, NULL)) {
                        printf("exec failed: %m\n");
                        exit(EXIT_FAILURE);