From 6d78f36633063dad0689ca42be1ad8d0313ebfab Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 4 Dec 2014 19:52:44 -0800 Subject: Update libvterm to upstream revision 619. Change-Id: I9a734b40a172d9c13be4fdf38db60c6916d7d8d0 --- Android.mk | 8 ++- include/vterm.h | 14 +++++ src/encoding.c | 3 +- src/input.c | 11 ---- src/pen.c | 44 +++++++++----- src/screen.c | 48 ++++++++++++++- src/state.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++----- src/unicode.c | 4 +- src/utf8.h | 3 +- src/vterm.c | 14 ++--- src/vterm_internal.h | 13 ++++ 11 files changed, 274 insertions(+), 56 deletions(-) diff --git a/Android.mk b/Android.mk index 4eeca87..dac5231 100644 --- a/Android.mk +++ b/Android.mk @@ -18,6 +18,12 @@ LOCAL_SRC_FILES := \ src/screen.c \ src/state.c -LOCAL_CFLAGS := -std=c99 +LOCAL_CFLAGS += \ + -std=c99 \ + -Wno-missing-field-initializers \ + -Wno-sign-compare \ + -Wno-unused-parameter \ + +LOCAL_CLANG := true include $(BUILD_STATIC_LIBRARY) diff --git a/include/vterm.h b/include/vterm.h index 2e2b32b..d43add7 100644 --- a/include/vterm.h +++ b/include/vterm.h @@ -103,8 +103,15 @@ typedef struct { const uint32_t *chars; int width; unsigned int protected_cell:1; /* DECSCA-protected against DECSEL/DECSED */ + unsigned int dwl:1; /* DECDWL or DECDHL double-width line */ + unsigned int dhl:2; /* DECDHL double-height line (1=top 2=bottom) */ } VTermGlyphInfo; +typedef struct { + unsigned int doublewidth:1; /* DECDWL or DECDHL line */ + unsigned int doubleheight:2; /* DECDHL line (1=top 2=bottom) */ +} VTermLineInfo; + typedef struct { /* libvterm relies on this memory to be zeroed out before it is returned * by the allocator. */ @@ -187,6 +194,7 @@ typedef struct { int (*setmousefunc)(VTermMouseFunc func, void *data, void *user); int (*bell)(void *user); int (*resize)(int rows, int cols, VTermPos *delta, void *user); + int (*setlineinfo)(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user); } VTermStateCallbacks; VTermState *vterm_obtain_state(VTerm *vt); @@ -197,9 +205,11 @@ void vterm_state_get_cursorpos(const VTermState *state, VTermPos *cursorpos); void vterm_state_get_default_colors(const VTermState *state, VTermColor *default_fg, VTermColor *default_bg); void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col); void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg); +void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col); void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright); int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val); int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val); +const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row); // ------------ // Screen layer @@ -217,6 +227,8 @@ typedef struct { unsigned int reverse : 1; unsigned int strike : 1; unsigned int font : 4; /* 0 to 9 */ + unsigned int dwl : 1; /* On a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* On a DECDHL line (1=top 2=bottom) */ } attrs; VTermColor fg, bg; } VTermScreenCell; @@ -249,6 +261,8 @@ void vterm_screen_flush_damage(VTermScreen *screen); void vterm_screen_set_damage_merge(VTermScreen *screen, VTermDamageSize size); void vterm_screen_reset(VTermScreen *screen, int hard); + +/* Neither of these functions NUL-terminate the buffer */ size_t vterm_screen_get_chars(const VTermScreen *screen, uint32_t *chars, size_t len, const VTermRect rect); size_t vterm_screen_get_text(const VTermScreen *screen, char *str, size_t len, const VTermRect rect); diff --git a/src/encoding.c b/src/encoding.c index a7629f9..1495855 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -2,7 +2,7 @@ #define UNICODE_INVALID 0xFFFD -#ifdef DEBUG +#if defined(DEBUG) && DEBUG > 1 # define DEBUG_PRINT_UTF8 #endif @@ -212,6 +212,7 @@ encodings[] = { { 0 }, }; +/* This ought to be INTERNAL but isn't because it's used by unit testing */ VTermEncoding *vterm_lookup_encoding(VTermEncodingType type, char designation) { for(int i = 0; encodings[i].designation; i++) diff --git a/src/input.c b/src/input.c index 36bec56..0eaf0e9 100644 --- a/src/input.c +++ b/src/input.c @@ -11,11 +11,6 @@ void vterm_input_push_char(VTerm *vt, VTermModifier mod, uint32_t c) */ if(c != ' ') mod &= ~VTERM_MOD_SHIFT; - /* However, since Shift-Space is too easy to mistype accidentally, remove - * shift if it's the only modifier - */ - else if(mod == VTERM_MOD_SHIFT) - mod = 0; if(mod == 0) { // Normal text - ignore just shift @@ -128,12 +123,6 @@ static keycodes_s keycodes_kp[] = { void vterm_input_push_key(VTerm *vt, VTermModifier mod, VTermKey key) { - /* Since Shift-Enter and Shift-Backspace are too easy to mistype - * accidentally, remove shift if it's the only modifier - */ - if((key == VTERM_KEY_ENTER || key == VTERM_KEY_BACKSPACE) && mod == VTERM_MOD_SHIFT) - mod = 0; - if(key == VTERM_KEY_NONE) return; diff --git a/src/pen.c b/src/pen.c index 044e9aa..fb8c8e3 100644 --- a/src/pen.c +++ b/src/pen.c @@ -33,18 +33,18 @@ static int ramp24[] = { 0x85, 0x90, 0x9B, 0xA6, 0xB1, 0xBC, 0xC7, 0xD2, 0xDD, 0xE8, 0xF3, 0xFF, }; -static void lookup_colour_ansi(long index, VTermColor *col) +static void lookup_colour_ansi(const VTermState *state, long index, VTermColor *col) { if(index >= 0 && index < 16) { - *col = ansi_colors[index]; + *col = state->colors[index]; } } -static void lookup_colour_palette(long index, VTermColor *col) +static void lookup_colour_palette(const VTermState *state, long index, VTermColor *col) { if(index >= 0 && index < 16) { // Normal 8 colours or high intensity - parse as palette 0 - lookup_colour_ansi(index, col); + lookup_colour_ansi(state, index, col); } else if(index >= 16 && index < 232) { // 216-colour cube @@ -64,7 +64,7 @@ static void lookup_colour_palette(long index, VTermColor *col) } } -static int lookup_colour(int palette, const long args[], int argcount, VTermColor *col, int *index) +static int lookup_colour(const VTermState *state, int palette, const long args[], int argcount, VTermColor *col, int *index) { switch(palette) { case 2: // RGB mode - 3 args contain colour values directly @@ -81,7 +81,7 @@ static int lookup_colour(int palette, const long args[], int argcount, VTermColo if(index) *index = CSI_ARG_OR(args[0], -1); - lookup_colour_palette(argcount ? CSI_ARG_OR(args[0], -1) : -1, col); + lookup_colour_palette(state, argcount ? CSI_ARG_OR(args[0], -1) : -1, col); return argcount ? 1 : 0; @@ -128,12 +128,22 @@ static void set_pen_col_ansi(VTermState *state, VTermAttr attr, long col) { VTermColor *colp = (attr == VTERM_ATTR_BACKGROUND) ? &state->pen.bg : &state->pen.fg; - lookup_colour_ansi(col, colp); + lookup_colour_ansi(state, col, colp); setpenattr_col(state, attr, *colp); } -void vterm_state_resetpen(VTermState *state) +INTERNAL void vterm_state_newpen(VTermState *state) +{ + // 90% grey so that pure white is brighter + state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240; + state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0; + + for(int col = 0; col < 16; col++) + state->colors[col] = ansi_colors[col]; +} + +INTERNAL void vterm_state_resetpen(VTermState *state) { state->pen.bold = 0; setpenattr_bool(state, VTERM_ATTR_BOLD, 0); state->pen.underline = 0; setpenattr_int( state, VTERM_ATTR_UNDERLINE, 0); @@ -149,7 +159,7 @@ void vterm_state_resetpen(VTermState *state) state->pen.bg = state->default_bg; setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->default_bg); } -void vterm_state_savepen(VTermState *state, int save) +INTERNAL void vterm_state_savepen(VTermState *state, int save) { if(save) { state->saved.pen = state->pen; @@ -177,7 +187,7 @@ void vterm_state_get_default_colors(const VTermState *state, VTermColor *default void vterm_state_get_palette_color(const VTermState *state, int index, VTermColor *col) { - lookup_colour_palette(index, col); + lookup_colour_palette(state, index, col); } void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg) @@ -186,12 +196,18 @@ void vterm_state_set_default_colors(VTermState *state, const VTermColor *default state->default_bg = *default_bg; } +void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col) +{ + if(index >= 0 && index < 16) + state->colors[index] = *col; +} + void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright) { state->bold_is_highbright = bold_is_highbright; } -void vterm_state_setpen(VTermState *state, const long args[], int argcount) +INTERNAL void vterm_state_setpen(VTermState *state, const long args[], int argcount) { // SGR - ECMA-48 8.3.117 @@ -296,7 +312,7 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount) state->fg_index = -1; if(argcount - argi < 1) return; - argi += 1 + lookup_colour(CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index); + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.fg, &state->fg_index); setpenattr_col(state, VTERM_ATTR_FOREGROUND, state->pen.fg); break; @@ -317,7 +333,7 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount) state->bg_index = -1; if(argcount - argi < 1) return; - argi += 1 + lookup_colour(CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index); + argi += 1 + lookup_colour(state, CSI_ARG(args[argi+1]), args+argi+2, argcount-argi-2, &state->pen.bg, &state->bg_index); setpenattr_col(state, VTERM_ATTR_BACKGROUND, state->pen.bg); break; @@ -353,7 +369,7 @@ void vterm_state_setpen(VTermState *state, const long args[], int argcount) } } -int vterm_state_getpen(VTermState *state, long args[], int argcount) +INTERNAL int vterm_state_getpen(VTermState *state, long args[], int argcount) { int argi = 0; diff --git a/src/screen.c b/src/screen.c index db11c6d..c4de59e 100644 --- a/src/screen.c +++ b/src/screen.c @@ -25,6 +25,8 @@ typedef struct /* Extra state storage that isn't strictly pen-related */ unsigned int protected_cell : 1; + unsigned int dwl : 1; /* on a DECDWL or DECDHL line */ + unsigned int dhl : 2; /* on a DECDHL line (1=top 2=bottom) */ } ScreenPen; /* Internal representation of a screen cell */ @@ -194,6 +196,8 @@ static int putglyph(VTermGlyphInfo *info, VTermPos pos, void *user) }; cell->pen.protected_cell = info->protected_cell; + cell->pen.dwl = info->dwl; + cell->pen.dhl = info->dhl; damagerect(screen, rect); @@ -262,7 +266,9 @@ static int erase_internal(VTermRect rect, int selective, void *user) { VTermScreen *screen = user; - for(int row = rect.start_row; row < rect.end_row; row++) + for(int row = rect.start_row; row < rect.end_row; row++) { + const VTermLineInfo *info = vterm_state_get_lineinfo(screen->state, row); + for(int col = rect.start_col; col < rect.end_col; col++) { ScreenCell *cell = getcell(screen, row, col); @@ -271,7 +277,10 @@ static int erase_internal(VTermRect rect, int selective, void *user) cell->chars[0] = 0; cell->pen = screen->pen; + cell->pen.dwl = info->doublewidth; + cell->pen.dhl = info->doubleheight; } + } return 1; } @@ -568,6 +577,37 @@ static int resize(int new_rows, int new_cols, VTermPos *delta, void *user) return 1; } +static int setlineinfo(int row, const VTermLineInfo *newinfo, const VTermLineInfo *oldinfo, void *user) +{ + VTermScreen *screen = user; + + if(newinfo->doublewidth != oldinfo->doublewidth || + newinfo->doubleheight != oldinfo->doubleheight) { + for(int col = 0; col < screen->cols; col++) { + ScreenCell *cell = getcell(screen, row, col); + cell->pen.dwl = newinfo->doublewidth; + cell->pen.dhl = newinfo->doubleheight; + } + + VTermRect rect = { + .start_row = row, + .end_row = row + 1, + .start_col = 0, + .end_col = newinfo->doublewidth ? screen->cols / 2 : screen->cols, + }; + damagerect(screen, rect); + + if(newinfo->doublewidth) { + rect.start_col = screen->cols / 2; + rect.end_col = screen->cols; + + erase_internal(rect, 0, user); + } + } + + return 1; +} + static VTermStateCallbacks state_cbs = { .putglyph = &putglyph, .movecursor = &movecursor, @@ -578,6 +618,7 @@ static VTermStateCallbacks state_cbs = { .setmousefunc = &setmousefunc, .bell = &bell, .resize = &resize, + .setlineinfo = &setlineinfo, }; static VTermScreen *screen_new(VTerm *vt) @@ -612,7 +653,7 @@ static VTermScreen *screen_new(VTerm *vt) return screen; } -void vterm_screen_free(VTermScreen *screen) +INTERNAL void vterm_screen_free(VTermScreen *screen) { vterm_allocator_free(screen->vt, screen->buffers[0]); if(screen->buffers[1]) @@ -712,6 +753,9 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe cell->attrs.strike = intcell->pen.strike; cell->attrs.font = intcell->pen.font; + cell->attrs.dwl = intcell->pen.dwl; + cell->attrs.dhl = intcell->pen.dhl; + cell->fg = intcell->pen.fg; cell->bg = intcell->pen.bg; diff --git a/src/state.c b/src/state.c index f5348c9..e42be53 100644 --- a/src/state.c +++ b/src/state.c @@ -7,7 +7,7 @@ #include "utf8.h" -#ifdef DEBUG +#if defined(DEBUG) && DEBUG > 1 # define DEBUG_GLYPH_COMBINE #endif @@ -23,6 +23,8 @@ static void putglyph(VTermState *state, const uint32_t chars[], int width, VTerm .chars = chars, .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) @@ -61,18 +63,17 @@ static VTermState *vterm_state_new(VTerm *vt) state->rows = vt->rows; state->cols = vt->cols; - // 90% grey so that pure white is brighter - state->default_fg.red = state->default_fg.green = state->default_fg.blue = 240; - state->default_bg.red = state->default_bg.green = state->default_bg.blue = 0; + vterm_state_newpen(state); state->bold_is_highbright = 0; return state; } -void vterm_state_free(VTermState *state) +INTERNAL void vterm_state_free(VTermState *state) { vterm_allocator_free(state->vt, state->tabstops); + vterm_allocator_free(state->vt, state->lineinfo); vterm_allocator_free(state->vt, state->combine_chars); vterm_allocator_free(state->vt, state); } @@ -82,6 +83,20 @@ static void scroll(VTermState *state, VTermRect rect, int downward, int rightwar if(!downward && !rightward) return; + // 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])); + else + memmove(state->lineinfo + rect.start_row - downward, + state->lineinfo + rect.start_row, + height * sizeof(state->lineinfo[0])); + } + if(state->callbacks && state->callbacks->scrollrect) if((*state->callbacks->scrollrect)(rect, downward, rightward, state->cbdata)) return; @@ -115,7 +130,9 @@ static void grow_combine_buffer(VTermState *state) memcpy(new_chars, state->combine_chars, state->combine_chars_size * sizeof(new_chars[0])); vterm_allocator_free(state->vt, state->combine_chars); + state->combine_chars = new_chars; + state->combine_chars_size = new_size; } static void set_col_tabstop(VTermState *state, int col) @@ -139,7 +156,7 @@ static int is_col_tabstop(VTermState *state, int col) static void tab(VTermState *state, int count, int direction) { while(count--) - while(state->pos.col >= 0 && state->pos.col < state->cols-1) { + while(state->pos.col >= 0 && state->pos.col < THISROWWIDTH(state)-1) { state->pos.col += direction; if(is_col_tabstop(state, state->pos.col)) @@ -147,6 +164,40 @@ static void tab(VTermState *state, int count, int direction) } } +#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; @@ -243,7 +294,7 @@ static int on_text(const char bytes[], size_t len, void *user) printf("}, onscreen width %d\n", width); #endif - if(state->at_phantom || state->pos.col + width > state->cols) { + if(state->at_phantom || state->pos.col + width > THISROWWIDTH(state)) { linefeed(state); state->pos.col = 0; state->at_phantom = 0; @@ -258,10 +309,11 @@ static int on_text(const char bytes[], size_t len, void *user) .start_row = state->pos.row, .end_row = state->pos.row + 1, .start_col = state->pos.col, - .end_col = state->cols, + .end_col = THISROWWIDTH(state), }; scroll(state, rect, 0, -1); } + putglyph(state, chars, width, state->pos); if(i == npoints - 1) { @@ -280,7 +332,7 @@ static int on_text(const char bytes[], size_t len, void *user) state->combine_pos = state->pos; } - if(state->pos.col + width >= state->cols) { + if(state->pos.col + width >= THISROWWIDTH(state)) { if(state->mode.autowrap) state->at_phantom = 1; } @@ -408,6 +460,7 @@ static void output_mouse(VTermState *state, int code, int pressed, int modifiers len += fill_utf8((code | modifiers) + 0x20, utf8 + len); len += fill_utf8(col + 0x21, utf8 + len); len += fill_utf8(row + 0x21, utf8 + len); + utf8[len] = 0; vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "M%s", utf8); } @@ -547,12 +600,36 @@ static int on_escape(const char *bytes, size_t len, void *user) 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; uint32_t E[] = { 'E', 0 }; for(pos.row = 0; pos.row < state->rows; pos.row++) - for(pos.col = 0; pos.col < state->cols; pos.col++) + for(pos.col = 0; pos.col < ROWWIDTH(state, pos.row); pos.col++) putglyph(state, E, 1, pos); break; } @@ -684,7 +761,14 @@ static void set_dec_mode(VTermState *state, int num, int 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: @@ -869,7 +953,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha 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(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); scroll(state, rect, 0, -count); @@ -950,6 +1037,8 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha 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; @@ -957,6 +1046,8 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha 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); @@ -969,6 +1060,8 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha 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; } @@ -983,11 +1076,11 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha switch(CSI_ARG(args[0])) { case CSI_ARG_MISSING: case 0: - rect.start_col = state->pos.col; rect.end_col = state->cols; break; + 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 = state->cols; break; + rect.start_col = 0; rect.end_col = THISROWWIDTH(state); break; default: return 0; } @@ -1027,7 +1120,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha 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(state->mode.leftrightmargin) + rect.end_col = SCROLLREGION_RIGHT(state); + else + rect.end_col = THISROWWIDTH(state); scroll(state, rect, 0, count); @@ -1064,7 +1160,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha rect.end_row = state->pos.row + 1; rect.start_col = state->pos.col; rect.end_col = state->pos.col + count; - UBOUND(rect.end_col, state->cols); + UBOUND(rect.end_col, THISROWWIDTH(state)); erase(state, rect, 0); break; @@ -1261,16 +1357,28 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha case 0x72: // DECSTBM - DEC custom state->scrollregion_top = CSI_ARG_OR(args[0], 1) - 1; state->scrollregion_bottom = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_top, -1); + UBOUND(state->scrollregion_top, state->rows); + LBOUND(state->scrollregion_bottom, -1); if(state->scrollregion_top == 0 && state->scrollregion_bottom == state->rows) state->scrollregion_bottom = -1; + else + UBOUND(state->scrollregion_bottom, state->rows); + break; case 0x73: // DECSLRM - DEC custom // Always allow setting these margins, just they won't take effect without DECVSSM state->scrollregion_left = CSI_ARG_OR(args[0], 1) - 1; state->scrollregion_right = argcount < 2 || CSI_ARG_IS_MISSING(args[1]) ? -1 : CSI_ARG(args[1]); + LBOUND(state->scrollregion_left, -1); + UBOUND(state->scrollregion_left, state->cols); + LBOUND(state->scrollregion_right, -1); if(state->scrollregion_left == 0 && state->scrollregion_right == state->cols) state->scrollregion_right = -1; + else + UBOUND(state->scrollregion_right, state->cols); + break; case INTERMED('\'', 0x7D): // DECIC @@ -1311,7 +1419,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha LBOUND(state->pos.row, 0); UBOUND(state->pos.row, state->rows-1); LBOUND(state->pos.col, 0); - UBOUND(state->pos.col, state->cols-1); + UBOUND(state->pos.col, THISROWWIDTH(state)-1); } updatecursor(state, &oldpos, 1); @@ -1434,6 +1542,24 @@ static int on_resize(int rows, int cols, void *user) state->tabstops = newtabstops; } + if(rows != state->rows) { + VTermLineInfo *newlineinfo = vterm_allocator_malloc(state->vt, rows * sizeof(VTermLineInfo)); + + int row; + for(row = 0; row < state->rows && row < rows; row++) { + newlineinfo[row] = state->lineinfo[row]; + } + + for( ; row < rows; row++) { + newlineinfo[row] = (VTermLineInfo){ + .doublewidth = 0, + }; + } + + vterm_allocator_free(state->vt, state->lineinfo); + state->lineinfo = newlineinfo; + } + state->rows = rows; state->cols = cols; @@ -1483,6 +1609,8 @@ VTermState *vterm_obtain_state(VTerm *vt) state->tabstops = vterm_allocator_malloc(state->vt, (state->cols + 7) / 8); + state->lineinfo = vterm_allocator_malloc(state->vt, state->rows * sizeof(VTermLineInfo)); + 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); @@ -1516,6 +1644,9 @@ void vterm_state_reset(VTermState *state, int hard) else clear_col_tabstop(state, col); + for(int row = 0; row < state->rows; row++) + set_lineinfo(state, row, FORCE, DWL_OFF, DHL_OFF); + if(state->callbacks && state->callbacks->initpen) (*state->callbacks->initpen)(state->cbdata); @@ -1613,3 +1744,8 @@ int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val) return 0; } + +const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row) +{ + return state->lineinfo + row; +} diff --git a/src/unicode.c b/src/unicode.c index ac1748c..69b7682 100644 --- a/src/unicode.c +++ b/src/unicode.c @@ -321,12 +321,12 @@ static int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n) // ################################ // ### The rest added by Paul Evans -int vterm_unicode_width(int codepoint) +INTERNAL int vterm_unicode_width(int codepoint) { return mk_wcwidth(codepoint); } -int vterm_unicode_is_combining(int codepoint) +INTERNAL int vterm_unicode_is_combining(int codepoint) { return bisearch(codepoint, combining, sizeof(combining) / sizeof(struct interval) - 1); } diff --git a/src/utf8.h b/src/utf8.h index 1c2a2d9..9a336d3 100644 --- a/src/utf8.h +++ b/src/utf8.h @@ -12,12 +12,11 @@ static inline unsigned int utf8_seqlen(long codepoint) return 6; } +/* Does NOT NUL-terminate the buffer */ static int fill_utf8(long codepoint, char *str) { int nbytes = utf8_seqlen(codepoint); - str[nbytes] = 0; - // This is easier done backwards int b = nbytes; while(b > 1) { diff --git a/src/vterm.c b/src/vterm.c index 940d1fb..04651d3 100644 --- a/src/vterm.c +++ b/src/vterm.c @@ -70,12 +70,12 @@ void vterm_free(VTerm *vt) vterm_allocator_free(vt, vt); } -void *vterm_allocator_malloc(VTerm *vt, size_t size) +INTERNAL void *vterm_allocator_malloc(VTerm *vt, size_t size) { return (*vt->allocator->malloc)(size, vt->allocdata); } -void vterm_allocator_free(VTerm *vt, void *ptr) +INTERNAL void vterm_allocator_free(VTerm *vt, void *ptr) { (*vt->allocator->free)(ptr, vt->allocdata); } @@ -108,7 +108,7 @@ void vterm_parser_set_utf8(VTerm *vt, int is_utf8) vt->mode.utf8 = is_utf8; } -void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) +INTERNAL void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) { if(len > vt->outbuffer_len - vt->outbuffer_cur) { fprintf(stderr, "vterm_push_output(): buffer overflow; truncating output\n"); @@ -119,7 +119,7 @@ void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len) vt->outbuffer_cur += len; } -void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) +INTERNAL void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) { int written = vsnprintf(vt->outbuffer + vt->outbuffer_cur, vt->outbuffer_len - vt->outbuffer_cur, @@ -127,7 +127,7 @@ void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args) vt->outbuffer_cur += written; } -void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) +INTERNAL void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) { va_list args; va_start(args, format); @@ -135,7 +135,7 @@ void vterm_push_output_sprintf(VTerm *vt, const char *format, ...) va_end(args); } -void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) +INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...) { if(ctrl >= 0x80 && !vt->mode.ctrl8bit) vterm_push_output_sprintf(vt, "\e%c", ctrl - 0x40); @@ -148,7 +148,7 @@ void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *f va_end(args); } -void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) +INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) { if(!vt->mode.ctrl8bit) vterm_push_output_sprintf(vt, "\e%c", C1_DCS - 0x40); diff --git a/src/vterm_internal.h b/src/vterm_internal.h index 9a0183e..4bc8e6b 100644 --- a/src/vterm_internal.h +++ b/src/vterm_internal.h @@ -5,6 +5,12 @@ #include +#if defined(__GNUC__) +# define INTERNAL __attribute__((visibility("internal"))) +#else +# define INTERNAL +#endif + typedef struct VTermEncoding VTermEncoding; typedef struct { @@ -58,6 +64,10 @@ struct VTermState /* Bitvector of tab stops */ unsigned char *tabstops; + VTermLineInfo *lineinfo; +#define ROWWIDTH(state,row) ((state)->lineinfo[(row)].doublewidth ? ((state)->cols / 2) : (state)->cols) +#define THISROWWIDTH(state) ROWWIDTH(state, (state)->pos.row) + /* Mouse state */ int mouse_col, mouse_row; int mouse_buttons; @@ -92,6 +102,8 @@ struct VTermState VTermColor default_fg; VTermColor default_bg; + VTermColor colors[16]; // Store the 8 ANSI and the 8 ANSI high-brights only + int fg_index; int bg_index; int bold_is_highbright; @@ -172,6 +184,7 @@ void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...); void vterm_state_free(VTermState *state); +void vterm_state_newpen(VTermState *state); void vterm_state_resetpen(VTermState *state); void vterm_state_setpen(VTermState *state, const long args[], int argcount); int vterm_state_getpen(VTermState *state, long args[], int argcount); -- cgit v1.2.3