forked from aniani/vim
patch 8.2.0798: libvterm code lags behind the upstream version
Problem: Libvterm code lags behind the upstream version. Solution: Include revisions 755 - 758.
This commit is contained in:
@@ -107,10 +107,17 @@ typedef enum {
|
|||||||
VTERM_N_VALUETYPES
|
VTERM_N_VALUETYPES
|
||||||
} VTermValueType;
|
} VTermValueType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *str;
|
||||||
|
size_t len : 30;
|
||||||
|
unsigned int initial : 1;
|
||||||
|
unsigned int final : 1;
|
||||||
|
} VTermStringFragment;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
int boolean;
|
int boolean;
|
||||||
int number;
|
int number;
|
||||||
char *string;
|
VTermStringFragment string;
|
||||||
VTermColor color;
|
VTermColor color;
|
||||||
} VTermValue;
|
} VTermValue;
|
||||||
|
|
||||||
@@ -257,8 +264,8 @@ typedef struct {
|
|||||||
int (*control)(unsigned char control, void *user);
|
int (*control)(unsigned char control, void *user);
|
||||||
int (*escape)(const char *bytes, size_t len, void *user);
|
int (*escape)(const char *bytes, size_t len, void *user);
|
||||||
int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
|
int (*csi)(const char *leader, const long args[], int argcount, const char *intermed, char command, void *user);
|
||||||
int (*osc)(const char *command, size_t cmdlen, void *user);
|
int (*osc)(int command, VTermStringFragment frag, void *user);
|
||||||
int (*dcs)(const char *command, size_t cmdlen, void *user);
|
int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
|
||||||
int (*resize)(int rows, int cols, void *user);
|
int (*resize)(int rows, int cols, void *user);
|
||||||
} VTermParserCallbacks;
|
} VTermParserCallbacks;
|
||||||
|
|
||||||
|
@@ -23,10 +23,10 @@ static void do_csi(VTerm *vt, char command)
|
|||||||
{
|
{
|
||||||
#ifdef DEBUG_PARSER
|
#ifdef DEBUG_PARSER
|
||||||
printf("Parsed CSI args as:\n", arglen, args);
|
printf("Parsed CSI args as:\n", arglen, args);
|
||||||
printf(" leader: %s\n", vt->parser.csi_leader);
|
printf(" leader: %s\n", vt->parser.v.csi.leader);
|
||||||
for(int argi = 0; argi < vt->parser.csi_argi; argi++) {
|
for(int argi = 0; argi < vt->parser.v.csi.argi; argi++) {
|
||||||
printf(" %lu", CSI_ARG(vt->parser.csi_args[argi]));
|
printf(" %lu", CSI_ARG(vt->parser.v.csi.args[argi]));
|
||||||
if(!CSI_ARG_HAS_MORE(vt->parser.csi_args[argi]))
|
if(!CSI_ARG_HAS_MORE(vt->parser.v.csi.args[argi]))
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" intermed: %s\n", vt->parser.intermed);
|
printf(" intermed: %s\n", vt->parser.intermed);
|
||||||
}
|
}
|
||||||
@@ -34,9 +34,9 @@ static void do_csi(VTerm *vt, char command)
|
|||||||
|
|
||||||
if(vt->parser.callbacks && vt->parser.callbacks->csi)
|
if(vt->parser.callbacks && vt->parser.callbacks->csi)
|
||||||
if((*vt->parser.callbacks->csi)(
|
if((*vt->parser.callbacks->csi)(
|
||||||
vt->parser.csi_leaderlen ? vt->parser.csi_leader : NULL,
|
vt->parser.v.csi.leaderlen ? vt->parser.v.csi.leader : NULL,
|
||||||
vt->parser.csi_args,
|
vt->parser.v.csi.args,
|
||||||
vt->parser.csi_argi,
|
vt->parser.v.csi.argi,
|
||||||
vt->parser.intermedlen ? vt->parser.intermed : NULL,
|
vt->parser.intermedlen ? vt->parser.intermed : NULL,
|
||||||
command,
|
command,
|
||||||
vt->parser.cbdata))
|
vt->parser.cbdata))
|
||||||
@@ -61,65 +61,36 @@ static void do_escape(VTerm *vt, char command)
|
|||||||
DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command);
|
DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append_strbuffer(VTerm *vt, const char *str, size_t len)
|
static void string_fragment(VTerm *vt, const char *str, size_t len, int final)
|
||||||
{
|
{
|
||||||
if(len > vt->parser.strbuffer_len - vt->parser.strbuffer_cur) {
|
VTermStringFragment frag;
|
||||||
len = vt->parser.strbuffer_len - vt->parser.strbuffer_cur;
|
|
||||||
DEBUG_LOG1("Truncating strbuffer preserve to %zu bytes\n", len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(len > 0) {
|
frag.str = str;
|
||||||
strncpy(vt->parser.strbuffer + vt->parser.strbuffer_cur, str, len);
|
frag.len = len;
|
||||||
vt->parser.strbuffer_cur += len;
|
frag.initial = vt->parser.string_initial;
|
||||||
}
|
frag.final = final;
|
||||||
}
|
|
||||||
|
|
||||||
static void start_string(VTerm *vt, VTermParserStringType type)
|
switch(vt->parser.state) {
|
||||||
{
|
case OSC:
|
||||||
vt->parser.stringtype = type;
|
|
||||||
|
|
||||||
vt->parser.strbuffer_cur = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void more_string(VTerm *vt, const char *str, size_t len)
|
|
||||||
{
|
|
||||||
append_strbuffer(vt, str, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void done_string(VTerm *vt, const char *str, size_t len)
|
|
||||||
{
|
|
||||||
if(vt->parser.strbuffer_cur) {
|
|
||||||
if(str)
|
|
||||||
append_strbuffer(vt, str, len);
|
|
||||||
|
|
||||||
str = vt->parser.strbuffer;
|
|
||||||
len = vt->parser.strbuffer_cur;
|
|
||||||
}
|
|
||||||
else if(!str) {
|
|
||||||
DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n");
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(vt->parser.stringtype) {
|
|
||||||
case VTERM_PARSER_OSC:
|
|
||||||
if(vt->parser.callbacks && vt->parser.callbacks->osc)
|
if(vt->parser.callbacks && vt->parser.callbacks->osc)
|
||||||
if((*vt->parser.callbacks->osc)(str, len, vt->parser.cbdata))
|
(*vt->parser.callbacks->osc)(vt->parser.v.osc.command, frag, vt->parser.cbdata);
|
||||||
return;
|
break;
|
||||||
|
|
||||||
DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str);
|
case DCS:
|
||||||
return;
|
if(len && vt->parser.callbacks && vt->parser.callbacks->dcs)
|
||||||
|
(*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata);
|
||||||
|
break;
|
||||||
|
|
||||||
case VTERM_PARSER_DCS:
|
case NORMAL:
|
||||||
if(vt->parser.callbacks && vt->parser.callbacks->dcs)
|
case CSI_LEADER:
|
||||||
if((*vt->parser.callbacks->dcs)(str, len, vt->parser.cbdata))
|
case CSI_ARGS:
|
||||||
return;
|
case CSI_INTERMED:
|
||||||
|
case OSC_COMMAND:
|
||||||
DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str);
|
case DCS_COMMAND:
|
||||||
return;
|
break;
|
||||||
|
|
||||||
case VTERM_N_PARSER_TYPES:
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vt->parser.string_initial = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
||||||
@@ -135,43 +106,45 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
case CSI_LEADER:
|
case CSI_LEADER:
|
||||||
case CSI_ARGS:
|
case CSI_ARGS:
|
||||||
case CSI_INTERMED:
|
case CSI_INTERMED:
|
||||||
case ESC:
|
case OSC_COMMAND:
|
||||||
|
case DCS_COMMAND:
|
||||||
string_start = NULL;
|
string_start = NULL;
|
||||||
break;
|
break;
|
||||||
case STRING:
|
case OSC:
|
||||||
case ESC_IN_STRING:
|
case DCS:
|
||||||
string_start = bytes;
|
string_start = bytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ENTER_STRING_STATE() do { vt->parser.state = STRING; string_start = bytes + pos + 1; } while(0)
|
|
||||||
#define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0)
|
#define ENTER_STATE(st) do { vt->parser.state = st; string_start = NULL; } while(0)
|
||||||
#define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL)
|
#define ENTER_NORMAL_STATE() ENTER_STATE(NORMAL)
|
||||||
|
|
||||||
for( ; pos < len; pos++) {
|
for( ; pos < len; pos++) {
|
||||||
unsigned char c = bytes[pos];
|
unsigned char c = bytes[pos];
|
||||||
|
int c1_allowed = !vt->mode.utf8;
|
||||||
|
size_t string_len;
|
||||||
|
|
||||||
if(c == 0x00 || c == 0x7f) { // NUL, DEL
|
if(c == 0x00 || c == 0x7f) { // NUL, DEL
|
||||||
if(vt->parser.state >= STRING) {
|
if(vt->parser.state >= OSC) {
|
||||||
more_string(vt, string_start, bytes + pos - string_start);
|
string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
|
||||||
string_start = bytes + pos + 1;
|
string_start = bytes + pos + 1;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(c == 0x18 || c == 0x1a) { // CAN, SUB
|
if(c == 0x18 || c == 0x1a) { // CAN, SUB
|
||||||
|
vt->parser.in_esc = FALSE;
|
||||||
ENTER_NORMAL_STATE();
|
ENTER_NORMAL_STATE();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(c == 0x1b) { // ESC
|
else if(c == 0x1b) { // ESC
|
||||||
vt->parser.intermedlen = 0;
|
vt->parser.intermedlen = 0;
|
||||||
if(vt->parser.state == STRING)
|
if(vt->parser.state < OSC)
|
||||||
vt->parser.state = ESC_IN_STRING;
|
vt->parser.state = NORMAL;
|
||||||
else
|
vt->parser.in_esc = TRUE;
|
||||||
ENTER_STATE(ESC);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state
|
else if(c == 0x07 && // BEL, can stand for ST in OSC or DCS state
|
||||||
vt->parser.state == STRING) {
|
vt->parser.state >= OSC) {
|
||||||
// fallthrough
|
// fallthrough
|
||||||
}
|
}
|
||||||
else if(c < 0x20) { // other C0
|
else if(c < 0x20) { // other C0
|
||||||
@@ -182,96 +155,72 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08)
|
if(pos + 2 < len && bytes[pos + 1] == 0x20 && bytes[pos + 2] == 0x08)
|
||||||
vt->in_backspace = 2; // Trigger when count down to 1
|
vt->in_backspace = 2; // Trigger when count down to 1
|
||||||
}
|
}
|
||||||
if(vt->parser.state >= STRING)
|
if(vt->parser.state >= OSC)
|
||||||
more_string(vt, string_start, bytes + pos - string_start);
|
string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
|
||||||
do_control(vt, c);
|
do_control(vt, c);
|
||||||
if(vt->parser.state >= STRING)
|
if(vt->parser.state >= OSC)
|
||||||
string_start = bytes + pos + 1;
|
string_start = bytes + pos + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// else fallthrough
|
// else fallthrough
|
||||||
|
|
||||||
switch(vt->parser.state) {
|
string_len = bytes + pos - string_start;
|
||||||
case ESC_IN_STRING:
|
|
||||||
if(c == 0x5c) { // ST
|
|
||||||
vt->parser.state = STRING;
|
|
||||||
done_string(vt, string_start, bytes + pos - string_start - 1);
|
|
||||||
ENTER_NORMAL_STATE();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
vt->parser.state = ESC;
|
|
||||||
// else fallthrough
|
|
||||||
|
|
||||||
case ESC:
|
if(vt->parser.in_esc) {
|
||||||
switch(c) {
|
// Hoist an ESC letter into a C1 if we're not in a string mode
|
||||||
case 0x50: // DCS
|
// Always accept ESC \ == ST even in string mode
|
||||||
start_string(vt, VTERM_PARSER_DCS);
|
if(!vt->parser.intermedlen &&
|
||||||
ENTER_STRING_STATE();
|
c >= 0x40 && c < 0x60 &&
|
||||||
break;
|
((vt->parser.state < OSC || c == 0x5c))) {
|
||||||
case 0x5b: // CSI
|
c += 0x40;
|
||||||
vt->parser.csi_leaderlen = 0;
|
c1_allowed = TRUE;
|
||||||
ENTER_STATE(CSI_LEADER);
|
string_len -= 1;
|
||||||
break;
|
vt->parser.in_esc = FALSE;
|
||||||
case 0x5d: // OSC
|
|
||||||
start_string(vt, VTERM_PARSER_OSC);
|
|
||||||
ENTER_STRING_STATE();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if(is_intermed(c)) {
|
|
||||||
if(vt->parser.intermedlen < INTERMED_MAX-1)
|
|
||||||
vt->parser.intermed[vt->parser.intermedlen++] = c;
|
|
||||||
}
|
|
||||||
else if(!vt->parser.intermedlen && c >= 0x40 && c < 0x60) {
|
|
||||||
do_control(vt, c + 0x40);
|
|
||||||
ENTER_NORMAL_STATE();
|
|
||||||
}
|
|
||||||
else if(c >= 0x30 && c < 0x7f) {
|
|
||||||
do_escape(vt, c);
|
|
||||||
ENTER_NORMAL_STATE();
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
|
string_start = NULL;
|
||||||
|
vt->parser.state = NORMAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
|
switch(vt->parser.state) {
|
||||||
case CSI_LEADER:
|
case CSI_LEADER:
|
||||||
// Extract leader bytes 0x3c to 0x3f
|
// Extract leader bytes 0x3c to 0x3f
|
||||||
if(c >= 0x3c && c <= 0x3f) {
|
if(c >= 0x3c && c <= 0x3f) {
|
||||||
if(vt->parser.csi_leaderlen < CSI_LEADER_MAX-1)
|
if(vt->parser.v.csi.leaderlen < CSI_LEADER_MAX-1)
|
||||||
vt->parser.csi_leader[vt->parser.csi_leaderlen++] = c;
|
vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen++] = c;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// else fallthrough
|
// else fallthrough
|
||||||
vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0;
|
vt->parser.v.csi.leader[vt->parser.v.csi.leaderlen] = 0;
|
||||||
|
|
||||||
vt->parser.csi_argi = 0;
|
vt->parser.v.csi.argi = 0;
|
||||||
vt->parser.csi_args[0] = CSI_ARG_MISSING;
|
vt->parser.v.csi.args[0] = CSI_ARG_MISSING;
|
||||||
vt->parser.state = CSI_ARGS;
|
vt->parser.state = CSI_ARGS;
|
||||||
|
|
||||||
// fallthrough
|
// fallthrough
|
||||||
case CSI_ARGS:
|
case CSI_ARGS:
|
||||||
// Numerical value of argument
|
// Numerical value of argument
|
||||||
if(c >= '0' && c <= '9') {
|
if(c >= '0' && c <= '9') {
|
||||||
if(vt->parser.csi_args[vt->parser.csi_argi] == CSI_ARG_MISSING)
|
if(vt->parser.v.csi.args[vt->parser.v.csi.argi] == CSI_ARG_MISSING)
|
||||||
vt->parser.csi_args[vt->parser.csi_argi] = 0;
|
vt->parser.v.csi.args[vt->parser.v.csi.argi] = 0;
|
||||||
vt->parser.csi_args[vt->parser.csi_argi] *= 10;
|
vt->parser.v.csi.args[vt->parser.v.csi.argi] *= 10;
|
||||||
vt->parser.csi_args[vt->parser.csi_argi] += c - '0';
|
vt->parser.v.csi.args[vt->parser.v.csi.argi] += c - '0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(c == ':') {
|
if(c == ':') {
|
||||||
vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE;
|
vt->parser.v.csi.args[vt->parser.v.csi.argi] |= CSI_ARG_FLAG_MORE;
|
||||||
c = ';';
|
c = ';';
|
||||||
}
|
}
|
||||||
if(c == ';') {
|
if(c == ';') {
|
||||||
vt->parser.csi_argi++;
|
vt->parser.v.csi.argi++;
|
||||||
vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING;
|
vt->parser.v.csi.args[vt->parser.v.csi.argi] = CSI_ARG_MISSING;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// else fallthrough
|
// else fallthrough
|
||||||
vt->parser.csi_argi++;
|
vt->parser.v.csi.argi++;
|
||||||
vt->parser.intermedlen = 0;
|
vt->parser.intermedlen = 0;
|
||||||
vt->parser.state = CSI_INTERMED;
|
vt->parser.state = CSI_INTERMED;
|
||||||
// fallthrough
|
// fallthrough
|
||||||
@@ -293,31 +242,77 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
ENTER_NORMAL_STATE();
|
ENTER_NORMAL_STATE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case STRING:
|
case OSC_COMMAND:
|
||||||
if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {
|
/* Numerical value of command */
|
||||||
done_string(vt, string_start, bytes + pos - string_start);
|
if(c >= '0' && c <= '9') {
|
||||||
ENTER_NORMAL_STATE();
|
if(vt->parser.v.osc.command == -1)
|
||||||
|
vt->parser.v.osc.command = 0;
|
||||||
|
else
|
||||||
|
vt->parser.v.osc.command *= 10;
|
||||||
|
vt->parser.v.osc.command += c - '0';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (pos + 1 == len) {
|
if(c == ';') {
|
||||||
// end of input but OSC string isn't finished yet, copy it to
|
vt->parser.state = OSC;
|
||||||
// vt->parser.strbuffer to continue it later
|
string_start = bytes + pos + 1;
|
||||||
more_string(vt, string_start, bytes + pos + 1 - string_start);
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* else fallthrough */
|
||||||
|
string_start = bytes + pos;
|
||||||
|
vt->parser.state = OSC;
|
||||||
|
goto string_state;
|
||||||
|
|
||||||
|
case DCS_COMMAND:
|
||||||
|
if(vt->parser.v.dcs.commandlen < CSI_LEADER_MAX)
|
||||||
|
vt->parser.v.dcs.command[vt->parser.v.dcs.commandlen++] = c;
|
||||||
|
|
||||||
|
if(c >= 0x40 && c<= 0x7e) {
|
||||||
|
string_start = bytes + pos + 1;
|
||||||
|
vt->parser.state = DCS;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
string_state:
|
||||||
|
case OSC:
|
||||||
|
case DCS:
|
||||||
|
if(c == 0x07 || (c1_allowed && c == 0x9c)) {
|
||||||
|
string_fragment(vt, string_start, string_len, TRUE);
|
||||||
|
ENTER_NORMAL_STATE();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {
|
if(vt->parser.in_esc) {
|
||||||
|
if(is_intermed(c)) {
|
||||||
|
if(vt->parser.intermedlen < INTERMED_MAX-1)
|
||||||
|
vt->parser.intermed[vt->parser.intermedlen++] = c;
|
||||||
|
}
|
||||||
|
else if(c >= 0x30 && c < 0x7f) {
|
||||||
|
do_escape(vt, c);
|
||||||
|
vt->parser.in_esc = 0;
|
||||||
|
ENTER_NORMAL_STATE();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(c1_allowed && c >= 0x80 && c < 0xa0) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 0x90: // DCS
|
case 0x90: // DCS
|
||||||
start_string(vt, VTERM_PARSER_DCS);
|
vt->parser.string_initial = TRUE;
|
||||||
ENTER_STRING_STATE();
|
vt->parser.v.dcs.commandlen = 0;
|
||||||
|
ENTER_STATE(DCS_COMMAND);
|
||||||
break;
|
break;
|
||||||
case 0x9b: // CSI
|
case 0x9b: // CSI
|
||||||
|
vt->parser.v.csi.leaderlen = 0;
|
||||||
ENTER_STATE(CSI_LEADER);
|
ENTER_STATE(CSI_LEADER);
|
||||||
break;
|
break;
|
||||||
case 0x9d: // OSC
|
case 0x9d: // OSC
|
||||||
start_string(vt, VTERM_PARSER_OSC);
|
vt->parser.v.osc.command = -1;
|
||||||
ENTER_STRING_STATE();
|
vt->parser.string_initial = TRUE;
|
||||||
|
ENTER_STATE(OSC_COMMAND);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
do_control(vt, c);
|
do_control(vt, c);
|
||||||
@@ -341,6 +336,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(string_start)
|
||||||
|
string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -533,7 +533,7 @@ static void resize_buffer(VTermScreen *screen, int bufidx, int new_rows, int new
|
|||||||
ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col];
|
ScreenCell *dst = &new_buffer[pos.row * new_cols + pos.col];
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; ; i++) {
|
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) {
|
||||||
dst->chars[i] = src->chars[i];
|
dst->chars[i] = src->chars[i];
|
||||||
if(!src->chars[i])
|
if(!src->chars[i])
|
||||||
break;
|
break;
|
||||||
@@ -804,7 +804,7 @@ int vterm_screen_get_cell(const VTermScreen *screen, VTermPos pos, VTermScreenCe
|
|||||||
if(!intcell)
|
if(!intcell)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
for(i = 0; ; i++) {
|
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL; i++) {
|
||||||
cell->chars[i] = intcell->chars[i];
|
cell->chars[i] = intcell->chars[i];
|
||||||
if(!intcell->chars[i])
|
if(!intcell->chars[i])
|
||||||
break;
|
break;
|
||||||
|
@@ -582,19 +582,12 @@ static int settermprop_int(VTermState *state, VTermProp prop, int v)
|
|||||||
return vterm_state_set_termprop(state, prop, &val);
|
return vterm_state_set_termprop(state, prop, &val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int settermprop_string(VTermState *state, VTermProp prop, const char *str, size_t len)
|
static int settermprop_string(VTermState *state, VTermProp prop, VTermStringFragment frag)
|
||||||
{
|
{
|
||||||
char *strvalue;
|
|
||||||
int r;
|
|
||||||
VTermValue val;
|
VTermValue val;
|
||||||
strvalue = vterm_allocator_malloc(state->vt, (len+1) * sizeof(char));
|
|
||||||
strncpy(strvalue, str, len);
|
|
||||||
strvalue[len] = 0;
|
|
||||||
|
|
||||||
val.string = strvalue;
|
val.string = frag;
|
||||||
r = vterm_state_set_termprop(state, prop, &val);
|
return vterm_state_set_termprop(state, prop, &val);
|
||||||
vterm_allocator_free(state->vt, strvalue);
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void savecursor(VTermState *state, int save)
|
static void savecursor(VTermState *state, int save)
|
||||||
@@ -1602,27 +1595,26 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_osc(const char *command, size_t cmdlen, void *user)
|
static int on_osc(int command, VTermStringFragment frag, void *user)
|
||||||
{
|
{
|
||||||
VTermState *state = user;
|
VTermState *state = user;
|
||||||
|
|
||||||
if(cmdlen < 2)
|
switch(command) {
|
||||||
return 0;
|
case 0:
|
||||||
|
settermprop_string(state, VTERM_PROP_ICONNAME, frag);
|
||||||
|
settermprop_string(state, VTERM_PROP_TITLE, frag);
|
||||||
|
return 1;
|
||||||
|
|
||||||
if(strneq(command, "0;", 2)) {
|
case 1:
|
||||||
settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2);
|
settermprop_string(state, VTERM_PROP_ICONNAME, frag);
|
||||||
settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
else if(strneq(command, "1;", 2)) {
|
case 2:
|
||||||
settermprop_string(state, VTERM_PROP_ICONNAME, command + 2, cmdlen - 2);
|
settermprop_string(state, VTERM_PROP_TITLE, frag);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
else if(strneq(command, "2;", 2)) {
|
case 10:
|
||||||
settermprop_string(state, VTERM_PROP_TITLE, command + 2, cmdlen - 2);
|
{
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
else if(strneq(command, "10;", 3)) {
|
|
||||||
// request foreground color: <Esc>]10;?<0x07>
|
// request foreground color: <Esc>]10;?<0x07>
|
||||||
int red = state->default_fg.red;
|
int red = state->default_fg.red;
|
||||||
int blue = state->default_fg.blue;
|
int blue = state->default_fg.blue;
|
||||||
@@ -1630,7 +1622,9 @@ static int on_osc(const char *command, size_t cmdlen, void *user)
|
|||||||
vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "10;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue);
|
vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "10;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if(strneq(command, "11;", 3)) {
|
|
||||||
|
case 11:
|
||||||
|
{
|
||||||
// request background color: <Esc>]11;?<0x07>
|
// request background color: <Esc>]11;?<0x07>
|
||||||
int red = state->default_bg.red;
|
int red = state->default_bg.red;
|
||||||
int blue = state->default_bg.blue;
|
int blue = state->default_bg.blue;
|
||||||
@@ -1638,64 +1632,84 @@ static int on_osc(const char *command, size_t cmdlen, void *user)
|
|||||||
vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "11;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue);
|
vterm_push_output_sprintf_ctrl(state->vt, C1_OSC, "11;rgb:%02x%02x/%02x%02x/%02x%02x\x07", red, red, green, green, blue, blue);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if(strneq(command, "12;", 3)) {
|
case 12:
|
||||||
settermprop_string(state, VTERM_PROP_CURSORCOLOR, command + 3, cmdlen - 3);
|
settermprop_string(state, VTERM_PROP_CURSORCOLOR, frag);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if(state->fallbacks && state->fallbacks->osc)
|
||||||
|
if((*state->fallbacks->osc)(command, frag, state->fbdata))
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if(state->fallbacks && state->fallbacks->osc)
|
|
||||||
if((*state->fallbacks->osc)(command, cmdlen, state->fbdata))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void request_status_string(VTermState *state, const char *command, size_t cmdlen)
|
static void request_status_string(VTermState *state, VTermStringFragment frag)
|
||||||
{
|
{
|
||||||
VTerm *vt = state->vt;
|
VTerm *vt = state->vt;
|
||||||
|
|
||||||
if(cmdlen == 1)
|
char *tmp = state->tmp.decrqss;
|
||||||
switch(command[0]) {
|
size_t i = 0;
|
||||||
case 'm': // Query SGR
|
|
||||||
{
|
if(frag.initial)
|
||||||
|
tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0;
|
||||||
|
|
||||||
|
while(i < sizeof(state->tmp.decrqss)-1 && tmp[i])
|
||||||
|
i++;
|
||||||
|
while(i < sizeof(state->tmp.decrqss)-1 && frag.len--)
|
||||||
|
tmp[i++] = (frag.str++)[0];
|
||||||
|
tmp[i] = 0;
|
||||||
|
|
||||||
|
if(!frag.final)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fprintf(stderr, "DECRQSS on <%s>\n", tmp);
|
||||||
|
|
||||||
|
switch(tmp[0] | tmp[1]<<8 | tmp[2]<<16) {
|
||||||
|
case 'm': {
|
||||||
|
// Query SGR
|
||||||
long args[20];
|
long args[20];
|
||||||
int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0]));
|
int argc = vterm_state_getpen(state, args, sizeof(args)/sizeof(args[0]));
|
||||||
int argi;
|
|
||||||
size_t cur = 0;
|
size_t cur = 0;
|
||||||
|
int argi;
|
||||||
|
|
||||||
cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
|
cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
|
||||||
vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ...
|
vt->mode.ctrl8bit ? "\x90" "1$r" : ESC_S "P" "1$r"); // DCS 1$r ...
|
||||||
if(cur >= vt->tmpbuffer_len)
|
if(cur >= vt->tmpbuffer_len)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for(argi = 0; argi < argc; argi++) {
|
for(argi = 0; argi < argc; argi++) {
|
||||||
cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
|
cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
|
||||||
argi == argc - 1 ? "%ld" :
|
argi == argc - 1 ? "%ld" :
|
||||||
CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" :
|
CSI_ARG_HAS_MORE(args[argi]) ? "%ld:" :
|
||||||
"%ld;",
|
"%ld;",
|
||||||
CSI_ARG(args[argi]));
|
CSI_ARG(args[argi]));
|
||||||
|
|
||||||
if(cur >= vt->tmpbuffer_len)
|
if(cur >= vt->tmpbuffer_len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur += SNPRINTF(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
|
cur += snprintf(vt->tmpbuffer + cur, vt->tmpbuffer_len - cur,
|
||||||
vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST
|
vt->mode.ctrl8bit ? "m" "\x9C" : "m" ESC_S "\\"); // ... m ST
|
||||||
if(cur >= vt->tmpbuffer_len)
|
if(cur >= vt->tmpbuffer_len)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
|
vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
|
||||||
}
|
|
||||||
return;
|
|
||||||
case 'r': // Query DECSTBM
|
|
||||||
vterm_push_output_sprintf_dcs(vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state));
|
|
||||||
return;
|
|
||||||
case 's': // Query DECSLRM
|
|
||||||
vterm_push_output_sprintf_dcs(vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(cmdlen == 2) {
|
case 'r':
|
||||||
if(strneq(command, " q", 2)) {
|
// Query DECSTBM
|
||||||
|
vterm_push_output_sprintf_dcs(vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
// Query DECSLRM
|
||||||
|
vterm_push_output_sprintf_dcs(vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state));
|
||||||
|
return;
|
||||||
|
|
||||||
|
case ' '|('q'<<8): {
|
||||||
|
// Query DECSCUSR
|
||||||
int reply;
|
int reply;
|
||||||
switch(state->mode.cursor_shape) {
|
switch(state->mode.cursor_shape) {
|
||||||
case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break;
|
case VTERM_PROP_CURSORSHAPE_BLOCK: reply = 2; break;
|
||||||
@@ -1707,27 +1721,29 @@ static void request_status_string(VTermState *state, const char *command, size_t
|
|||||||
vterm_push_output_sprintf_dcs(vt, "1$r%d q", reply);
|
vterm_push_output_sprintf_dcs(vt, "1$r%d q", reply);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if(strneq(command, "\"q", 2)) {
|
|
||||||
|
case '\"'|('q'<<8):
|
||||||
|
// Query DECSCA
|
||||||
vterm_push_output_sprintf_dcs(vt, "1$r%d\"q", state->protected_cell ? 1 : 2);
|
vterm_push_output_sprintf_dcs(vt, "1$r%d\"q", state->protected_cell ? 1 : 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
vterm_push_output_sprintf_dcs(state->vt, "0$r%.s", (int)cmdlen, command);
|
vterm_push_output_sprintf_dcs(state->vt, "0$r%s", tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_dcs(const char *command, size_t cmdlen, void *user)
|
static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
|
||||||
{
|
{
|
||||||
VTermState *state = user;
|
VTermState *state = user;
|
||||||
|
|
||||||
if(cmdlen >= 2 && strneq(command, "$q", 2)) {
|
if(commandlen == 2 && strneq(command, "$q", 2)) {
|
||||||
request_status_string(state, command+2, cmdlen-2);
|
request_status_string(state, frag);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if(state->fallbacks && state->fallbacks->dcs)
|
else if(state->fallbacks && state->fallbacks->dcs)
|
||||||
if((*state->fallbacks->dcs)(command, cmdlen, state->fbdata))
|
if((*state->fallbacks->dcs)(command, commandlen, frag, state->fbdata))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)commandlen, command);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -55,35 +55,23 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun
|
|||||||
vt->parser.callbacks = NULL;
|
vt->parser.callbacks = NULL;
|
||||||
vt->parser.cbdata = NULL;
|
vt->parser.cbdata = NULL;
|
||||||
|
|
||||||
vt->parser.strbuffer_len = 500; // should be able to hold an OSC string
|
|
||||||
vt->parser.strbuffer_cur = 0;
|
|
||||||
vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);
|
|
||||||
if (vt->parser.strbuffer == NULL)
|
|
||||||
{
|
|
||||||
vterm_allocator_free(vt, vt);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
vt->outfunc = NULL;
|
vt->outfunc = NULL;
|
||||||
vt->outdata = NULL;
|
vt->outdata = NULL;
|
||||||
|
|
||||||
vt->outbuffer_len = 200;
|
vt->outbuffer_len = 200;
|
||||||
vt->outbuffer_cur = 0;
|
vt->outbuffer_cur = 0;
|
||||||
vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
|
vt->outbuffer = vterm_allocator_malloc(vt, vt->outbuffer_len);
|
||||||
if (vt->outbuffer == NULL)
|
|
||||||
{
|
|
||||||
vterm_allocator_free(vt, vt->parser.strbuffer);
|
|
||||||
vterm_allocator_free(vt, vt);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
vt->tmpbuffer_len = 64;
|
vt->tmpbuffer_len = 64;
|
||||||
vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len);
|
vt->tmpbuffer = vterm_allocator_malloc(vt, vt->tmpbuffer_len);
|
||||||
if (vt->tmpbuffer == NULL)
|
|
||||||
|
if (vt->tmpbuffer == NULL
|
||||||
|
|| vt->outbuffer == NULL
|
||||||
|
|| vt->tmpbuffer == NULL)
|
||||||
{
|
{
|
||||||
vterm_allocator_free(vt, vt->parser.strbuffer);
|
|
||||||
vterm_allocator_free(vt, vt);
|
|
||||||
vterm_allocator_free(vt, vt->outbuffer);
|
vterm_allocator_free(vt, vt->outbuffer);
|
||||||
|
vterm_allocator_free(vt, vt->tmpbuffer);
|
||||||
|
vterm_allocator_free(vt, vt);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,7 +86,6 @@ void vterm_free(VTerm *vt)
|
|||||||
if(vt->state)
|
if(vt->state)
|
||||||
vterm_state_free(vt->state);
|
vterm_state_free(vt->state);
|
||||||
|
|
||||||
vterm_allocator_free(vt, vt->parser.strbuffer);
|
|
||||||
vterm_allocator_free(vt, vt->outbuffer);
|
vterm_allocator_free(vt, vt->outbuffer);
|
||||||
vterm_allocator_free(vt, vt->tmpbuffer);
|
vterm_allocator_free(vt, vt->tmpbuffer);
|
||||||
|
|
||||||
|
@@ -160,15 +160,13 @@ struct VTermState
|
|||||||
unsigned int cursor_shape:2;
|
unsigned int cursor_shape:2;
|
||||||
} mode;
|
} mode;
|
||||||
} saved;
|
} saved;
|
||||||
|
|
||||||
|
/* Temporary state for DECRQSS parsing */
|
||||||
|
union {
|
||||||
|
char decrqss[4];
|
||||||
|
} tmp;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
VTERM_PARSER_OSC,
|
|
||||||
VTERM_PARSER_DCS,
|
|
||||||
|
|
||||||
VTERM_N_PARSER_TYPES
|
|
||||||
} VTermParserStringType;
|
|
||||||
|
|
||||||
struct VTerm
|
struct VTerm
|
||||||
{
|
{
|
||||||
VTermAllocatorFunctions *allocator;
|
VTermAllocatorFunctions *allocator;
|
||||||
@@ -188,28 +186,39 @@ struct VTerm
|
|||||||
CSI_LEADER,
|
CSI_LEADER,
|
||||||
CSI_ARGS,
|
CSI_ARGS,
|
||||||
CSI_INTERMED,
|
CSI_INTERMED,
|
||||||
ESC,
|
OSC_COMMAND,
|
||||||
|
DCS_COMMAND,
|
||||||
// below here are the "string states"
|
// below here are the "string states"
|
||||||
STRING,
|
OSC,
|
||||||
ESC_IN_STRING,
|
DCS,
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
|
unsigned int in_esc : 1;
|
||||||
|
|
||||||
int intermedlen;
|
int intermedlen;
|
||||||
char intermed[INTERMED_MAX];
|
char intermed[INTERMED_MAX];
|
||||||
|
|
||||||
int csi_leaderlen;
|
union {
|
||||||
char csi_leader[CSI_LEADER_MAX];
|
struct {
|
||||||
|
int leaderlen;
|
||||||
|
char leader[CSI_LEADER_MAX];
|
||||||
|
|
||||||
int csi_argi;
|
int argi;
|
||||||
long csi_args[CSI_ARGS_MAX];
|
long args[CSI_ARGS_MAX];
|
||||||
|
} csi;
|
||||||
|
struct {
|
||||||
|
int command;
|
||||||
|
} osc;
|
||||||
|
struct {
|
||||||
|
int commandlen;
|
||||||
|
char command[CSI_LEADER_MAX];
|
||||||
|
} dcs;
|
||||||
|
} v;
|
||||||
|
|
||||||
const VTermParserCallbacks *callbacks;
|
const VTermParserCallbacks *callbacks;
|
||||||
void *cbdata;
|
void *cbdata;
|
||||||
|
|
||||||
VTermParserStringType stringtype;
|
int string_initial;
|
||||||
char *strbuffer;
|
|
||||||
size_t strbuffer_len;
|
|
||||||
size_t strbuffer_cur;
|
|
||||||
} parser;
|
} parser;
|
||||||
|
|
||||||
// len == malloc()ed size; cur == number of valid bytes
|
// len == malloc()ed size; cur == number of valid bytes
|
||||||
|
@@ -132,15 +132,23 @@ PUSH "\e[12\n;3X"
|
|||||||
|
|
||||||
!OSC BEL
|
!OSC BEL
|
||||||
PUSH "\e]1;Hello\x07"
|
PUSH "\e]1;Hello\x07"
|
||||||
osc "1;Hello"
|
osc [1 "Hello"]
|
||||||
|
|
||||||
!OSC ST (7bit)
|
!OSC ST (7bit)
|
||||||
PUSH "\e]1;Hello\e\\"
|
PUSH "\e]1;Hello\e\\"
|
||||||
osc "1;Hello"
|
osc [1 "Hello"]
|
||||||
|
|
||||||
!OSC ST (8bit)
|
!OSC ST (8bit)
|
||||||
PUSH "\x{9d}1;Hello\x9c"
|
PUSH "\x{9d}1;Hello\x9c"
|
||||||
osc "1;Hello"
|
osc [1 "Hello"]
|
||||||
|
|
||||||
|
!OSC in parts
|
||||||
|
PUSH "\e]52;abc"
|
||||||
|
osc [52 "abc"
|
||||||
|
PUSH "def"
|
||||||
|
osc "def"
|
||||||
|
PUSH "ghi\e\\"
|
||||||
|
osc "ghi"]
|
||||||
|
|
||||||
!Escape cancels OSC, starts Escape
|
!Escape cancels OSC, starts Escape
|
||||||
PUSH "\e]Something\e9"
|
PUSH "\e]Something\e9"
|
||||||
@@ -152,20 +160,21 @@ PUSH "\e]12\x{18}AB"
|
|||||||
|
|
||||||
!C0 in OSC interrupts and continues
|
!C0 in OSC interrupts and continues
|
||||||
PUSH "\e]2;\nBye\x07"
|
PUSH "\e]2;\nBye\x07"
|
||||||
|
osc [2 ""
|
||||||
control 10
|
control 10
|
||||||
osc "2;Bye"
|
osc "Bye"]
|
||||||
|
|
||||||
!DCS BEL
|
!DCS BEL
|
||||||
PUSH "\ePHello\x07"
|
PUSH "\ePHello\x07"
|
||||||
dcs "Hello"
|
dcs ["Hello"]
|
||||||
|
|
||||||
!DCS ST (7bit)
|
!DCS ST (7bit)
|
||||||
PUSH "\ePHello\e\\"
|
PUSH "\ePHello\e\\"
|
||||||
dcs "Hello"
|
dcs ["Hello"]
|
||||||
|
|
||||||
!DCS ST (8bit)
|
!DCS ST (8bit)
|
||||||
PUSH "\x{90}Hello\x9c"
|
PUSH "\x{90}Hello\x9c"
|
||||||
dcs "Hello"
|
dcs ["Hello"]
|
||||||
|
|
||||||
!Escape cancels DCS, starts Escape
|
!Escape cancels DCS, starts Escape
|
||||||
PUSH "\ePSomething\e9"
|
PUSH "\ePSomething\e9"
|
||||||
@@ -177,8 +186,9 @@ PUSH "\eP12\x{18}AB"
|
|||||||
|
|
||||||
!C0 in OSC interrupts and continues
|
!C0 in OSC interrupts and continues
|
||||||
PUSH "\ePBy\ne\x07"
|
PUSH "\ePBy\ne\x07"
|
||||||
|
dcs ["By"
|
||||||
control 10
|
control 10
|
||||||
dcs "Bye"
|
dcs "e"]
|
||||||
|
|
||||||
!NUL ignored
|
!NUL ignored
|
||||||
PUSH "\x{00}"
|
PUSH "\x{00}"
|
||||||
|
@@ -33,4 +33,10 @@ PUSH "\e[3 q"
|
|||||||
|
|
||||||
!Title
|
!Title
|
||||||
PUSH "\e]2;Here is my title\a"
|
PUSH "\e]2;Here is my title\a"
|
||||||
settermprop 4 "Here is my title"
|
settermprop 4 ["Here is my title"]
|
||||||
|
|
||||||
|
!Title split write
|
||||||
|
PUSH "\e]2;Here is"
|
||||||
|
settermprop 4 ["Here is"
|
||||||
|
PUSH " another title\a"
|
||||||
|
settermprop 4 " another title"]
|
||||||
|
@@ -12,8 +12,8 @@ PUSH "\e[?15;2z"
|
|||||||
|
|
||||||
!Unrecognised OSC
|
!Unrecognised OSC
|
||||||
PUSH "\e]27;Something\e\\"
|
PUSH "\e]27;Something\e\\"
|
||||||
osc "27;Something"
|
osc [27 "Something"]
|
||||||
|
|
||||||
!Unrecognised DCS
|
!Unrecognised DCS
|
||||||
PUSH "\ePz123\e\\"
|
PUSH "\ePz123\e\\"
|
||||||
dcs "z123"
|
dcs ["z123"]
|
||||||
|
@@ -14,4 +14,4 @@ PUSH "\e[?25l"
|
|||||||
|
|
||||||
!Title
|
!Title
|
||||||
PUSH "\e]2;Here is my title\a"
|
PUSH "\e]2;Here is my title\a"
|
||||||
settermprop 4 "Here is my title"
|
settermprop 4 ["Here is my title"]
|
||||||
|
@@ -153,21 +153,44 @@ static int parser_csi(const char *leader, const long args[], int argcount, const
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parser_osc(const char *command, size_t cmdlen, void *user UNUSED)
|
static int parser_osc(int command, VTermStringFragment frag, void *user UNUSED)
|
||||||
{
|
{
|
||||||
|
|
||||||
printf("osc ");
|
printf("osc ");
|
||||||
printhex(command, cmdlen);
|
|
||||||
|
if(frag.initial) {
|
||||||
|
if(command == -1)
|
||||||
|
printf("[");
|
||||||
|
else
|
||||||
|
printf("[%d;", command);
|
||||||
|
}
|
||||||
|
|
||||||
|
printhex(frag.str, frag.len);
|
||||||
|
|
||||||
|
if(frag.final)
|
||||||
|
printf("]");
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parser_dcs(const char *command, size_t cmdlen, void *user UNUSED)
|
static int parser_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user UNUSED)
|
||||||
{
|
{
|
||||||
|
|
||||||
printf("dcs ");
|
printf("dcs ");
|
||||||
printhex(command, cmdlen);
|
|
||||||
|
if(frag.initial) {
|
||||||
|
size_t i;
|
||||||
|
printf("[");
|
||||||
|
for(i = 0; i < commandlen; i++)
|
||||||
|
printf("%02x", command[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
printhex(frag.str, frag.len);
|
||||||
|
|
||||||
|
if(frag.final)
|
||||||
|
printf("]");
|
||||||
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -239,7 +262,8 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user UNUSED)
|
|||||||
printf("settermprop %d %d\n", prop, val->number);
|
printf("settermprop %d %d\n", prop, val->number);
|
||||||
return 1;
|
return 1;
|
||||||
case VTERM_VALUETYPE_STRING:
|
case VTERM_VALUETYPE_STRING:
|
||||||
printf("settermprop %d \"%s\"\n", prop, val->string);
|
printf("settermprop %d %s\"%.*s\"%s\n", prop,
|
||||||
|
val->string.initial ? "[" : "", val->string.len, val->string.str, val->string.final ? "]" : "");
|
||||||
return 1;
|
return 1;
|
||||||
case VTERM_VALUETYPE_COLOR:
|
case VTERM_VALUETYPE_COLOR:
|
||||||
printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue);
|
printf("settermprop %d rgb(%d,%d,%d)\n", prop, val->color.red, val->color.green, val->color.blue);
|
||||||
@@ -262,7 +286,7 @@ static int state_putglyph(VTermGlyphInfo *info, VTermPos pos, void *user UNUSED)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
printf("putglyph ");
|
printf("putglyph ");
|
||||||
for(i = 0; info->chars[i]; i++)
|
for(i = 0; i < VTERM_MAX_CHARS_PER_CELL && info->chars[i]; i++)
|
||||||
printf(i ? ",%x" : "%x", info->chars[i]);
|
printf(i ? ",%x" : "%x", info->chars[i]);
|
||||||
printf(" %d %d,%d", info->width, pos.row, pos.col);
|
printf(" %d %d,%d", info->width, pos.row, pos.col);
|
||||||
if(info->protected_cell)
|
if(info->protected_cell)
|
||||||
|
@@ -11,7 +11,8 @@ my $VALGRIND = 0;
|
|||||||
my $EXECUTABLE = "t/.libs/harness";
|
my $EXECUTABLE = "t/.libs/harness";
|
||||||
GetOptions(
|
GetOptions(
|
||||||
'valgrind|v+' => \$VALGRIND,
|
'valgrind|v+' => \$VALGRIND,
|
||||||
'executable|e=s' => \$EXECUTABLE
|
'executable|e=s' => \$EXECUTABLE,
|
||||||
|
'fail-early|F' => \(my $FAIL_EARLY),
|
||||||
) or exit 1;
|
) or exit 1;
|
||||||
|
|
||||||
my ( $hin, $hout, $hpid );
|
my ( $hin, $hout, $hpid );
|
||||||
@@ -65,6 +66,7 @@ sub do_onetest
|
|||||||
}
|
}
|
||||||
|
|
||||||
$exitcode = 1 if $fail_printed;
|
$exitcode = 1 if $fail_printed;
|
||||||
|
exit $exitcode if $exitcode and $FAIL_EARLY;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub do_line
|
sub do_line
|
||||||
@@ -105,8 +107,15 @@ sub do_line
|
|||||||
elsif( $line =~ m/^csi (\S+) (.*)$/ ) {
|
elsif( $line =~ m/^csi (\S+) (.*)$/ ) {
|
||||||
$line = sprintf "csi %02x %s", eval($1), $2; # TODO
|
$line = sprintf "csi %02x %s", eval($1), $2; # TODO
|
||||||
}
|
}
|
||||||
elsif( $line =~ m/^(escape|osc|dcs) (.*)$/ ) {
|
elsif( $line =~ m/^(osc) (\[\d+)? *(.*?)(\]?)$/ ) {
|
||||||
$line = "$1 " . join "", map sprintf("%02x", $_), unpack "C*", eval($2);
|
my ( $cmd, $initial, $data, $final ) = ( $1, $2, $3, $4 );
|
||||||
|
$initial //= "";
|
||||||
|
$initial .= ";" if $initial =~ m/\d+/;
|
||||||
|
|
||||||
|
$line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", eval($data) ) . "$final";
|
||||||
|
}
|
||||||
|
elsif( $line =~ m/^(escape|dcs) (\[?)(.*?)(\]?)$/ ) {
|
||||||
|
$line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", eval($3) ) . "$4";
|
||||||
}
|
}
|
||||||
elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) {
|
elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) {
|
||||||
$line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2";
|
$line = "putglyph " . join( ",", map sprintf("%x", $_), eval($1) ) . " $2";
|
||||||
@@ -139,6 +148,7 @@ sub do_line
|
|||||||
"# Expected: $want\n" .
|
"# Expected: $want\n" .
|
||||||
"# Actual: $response\n";
|
"# Actual: $response\n";
|
||||||
$exitcode = 1;
|
$exitcode = 1;
|
||||||
|
exit $exitcode if $exitcode and $FAIL_EARLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Assertions start with '?'
|
# Assertions start with '?'
|
||||||
@@ -162,6 +172,7 @@ sub do_line
|
|||||||
"# Expected: $expectation\n" .
|
"# Expected: $expectation\n" .
|
||||||
"# Actual: $response\n";
|
"# Actual: $response\n";
|
||||||
$exitcode = 1;
|
$exitcode = 1;
|
||||||
|
exit $exitcode if $exitcode and $FAIL_EARLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# Test controls start with '$'
|
# Test controls start with '$'
|
||||||
|
@@ -2998,22 +2998,27 @@ handle_settermprop(
|
|||||||
void *user)
|
void *user)
|
||||||
{
|
{
|
||||||
term_T *term = (term_T *)user;
|
term_T *term = (term_T *)user;
|
||||||
|
char_u *strval = NULL;
|
||||||
|
|
||||||
switch (prop)
|
switch (prop)
|
||||||
{
|
{
|
||||||
case VTERM_PROP_TITLE:
|
case VTERM_PROP_TITLE:
|
||||||
|
strval = vim_strnsave((char_u *)value->string.str,
|
||||||
|
(int)value->string.len);
|
||||||
|
if (strval == NULL)
|
||||||
|
break;
|
||||||
vim_free(term->tl_title);
|
vim_free(term->tl_title);
|
||||||
// a blank title isn't useful, make it empty, so that "running" is
|
// a blank title isn't useful, make it empty, so that "running" is
|
||||||
// displayed
|
// displayed
|
||||||
if (*skipwhite((char_u *)value->string) == NUL)
|
if (*skipwhite(strval) == NUL)
|
||||||
term->tl_title = NULL;
|
term->tl_title = NULL;
|
||||||
// Same as blank
|
// Same as blank
|
||||||
else if (term->tl_arg0_cmd != NULL
|
else if (term->tl_arg0_cmd != NULL
|
||||||
&& STRNCMP(term->tl_arg0_cmd, (char_u *)value->string,
|
&& STRNCMP(term->tl_arg0_cmd, strval,
|
||||||
(int)STRLEN(term->tl_arg0_cmd)) == 0)
|
(int)STRLEN(term->tl_arg0_cmd)) == 0)
|
||||||
term->tl_title = NULL;
|
term->tl_title = NULL;
|
||||||
// Empty corrupted data of winpty
|
// Empty corrupted data of winpty
|
||||||
else if (STRNCMP(" - ", (char_u *)value->string, 4) == 0)
|
else if (STRNCMP(" - ", strval, 4) == 0)
|
||||||
term->tl_title = NULL;
|
term->tl_title = NULL;
|
||||||
#ifdef MSWIN
|
#ifdef MSWIN
|
||||||
else if (!enc_utf8 && enc_codepage > 0)
|
else if (!enc_utf8 && enc_codepage > 0)
|
||||||
@@ -3022,8 +3027,8 @@ handle_settermprop(
|
|||||||
int length = 0;
|
int length = 0;
|
||||||
|
|
||||||
MultiByteToWideChar_alloc(CP_UTF8, 0,
|
MultiByteToWideChar_alloc(CP_UTF8, 0,
|
||||||
(char*)value->string, (int)STRLEN(value->string),
|
(char*)value->string.str,
|
||||||
&ret, &length);
|
(int)value->string.len, &ret, &length);
|
||||||
if (ret != NULL)
|
if (ret != NULL)
|
||||||
{
|
{
|
||||||
WideCharToMultiByte_alloc(enc_codepage, 0,
|
WideCharToMultiByte_alloc(enc_codepage, 0,
|
||||||
@@ -3034,7 +3039,10 @@ handle_settermprop(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
term->tl_title = vim_strsave((char_u *)value->string);
|
{
|
||||||
|
term->tl_title = vim_strsave(strval);
|
||||||
|
strval = NULL;
|
||||||
|
}
|
||||||
VIM_CLEAR(term->tl_status_text);
|
VIM_CLEAR(term->tl_status_text);
|
||||||
if (term == curbuf->b_term)
|
if (term == curbuf->b_term)
|
||||||
maketitle();
|
maketitle();
|
||||||
@@ -3057,7 +3065,11 @@ handle_settermprop(
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VTERM_PROP_CURSORCOLOR:
|
case VTERM_PROP_CURSORCOLOR:
|
||||||
cursor_color_copy(&term->tl_cursor_color, (char_u*)value->string);
|
strval = vim_strnsave((char_u *)value->string.str,
|
||||||
|
(int)value->string.len);
|
||||||
|
if (strval == NULL)
|
||||||
|
break;
|
||||||
|
cursor_color_copy(&term->tl_cursor_color, strval);
|
||||||
may_set_cursor_props(term);
|
may_set_cursor_props(term);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3069,6 +3081,8 @@ handle_settermprop(
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
vim_free(strval);
|
||||||
|
|
||||||
// Always return 1, otherwise vterm doesn't store the value internally.
|
// Always return 1, otherwise vterm doesn't store the value internally.
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -4181,7 +4195,7 @@ handle_call_command(term_T *term, channel_T *channel, listitem_T *item)
|
|||||||
* We recognize a terminal API command.
|
* We recognize a terminal API command.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
parse_osc(const char *command, size_t cmdlen, void *user)
|
parse_osc(int command, VTermStringFragment frag, void *user)
|
||||||
{
|
{
|
||||||
term_T *term = (term_T *)user;
|
term_T *term = (term_T *)user;
|
||||||
js_read_T reader;
|
js_read_T reader;
|
||||||
@@ -4190,10 +4204,10 @@ parse_osc(const char *command, size_t cmdlen, void *user)
|
|||||||
: term->tl_job->jv_channel;
|
: term->tl_job->jv_channel;
|
||||||
|
|
||||||
// We recognize only OSC 5 1 ; {command}
|
// We recognize only OSC 5 1 ; {command}
|
||||||
if (cmdlen < 3 || STRNCMP(command, "51;", 3) != 0)
|
if (command != 51)
|
||||||
return 0; // not handled
|
return 0;
|
||||||
|
|
||||||
reader.js_buf = vim_strnsave((char_u *)command + 3, (int)(cmdlen - 3));
|
reader.js_buf = vim_strnsave((char_u *)frag.str, (int)(frag.len));
|
||||||
if (reader.js_buf == NULL)
|
if (reader.js_buf == NULL)
|
||||||
return 1;
|
return 1;
|
||||||
reader.js_fill = NULL;
|
reader.js_fill = NULL;
|
||||||
|
@@ -746,6 +746,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
798,
|
||||||
/**/
|
/**/
|
||||||
797,
|
797,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user