aboutsummaryrefslogtreecommitdiff
path: root/src/vterm/state.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vterm/state.c')
-rw-r--r--src/vterm/state.c2281
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<