Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
patch 9.0.1684: Update libvterm to rev 839
Problem: libvterm slightly outdated
Solution: Update libvterm from rev 818 to rev 839

Notable fix: libvterm now handles DECSM/DECRM with multiple arguents,
so several ncurses programs (e.g. nnn) can enable mouse properly when
run in Vim's terminal in XTerm.

closes: #12746

Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: zeertzjq <zeertzjq@outlook.com>
  • Loading branch information
zeertzjq authored and chrisbra committed Aug 11, 2023
1 parent 8f5a8d8 commit b00df7a
Show file tree
Hide file tree
Showing 17 changed files with 313 additions and 38 deletions.
66 changes: 66 additions & 0 deletions src/libvterm/CODE-MAP
@@ -0,0 +1,66 @@
CODE-MAP
- high-level list and description of files in the repository

CONTRIBUTING
- documentation explaining how developers can contribute fixes and features

doc/
- contains documentation

doc/seqs.txt
- documents the sequences recognised by the library

include/vterm.h
- main include file

include/vterm_keycodes.h
- include file containing the keyboard input keycode enumerations

LICENSE
- legalese

Makefile
- main build file

src/
- contains the source code for the library

src/encoding.c
- handles mapping ISO/IEC 2022 alternate character sets into Unicode
codepoints

src/keyboard.c
- handles sending reported keyboard events to the output stream

src/mouse.c
- handles sending reported mouse events to the output stream

src/parser.c
- parses bytes from the input stream into parser-level events

src/pen.c
- interprets SGR sequences and maintains current rendering attributes

src/screen.c
- uses state-level events to maintain a buffer of current screen contents

src/state.c
- follows parser-level events to keep track of the overall terminal state

src/unicode.c
- utility functions for Unicode and UTF-8 handling

src/vterm.c
- toplevel object state and miscellaneous functions

src/vterm_internal.h
- include file for definitions private to the library's internals

t/
- contains unit tests

t/harness.c
- standalone program to embed the library into for unit-test purposes

t/run-test.pl
- invokes the test harness to run a single unit test script
5 changes: 1 addition & 4 deletions src/libvterm/Makefile
Expand Up @@ -36,14 +36,11 @@ INCFILES=$(TBLFILES:.tbl=.inc)

HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES)

VERSION_MAJOR=0
VERSION_MINOR=3

VERSION_CURRENT=0
VERSION_REVISION=0
VERSION_AGE=0

VERSION=$(VERSION_MAJOR).$(VERSION_MINOR)
VERSION=0.3.3

PREFIX=/usr/local
BINDIR=$(PREFIX)/bin
Expand Down
13 changes: 13 additions & 0 deletions src/libvterm/include/vterm.h
Expand Up @@ -23,6 +23,7 @@ typedef unsigned int uint32_t;

#define VTERM_VERSION_MAJOR 0
#define VTERM_VERSION_MINOR 3
#define VTERM_VERSION_PATCH 3

#define VTERM_CHECK_VERSION \
vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR)
Expand Down Expand Up @@ -255,6 +256,7 @@ typedef enum {
VTERM_PROP_REVERSE, // bool
VTERM_PROP_CURSORSHAPE, // number
VTERM_PROP_MOUSE, // number
VTERM_PROP_FOCUSREPORT, // bool
VTERM_PROP_CURSORCOLOR, // VIM - string

VTERM_N_PROPS
Expand Down Expand Up @@ -422,6 +424,11 @@ typedef struct {
void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user);
void *vterm_parser_get_cbdata(VTerm *vt);

/* Normally NUL, CAN, SUB and DEL are ignored. Setting this true causes them
* to be emitted by the 'control' callback
*/
void vterm_parser_set_emit_nul(VTerm *vt, int emit);

// -----------
// State layer
// -----------
Expand Down Expand Up @@ -645,6 +652,12 @@ int vterm_screen_is_eol(const VTermScreen *screen, VTermPos pos);
*/
void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *col);

/**
* Similar to vterm_state_set_default_colors(), but also resets colours in the
* screen buffer(s)
*/
void vterm_screen_set_default_colors(VTermScreen *screen, const VTermColor *default_fg, const VTermColor *default_bg);

