diff options
Diffstat (limited to 'src/vterm/state.c')
| -rw-r--r-- | src/vterm/state.c | 2281 |
1 files changed, 0 insertions, 2281 deletions
diff --git a/src/vterm/state.c b/src/vterm/state.c deleted file mode 100644 index d546672e67..0000000000 --- a/src/vterm/state.c +++ /dev/null @@ -1,2281 +0,0 @@ -#include "vterm_internal.h" - -#include <stdio.h> -#include <string.h> - -#include "nvim/grid.h" -#include "nvim/mbyte.h" - -#define strneq(a,b,n) (strncmp(a,b,n)==0) - -#if defined(DEBUG) && DEBUG > 1 -# define DEBUG_GLYPH_COMBINE -#endif - -/* Some convenient wrappers to make callback functions easier */ - -static void putglyph(VTermState *state, const schar_T schar, int width, VTermPos pos) -{ - VTermGlyphInfo info = { - .schar = schar, - .width = width, - .protected_cell = state->protected_cell, - .dwl = state->lineinfo[pos.row].doublewidth, - .dhl = state->lineinfo[pos.row].doubleheight, - }; - - if(state->callbacks && state->callbacks->putglyph) - if((*state->callbacks->putglyph)(&info, pos, state->cbdata)) - return; - - DEBUG_LOG("libvterm: Unhandled putglyph U+%04x at (%d,%d)\n", chars[0], pos.col, pos.row); -} - -static void updatecursor(VTermState *state, VTermPos *oldpos, int cancel_phantom) -{ - if(state->pos.col == oldpos->col && state->pos.row == oldpos->row) - return; - - if(cancel_phantom) - state->at_phantom = 0; - - if(state->callbacks && state->callbacks->movecursor) - if((*state->callbacks->movecursor)(state->pos, *oldpos, state->mode.cursor_visible, state->cbdata)) - return; -} - -static void erase(VTermState *state, VTermRect rect, int selective) -{ - if(rect.end_col == state->cols) { - /* If we're erasing the final cells of any lines, cancel the continuation - * marker on the subsequent line - */ - for(int row = rect.start_row + 1; row < rect.end_row + 1 && row < state->rows; row++) - state->lineinfo[row].continuation = 0; - } - - if(state->callbacks && state->callbacks->erase) - if((*state->callbacks->erase)(rect, selective, state->cbdata)) - return; -} - -static VTermState *vterm_state_new(VTerm *vt) -{ - VTermState *state = vterm_allocator_malloc(vt, sizeof(VTermState)); - - state->vt = vt; - - state->rows = vt->rows; - state->cols = vt->cols; - - state->mouse_col = 0; - state->mouse_row = 0; - state->mouse_buttons = 0; - - state->mouse_protocol = MOUSE_X10; - - state->callbacks = NULL; - state->cbdata = NULL; - - state->selection.callbacks = NULL; - state->selection.user = NULL; - state->selection.buffer = NULL; - - vterm_state_newpen(state); - - state->bold_is_highbright = 0; - - state->combine_pos.row = -1; - - state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); - - state->lineinfos[BUFIDX_PRIMARY] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); - /* TODO: Make an 'enable' function */ - state->lineinfos[BUFIDX_ALTSCREEN] = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); - state->lineinfo = state->lineinfos[BUFIDX_PRIMARY]; - - state->encoding_utf8.enc = vterm_lookup_encoding(ENC_UTF8, 'u'); - if(*state->encoding_utf8.enc->init) - (*state->encoding_utf8.enc->init)(state->encoding_utf8.enc, state->encoding_utf8.data); - - return state; -} - -INTERNAL void vterm_state_free(VTermState *state) -{ - vterm_allocator_free(state->vt, state->tabstops); - vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_PRIMARY]); - if(state->lineinfos[BUFIDX_ALTSCREEN]) - vterm_allocator_free(state->vt, state->lineinfos[BUFIDX_ALTSCREEN]); - vterm_allocator_free(state->vt, state); -} - -static void scroll(VTermState *state, VTermRect rect, int downward, int rightward) -{ - if(!downward && !rightward) - return; - - int rows = rect.end_row - rect.start_row; - if(downward > rows) - downward = rows; - else if(downward < -rows) - downward = -rows; - - int cols = rect.end_col - rect.start_col; - if(rightward > cols) - rightward = cols; - else if(rightward < -cols) - rightward = -cols; - - // Update lineinfo if full line - if(rect.start_col == 0 && rect.end_col == state->cols && rightward == 0) { - int height = rect.end_row - rect.start_row - abs(downward); - - if(downward > 0) { - memmove(state->lineinfo + rect.start_row, - state->lineinfo + rect.start_row + downward, - height * sizeof(state->lineinfo[0])); - for(int row = rect.end_row - downward; row < rect.end_row; row++) - state->lineinfo[row] = (VTermLineInfo){ 0 }; - } - else { - memmove(state->lineinfo + rect.start_row - downward, - state->lineinfo + rect.start_row, - height * sizeof(state->lineinfo[0])); - for(int row = rect.start_row; row < rect.start_row - downward; row++) - state->lineinfo[row] = (VTermLineInfo){ 0 }; - } - } - - if(state->callbacks && state->callbacks->scrollrect) - if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata)) - return; - - if(state->callbacks) - vterm_scroll_rect(rect, downward, rightward, - state->callbacks->moverect, state->callbacks->erase, state->cbdata); -} - -static void linefeed(VTermState *state) -{ - if(state->pos.row == SCROLLREGION_BOTTOM(state) - 1) { - VTermRect rect = { - .start_row = state->scrollregion_top, - .end_row = SCROLLREGION_BOTTOM(state), - .start_col = SCROLLREGION_LEFT(state), - .end_col = SCROLLREGION_RIGHT(state), - }; - - scroll(state, rect, 1, 0); - } - else if(state->pos.row < state->rows-1) - state->pos.row++; -} - -static void set_col_tabstop(VTermState *state, int col) -{ - unsigned char mask = 1 << (col & 7); - state->tabstops[col >> 3] |= mask; -} - -static void clear_col_tabstop(VTermState *state, int col) -{ - unsigned char mask = 1 << (col & 7); - state->tabstops[col >> 3] &= ~mask; -} - -static int is_col_tabstop(VTermState *state, int col) -{ - unsigned char mask = 1 << (col & 7); - return state->tabstops[col >> 3] & mask; -} - -static int is_cursor_in_scrollregion(const VTermState *state) -{ - if(state->pos.row < state->scrollregion_top || - state->pos.row >= SCROLLREGION_BOTTOM(state)) - return 0; - if(state->pos.col < SCROLLREGION_LEFT(state) || - state->pos.col >= SCROLLREGION_RIGHT(state)) - return 0; - - return 1; -} - -static void tab(VTermState *state, int count, int direction) -{ - while(count > 0) { - if(direction > 0) { - if(state->pos.col >= THISROWWIDTH(state)-1) - return; - - state->pos.col++; - } - else if(direction < 0) { - if(state->pos.col < 1) - return; - - state->pos.col--; - } - - if(is_col_tabstop(state, state->pos.col)) - count--; - } -} - -#define NO_FORCE 0 -#define FORCE 1 - -#define DWL_OFF 0 -#define DWL_ON 1 - -#define DHL_OFF 0 -#define DHL_TOP 1 -#define DHL_BOTTOM 2 - -static void set_lineinfo(VTermState *state, int row, int force, int dwl, int dhl) -{ - VTermLineInfo info = state->lineinfo[row]; - - if(dwl == DWL_OFF) - info.doublewidth = DWL_OFF; - else if(dwl == DWL_ON) - info.doublewidth = DWL_ON; - // else -1 to ignore - - if(dhl == DHL_OFF) - info.doubleheight = DHL_OFF; - else if(dhl == DHL_TOP) - info.doubleheight = DHL_TOP; - else if(dhl == DHL_BOTTOM) - info.doubleheight = DHL_BOTTOM; - - if((state->callbacks && - state->callbacks->setlineinfo && - (*state->callbacks->setlineinfo)(row, &info, state->lineinfo + row, state->cbdata)) - || force) - state->lineinfo[row] = info; -} - -static int on_text(const char bytes[], size_t len, void *user) -{ - VTermState *state = user; - - VTermPos oldpos = state->pos; - - uint32_t *codepoints = (uint32_t *)(state->vt->tmpbuffer); - size_t maxpoints = (state->vt->tmpbuffer_len) / sizeof(uint32_t); - - int npoints = 0; - size_t eaten = 0; - - VTermEncodingInstance *encoding = - state->gsingle_set ? &state->encoding[state->gsingle_set] : - !(bytes[eaten] & 0x80) ? &state->encoding[state->gl_set] : - state->vt->mode.utf8 ? &state->encoding_utf8 : - &state->encoding[state->gr_set]; - - (*encoding->enc->decode)(encoding->enc, encoding->data, - codepoints, &npoints, state->gsingle_set ? 1 : maxpoints, - bytes, &eaten, len); - - /* There's a chance an encoding (e.g. UTF-8) hasn't found enough bytes yet - * for even a single codepoint - */ - if(!npoints) - return eaten; - - if(state->gsingle_set && npoints) - state->gsingle_set = 0; - - int i = 0; - GraphemeState grapheme_state = GRAPHEME_STATE_INIT; - size_t grapheme_len = 0; - bool recombine = false; - - /* See if the cursor has moved since */ - if(state->pos.row == state->combine_pos.row && state->pos.col == state->combine_pos.col + state->combine_width) { - /* This is a combining char. that needs to be merged with the previous - * glyph output */ - if(utf_iscomposing(state->grapheme_last, codepoints[i], &state->grapheme_state)) { - /* Find where we need to append these combining chars */ - grapheme_len = state->grapheme_len; - grapheme_state = state->grapheme_state; - state->pos.col = state->combine_pos.col; - recombine = true; - } else { - DEBUG_LOG("libvterm: TODO: Skip over split char+combining\n"); - } - } - - while(i < npoints) { - // Try to find combining characters following this - do { - if (grapheme_len < sizeof(state->grapheme_buf) - 4) { - grapheme_len += utf_char2bytes(codepoints[i], state->grapheme_buf + grapheme_len); - } - i++; - } while(i < npoints && utf_iscomposing(codepoints[i-1], codepoints[i], &grapheme_state)); - - int width = utf_ptr2cells_len(state->grapheme_buf, grapheme_len); - - if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) { - linefeed(state); - state->pos.col = 0; - state->at_phantom = 0; - state->lineinfo[state->pos.row].continuation = 1; - } - - if(state->mode.insert && !recombine) { - /* TODO: This will be a little inefficient for large bodies of text, as - * it'll have to 'ICH' effectively before every glyph. We should scan - * ahead and ICH as many times as required - */ - VTermRect rect = { - .start_row = state->pos.row, - .end_row = state->pos.row + 1, - .start_col = state->pos.col, - .end_col = THISROWWIDTH(state), - }; - scroll(state, rect, 0, -1); - } - - schar_T sc = schar_from_buf(state->grapheme_buf, grapheme_len); - putglyph(state, sc, width, state->pos); - - if(i == npoints) { - /* End of the buffer. Save the chars in case we have to combine with - * more on the next call */ - state->grapheme_len = grapheme_len; - state->grapheme_last = codepoints[i-1]; - state->grapheme_state = grapheme_state; - state->combine_width = width; - state->combine_pos = state->pos; - } else { - grapheme_len = 0; - recombine = false; - } - - if(state->pos.col + width >= THISROWWIDTH(state)) { - if(state->mode.autowrap) - state->at_phantom = 1; - } - else { - state->pos.col += width; - } - } - - updatecursor(state, &oldpos, 0); - -#ifdef DEBUG - if(state->pos.row < 0 || state->pos.row >= state->rows || - state->pos.col < 0 || state->pos.col >= state->cols) { - fprintf(stderr, "Position out of bounds after text: (%d,%d)\n", - state->pos.row, state->pos.col); - abort(); - } -#endif - - return eaten; -} - -static int on_control(unsigned char control, void *user) -{ - VTermState *state = user; - - VTermPos oldpos = state->pos; - - switch(control) { - case 0x07: // BEL - ECMA-48 8.3.3 - if(state->callbacks && state->callbacks->bell) - (*state->callbacks->bell)(state->cbdata); - break; - - case 0x08: // BS - ECMA-48 8.3.5 - if(state->pos.col > 0) - state->pos.col--; - break; - - case 0x09: // HT - ECMA-48 8.3.60 - tab(state, 1, +1); - break; - - case 0x0a: // LF - ECMA-48 8.3.74 - case 0x0b: // VT - case 0x0c: // FF - linefeed(state); - if(state->mode.newline) - state->pos.col = 0; - break; - - case 0x0d: // CR - ECMA-48 8.3.15 - state->pos.col = 0; - break; - - case 0x0e: // LS1 - ECMA-48 8.3.76 - state->gl_set = 1; - break; - - case 0x0f: // LS0 - ECMA-48 8.3.75 - state->gl_set = 0; - break; - - case 0x84: // IND - DEPRECATED but implemented for completeness - linefeed(state); - break; - - case 0x85: // NEL - ECMA-48 8.3.86 - linefeed(state); - state->pos.col = 0; - break; - - case 0x88: // HTS - ECMA-48 8.3.62 - set_col_tabstop(state, state->pos.col); - break; - - case 0x8d: // RI - ECMA-48 8.3.104 - if(state->pos.row == state->scrollregion_top) { - VTermRect rect = { - .start_row = state->scrollregion_top, - .end_row = SCROLLREGION_BOTTOM(state), - .start_col = SCROLLREGION_LEFT(state), - .end_col = SCROLLREGION_RIGHT(state), - }; - - scroll(state, rect, -1, 0); - } - else if(state->pos.row > 0) - state->pos.row--; - break; - - case 0x8e: // SS2 - ECMA-48 8.3.141 - state->gsingle_set = 2; - break; - - case 0x8f: // SS3 - ECMA-48 8.3.142 - state->gsingle_set = 3; - break; - - default: - if(state->fallbacks && state->fallbacks->control) - if((*state->fallbacks->control)(control, state->fbdata)) - return 1; - - return 0; - } - - updatecursor(state, &oldpos, 1); - -#ifdef DEBUG - if(state->pos.row < 0 || state->pos.row >= state->rows || - state->pos.col < 0 || state->pos.col >= state->cols) { - fprintf(stderr, "Position out of bounds after Ctrl %02x: (%d,%d)\n", - control, state->pos.row, state->pos.col); - abort(); - } -#endif - - return 1; -} - -static int settermprop_bool(VTermState *state, VTermProp prop, int v) -{ - VTermValue val = { .boolean = v }; - return vterm_state_set_termprop(state, prop, &val); -} - -static int settermprop_int(VTermState *state, VTermProp prop, int v) -{ - VTermValue val = { .number = v }; - return vterm_state_set_termprop(state, prop, &val); -} - -static int settermprop_string(VTermState *state, VTermProp prop, VTermStringFragment frag) -{ - VTermValue val = { .string = frag }; - return vterm_state_set_termprop(state, prop, &val); -} - -static void savecursor(VTermState *state, int save) -{ - if(save) { - state->saved.pos = state->pos; - state->saved.mode.cursor_visible = state->mode.cursor_visible; - state->saved.mode.cursor_blink = state->mode.cursor_blink; - state->saved.mode.cursor_shape = state->mode.cursor_shape; - - vterm_state_savepen(state, 1); - } - else { - VTermPos oldpos = state->pos; - - state->pos = state->saved.pos; - - settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, state->saved.mode.cursor_visible); - settermprop_bool(state, VTERM_PROP_CURSORBLINK, state->saved.mode.cursor_blink); - settermprop_int (state, VTERM_PROP_CURSORSHAPE, state->saved.mode.cursor_shape); - - vterm_state_savepen(state, 0); - - updatecursor(state, &oldpos, 1); - } -} - -static int on_escape(const char *bytes, size_t len, void *user) -{ - VTermState *state = user; - - /* Easier to decode this from the first byte, even though the final - * byte terminates it - */ - switch(bytes[0]) { - case ' ': - if(len != 2) - return 0; - - switch(bytes[1]) { - case 'F': // S7C1T - state->vt->mode.ctrl8bit = 0; - break; - - case 'G': // S8C1T - state->vt->mode.ctrl8bit = 1; - break; - - default: - return 0; - } - return 2; - - case '#': - if(len != 2) - return 0; - - switch(bytes[1]) { - case '3': // DECDHL top - if(state->mode.leftrightmargin) - break; - set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_TOP); - break; - - case '4': // DECDHL bottom - if(state->mode.leftrightmargin) - break; - set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_BOTTOM); - break; - - case '5': // DECSWL - if(state->mode.leftrightmargin) - break; - set_lineinfo(state, state->pos.row, NO_FORCE, DWL_OFF, DHL_OFF); - break; - - case '6': // DECDWL - if(state->mode.leftrightmargin) - break; - set_lineinfo(state, state->pos.row, NO_FORCE, DWL_ON, DHL_OFF); - break; - - case '8': // DECALN - { - VTermPos pos; - schar_T E = schar_from_ascii('E'); // E - for(pos.row = 0; pos.row < state->rows; pos.row++) - for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++) - putglyph(state, E, 1, pos); - break; - } - - default: - return 0; - } - return 2; - - case '(': case ')': case '*': case '+': // SCS - if(len != 2) - return 0; - - { - int setnum = bytes[0] - 0x28; - VTermEncoding *newenc = vterm_lookup_encoding(ENC_SINGLE_94, bytes[1]); - - if(newenc) { - state->encoding[setnum].enc = newenc; - - if(newenc->init) - (*newenc->init)(newenc, state->encoding[setnum].data); - } - } - - return 2; - - case '7': // DECSC - savecursor(state, 1); - return 1; - - case '8': // DECRC - savecursor(state, 0); - return 1; - - case '<': // Ignored by VT100. Used in VT52 mode to switch up to VT100 - return 1; - - case '=': // DECKPAM - state->mode.keypad = 1; - return 1; - - case '>': // DECKPNM - state->mode.keypad = 0; - return 1; - - case 'c': // RIS - ECMA-48 8.3.105 - { - VTermPos oldpos = state->pos; - vterm_state_reset(state, 1); - if(state->callbacks && state->callbacks->movecursor) - (*state->callbacks->movecursor)(state->pos, oldpos, state->mode.cursor_visible, state->cbdata); - return 1; - } - - case 'n': // LS2 - ECMA-48 8.3.78 - state->gl_set = 2; - return 1; - - case 'o': // LS3 - ECMA-48 8.3.80 - state->gl_set = 3; - return 1; - - case '~': // LS1R - ECMA-48 8.3.77 - state->gr_set = 1; - return 1; - - case '}': // LS2R - ECMA-48 8.3.79 - state->gr_set = 2; - return 1; - - case '|': // LS3R - ECMA-48 8.3.81 - state->gr_set = 3; - return 1; - - default: - return 0; - } -} - -static void set_mode(VTermState *state, int num, int val) -{ - switch(num) { - case 4: // IRM - ECMA-48 7.2.10 - state->mode.insert = val; - break; - - case 20: // LNM - ANSI X3.4-1977 - state->mode.newline = val; - break; - - default: - DEBUG_LOG("libvterm: Unknown mode %d\n", num); - return; - } -} - -static void set_dec_mode(VTermState *state, int num, int val) -{ - switch(num) { - case 1: - state->mode.cursor = val; - break; - - case 5: // DECSCNM - screen mode - settermprop_bool(state, VTERM_PROP_REVERSE, val); - break; - - case 6: // DECOM - origin mode - { - VTermPos oldpos = state->pos; - state->mode.origin = val; - state->pos.row = state->mode.origin ? state->scrollregion_top : 0; - state->pos.col = state->mode.origin ? SCROLLREGION_LEFT(state) : 0; - updatecursor(state, &oldpos, 1); - } - break; - - case 7: - state->mode.autowrap = val; - break; - - case 12: - settermprop_bool(state, VTERM_PROP_CURSORBLINK, val); - break; - - case 25: - settermprop_bool(state, VTERM_PROP_CURSORVISIBLE, val); - break; - - case 69: // DECVSSM - vertical split screen mode - // DECLRMM - left/right margin mode - state->mode.leftrightmargin = val; - if(val) { - // Setting DECVSSM must clear doublewidth/doubleheight state of every line - for(int row = 0; row < state->rows; row++) - set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); - } - - break; - - case 1000: - case 1002: - case 1003: - settermprop_int(state, VTERM_PROP_MOUSE, - !val ? VTERM_PROP_MOUSE_NONE : - (num == 1000) ? VTERM_PROP_MOUSE_CLICK : - (num == 1002) ? VTERM_PROP_MOUSE_DRAG : - VTERM_PROP_MOUSE_MOVE); - break; - - case 1004: - settermprop_bool(state, VTERM_PROP_FOCUSREPORT, val); - state->mode.report_focus = val; - break; - - case 1005: - state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10; - break; - - case 1006: - state->mouse_protocol = val ? MOUSE_SGR : MOUSE_X10; - break; - - case 1015: - state->mouse_protocol = val ? MOUSE_RXVT : MOUSE_X10; - break; - - case 1047: - settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); - break; - - case 1048: - savecursor(state, val); - break; - - case 1049: - settermprop_bool(state, VTERM_PROP_ALTSCREEN, val); - savecursor(state, val); - break; - - case 2004: - state->mode.bracketpaste = val; - break; - - default: - DEBUG_LOG("libvterm: Unknown DEC mode %d\n", num); - return; - } -} - -static void request_dec_mode(VTermState *state, int num) -{ - int reply; - - switch(num) { - case 1: - reply = state->mode.cursor; - break; - - case 5: - reply = state->mode.screen; - break; - - case 6: - reply = state->mode.origin; - break; - - case 7: - reply = state->mode.autowrap; - break; - - case 12: - reply = state->mode.cursor_blink; - break; - - case 25: - reply = state->mode.cursor_visible; - break; - - case 69: - reply = state->mode.leftrightmargin; - break; - - case 1000: - reply = state->mouse_flags == MOUSE_WANT_CLICK; - break; - - case 1002: - reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_DRAG); - break; - - case 1003: - reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE); - break; - - case 1004: - reply = state->mode.report_focus; - break; - - case 1005: - reply = state->mouse_protocol == MOUSE_UTF8; - break; - - case 1006: - reply = state->mouse_protocol == MOUSE_SGR; - break; - - case 1015: - reply = state->mouse_protocol == MOUSE_RXVT; - break; - - case 1047: - reply = state->mode.alt_screen; - break; - - case 2004: - reply = state->mode.bracketpaste; - break; - - default: - vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, 0); - return; - } - - vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "?%d;%d$y", num, reply ? 1 : 2); -} - -static void request_version_string(VTermState *state) -{ - vterm_push_output_sprintf_str(state->vt, C1_DCS, true, ">|libvterm(%d.%d)", - VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR); -} - -static int on_csi(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user) -{ - VTermState *state = user; - int leader_byte = 0; - int intermed_byte = 0; - int cancel_phantom = 1; - - if(leader && leader[0]) { - if(leader[1]) // longer than 1 char - return 0; - - switch(leader[0]) { - case '?': - case '>': - leader_byte = leader[0]; - break; - default: - return 0; - } - } - - if(intermed && intermed[0]) { - if(intermed[1]) // longer than 1 char - return 0; - - switch(intermed[0]) { - case ' ': - case '!': - case '"': - case '$': - case '\'': - intermed_byte = intermed[0]; - break; - default: - return 0; - } - } - - VTermPos oldpos = state->pos; - - // Some temporaries for later code - int count, val; - int row, col; - VTermRect rect; - int selective; - -#define LBOUND(v,min) if((v) < (min)) (v) = (min) -#define UBOUND(v,max) if((v) > (max)) (v) = (max) - -#define LEADER(l,b) ((l << 8) | b) -#define INTERMED(i,b) ((i << 16) | b) - - switch(intermed_byte << 16 | leader_byte << 8 | command) { - case 0x40: // ICH - ECMA-48 8.3.64 - count = CSI_ARG_COUNT(args[0]); - - if(!is_cursor_in_scrollregion(state)) - break; - - rect.start_row = state->pos.row; - rect.end_row = state->pos.row + 1; - rect.start_col = state->pos.col; - if(state->mode.leftrightmargin) - rect.end_col = SCROLLREGION_RIGHT(state); - else - rect.end_col = THISROWWIDTH(state); - - scroll(state, rect, 0, -count); - - break; - - case 0x41: // CUU - ECMA-48 8.3.22 - count = CSI_ARG_COUNT(args[0]); - state->pos.row -= count; - state->at_phantom = 0; - break; - - case 0x42: // CUD - ECMA-48 8.3.19 - count = CSI_ARG_COUNT(args[0]); - state->pos.row += count; - state->at_phantom = 0; - break; - - case 0x43: // CUF - ECMA-48 8.3.20 - count = CSI_ARG_COUNT(args[0]); - state->pos.col += count; - state->at_phantom = 0; - break; - - case 0x44: // CUB - ECMA-48 8.3.18 - count = CSI_ARG_COUNT(args[0]); - state->pos.col -= count; - state->at_phantom = 0; - break; - - case 0x45: // CNL - ECMA-48 8.3.12 - count = CSI_ARG_COUNT(args[0]); - state->pos.col = 0; - state->pos.row += count; - state->at_phantom = 0; - break; - - case 0x46: // CPL - ECMA-48 8.3.13 - count = CSI_ARG_COUNT(args[0]); - state->pos.col = 0; - state->pos.row -= count; - state->at_phantom = 0; - break; - - case 0x47: // CHA - ECMA-48 8.3.9 - val = CSI_ARG_OR(args[0], 1); - state->pos.col = val-1; - state->at_phantom = 0; - break; - - case 0x48: // CUP - ECMA-48 8.3.21 - row = CSI_ARG_OR(args[0], 1); - col = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? 1 : CSI_ARG(args[1]); - // zero-based - state->pos.row = row-1; - state->pos.col = col-1; - if(state->mode.origin) { - state->pos.row += state->scrollregion_top; - state->pos.col += SCROLLREGION_LEFT(state); - } - state->at_phantom = 0; - break; - - case 0x49: // CHT - ECMA-48 8.3.10 - count = CSI_ARG_COUNT(args[0]); - tab(state, count, +1); - break; - - case 0x4a: // ED - ECMA-48 8.3.39 - case LEADER('?', 0x4a): // DECSED - Selective Erase in Display - selective = (leader_byte == '?'); - switch(CSI_ARG(args[0])) { - case CSI_ARG_MISSING: - case 0: - rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; - rect.start_col = state->pos.col; rect.end_col = state->cols; - if(rect.end_col > rect.start_col) - erase(state, rect, selective); - - rect.start_row = state->pos.row + 1; rect.end_row = state->rows; - rect.start_col = 0; - for(int row_ = rect.start_row; row_ < rect.end_row; row_++) - set_lineinfo(state, row_, FORCE, DWL_OFF, DHL_OFF); - if(rect.end_row > rect.start_row) - erase(state, rect, selective); - break; - - case 1: - rect.start_row = 0; rect.end_row = state->pos.row; - rect.start_col = 0; rect.end_col = state->cols; - for(int row_ = rect.start_row; row_ < rect.end_row; row_++) - set_lineinfo(state, row_, FORCE, DWL_OFF, DHL_OFF); - if(rect.end_col > rect.start_col) - erase(state, rect, selective); - - rect.start_row = state->pos.row; rect.end_row = state->pos.row + 1; - rect.end_col = state->pos.col + 1; - if(rect.end_row > rect.start_row) - erase(state, rect, selective); - break; - - case 2: - rect.start_row = 0; rect.end_row = state->rows; - rect.start_col = 0; rect.end_col = state->cols; - for(int row_ = rect.start_row; row_ < rect.end_row; row_++) - set_lineinfo(state, row_, FORCE, DWL_OFF, DHL_OFF); - erase(state, rect, selective); - break; - - case 3: - if(state->callbacks && state->callbacks->sb_clear) - if((*state->callbacks->sb_clear)(state->cbdata)) - return 1; - break; - } - break; - - case 0x4b: // EL - ECMA-48 8.3.41 - case LEADER('?', 0x4b): // DECSEL - Selective Erase in Line - selective = (leader_byte == '?'); - rect.start_row = state->pos.row; - rect.end_row = state->pos.row + 1; - - switch(CSI_ARG(args[0])) { - case CSI_ARG_MISSING: - case 0: - rect.start_col = state->pos.col; rect.end_col = THISROWWIDTH(state); break; - case 1: - rect.start_col = 0; rect.end_col = state->pos.col + 1; break; - case 2: - rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break; - default: - return 0; - } - - if(rect.end_col > rect.start_col) - erase(state, rect, selective); - - break; - - case 0x4c: // IL - ECMA-48 8.3.67 - count = CSI_ARG_COUNT(args[0]); - - if(!is_cursor_in_scrollregion(state)) - break; - - rect.start_row = state->pos.row; - rect.end_row = SCROLLREGION_BOTTOM(state); - rect.start_col = SCROLLREGION_LEFT(state); - rect.end_col = SCROLLREGION_RIGHT(state); - - scroll(state, rect, -count, 0); - - break; - - case 0x4d: // DL - ECMA-48 8.3.32 - count = CSI_ARG_COUNT(args[0]); - - if(!is_cursor_in_scrollregion(state)) - break; - - rect.start_row = state->pos.row; - rect.end_row = SCROLLREGION_BOTTOM(state); - rect.start_col = SCROLLREGION_LEFT(state); - rect.end_col = SCROLLREGION_RIGHT(state); - - scroll(state, rect, count, 0); - - break; - - case 0x50: // DCH - ECMA-48 8.3.26 - count = CSI_ARG_COUNT(args[0]); - - if(!is_cursor_in_scrollregion(state)) - break; - - rect.start_row = state->pos.row; - rect.end_row = state->pos.row + 1; - rect.start_col = state->pos.col; - if(state->mode.leftrightmargin) - rect.end_col = SCROLLREGION_RIGHT(state); - else - rect.end_col = THISROWWIDTH(state); - - scroll(state, rect, 0, count); - - break; - - case 0x53: // SU - ECMA-48 8.3.147 - count = CSI_ARG_COUNT(args[0]); - - rect.start_row = state->scrollregion_top; - rect.end_row = SCROLLREGION_BOTTOM(state); - rect.start_col = SCROLLREGION_LEFT(state); - rect.end_col = SCROLLREGION_RIGHT(state); - - scroll(state, rect, count, 0); - - break; - - case 0x54: // SD - ECMA-48 8.3.113 - count = CSI_ARG_COUNT(args[0]); - - rect.start_row = state->scrollregion_top; - rect.end_row = SCROLLREGION_BOTTOM(state); - rect.start_col = SCROLLREGION_LEFT(state); - rect.end_col = SCROLLREGION_RIGHT(state); - - scroll(state, rect, -count, 0); - - break; - - case 0x58: // ECH - ECMA-48 8.3.38 - count = CSI_ARG_COUNT(args[0]); - - rect.start_row = state->pos.row; - rect.end_row = state->pos.row + 1; - rect.start_col = state->pos.col; - rect.end_col = state->pos.col + count; - UBOUND(rect.end_col, THISROWWIDTH(state)); - - erase(state, rect, 0); - break; - - case 0x5a: // CBT - ECMA-48 8.3.7 - count = CSI_ARG_COUNT(args[0]); - tab(state, count, -1); - break; - - case 0x60: // HPA - ECMA-48 8.3.57 - col = CSI_ARG_OR(args[0], 1); - state->pos.col = col-1; - state->at_phantom = 0; - break; - - case 0x61: // HPR - ECMA-48 8.3.59 - count = CSI_ARG_COUNT(args[0]); - state->pos.col += count; - state->at_phantom = 0; - break; - - case 0x62: { // REP - ECMA-48 8.3.103 - const int row_width = THISROWWIDTH(state); - count = CSI_ARG_COUNT(args[0]); - col = state->pos.col + count; - UBOUND(col, row_width); - schar_T sc = schar_from_buf(state->grapheme_buf, state->grapheme_len); - while (state->pos.col < col) { - putglyph(state, sc, state->combine_width, state->pos); - state->pos.col += state->combine_width; - } - if (state->pos.col + state->combine_width >= row_width) { - if (state->mode.autowrap) { - state->at_phantom = 1; - cancel_phantom = 0; - } - } - break; - } - - case 0x63: // DA - ECMA-48 8.3.24 - val = CSI_ARG_OR(args[0], 0); - if(val == 0) - // DEC VT100 response< |