forked from aniani/vim
patch 8.0.1639: libvterm code lags behind master
Problem: Libvterm code lags behind master. Solution: Sync to head, solve merge problems.
This commit is contained in:
@@ -10,3 +10,21 @@ Modifications:
|
|||||||
- Add a .gitignore file.
|
- Add a .gitignore file.
|
||||||
- Convert from C99 to C90.
|
- Convert from C99 to C90.
|
||||||
- Other changes to support embedding in Vim.
|
- Other changes to support embedding in Vim.
|
||||||
|
|
||||||
|
|
||||||
|
To merge in changes from Github, do this:
|
||||||
|
- Commit any pending changes.
|
||||||
|
- Setup the merge tool:
|
||||||
|
git config merge.tool vimdiff
|
||||||
|
git config merge.conflictstyle diff3
|
||||||
|
git config mergetool.prompt false
|
||||||
|
- Run the merge tool:
|
||||||
|
git mergetool
|
||||||
|
This will open a four-way diff between:
|
||||||
|
LOCAL - your current version
|
||||||
|
BASE - version as it was at your last sync
|
||||||
|
REMOTE - version at head on Github
|
||||||
|
MERGED - best-effort merge of LOCAL and REMOTE
|
||||||
|
Now find places where automatic merge didn't work, they are marked with
|
||||||
|
<<<<<<<<, ======= and >>>>>>>
|
||||||
|
Fix those places in MERGED, remove the markers, and save the file :wqall.
|
||||||
|
@@ -95,8 +95,8 @@ static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevce
|
|||||||
sgr[sgri++] = 90 + (index - 8);
|
sgr[sgri++] = 90 + (index - 8);
|
||||||
else {
|
else {
|
||||||
sgr[sgri++] = 38;
|
sgr[sgri++] = 38;
|
||||||
sgr[sgri++] = 5 | (1<<31);
|
sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
|
||||||
sgr[sgri++] = index | (1<<31);
|
sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,8 +112,8 @@ static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevce
|
|||||||
sgr[sgri++] = 100 + (index - 8);
|
sgr[sgri++] = 100 + (index - 8);
|
||||||
else {
|
else {
|
||||||
sgr[sgri++] = 48;
|
sgr[sgri++] = 48;
|
||||||
sgr[sgri++] = 5 | (1<<31);
|
sgr[sgri++] = 5 | CSI_ARG_FLAG_MORE;
|
||||||
sgr[sgri++] = index | (1<<31);
|
sgr[sgri++] = index | CSI_ARG_FLAG_MORE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,9 +125,9 @@ static void dump_cell(const VTermScreenCell *cell, const VTermScreenCell *prevce
|
|||||||
int i;
|
int i;
|
||||||
for(i = 0; i < sgri; i++)
|
for(i = 0; i < sgri; i++)
|
||||||
printf(!i ? "%d" :
|
printf(!i ? "%d" :
|
||||||
sgr[i] & (1<<31) ? ":%d" :
|
CSI_ARG_HAS_MORE(sgr[i]) ? ":%d" :
|
||||||
";%d",
|
";%d",
|
||||||
sgr[i] & ~(1<<31));
|
CSI_ARG(sgr[i]));
|
||||||
}
|
}
|
||||||
printf("m");
|
printf("m");
|
||||||
}
|
}
|
||||||
@@ -283,5 +283,6 @@ int main(int argc, char *argv[])
|
|||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
vterm_free(vt);
|
vterm_free(vt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -53,6 +53,7 @@ static char *helptext[] = {
|
|||||||
"curblink [off|on|query]",
|
"curblink [off|on|query]",
|
||||||
"curshape [block|under|bar|query]",
|
"curshape [block|under|bar|query]",
|
||||||
"mouse [off|click|clickdrag|motion]",
|
"mouse [off|click|clickdrag|motion]",
|
||||||
|
"reportfocus [off|on|query]",
|
||||||
"altscreen [off|on|query]",
|
"altscreen [off|on|query]",
|
||||||
"bracketpaste [off|on|query]",
|
"bracketpaste [off|on|query]",
|
||||||
"icontitle [STR]",
|
"icontitle [STR]",
|
||||||
@@ -81,9 +82,9 @@ static int seticanon(int icanon, int echo)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void await_c1(int c1)
|
static void await_c1(unsigned char c1)
|
||||||
{
|
{
|
||||||
int c;
|
unsigned char c;
|
||||||
|
|
||||||
/* await CSI - 8bit or 2byte 7bit form */
|
/* await CSI - 8bit or 2byte 7bit form */
|
||||||
int in_esc = FALSE;
|
int in_esc = FALSE;
|
||||||
@@ -340,6 +341,9 @@ int main(int argc, char *argv[])
|
|||||||
printf("\x1b[?1003h"); break;
|
printf("\x1b[?1003h"); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(streq(arg, "reportfocus")) {
|
||||||
|
do_dec_mode(1004, getboolq(&argi, argc, argv), "reportfocus");
|
||||||
|
}
|
||||||
else if(streq(arg, "altscreen")) {
|
else if(streq(arg, "altscreen")) {
|
||||||
do_dec_mode(1049, getboolq(&argi, argc, argv), "altscreen");
|
do_dec_mode(1049, getboolq(&argi, argc, argv), "altscreen");
|
||||||
}
|
}
|
||||||
|
@@ -227,5 +227,6 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
vterm_free(vt);
|
vterm_free(vt);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -9,3 +9,6 @@ Digital VT100 User Guide:
|
|||||||
|
|
||||||
Digital VT220 Programmer Reference Manual
|
Digital VT220 Programmer Reference Manual
|
||||||
http://vt100.net/docs/vt220-rm/
|
http://vt100.net/docs/vt220-rm/
|
||||||
|
|
||||||
|
Summary of ANSI standards for ASCII terminals
|
||||||
|
http://www.inwap.com/pdp10/ansicode.txt
|
||||||
|
@@ -151,6 +151,7 @@ between states.
|
|||||||
DECSM 1000 = Mouse click/release tracking
|
DECSM 1000 = Mouse click/release tracking
|
||||||
DECSM 1002 = Mouse click/release/drag tracking
|
DECSM 1002 = Mouse click/release/drag tracking
|
||||||
DECSM 1003 = Mouse all movements tracking
|
DECSM 1003 = Mouse all movements tracking
|
||||||
|
DECSM 1004 = Focus in/out reporting
|
||||||
DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended
|
DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended
|
||||||
DECSM 1006 = Mouse protocol SGR
|
DECSM 1006 = Mouse protocol SGR
|
||||||
DECSM 1015 = Mouse protocol rxvt
|
DECSM 1015 = Mouse protocol rxvt
|
||||||
|
@@ -96,7 +96,9 @@ typedef enum {
|
|||||||
VTERM_VALUETYPE_BOOL = 1,
|
VTERM_VALUETYPE_BOOL = 1,
|
||||||
VTERM_VALUETYPE_INT,
|
VTERM_VALUETYPE_INT,
|
||||||
VTERM_VALUETYPE_STRING,
|
VTERM_VALUETYPE_STRING,
|
||||||
VTERM_VALUETYPE_COLOR
|
VTERM_VALUETYPE_COLOR,
|
||||||
|
|
||||||
|
VTERM_N_VALUETYPES
|
||||||
} VTermValueType;
|
} VTermValueType;
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
@@ -116,7 +118,9 @@ typedef enum {
|
|||||||
VTERM_ATTR_STRIKE, /* bool: 9, 29 */
|
VTERM_ATTR_STRIKE, /* bool: 9, 29 */
|
||||||
VTERM_ATTR_FONT, /* number: 10-19 */
|
VTERM_ATTR_FONT, /* number: 10-19 */
|
||||||
VTERM_ATTR_FOREGROUND, /* color: 30-39 90-97 */
|
VTERM_ATTR_FOREGROUND, /* color: 30-39 90-97 */
|
||||||
VTERM_ATTR_BACKGROUND /* color: 40-49 100-107 */
|
VTERM_ATTR_BACKGROUND, /* color: 40-49 100-107 */
|
||||||
|
|
||||||
|
VTERM_N_ATTRS
|
||||||
} VTermAttr;
|
} VTermAttr;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -129,20 +133,26 @@ typedef enum {
|
|||||||
VTERM_PROP_REVERSE, /* bool */
|
VTERM_PROP_REVERSE, /* bool */
|
||||||
VTERM_PROP_CURSORSHAPE, /* number */
|
VTERM_PROP_CURSORSHAPE, /* number */
|
||||||
VTERM_PROP_MOUSE, /* number */
|
VTERM_PROP_MOUSE, /* number */
|
||||||
VTERM_PROP_CURSORCOLOR /* string */
|
VTERM_PROP_CURSORCOLOR, /* string */
|
||||||
|
|
||||||
|
VTERM_N_PROPS
|
||||||
} VTermProp;
|
} VTermProp;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
VTERM_PROP_CURSORSHAPE_BLOCK = 1,
|
VTERM_PROP_CURSORSHAPE_BLOCK = 1,
|
||||||
VTERM_PROP_CURSORSHAPE_UNDERLINE,
|
VTERM_PROP_CURSORSHAPE_UNDERLINE,
|
||||||
VTERM_PROP_CURSORSHAPE_BAR_LEFT
|
VTERM_PROP_CURSORSHAPE_BAR_LEFT,
|
||||||
|
|
||||||
|
VTERM_N_PROP_CURSORSHAPES
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
VTERM_PROP_MOUSE_NONE = 0,
|
VTERM_PROP_MOUSE_NONE = 0,
|
||||||
VTERM_PROP_MOUSE_CLICK,
|
VTERM_PROP_MOUSE_CLICK,
|
||||||
VTERM_PROP_MOUSE_DRAG,
|
VTERM_PROP_MOUSE_DRAG,
|
||||||
VTERM_PROP_MOUSE_MOVE
|
VTERM_PROP_MOUSE_MOVE,
|
||||||
|
|
||||||
|
VTERM_N_PROP_MOUSES
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -213,8 +223,8 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod);
|
|||||||
*
|
*
|
||||||
* Don't confuse this with the final byte of the CSI escape; 'a' in this case.
|
* Don't confuse this with the final byte of the CSI escape; 'a' in this case.
|
||||||
*/
|
*/
|
||||||
#define CSI_ARG_FLAG_MORE (1<<30)
|
#define CSI_ARG_FLAG_MORE (1U<<31)
|
||||||
#define CSI_ARG_MASK (~(1<<30))
|
#define CSI_ARG_MASK (~(1U<<31))
|
||||||
|
|
||||||
#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)
|
#define CSI_ARG_HAS_MORE(a) ((a) & CSI_ARG_FLAG_MORE)
|
||||||
#define CSI_ARG(a) ((a) & CSI_ARG_MASK)
|
#define CSI_ARG(a) ((a) & CSI_ARG_MASK)
|
||||||
@@ -293,6 +303,8 @@ void vterm_state_set_palette_color(VTermState *state, int index, const VTermColo
|
|||||||
void vterm_state_set_bold_highbright(VTermState *state, int bold_is_highbright);
|
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_get_penattr(const VTermState *state, VTermAttr attr, VTermValue *val);
|
||||||
int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val);
|
int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val);
|
||||||
|
void vterm_state_focus_in(VTermState *state);
|
||||||
|
void vterm_state_focus_out(VTermState *state);
|
||||||
const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);
|
const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);
|
||||||
|
|
||||||
/* ------------
|
/* ------------
|
||||||
@@ -357,7 +369,9 @@ typedef enum {
|
|||||||
VTERM_DAMAGE_CELL, /* every cell */
|
VTERM_DAMAGE_CELL, /* every cell */
|
||||||
VTERM_DAMAGE_ROW, /* entire rows */
|
VTERM_DAMAGE_ROW, /* entire rows */
|
||||||
VTERM_DAMAGE_SCREEN, /* entire screen */
|
VTERM_DAMAGE_SCREEN, /* entire screen */
|
||||||
VTERM_DAMAGE_SCROLL /* entire screen + scrollrect */
|
VTERM_DAMAGE_SCROLL, /* entire screen + scrollrect */
|
||||||
|
|
||||||
|
VTERM_N_DAMAGES
|
||||||
} VTermDamageSize;
|
} VTermDamageSize;
|
||||||
|
|
||||||
/* Invoke the relevant callbacks to update the screen. */
|
/* Invoke the relevant callbacks to update the screen. */
|
||||||
@@ -384,7 +398,9 @@ typedef enum {
|
|||||||
VTERM_ATTR_STRIKE_MASK = 1 << 5,
|
VTERM_ATTR_STRIKE_MASK = 1 << 5,
|
||||||
VTERM_ATTR_FONT_MASK = 1 << 6,
|
VTERM_ATTR_FONT_MASK = 1 << 6,
|
||||||
VTERM_ATTR_FOREGROUND_MASK = 1 << 7,
|
VTERM_ATTR_FOREGROUND_MASK = 1 << 7,
|
||||||
VTERM_ATTR_BACKGROUND_MASK = 1 << 8
|
VTERM_ATTR_BACKGROUND_MASK = 1 << 8,
|
||||||
|
|
||||||
|
VTERM_ALL_ATTRS_MASK = (1 << 9) - 1
|
||||||
} VTermAttrMask;
|
} VTermAttrMask;
|
||||||
|
|
||||||
int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);
|
int vterm_screen_get_attrs_extent(const VTermScreen *screen, VTermRect *extent, VTermPos pos, VTermAttrMask attrs);
|
||||||
|
@@ -5,7 +5,9 @@ typedef enum {
|
|||||||
VTERM_MOD_NONE = 0x00,
|
VTERM_MOD_NONE = 0x00,
|
||||||
VTERM_MOD_SHIFT = 0x01,
|
VTERM_MOD_SHIFT = 0x01,
|
||||||
VTERM_MOD_ALT = 0x02,
|
VTERM_MOD_ALT = 0x02,
|
||||||
VTERM_MOD_CTRL = 0x04
|
VTERM_MOD_CTRL = 0x04,
|
||||||
|
|
||||||
|
VTERM_ALL_MODS_MASK = 0x07
|
||||||
} VTermModifier;
|
} VTermModifier;
|
||||||
|
|
||||||
/* The order here must match keycodes[] in src/keyboard.c! */
|
/* The order here must match keycodes[] in src/keyboard.c! */
|
||||||
@@ -53,7 +55,8 @@ typedef enum {
|
|||||||
VTERM_KEY_KP_ENTER,
|
VTERM_KEY_KP_ENTER,
|
||||||
VTERM_KEY_KP_EQUAL,
|
VTERM_KEY_KP_EQUAL,
|
||||||
|
|
||||||
VTERM_KEY_MAX /* Must be last */
|
VTERM_KEY_MAX, /* Must be last */
|
||||||
|
VTERM_N_KEYS = VTERM_KEY_MAX
|
||||||
} VTermKey;
|
} VTermKey;
|
||||||
|
|
||||||
#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n))
|
#define VTERM_KEY_FUNCTION(n) (VTERM_KEY_FUNCTION_0+(n))
|
||||||
|
@@ -63,9 +63,9 @@ void vterm_mouse_move(VTerm *vt, int row, int col, VTermModifier mod)
|
|||||||
|
|
||||||
if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||
|
if((state->mouse_flags & MOUSE_WANT_DRAG && state->mouse_buttons) ||
|
||||||
(state->mouse_flags & MOUSE_WANT_MOVE)) {
|
(state->mouse_flags & MOUSE_WANT_MOVE)) {
|
||||||
int button = state->mouse_buttons & 0x01 ? 1 :
|
int button = state->mouse_buttons & MOUSE_BUTTON_LEFT ? 1 :
|
||||||
state->mouse_buttons & 0x02 ? 2 :
|
state->mouse_buttons & MOUSE_BUTTON_MIDDLE ? 2 :
|
||||||
state->mouse_buttons & 0x04 ? 3 : 4;
|
state->mouse_buttons & MOUSE_BUTTON_RIGHT ? 3 : 4;
|
||||||
output_mouse(state, button-1 + 0x20, 1, mod, col, row);
|
output_mouse(state, button-1 + 0x20, 1, mod, col, row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -3,188 +3,123 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#define CSI_ARGS_MAX 16
|
#undef DEBUG_PARSER
|
||||||
#define CSI_LEADER_MAX 16
|
|
||||||
#define CSI_INTERMED_MAX 16
|
static int is_intermed(unsigned char c)
|
||||||
|
{
|
||||||
|
return c >= 0x20 && c <= 0x2f;
|
||||||
|
}
|
||||||
|
|
||||||
static void do_control(VTerm *vt, unsigned char control)
|
static void do_control(VTerm *vt, unsigned char control)
|
||||||
{
|
{
|
||||||
if(vt->parser_callbacks && vt->parser_callbacks->control)
|
if(vt->parser.callbacks && vt->parser.callbacks->control)
|
||||||
if((*vt->parser_callbacks->control)(control, vt->cbdata))
|
if((*vt->parser.callbacks->control)(control, vt->parser.cbdata))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DEBUG_LOG1("libvterm: Unhandled control 0x%02x\n", control);
|
DEBUG_LOG1("libvterm: Unhandled control 0x%02x\n", control);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_string_csi(VTerm *vt, const char *args, size_t arglen, char command)
|
static void do_csi(VTerm *vt, char command)
|
||||||
{
|
{
|
||||||
int i = 0;
|
#ifdef DEBUG_PARSER
|
||||||
|
printf("Parsed CSI args as:\n", arglen, args);
|
||||||
int leaderlen = 0;
|
printf(" leader: %s\n", vt->parser.csi_leader);
|
||||||
char leader[CSI_LEADER_MAX];
|
for(int argi = 0; argi < vt->parser.csi_argi; argi++) {
|
||||||
int argcount = 1; /* Always at least 1 arg */
|
printf(" %lu", CSI_ARG(vt->parser.csi_args[argi]));
|
||||||
long csi_args[CSI_ARGS_MAX];
|
if(!CSI_ARG_HAS_MORE(vt->parser.csi_args[argi]))
|
||||||
int argi;
|
|
||||||
int intermedlen = 0;
|
|
||||||
char intermed[CSI_INTERMED_MAX];
|
|
||||||
|
|
||||||
/* Extract leader bytes 0x3c to 0x3f */
|
|
||||||
for( ; i < (int)arglen; i++) {
|
|
||||||
if(args[i] < 0x3c || args[i] > 0x3f)
|
|
||||||
break;
|
|
||||||
if(leaderlen < CSI_LEADER_MAX-1)
|
|
||||||
leader[leaderlen++] = args[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
leader[leaderlen] = 0;
|
|
||||||
|
|
||||||
for( ; i < (int)arglen; i++)
|
|
||||||
if(args[i] == 0x3b || args[i] == 0x3a) /* ; or : */
|
|
||||||
argcount++;
|
|
||||||
|
|
||||||
/* TODO: Consider if these buffers should live in the VTerm struct itself */
|
|
||||||
if(argcount > CSI_ARGS_MAX)
|
|
||||||
argcount = CSI_ARGS_MAX;
|
|
||||||
|
|
||||||
for(argi = 0; argi < argcount; argi++)
|
|
||||||
csi_args[argi] = CSI_ARG_MISSING;
|
|
||||||
|
|
||||||
argi = 0;
|
|
||||||
for(i = leaderlen; i < (int)arglen && argi < argcount; i++) {
|
|
||||||
switch(args[i]) {
|
|
||||||
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
|
|
||||||
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
|
|
||||||
if(csi_args[argi] == CSI_ARG_MISSING)
|
|
||||||
csi_args[argi] = 0;
|
|
||||||
csi_args[argi] *= 10;
|
|
||||||
csi_args[argi] += args[i] - '0';
|
|
||||||
break;
|
|
||||||
case 0x3a:
|
|
||||||
csi_args[argi] |= CSI_ARG_FLAG_MORE;
|
|
||||||
/* FALLTHROUGH */
|
|
||||||
case 0x3b:
|
|
||||||
argi++;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto done_leader;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
done_leader: ;
|
|
||||||
|
|
||||||
for( ; i < (int)arglen; i++) {
|
|
||||||
if((args[i] & 0xf0) != 0x20)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if(intermedlen < CSI_INTERMED_MAX-1)
|
|
||||||
intermed[intermedlen++] = args[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
intermed[intermedlen] = 0;
|
|
||||||
|
|
||||||
if(i < (int)arglen) {
|
|
||||||
DEBUG_LOG2("libvterm: TODO unhandled CSI bytes \"%.*s\"\n", (int)(arglen - i), args + i);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
printf("Parsed CSI args %.*s as:\n", arglen, args);
|
|
||||||
printf(" leader: %s\n", leader);
|
|
||||||
for(argi = 0; argi < argcount; argi++) {
|
|
||||||
printf(" %lu", CSI_ARG(csi_args[argi]));
|
|
||||||
if(!CSI_ARG_HAS_MORE(csi_args[argi]))
|
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf(" intermed: %s\n", intermed);
|
printf(" intermed: %s\n", vt->parser.intermed);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(vt->parser_callbacks && vt->parser_callbacks->csi)
|
if(vt->parser.callbacks && vt->parser.callbacks->csi)
|
||||||
if((*vt->parser_callbacks->csi)(leaderlen ? leader : NULL, csi_args, argcount, intermedlen ? intermed : NULL, command, vt->cbdata))
|
if((*vt->parser.callbacks->csi)(
|
||||||
|
vt->parser.csi_leaderlen ? vt->parser.csi_leader : NULL,
|
||||||
|
vt->parser.csi_args,
|
||||||
|
vt->parser.csi_argi,
|
||||||
|
vt->parser.intermedlen ? vt->parser.intermed : NULL,
|
||||||
|
command,
|
||||||
|
vt->parser.cbdata))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DEBUG_LOG3("libvterm: Unhandled CSI %.*s %c\n", (int)arglen, args, command);
|
DEBUG_LOG1("libvterm: Unhandled CSI %c\n", command);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_escape(VTerm *vt, char command)
|
||||||
|
{
|
||||||
|
char seq[INTERMED_MAX+1];
|
||||||
|
|
||||||
|
size_t len = vt->parser.intermedlen;
|
||||||
|
strncpy(seq, vt->parser.intermed, len);
|
||||||
|
seq[len++] = command;
|
||||||
|
seq[len] = 0;
|
||||||
|
|
||||||
|
if(vt->parser.callbacks && vt->parser.callbacks->escape)
|
||||||
|
if((*vt->parser.callbacks->escape)(seq, len, vt->parser.cbdata))
|
||||||
|
return;
|
||||||
|
|
||||||
|
DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void append_strbuffer(VTerm *vt, const char *str, size_t len)
|
static void append_strbuffer(VTerm *vt, const char *str, size_t len)
|
||||||
{
|
{
|
||||||
if(len > vt->strbuffer_len - vt->strbuffer_cur) {
|
if(len > vt->parser.strbuffer_len - vt->parser.strbuffer_cur) {
|
||||||
len = vt->strbuffer_len - vt->strbuffer_cur;
|
len = vt->parser.strbuffer_len - vt->parser.strbuffer_cur;
|
||||||
DEBUG_LOG1("Truncating strbuffer preserve to %zd bytes\n", len);
|
DEBUG_LOG1("Truncating strbuffer preserve to %zd bytes\n", len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(len > 0) {
|
if(len > 0) {
|
||||||
strncpy(vt->strbuffer + vt->strbuffer_cur, str, len);
|
strncpy(vt->parser.strbuffer + vt->parser.strbuffer_cur, str, len);
|
||||||
vt->strbuffer_cur += len;
|
vt->parser.strbuffer_cur += len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t do_string(VTerm *vt, const char *str_frag, size_t len)
|
static void start_string(VTerm *vt, VTermParserStringType type)
|
||||||
{
|
{
|
||||||
size_t eaten;
|
vt->parser.stringtype = type;
|
||||||
|
|
||||||
if(vt->strbuffer_cur) {
|
vt->parser.strbuffer_cur = 0;
|
||||||
if(str_frag)
|
|
||||||
append_strbuffer(vt, str_frag, len);
|
|
||||||
|
|
||||||
str_frag = vt->strbuffer;
|
|
||||||
len = vt->strbuffer_cur;
|
|
||||||
}
|
}
|
||||||
else if(!str_frag) {
|
|
||||||
|
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");
|
DEBUG_LOG("parser.c: TODO: No strbuffer _and_ no final fragment???\n");
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
vt->strbuffer_cur = 0;
|
switch(vt->parser.stringtype) {
|
||||||
|
case VTERM_PARSER_OSC:
|
||||||
|
if(vt->parser.callbacks && vt->parser.callbacks->osc)
|
||||||
|
if((*vt->parser.callbacks->osc)(str, len, vt->parser.cbdata))
|
||||||
|
return;
|
||||||
|
|
||||||
switch(vt->parser_state) {
|
DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str);
|
||||||
case NORMAL:
|
return;
|
||||||
if(vt->parser_callbacks && vt->parser_callbacks->text)
|
|
||||||
if((eaten = (*vt->parser_callbacks->text)(str_frag, len, vt->cbdata)))
|
|
||||||
return eaten;
|
|
||||||
|
|
||||||
DEBUG_LOG1("libvterm: Unhandled text (%zu chars)\n", len);
|
case VTERM_PARSER_DCS:
|
||||||
return 0;
|
if(vt->parser.callbacks && vt->parser.callbacks->dcs)
|
||||||
|
if((*vt->parser.callbacks->dcs)(str, len, vt->parser.cbdata))
|
||||||
|
return;
|
||||||
|
|
||||||
case ESC:
|
DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str);
|
||||||
if(len == 1 && str_frag[0] >= 0x40 && str_frag[0] < 0x60) {
|
return;
|
||||||
/* C1 emulations using 7bit clean */
|
|
||||||
/* ESC 0x40 == 0x80 */
|
case VTERM_N_PARSER_TYPES:
|
||||||
do_control(vt, str_frag[0] + 0x40);
|
return;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(vt->parser_callbacks && vt->parser_callbacks->escape)
|
|
||||||
if((*vt->parser_callbacks->escape)(str_frag, len, vt->cbdata))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
DEBUG_LOG1("libvterm: Unhandled escape ESC 0x%02x\n", str_frag[len-1]);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case CSI:
|
|
||||||
do_string_csi(vt, str_frag, len - 1, str_frag[len - 1]);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case OSC:
|
|
||||||
if(vt->parser_callbacks && vt->parser_callbacks->osc)
|
|
||||||
if((*vt->parser_callbacks->osc)(str_frag, len, vt->cbdata))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
DEBUG_LOG2("libvterm: Unhandled OSC %.*s\n", (int)len, str_frag);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case DCS:
|
|
||||||
if(vt->parser_callbacks && vt->parser_callbacks->dcs)
|
|
||||||
if((*vt->parser_callbacks->dcs)(str_frag, len, vt->cbdata))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
DEBUG_LOG2("libvterm: Unhandled DCS %.*s\n", (int)len, str_frag);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case ESC_IN_OSC:
|
|
||||||
case ESC_IN_DCS:
|
|
||||||
DEBUG_LOG("libvterm: ARGH! Should never do_string() in ESC_IN_{OSC,DCS}\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
@@ -192,29 +127,30 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
const char *string_start = NULL; /* init to avoid gcc warning */
|
const char *string_start = NULL; /* init to avoid gcc warning */
|
||||||
|
|
||||||
switch(vt->parser_state) {
|
switch(vt->parser.state) {
|
||||||
case NORMAL:
|
case NORMAL:
|
||||||
|
case CSI_LEADER:
|
||||||
|
case CSI_ARGS:
|
||||||
|
case CSI_INTERMED:
|
||||||
|
case ESC:
|
||||||
string_start = NULL;
|
string_start = NULL;
|
||||||
break;
|
break;
|
||||||
case ESC:
|
case STRING:
|
||||||
case ESC_IN_OSC:
|
case ESC_IN_STRING:
|
||||||
case ESC_IN_DCS:
|
|
||||||
case CSI:
|
|
||||||
case OSC:
|
|
||||||
case DCS:
|
|
||||||
string_start = bytes;
|
string_start = bytes;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ENTER_STRING_STATE(st) do { vt->parser_state = st; string_start = bytes + pos + 1; } while(0)
|
#define ENTER_STRING_STATE(st) do { vt->parser.state = STRING; string_start = bytes + pos + 1; } while(0)
|
||||||
#define ENTER_NORMAL_STATE() do { vt->parser_state = NORMAL; 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)
|
||||||
|
|
||||||
for( ; pos < len; pos++) {
|
for( ; pos < len; pos++) {
|
||||||
unsigned char c = bytes[pos];
|
unsigned char c = bytes[pos];
|
||||||
|
|
||||||
if(c == 0x00 || c == 0x7f) { /* NUL, DEL */
|
if(c == 0x00 || c == 0x7f) { /* NUL, DEL */
|
||||||
if(vt->parser_state != NORMAL) {
|
if(vt->parser.state >= STRING) {
|
||||||
append_strbuffer(vt, string_start, bytes + pos - string_start);
|
more_string(vt, string_start, bytes + pos - string_start);
|
||||||
string_start = bytes + pos + 1;
|
string_start = bytes + pos + 1;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
@@ -224,64 +160,64 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if(c == 0x1b) { /* ESC */
|
else if(c == 0x1b) { /* ESC */
|
||||||
if(vt->parser_state == OSC)
|
vt->parser.intermedlen = 0;
|
||||||
vt->parser_state = ESC_IN_OSC;
|
if(vt->parser.state == STRING)
|
||||||
else if(vt->parser_state == DCS)
|
vt->parser.state = ESC_IN_STRING;
|
||||||
vt->parser_state = ESC_IN_DCS;
|
|
||||||
else
|
else
|
||||||
ENTER_STRING_STATE(ESC);
|
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 == OSC || vt->parser_state == DCS)) {
|
vt->parser.state == STRING) {
|
||||||
/* fallthrough */
|
/* fallthrough */
|
||||||
}
|
}
|
||||||
else if(c < 0x20) { /* other C0 */
|
else if(c < 0x20) { /* other C0 */
|
||||||
if(vt->parser_state != NORMAL)
|
if(vt->parser.state >= STRING)
|
||||||
append_strbuffer(vt, string_start, bytes + pos - string_start);
|
more_string(vt, string_start, bytes + pos - string_start);
|
||||||
do_control(vt, c);
|
do_control(vt, c);
|
||||||
if(vt->parser_state != NORMAL)
|
if(vt->parser.state >= STRING)
|
||||||
string_start = bytes + pos + 1;
|
string_start = bytes + pos + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* else fallthrough */
|
/* else fallthrough */
|
||||||
|
|
||||||
switch(vt->parser_state) {
|
switch(vt->parser.state) {
|
||||||
case ESC_IN_OSC:
|
case ESC_IN_STRING:
|
||||||
case ESC_IN_DCS:
|
|
||||||
if(c == 0x5c) { /* ST */
|
if(c == 0x5c) { /* ST */
|
||||||
switch(vt->parser_state) {
|
vt->parser.state = STRING;
|
||||||
case ESC_IN_OSC: vt->parser_state = OSC; break;
|
done_string(vt, string_start, bytes + pos - string_start - 1);
|
||||||
case ESC_IN_DCS: vt->parser_state = DCS; break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
do_string(vt, string_start, bytes + pos - string_start - 1);
|
|
||||||
ENTER_NORMAL_STATE();
|
ENTER_NORMAL_STATE();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vt->parser_state = ESC;
|
vt->parser.state = ESC;
|
||||||
string_start = bytes + pos;
|
|
||||||
/* else fallthrough */
|
/* else fallthrough */
|
||||||
|
|
||||||
case ESC:
|
case ESC:
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 0x50: /* DCS */
|
case 0x50: /* DCS */
|
||||||
ENTER_STRING_STATE(DCS);
|
start_string(vt, VTERM_PARSER_DCS);
|
||||||
|
ENTER_STRING_STATE();
|
||||||
break;
|
break;
|
||||||
case 0x5b: /* CSI */
|
case 0x5b: /* CSI */
|
||||||
ENTER_STRING_STATE(CSI);
|
vt->parser.csi_leaderlen = 0;
|
||||||
|
ENTER_STATE(CSI_LEADER);
|
||||||
break;
|
break;
|
||||||
case 0x5d: /* OSC */
|
case 0x5d: /* OSC */
|
||||||
ENTER_STRING_STATE(OSC);
|
start_string(vt, VTERM_PARSER_OSC);
|
||||||
|
ENTER_STRING_STATE();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if(c >= 0x30 && c < 0x7f) {
|
if(is_intermed(c)) {
|
||||||
/* +1 to pos because we want to include this command byte as well */
|
if(vt->parser.intermedlen < INTERMED_MAX-1)
|
||||||
do_string(vt, string_start, bytes + pos - string_start + 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();
|
ENTER_NORMAL_STATE();
|
||||||
}
|
}
|
||||||
else if(c >= 0x20 && c < 0x30) {
|
else if(c >= 0x30 && c < 0x7f) {
|
||||||
/* intermediate byte */
|
do_escape(vt, c);
|
||||||
|
ENTER_NORMAL_STATE();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
|
DEBUG_LOG1("TODO: Unhandled byte %02x in Escape\n", c);
|
||||||
@@ -289,18 +225,67 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CSI:
|
case CSI_LEADER:
|
||||||
if(c >= 0x40 && c <= 0x7f) {
|
/* Extract leader bytes 0x3c to 0x3f */
|
||||||
/* +1 to pos because we want to include this command byte as well */
|
if(c >= 0x3c && c <= 0x3f) {
|
||||||
do_string(vt, string_start, bytes + pos - string_start + 1);
|
if(vt->parser.csi_leaderlen < CSI_LEADER_MAX-1)
|
||||||
ENTER_NORMAL_STATE();
|
vt->parser.csi_leader[vt->parser.csi_leaderlen++] = c;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* else fallthrough */
|
||||||
|
vt->parser.csi_leader[vt->parser.csi_leaderlen] = 0;
|
||||||
|
|
||||||
|
vt->parser.csi_argi = 0;
|
||||||
|
vt->parser.csi_args[0] = CSI_ARG_MISSING;
|
||||||
|
vt->parser.state = CSI_ARGS;
|
||||||
|
|
||||||
|
/* fallthrough */
|
||||||
|
case CSI_ARGS:
|
||||||
|
/* Numerical value of argument */
|
||||||
|
if(c >= '0' && c <= '9') {
|
||||||
|
if(vt->parser.csi_args[vt->parser.csi_argi] == CSI_ARG_MISSING)
|
||||||
|
vt->parser.csi_args[vt->parser.csi_argi] = 0;
|
||||||
|
vt->parser.csi_args[vt->parser.csi_argi] *= 10;
|
||||||
|
vt->parser.csi_args[vt->parser.csi_argi] += c - '0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(c == ':') {
|
||||||
|
vt->parser.csi_args[vt->parser.csi_argi] |= CSI_ARG_FLAG_MORE;
|
||||||
|
c = ';';
|
||||||
|
}
|
||||||
|
if(c == ';') {
|
||||||
|
vt->parser.csi_argi++;
|
||||||
|
vt->parser.csi_args[vt->parser.csi_argi] = CSI_ARG_MISSING;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* else fallthrough */
|
||||||
|
vt->parser.csi_argi++;
|
||||||
|
vt->parser.intermedlen = 0;
|
||||||
|
vt->parser.state = CSI_INTERMED;
|
||||||
|
/* fallthrough */
|
||||||
|
case CSI_INTERMED:
|
||||||
|
if(is_intermed(c)) {
|
||||||
|
if(vt->parser.intermedlen < INTERMED_MAX-1)
|
||||||
|
vt->parser.intermed[vt->parser.intermedlen++] = c;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(c == 0x1b) {
|
||||||
|
/* ESC in CSI cancels */
|
||||||
|
}
|
||||||
|
else if(c >= 0x40 && c <= 0x7e) {
|
||||||
|
vt->parser.intermed[vt->parser.intermedlen] = 0;
|
||||||
|
do_csi(vt, c);
|
||||||
|
}
|
||||||
|
/* else was invalid CSI */
|
||||||
|
|
||||||
|
ENTER_NORMAL_STATE();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OSC:
|
case STRING:
|
||||||
case DCS:
|
|
||||||
if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {
|
if(c == 0x07 || (c == 0x9c && !vt->mode.utf8)) {
|
||||||
do_string(vt, string_start, bytes + pos - string_start);
|
done_string(vt, string_start, bytes + pos - string_start);
|
||||||
ENTER_NORMAL_STATE();
|
ENTER_NORMAL_STATE();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -309,13 +294,15 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {
|
if(c >= 0x80 && c < 0xa0 && !vt->mode.utf8) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 0x90: /* DCS */
|
case 0x90: /* DCS */
|
||||||
ENTER_STRING_STATE(DCS);
|
start_string(vt, VTERM_PARSER_DCS);
|
||||||
|
ENTER_STRING_STATE();
|
||||||
break;
|
break;
|
||||||
case 0x9b: /* CSI */
|
case 0x9b: /* CSI */
|
||||||
ENTER_STRING_STATE(CSI);
|
ENTER_STATE(CSI_LEADER);
|
||||||
break;
|
break;
|
||||||
case 0x9d: /* OSC */
|
case 0x9d: /* OSC */
|
||||||
ENTER_STRING_STATE(OSC);
|
start_string(vt, VTERM_PARSER_OSC);
|
||||||
|
ENTER_STRING_STATE();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
do_control(vt, c);
|
do_control(vt, c);
|
||||||
@@ -323,24 +310,32 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
size_t text_eaten = do_string(vt, bytes + pos, len - pos);
|
size_t eaten = 0;
|
||||||
|
if(vt->parser.callbacks && vt->parser.callbacks->text)
|
||||||
|
eaten = (*vt->parser.callbacks->text)(bytes + pos, len - pos, vt->parser.cbdata);
|
||||||
|
|
||||||
if(text_eaten == 0) {
|
if(!eaten) {
|
||||||
string_start = bytes + pos;
|
DEBUG_LOG("libvterm: Text callback did not consume any input\n");
|
||||||
goto pause;
|
/* force it to make progress */
|
||||||
|
eaten = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos += (text_eaten - 1); /* we'll ++ it again in a moment */
|
pos += (eaten - 1); /* we'll ++ it again in a moment */
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pause:
|
|
||||||
if(string_start && string_start < len + bytes) {
|
|
||||||
size_t remaining = len - (string_start - bytes);
|
|
||||||
append_strbuffer(vt, string_start, remaining);
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
|
||||||
|
{
|
||||||
|
vt->parser.callbacks = callbacks;
|
||||||
|
vt->parser.cbdata = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *vterm_parser_get_cbdata(VTerm *vt)
|
||||||
|
{
|
||||||
|
return vt->parser.cbdata;
|
||||||
|
}
|
||||||
|
@@ -507,6 +507,9 @@ int vterm_state_get_penattr(const VTermState *state, VTermAttr attr, VTermValue
|
|||||||
case VTERM_ATTR_BACKGROUND:
|
case VTERM_ATTR_BACKGROUND:
|
||||||
val->color = state->pen.bg;
|
val->color = state->pen.bg;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case VTERM_N_ATTRS:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -429,6 +429,9 @@ static int setpenattr(VTermAttr attr, VTermValue *val, void *user)
|
|||||||
case VTERM_ATTR_BACKGROUND:
|
case VTERM_ATTR_BACKGROUND:
|
||||||
screen->pen.bg = val->color;
|
screen->pen.bg = val->color;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case VTERM_N_ATTRS:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@@ -268,7 +268,7 @@ static int on_text(const char bytes[], size_t len, void *user)
|
|||||||
if(!npoints)
|
if(!npoints)
|
||||||
{
|
{
|
||||||
vterm_allocator_free(state->vt, codepoints);
|
vterm_allocator_free(state->vt, codepoints);
|
||||||
return 0;
|
return eaten;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state->gsingle_set && npoints)
|
if(state->gsingle_set && npoints)
|
||||||
@@ -781,6 +781,10 @@ static void set_dec_mode(VTermState *state, int num, int val)
|
|||||||
VTERM_PROP_MOUSE_MOVE);
|
VTERM_PROP_MOUSE_MOVE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1004:
|
||||||
|
state->mode.report_focus = val;
|
||||||
|
break;
|
||||||
|
|
||||||
case 1005:
|
case 1005:
|
||||||
state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10;
|
state->mouse_protocol = val ? MOUSE_UTF8 : MOUSE_X10;
|
||||||
break;
|
break;
|
||||||
@@ -861,6 +865,10 @@ static void request_dec_mode(VTermState *state, int num)
|
|||||||
reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE);
|
reply = state->mouse_flags == (MOUSE_WANT_CLICK|MOUSE_WANT_MOVE);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 1004:
|
||||||
|
reply = state->mode.report_focus;
|
||||||
|
break;
|
||||||
|
|
||||||
case 1005:
|
case 1005:
|
||||||
reply = state->mouse_protocol == MOUSE_UTF8;
|
reply = state->mouse_protocol == MOUSE_UTF8;
|
||||||
break;
|
break;
|
||||||
@@ -1728,6 +1736,7 @@ void vterm_state_reset(VTermState *state, int hard)
|
|||||||
state->mode.origin = 0;
|
state->mode.origin = 0;
|
||||||
state->mode.leftrightmargin = 0;
|
state->mode.leftrightmargin = 0;
|
||||||
state->mode.bracketpaste = 0;
|
state->mode.bracketpaste = 0;
|
||||||
|
state->mode.report_focus = 0;
|
||||||
|
|
||||||
state->vt->mode.ctrl8bit = 0;
|
state->vt->mode.ctrl8bit = 0;
|
||||||
|
|
||||||
@@ -1882,11 +1891,26 @@ int vterm_state_set_termprop(VTermState *state, VTermProp prop, VTermValue *val)
|
|||||||
if(val->number == VTERM_PROP_MOUSE_MOVE)
|
if(val->number == VTERM_PROP_MOUSE_MOVE)
|
||||||
state->mouse_flags |= MOUSE_WANT_MOVE;
|
state->mouse_flags |= MOUSE_WANT_MOVE;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case VTERM_N_PROPS:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vterm_state_focus_in(VTermState *state)
|
||||||
|
{
|
||||||
|
if(state->mode.report_focus)
|
||||||
|
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "I");
|
||||||
|
}
|
||||||
|
|
||||||
|
void vterm_state_focus_out(VTermState *state)
|
||||||
|
{
|
||||||
|
if(state->mode.report_focus)
|
||||||
|
vterm_push_output_sprintf_ctrl(state->vt, C1_CSI, "O");
|
||||||
|
}
|
||||||
|
|
||||||
const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row)
|
const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row)
|
||||||
{
|
{
|
||||||
return state->lineinfo + row;
|
return state->lineinfo + row;
|
||||||
|
@@ -47,14 +47,14 @@ VTerm *vterm_new_with_allocator(int rows, int cols, VTermAllocatorFunctions *fun
|
|||||||
vt->rows = rows;
|
vt->rows = rows;
|
||||||
vt->cols = cols;
|
vt->cols = cols;
|
||||||
|
|
||||||
vt->parser_state = NORMAL;
|
vt->parser.state = NORMAL;
|
||||||
|
|
||||||
vt->parser_callbacks = NULL;
|
vt->parser.callbacks = NULL;
|
||||||
vt->cbdata = NULL;
|
vt->parser.cbdata = NULL;
|
||||||
|
|
||||||
vt->strbuffer_len = 64;
|
vt->parser.strbuffer_len = 64;
|
||||||
vt->strbuffer_cur = 0;
|
vt->parser.strbuffer_cur = 0;
|
||||||
vt->strbuffer = vterm_allocator_malloc(vt, vt->strbuffer_len);
|
vt->parser.strbuffer = vterm_allocator_malloc(vt, vt->parser.strbuffer_len);
|
||||||
|
|
||||||
vt->outbuffer_len = 200;
|
vt->outbuffer_len = 200;
|
||||||
vt->outbuffer_cur = 0;
|
vt->outbuffer_cur = 0;
|
||||||
@@ -71,7 +71,7 @@ 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->strbuffer);
|
vterm_allocator_free(vt, vt->parser.strbuffer);
|
||||||
vterm_allocator_free(vt, vt->outbuffer);
|
vterm_allocator_free(vt, vt->outbuffer);
|
||||||
|
|
||||||
vterm_allocator_free(vt, vt);
|
vterm_allocator_free(vt, vt);
|
||||||
@@ -100,8 +100,8 @@ void vterm_set_size(VTerm *vt, int rows, int cols)
|
|||||||
vt->rows = rows;
|
vt->rows = rows;
|
||||||
vt->cols = cols;
|
vt->cols = cols;
|
||||||
|
|
||||||
if(vt->parser_callbacks && vt->parser_callbacks->resize)
|
if(vt->parser.callbacks && vt->parser.callbacks->resize)
|
||||||
(*vt->parser_callbacks->resize)(rows, cols, vt->cbdata);
|
(*vt->parser.callbacks->resize)(rows, cols, vt->parser.cbdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
int vterm_get_utf8(const VTerm *vt)
|
int vterm_get_utf8(const VTerm *vt)
|
||||||
@@ -257,17 +257,6 @@ size_t vterm_output_read(VTerm *vt, char *buffer, size_t len)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vterm_parser_set_callbacks(VTerm *vt, const VTermParserCallbacks *callbacks, void *user)
|
|
||||||
{
|
|
||||||
vt->parser_callbacks = callbacks;
|
|
||||||
vt->cbdata = user;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *vterm_parser_get_cbdata(VTerm *vt)
|
|
||||||
{
|
|
||||||
return vt->cbdata;
|
|
||||||
}
|
|
||||||
|
|
||||||
VTermValueType vterm_get_attr_type(VTermAttr attr)
|
VTermValueType vterm_get_attr_type(VTermAttr attr)
|
||||||
{
|
{
|
||||||
switch(attr) {
|
switch(attr) {
|
||||||
@@ -280,6 +269,8 @@ VTermValueType vterm_get_attr_type(VTermAttr attr)
|
|||||||
case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT;
|
case VTERM_ATTR_FONT: return VTERM_VALUETYPE_INT;
|
||||||
case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
|
case VTERM_ATTR_FOREGROUND: return VTERM_VALUETYPE_COLOR;
|
||||||
case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
|
case VTERM_ATTR_BACKGROUND: return VTERM_VALUETYPE_COLOR;
|
||||||
|
|
||||||
|
case VTERM_N_ATTRS: return 0;
|
||||||
}
|
}
|
||||||
return 0; /* UNREACHABLE */
|
return 0; /* UNREACHABLE */
|
||||||
}
|
}
|
||||||
@@ -296,6 +287,8 @@ VTermValueType vterm_get_prop_type(VTermProp prop)
|
|||||||
case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT;
|
case VTERM_PROP_CURSORSHAPE: return VTERM_VALUETYPE_INT;
|
||||||
case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT;
|
case VTERM_PROP_MOUSE: return VTERM_VALUETYPE_INT;
|
||||||
case VTERM_PROP_CURSORCOLOR: return VTERM_VALUETYPE_STRING;
|
case VTERM_PROP_CURSORCOLOR: return VTERM_VALUETYPE_STRING;
|
||||||
|
|
||||||
|
case VTERM_N_PROPS: return 0;
|
||||||
}
|
}
|
||||||
return 0; /* UNREACHABLE */
|
return 0; /* UNREACHABLE */
|
||||||
}
|
}
|
||||||
|
@@ -27,6 +27,11 @@
|
|||||||
|
|
||||||
#define ESC_S "\x1b"
|
#define ESC_S "\x1b"
|
||||||
|
|
||||||
|
#define INTERMED_MAX 16
|
||||||
|
|
||||||
|
#define CSI_ARGS_MAX 16
|
||||||
|
#define CSI_LEADER_MAX 16
|
||||||
|
|
||||||
typedef struct VTermEncoding VTermEncoding;
|
typedef struct VTermEncoding VTermEncoding;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -118,6 +123,7 @@ struct VTermState
|
|||||||
unsigned int screen:1;
|
unsigned int screen:1;
|
||||||
unsigned int leftrightmargin:1;
|
unsigned int leftrightmargin:1;
|
||||||
unsigned int bracketpaste:1;
|
unsigned int bracketpaste:1;
|
||||||
|
unsigned int report_focus:1;
|
||||||
} mode;
|
} mode;
|
||||||
|
|
||||||
VTermEncodingInstance encoding[4], encoding_utf8;
|
VTermEncodingInstance encoding[4], encoding_utf8;
|
||||||
@@ -148,6 +154,13 @@ struct VTermState
|
|||||||
} saved;
|
} saved;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VTERM_PARSER_OSC,
|
||||||
|
VTERM_PARSER_DCS,
|
||||||
|
|
||||||
|
VTERM_N_PARSER_TYPES
|
||||||
|
} VTermParserStringType;
|
||||||
|
|
||||||
struct VTerm
|
struct VTerm
|
||||||
{
|
{
|
||||||
VTermAllocatorFunctions *allocator;
|
VTermAllocatorFunctions *allocator;
|
||||||
@@ -161,22 +174,37 @@ struct VTerm
|
|||||||
unsigned int ctrl8bit:1;
|
unsigned int ctrl8bit:1;
|
||||||
} mode;
|
} mode;
|
||||||
|
|
||||||
|
struct {
|
||||||
enum VTermParserState {
|
enum VTermParserState {
|
||||||
NORMAL,
|
NORMAL,
|
||||||
CSI,
|
CSI_LEADER,
|
||||||
OSC,
|
CSI_ARGS,
|
||||||
DCS,
|
CSI_INTERMED,
|
||||||
ESC,
|
ESC,
|
||||||
ESC_IN_OSC,
|
/* below here are the "string states" */
|
||||||
ESC_IN_DCS
|
STRING,
|
||||||
} parser_state;
|
ESC_IN_STRING
|
||||||
const VTermParserCallbacks *parser_callbacks;
|
} state;
|
||||||
|
|
||||||
|
int intermedlen;
|
||||||
|
char intermed[INTERMED_MAX];
|
||||||
|
|
||||||
|
int csi_leaderlen;
|
||||||
|
char csi_leader[CSI_LEADER_MAX];
|
||||||
|
|
||||||
|
int csi_argi;
|
||||||
|
long csi_args[CSI_ARGS_MAX];
|
||||||
|
|
||||||
|
const VTermParserCallbacks *callbacks;
|
||||||
void *cbdata;
|
void *cbdata;
|
||||||
|
|
||||||
/* len == malloc()ed size; cur == number of valid bytes */
|
VTermParserStringType stringtype;
|
||||||
char *strbuffer;
|
char *strbuffer;
|
||||||
size_t strbuffer_len;
|
size_t strbuffer_len;
|
||||||
size_t strbuffer_cur;
|
size_t strbuffer_cur;
|
||||||
|
} parser;
|
||||||
|
|
||||||
|
/* len == malloc()ed size; cur == number of valid bytes */
|
||||||
|
|
||||||
char *outbuffer;
|
char *outbuffer;
|
||||||
size_t outbuffer_len;
|
size_t outbuffer_len;
|
||||||
|
@@ -17,6 +17,12 @@ PUSH "\xC3\x81\xC3\xA9"
|
|||||||
putglyph 0xc1 1 0,0
|
putglyph 0xc1 1 0,0
|
||||||
putglyph 0xe9 1 0,1
|
putglyph 0xe9 1 0,1
|
||||||
|
|
||||||
|
!UTF-8 split writes
|
||||||
|
RESET
|
||||||
|
PUSH "\xC3"
|
||||||
|
PUSH "\x81"
|
||||||
|
putglyph 0xc1 1 0,0
|
||||||
|
|
||||||
!UTF-8 wide char
|
!UTF-8 wide char
|
||||||
# U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO
|
# U+FF10 = 0xEF 0xBC 0x90 name: FULLWIDTH DIGIT ZERO
|
||||||
RESET
|
RESET
|
||||||
|
@@ -130,3 +130,14 @@ PASTE START
|
|||||||
output "\e[200~"
|
output "\e[200~"
|
||||||
PASTE END
|
PASTE END
|
||||||
output "\e[201~"
|
output "\e[201~"
|
||||||
|
|
||||||
|
!Focus reporting disabled
|
||||||
|
FOCUS IN
|
||||||
|
FOCUS OUT
|
||||||
|
|
||||||
|
!Focus reporting enabled
|
||||||
|
PUSH "\e[?1004h"
|
||||||
|
FOCUS IN
|
||||||
|
output "\e[I"
|
||||||
|
FOCUS OUT
|
||||||
|
output "\e[O"
|
||||||
|
@@ -58,5 +58,5 @@ PUSH "\e[5n"
|
|||||||
PUSH "\e F"
|
PUSH "\e F"
|
||||||
|
|
||||||
!Truncation on attempted buffer overflow
|
!Truncation on attempted buffer overflow
|
||||||
PUSH "\e[6n" x 20
|
PUSH "\e[6n" x 30
|
||||||
output "\e[10;10R" x 7
|
output "\e[10;10R" x 24
|
||||||
|
@@ -233,6 +233,9 @@ static int settermprop(VTermProp prop, VTermValue *val, void *user)
|
|||||||
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);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
case VTERM_N_VALUETYPES:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -316,6 +319,9 @@ static int state_setpenattr(VTermAttr attr, VTermValue *val, void *user)
|
|||||||
case VTERM_ATTR_BACKGROUND:
|
case VTERM_ATTR_BACKGROUND:
|
||||||
state_pen.background = val->color;
|
state_pen.background = val->color;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case VTERM_N_ATTRS:
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -651,6 +657,16 @@ int main(int argc, char **argv)
|
|||||||
goto abort_line;
|
goto abort_line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if(strstartswith(line, "FOCUS ")) {
|
||||||
|
char *linep = line + 6;
|
||||||
|
if(streq(linep, "IN"))
|
||||||
|
vterm_state_focus_in(state);
|
||||||
|
else if(streq(linep, "OUT"))
|
||||||
|
vterm_state_focus_out(state);
|
||||||
|
else
|
||||||
|
goto abort_line;
|
||||||
|
}
|
||||||
|
|
||||||
else if(strstartswith(line, "MOUSEMOVE ")) {
|
else if(strstartswith(line, "MOUSEMOVE ")) {
|
||||||
char *linep = line + 10;
|
char *linep = line + 10;
|
||||||
int row, col, len;
|
int row, col, len;
|
||||||
|
@@ -766,6 +766,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 */
|
||||||
|
/**/
|
||||||
|
1639,
|
||||||
/**/
|
/**/
|
||||||
1638,
|
1638,
|
||||||
/**/
|
/**/
|
||||||
|
Reference in New Issue
Block a user