// ---------
// Utilities
// ---------
Expand Down
9 changes: 9 additions & 0 deletions src/libvterm/src/parser.c
Expand Up @@ -148,11 +148,15 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
string_start = bytes + pos + 1;
}
if(vt->parser.emit_nul)
do_control(vt, c);
continue;
}
if(c == 0x18 || c == 0x1a) { // CAN, SUB
vt->parser.in_esc = FALSE;
ENTER_NORMAL_STATE();
if(vt->parser.emit_nul)
do_control(vt, c);
continue;
}
else if(c == 0x1b) { // ESC
Expand Down Expand Up @@ -402,3 +406,8 @@ void *vterm_parser_get_cbdata(VTerm *vt)
{
return vt->parser.cbdata;
}

void vterm_parser_set_emit_nul(VTerm *vt, int emit)
{
vt->parser.emit_nul = emit;
}
20 changes: 11 additions & 9 deletions src/libvterm/src/pen.c
Expand Up @@ -259,15 +259,17 @@ void vterm_state_get_palette_color(const VTermState *state, int index, VTermColo

void vterm_state_set_default_colors(VTermState *state, const VTermColor *default_fg, const VTermColor *default_bg)
{
/* Copy the given colors */
state->default_fg = *default_fg;
state->default_bg = *default_bg;

/* Make sure the correct type flags are set */
state->default_fg.type = (state->default_fg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_FG;
state->default_bg.type = (state->default_bg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_BG;
if(default_fg) {
state->default_fg = *default_fg;
state->default_fg.type = (state->default_fg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_FG;
}

if(default_bg) {
state->default_bg = *default_bg;
state->default_bg.type = (state->default_bg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_BG;
}
}

void vterm_state_set_palette_color(VTermState *state, int index, const VTermColor *col)
Expand Down
53 changes: 49 additions & 4 deletions src/libvterm/src/screen.c
Expand Up @@ -292,7 +292,11 @@ static int erase_internal(VTermRect rect, int selective, void *user)
continue;

cell->chars[0] = 0;
cell->pen = screen->pen;
cell->pen = (ScreenPen){
/* Only copy .fg and .bg; leave things like rv in reset state */
.fg = screen->pen.fg,
.bg = screen->pen.bg,
};
cell->pen.dwl = info->doublewidth;
cell->pen.dhl = info->doubleheight;
}
Expand Down Expand Up @@ -603,8 +607,15 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new
new_row_start, new_row_end, old_row_start, old_row_end, width);
#endif

if(new_row_start < 0)
if(new_row_start < 0) {
if(old_row_start <= old_cursor.row && old_cursor.row < old_row_end) {
new_cursor.row = 0;
new_cursor.col = old_cursor.col;
if(new_cursor.col >= new_cols)
new_cursor.col = new_cols-1;
}
break;
}

for(new_row = new_row_start, old_row = old_row_start; new_row <= new_row_end; new_row++) {
int count = width >= new_cols ? new_cols : width;
Expand Down Expand Up @@ -674,8 +685,9 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new

if(old_row >= 0 && bufidx == BUFIDX_PRIMARY) {
/* Push spare lines to scrollback buffer */
for(int row = 0; row <= old_row; row++)
sb_pushline_from_row(screen, row);
if(screen->callbacks && screen->callbacks->sb_pushline)
for(int row = 0; row <= old_row; row++)
sb_pushline_from_row(screen, row);
if(active)
statefields->pos.row -= (old_row + 1);
}
Expand Down Expand Up @@ -1204,3 +1216,36 @@ void vterm_screen_convert_color_to_rgb(const VTermScreen *screen, VTermColor *co
{
vterm_state_convert_color_to_rgb(screen->state, col);
}

static void reset_default_colours(VTermScreen *screen, ScreenCell *buffer)
{
for(int row = 0; row <= screen->rows - 1; row++)
for(int col = 0; col <= screen->cols - 1; col++) {
ScreenCell *cell = &buffer[row * screen->cols + col];
if(VTERM_COLOR_IS_DEFAULT_FG(&cell->pen.fg))
cell->pen.fg = screen->pen.fg;
if(VTERM_COLOR_IS_DEFAULT_BG(&cell->pen.bg))
cell->pen.bg = screen->pen.bg;
}
}

void vterm_screen_set_default_colors(VTermScreen *screen, const VTermColor *default_fg, const VTermColor *default_bg)
{
vterm_state_set_default_colors(screen->state, default_fg, default_bg);

if(default_fg && VTERM_COLOR_IS_DEFAULT_FG(&screen->pen.fg)) {
screen->pen.fg = *default_fg;
screen->pen.fg.type = (screen->pen.fg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_FG;
}

if(default_bg && VTERM_COLOR_IS_DEFAULT_BG(&screen->pen.bg)) {
screen->pen.bg = *default_bg;
screen->pen.bg.type = (screen->pen.bg.type & ~VTERM_COLOR_DEFAULT_MASK)
| VTERM_COLOR_DEFAULT_BG;
}

reset_default_colours(screen, screen->buffers[0]);
if(screen->buffers[1])
reset_default_colours(screen, screen->buffers[1]);
}
56 changes: 44 additions & 12 deletions src/libvterm/src/state.c
Expand Up @@ -837,6 +837,7 @@ static void set_dec_mode(VTermState *state, int num, int val)
break;

case 1004:
settermprop_bool(state, VTERM_PROP_FOCUSREPORT, val);
state->mode.report_focus = val;
break;

Expand Down Expand Up @@ -993,6 +994,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha

switch(intermed[0]) {
case ' ':
case '!':
case '"':
case '$':
case '\'':
Expand Down Expand Up @@ -1370,8 +1372,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
break;

case LEADER('?', 0x68): // DEC private mode set
if(!CSI_ARG_IS_MISSING(args[0]))
set_dec_mode(state, CSI_ARG(args[0]), 1);
for(int i = 0; i < argcount; i++) {
if(!CSI_ARG_IS_MISSING(args[i]))
set_dec_mode(state, CSI_ARG(args[i]), 1);
}
break;

case 0x6a: // HPB - ECMA-48 8.3.58
Expand All @@ -1392,8 +1396,10 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
break;

case LEADER('?', 0x6c): // DEC private mode reset
if(!CSI_ARG_IS_MISSING(args[0]))
set_dec_mode(state, CSI_ARG(args[0]), 0);
for(int i = 0; i < argcount; i++) {
if(!CSI_ARG_IS_MISSING(args[i]))
set_dec_mode(state, CSI_ARG(args[i]), 0);
}
break;

case 0x6d: // SGR - ECMA-48 8.3.117
Expand Down Expand Up @@ -1486,7 +1492,7 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
break;


case LEADER('!', 0x70): // DECSTR - DEC soft terminal reset
case INTERMED('!', 0x70): // DECSTR - DEC soft terminal reset
vterm_state_reset(state, 0);
break;

Expand Down Expand Up @@ -1769,8 +1775,18 @@ static void osc_selection(VTermState *state, VTermStringFragment frag)
frag.len--;
}

if(!frag.len)
if(!frag.len) {
/* Clear selection if we're already finished but didn't do anything */
if(frag.final && state->selection.callbacks->set) {
(*state->selection.callbacks->set)(state->tmp.selection.mask, (VTermStringFragment){
.str = NULL,
.len = 0,
.initial = state->tmp.selection.state != SELECTION_SET,
.final = TRUE,
}, state->selection.user);
}
return;
}

if(state->tmp.selection.state == SELECTION_SELECTED) {
if(frag.str[0] == '?') {
Expand All @@ -1788,6 +1804,9 @@ static void osc_selection(VTermState *state, VTermStringFragment frag)
return;
}

if(state->tmp.selection.state == SELECTION_INVALID)
return;

if(state->selection.callbacks->set) {
size_t bufcur = 0;
char *buffer = state->selection.buffer;
Expand Down Expand Up @@ -1823,11 +1842,21 @@ static void osc_selection(VTermState *state, VTermStringFragment frag)
uint8_t b = unbase64one(frag.str[0]);
if(b == 0xFF) {
DEBUG_LOG1("base64decode bad input %02X\n", (uint8_t)frag.str[0]);

state->tmp.selection.state = SELECTION_INVALID;
if(state->selection.callbacks->set) {
(*state->selection.callbacks->set)(state->tmp.selection.mask, (VTermStringFragment){
.str = NULL,
.len = 0,
.initial = TRUE,
.final = TRUE,
}, state->selection.user);
}
break;
}
else {
x = (x << 6) | b;
n++;
}

x = (x << 6) | b;
n++;
frag.str++, frag.len--;

if(n == 4) {
Expand All @@ -1847,7 +1876,7 @@ static void osc_selection(VTermState *state, VTermStringFragment frag)
state->selection.buffer, // str
bufcur, // len
state->tmp.selection.state == SELECTION_SET_INITIAL, // initial
frag.final // final
frag.final && !frag.len // final
};
(*state->selection.callbacks->set)(state->tmp.selection.mask,
setfrag, state->selection.user);
Expand Down Expand Up @@ -2004,7 +2033,7 @@ static void request_status_string(VTermState *state, VTermStringFragment frag)
return;
}

vterm_push_output_sprintf_str(state->vt, C1_DCS, TRUE, "0$r%s", tmp);
vterm_push_output_sprintf_str(state->vt, C1_DCS, TRUE, "0$r");
}

static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
Expand Down Expand Up @@ -2354,6 +2383,9 @@ int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val)
if(val->number == VTERM_PROP_MOUSE_MOVE)
state->mouse_flags |= MOUSE_WANT_MOVE;
return 1;
case VTERM_PROP_FOCUSREPORT:
state->mode.report_focus = val->boolean;
return 1;

case VTERM_N_PROPS:
return 0;
Expand Down

0 comments on commit b00df7a

Please sign in to comment.