patch 8.2.3666: libvterm is outdated

Problem:    Libvterm is outdated.
Solution:   Include patches from revision 769 to revision 789.
This commit is contained in:
Bram Moolenaar
2021-11-24 19:30:55 +00:00
parent 19916a8c89
commit 7da341560e
18 changed files with 953 additions and 238 deletions

View File

@ -377,6 +377,7 @@ SRC_ALL = \
src/libvterm/t/30state_pen.test \ src/libvterm/t/30state_pen.test \
src/libvterm/t/31state_rep.test \ src/libvterm/t/31state_rep.test \
src/libvterm/t/32state_flow.test \ src/libvterm/t/32state_flow.test \
src/libvterm/t/40state_selection.test \
src/libvterm/t/60screen_ascii.test \ src/libvterm/t/60screen_ascii.test \
src/libvterm/t/61screen_unicode.test \ src/libvterm/t/61screen_unicode.test \
src/libvterm/t/62screen_damage.test \ src/libvterm/t/62screen_damage.test \

View File

@ -37,7 +37,7 @@ INCFILES=$(TBLFILES:.tbl=.inc)
HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES) HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES)
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=1 VERSION_MINOR=2
VERSION_CURRENT=0 VERSION_CURRENT=0
VERSION_REVISION=0 VERSION_REVISION=0
@ -97,7 +97,7 @@ install-inc:
install -d $(DESTDIR)$(INCDIR) install -d $(DESTDIR)$(INCDIR)
install -m644 $(HFILES) $(DESTDIR)$(INCDIR) install -m644 $(HFILES) $(DESTDIR)$(INCDIR)
install -d $(DESTDIR)$(LIBDIR)/pkgconfig install -d $(DESTDIR)$(LIBDIR)/pkgconfig
sed -e "s,@PREFIX@,$(PREFIX)," -e "s,@LIBDIR@,$(LIBDIR)," -e "s,@VERSION@,$(VERSION)," <vterm.pc.in >$(DESTDIR)$(LIBDIR)/pkgconfig/vterm.pc sed -e "s,@INCDIR@,$(INCDIR)," -e "s,@LIBDIR@,$(LIBDIR)," -e "s,@VERSION@,$(VERSION)," <vterm.pc.in >$(DESTDIR)$(LIBDIR)/pkgconfig/vterm.pc
install-lib: $(LIBRARY) install-lib: $(LIBRARY)
install -d $(DESTDIR)$(LIBDIR) install -d $(DESTDIR)$(LIBDIR)

View File

@ -4,228 +4,275 @@ between states.
1 = VT100 1 = VT100
2 = VT220 2 = VT220
3 = VT320 3 = VT320
x = xterm
C0 controls C0 controls
123 0x00 = NUL 123 0x00 = NUL
123 0x07 = BEL 123x 0x07 = BEL
123 0x08 = BS 123x 0x08 = BS
123 0x09 = HT 123x 0x09 = HT
123 0x0A = LF 123x 0x0A = LF
123 0x0B = VT 123x 0x0B = VT
123 0x0C = FF 123x 0x0C = FF
123 0x0D = CR 123x 0x0D = CR
123 0x0E = LS1 123x 0x0E = LS1
123 0x0F = LS0 123x 0x0F = LS0
(0x18 = CAN) (0x18 = CAN)
(0x1A = SUB) (0x1A = SUB)
(0x1B = ESC) (0x1B = ESC)
123 0x7f = DEL (ignored) 123 0x7f = DEL (ignored)
C1 controls C1 controls
123 0x84 = IND 123x 0x84 = IND
123 0x85 = NEL 123x 0x85 = NEL
123 0x88 = HTS 123x 0x88 = HTS
123 0x8D = RI 123x 0x8D = RI
23 0x8e = SS2 23x 0x8E = SS2
23 0x8f = SS3 23x 0x8F = SS3
(0x90 = DCS) (0x90 = DCS)
(0x9B = CSI) (0x98 = SOS)
(0x9C = ST) (0x9B = CSI)
(0x9D = OSC) (0x9C = ST)
(0x9D = OSC)
(0x9E = PM)
(0x9F = APC)
Escape sequences Escape sequences
- excluding sequences that are C1 aliases - excluding sequences that are C1 aliases
123 ESC () = SCS, select character set (G0, G1) 123x ESC ( = SCS, select character set G0
23 ESC *+ = SCS, select character set (G2, G3) 123x ESC ) = SCS, select character set G1
123 ESC 7 = DECSC - save cursor 23x ESC * = SCS, select character set G2
123 ESC 8 = DECRC - restore cursor 23x ESC + = SCS, select character set G3
123 ESC # 3 = DECDHL, double-height line (top half) 123x ESC 7 = DECSC - save cursor
123 ESC # 4 = DECDHL, double-height line (bottom half) 123x ESC 8 = DECRC - restore cursor
123 ESC # 5 = DECSWL, single-width single-height line 123x ESC # 3 = DECDHL, double-height line (top half)
123 ESC # 6 = DECDWL, double-width single-height line 123x ESC # 4 = DECDHL, double-height line (bottom half)
123 ESC # 8 = DECALN 123x ESC # 5 = DECSWL, single-width single-height line
123 ESC < = Ignored (used by VT100 to exit VT52 mode) 123x ESC # 6 = DECDWL, double-width single-height line
123 ESC = = DECKPAM, keypad application mode 123x ESC # 8 = DECALN
123 ESC > = DECKPNM, keypad numeric mode 123 ESC < = Ignored (used by VT100 to exit VT52 mode)
23 ESC Sp F = S7C1T 123x ESC = = DECKPAM, keypad application mode
23 ESC Sp G = S8C1T 123x ESC > = DECKPNM, keypad numeric mode
(ESC P = DCS) 23x ESC Sp F = S7C1T
(ESC [ = CSI) 23x ESC Sp G = S8C1T
(ESC \ = ST) (ESC P = DCS)
(ESC ] = OSC) (ESC X = SOS)
123 ESC c = RIS, reset initial state (ESC [ = CSI)
3 ESC n = LS2 (ESC \ = ST)
3 ESC o = LS3 (ESC ] = OSC)
3 ESC ~ = LS1R (ESC ^ = PM)
3 ESC } = LS2R (ESC _ = APC)
3 ESC | = LS3R 123x ESC c = RIS, reset initial state
3x ESC n = LS2
3x ESC o = LS3
3x ESC | = LS3R
3x ESC } = LS2R
3x ESC ~ = LS1R
DCSes DCSes
3 DCS $ q ST = DECRQSS 3x DCS $ q ST = DECRQSS
3 m = Request SGR 3x m = Request SGR
Sp q = Request DECSCUSR x Sp q = Request DECSCUSR
3 " q = Request DECSCA 3x " q = Request DECSCA
3 r = Request DECSTBM 3x r = Request DECSTBM
s = Request DECSLRM x s = Request DECSLRM
CSIs CSIs
23 CSI @ = ICH 23x CSI @ = ICH
123 CSI A = CUU 123x CSI A = CUU
123 CSI B = CUD 123x CSI B = CUD
123 CSI C = CUF 123x CSI C = CUF
123 CSI D = CUB 123x CSI D = CUB
CSI E = CNL x CSI E = CNL
CSI F = CPL x CSI F = CPL
CSI G = CHA x CSI G = CHA
123 CSI H = CUP 123x CSI H = CUP
CSI I = CHT x CSI I = CHT
123 CSI J = ED 123x CSI J = ED
23 CSI ? J = DECSED, selective erase in display 23x CSI ? J = DECSED, selective erase in display
123 CSI K = EL 123x CSI K = EL
23 CSI ? K = DECSEL, selective erase in line 23x CSI ? K = DECSEL, selective erase in line
23 CSI L = IL 23x CSI L = IL
23 CSI M = DL 23x CSI M = DL
23 CSI P = DCH 23x CSI P = DCH
CSI S = SU x CSI S = SU
CSI T = SD x CSI T = SD
23 CSI X = ECH 23x CSI X = ECH
CSI Z = CBT x CSI Z = CBT
CSI ` = HPA x CSI ` = HPA
CSI a = HPR x CSI a = HPR
CSI b = REP x CSI b = REP
123 CSI c = DA, device attributes 123x CSI c = DA, device attributes
123 0 = DA 123 0 = DA
23 CSI > c = DECSDA 23x CSI > c = DECSDA
23 0 = SDA 23 0 = SDA
CSI d = VPA x CSI d = VPA
CSI e = VPR x CSI e = VPR
123 CSI f = HVP 123x CSI f = HVP
123 CSI g = TBC 123x CSI g = TBC
123 CSI h = SM, Set mode 123x CSI h = SM, Set mode
123 CSI ? h = DECSM, DEC set mode 123x CSI ? h = DECSM, DEC set mode
CSI j = HPB CSI j = HPB
CSI k = VPB CSI k = VPB
123 CSI l = RM, Reset mode 123x CSI l = RM, Reset mode
123 CSI ? l = DECRM, DEC reset mode 123x CSI ? l = DECRM, DEC reset mode
123 CSI m = SGR, Set Graphic Rendition 123x CSI m = SGR, Set Graphic Rendition
123 CSI n = DSR, Device Status Report 123x CSI n = DSR, Device Status Report
23 5 = operating status 23x 5 = operating status
23 6 = CPR = cursor position 23x 6 = CPR = cursor position
23 CSI ? n = DECDSR; behaves as DSR but uses CSI ? instead of CSI to respond 23x CSI ? n = DECDSR; behaves as DSR but uses CSI ? instead of CSI to respond
23 CSI ! p = DECSTR, soft terminal reset 23x CSI ! p = DECSTR, soft terminal reset
3 CSI ? $ p = DECRQM, request mode 3x CSI ? $ p = DECRQM, request private mode
CSI Sp q = DECSCUSR (odd numbers blink, even numbers solid) x CSI Sp q = DECSCUSR (odd numbers blink, even numbers solid)
1 or 2 = block 1 or 2 = block
3 or 4 = underline 3 or 4 = underline
5 or 6 = I-beam to left 5 or 6 = I-beam to left
23 CSI " q = DECSCA, select character attributes 23x CSI " q = DECSCA, select character attributes
123 CSI r = DECSTBM 123x CSI r = DECSTBM
CSI s = DECSLRM x CSI s = DECSLRM
CSI ' } = DECIC x CSI ' } = DECIC
CSI ' ~ = DECDC x CSI ' ~ = DECDC
OSCs OSCs
OSC 0; = Set icon name and title x OSC 0; = Set icon name and title
OSC 1; = Set icon name x OSC 1; = Set icon name
OSC 2; = Set title x OSC 2; = Set title
x OSC 52; = Selection management
Standard modes Standard modes
23 SM 4 = IRM 23x SM 4 = IRM
123 SM 20 = NLM, linefeed/newline 123x SM 20 = NLM, linefeed/newline
DEC modes DEC modes
123 DECSM 1 = DECCKM, cursor keys 123x DECSM 1 = DECCKM, cursor keys
123 DECSM 5 = DECSCNM, screen 123x DECSM 5 = DECSCNM, screen
123 DECSM 6 = DECOM, origin 123x DECSM 6 = DECOM, origin
123 DECSM 7 = DECAWM, autowrap 123x DECSM 7 = DECAWM, autowrap
DECSM 12 = Cursor blink x DECSM 12 = Cursor blink
23 DECSM 25 = DECTCEM, text cursor enable 23x DECSM 25 = DECTCEM, text cursor enable
DECSM 69 = DECVSSM, vertical screen split x DECSM 69 = DECVSSM, vertical screen split
DECSM 1000 = Mouse click/release tracking x DECSM 1000 = Mouse click/release tracking
DECSM 1002 = Mouse click/release/drag tracking x DECSM 1002 = Mouse click/release/drag tracking
DECSM 1003 = Mouse all movements tracking x DECSM 1003 = Mouse all movements tracking
DECSM 1004 = Focus in/out reporting x DECSM 1004 = Focus in/out reporting
DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended x DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended
DECSM 1006 = Mouse protocol SGR x DECSM 1006 = Mouse protocol SGR
DECSM 1015 = Mouse protocol rxvt x DECSM 1015 = Mouse protocol rxvt
DECSM 1047 = Altscreen x DECSM 1047 = Altscreen
DECSM 1048 = Save cursor x DECSM 1048 = Save cursor
DECSM 1049 = 1047 + 1048 x DECSM 1049 = 1047 + 1048
DECSM 2004 = Bracketed paste x DECSM 2004 = Bracketed paste
Graphic Renditions Graphic Renditions
123 SGR 0 = Reset 123x SGR 0 = Reset
123 SGR 1 = Bold on 123x SGR 1 = Bold on
SGR 3 = Italic on x SGR 3 = Italic on
123 SGR 4 = Underline single 123x SGR 4 = Underline single
SGR 4:x = Underline style SGR 4:x = Underline style
123 SGR 5 = Blink on 123x SGR 5 = Blink on
123 SGR 7 = Reverse on 123x SGR 7 = Reverse on
SGR 8 = Conceal on x SGR 8 = Conceal on
SGR 9 = Strikethrough on x SGR 9 = Strikethrough on
SGR 10-19 = Select font SGR 10-19 = Select font
SGR 21 = Underline double x SGR 21 = Underline double
23 SGR 22 = Bold off 23x SGR 22 = Bold off
SGR 23 = Italic off x SGR 23 = Italic off
23 SGR 24 = Underline off 23x SGR 24 = Underline off
23 SGR 25 = Blink off 23x SGR 25 = Blink off
23 SGR 27 = Reverse off 23x SGR 27 = Reverse off
SGR 28 = Conceal off x SGR 28 = Conceal off
SGR 29 = Strikethrough off x SGR 29 = Strikethrough off
SGR 30-37 = Foreground ANSI x SGR 30-37 = Foreground ANSI
SGR 38 = Foreground alternative palette x SGR 38 = Foreground alternative palette
SGR 39 = Foreground default x SGR 39 = Foreground default
SGR 40-47 = Background ANSI x SGR 40-47 = Background ANSI
SGR 48 = Background alternative palette x SGR 48 = Background alternative palette
SGR 49 = Background default x SGR 49 = Background default
SGR 90-97 = Foreground ANSI high-intensity x SGR 90-97 = Foreground ANSI high-intensity
SGR 100-107 = Background ANSI high-intensity x SGR 100-107 = Background ANSI high-intensity
The state storage used by ESC 7 and DECSM 1048/1049 is shared. The state storage used by ESC 7 and DECSM 1048/1049 is shared.
Unimplemented sequences: Unimplemented sequences:
The following sequences are not recognised by libvterm. The following sequences are not recognised by libvterm.
123 0x05 = ENQ 123x 0x05 = ENQ
3 0x11 = DC1 (XON) 3 0x11 = DC1 (XON)
3 0x13 = DC3 (XOFF) 3 0x13 = DC3 (XOFF)
12 ESC Z = DECID, identify terminal x ESC % @ = Select default character set
DCS $ q = [DECRQSS] x ESC % G = Select UTF-8 character set
3 " p = Request DECSCL x ESC 6 = DECBI, Back Index
3 $ } = Request DECSASD 12 ESC Z = DECID, identify terminal
3 $ ~ = Request DECSSDT x DCS + Q = XTGETXRES, Request resource values
23 DCS { = DECDLD, down-line-loadable character set DCS $ q = [DECRQSS]
23 DCS | = DECUDK, user-defined key 3x " p = Request DECSCL
23 CSI i = DEC printer control x t = Request DECSLPP
23 CSI " p = DECSCL, set compatibility level x $ | = Request DECSCPP
1 CSI q = DECLL, load LEDs x * | = Request DECSLNS
3 CSI $ u = DECRQTSR, request terminal state report 3 $ } = Request DECSASD
3 1 = terminal state report 3 $ ~ = Request DECSSDT
3 CSI & u = DECRQUPSS, request user-preferred supplemental set x DCS + p = XTSETTCAP, set termcap/terminfo data
3 CSI $ w = DECRQPSR, request presentation state report x DCS + q = XTGETTCAP, request termcap/terminfo
3 1 = cursor information report 23 DCS { = DECDLD, down-line-loadable character set
3 2 = tab stop report 23x DCS | = DECUDK, user-defined key
1 CSI x = DECREQTPARM, request terminal parameters x CSI Sp @ = Shift left columns
123 CSI y = DECTST, invoke confidence test x CSI Sp A = Shift right columns
3 CSI $ } = DECSASD, select active status display x CSI # P = XTPUSHCOLORS, push current dynamic colours to stack
3 CSI $ ~ = DECSSDT, select status line type x CSI # Q = XTPOPCOLORS, pop dynamic colours from stack
23 SM 2 = KAM, keyboard action x CSI # R = XTREPORTCOLORS, report current entry on palette stack
123 SM 12 = SRM, send/receive x CSI ? S = XTSMGRAPHICS, set/request graphics attribute
123 DECSM 2 = DECANM, ANSI/VT52 x CSI > T = XTRMTITLE, reset title mode features
123 DECSM 3 = DECCOLM, 132 column 23x CSI i = DEC printer control
123 DECSM 4 = DECSCLM, scrolling x CSI > m = XTMODKEYS, set key modifier options
123 DECSM 8 = DECARM, auto-repeat x CSI > n = (XTMODKEYS), reset key modifier options
12 DECSM 9 = DECINLM, interlace x CSI $ p = DECRQM, request ANSI mode
23 DECSM 18 = DECPFF, print form feed 23x CSI " p = DECSCL, set compatibility level
23 DECSM 19 = DECPEX, print extent x CSI > p = XTSMPOINTER, set resource value pointer mode
23 DECSM 42 = DECNRCM, national/multinational character 1 x CSI q = DECLL, load LEDs
x CSI ? r = XTRESTORE, restore DEC private mode values
x CSI $ r = DECCARA, change attributes in rectangular area
x CSI > s = XTSHIFTESCAPE, set/reset shift-escape options
x CSI ? s = XTSAVE, save DEC private mode values
x CSI t = XTWINOPS, window operations
x CSI > t = XTSMTITLE, set title mode features
x CSI $ t = DECRARA, reset attributes in rectangular area
3 CSI $ u = DECRQTSR, request terminal state report
3 1 = terminal state report
3 CSI & u = DECRQUPSS, request user-preferred supplemental set
x CSI $ v = DECCRA, copy rectangular area
3x CSI $ w = DECRQPSR, request presentation state report
3x 1 = cursor information report
3x 2 = tab stop report
x CSI ' w = DECEFR, enable filter rectangle
1 x CSI x = DECREQTPARM, request terminal parameters
x CSI * x = DECSACE, select attribute change extent
x CSI $ x = DECFRA, fill rectangular area
123 CSI y = DECTST, invoke confidence test
x CSI $ z = DECERA, erase rectangular area
x CSI # { = XTPUSHSGR, push video attributes onto stack
x CSI $ { = DECSERA, selective erase in rectangular area
x CSI # | = XTREPORTSGR, report selected graphic rendition
x CSI $ | = DECSCPP, select columns per page
x CSI # } = XTPOPSGR, pop video attributes from stack
3 CSI $ } = DECSASD, select active status display
3 CSI $ ~ = DECSSDT, select status line type
23 SM 2 = KAM, keyboard action
123 SM 12 = SRM, send/receive
123 DECSM 2 = DECANM, ANSI/VT52
123 DECSM 3 = DECCOLM, 132 column
123 DECSM 4 = DECSCLM, scrolling
123 DECSM 8 = DECARM, auto-repeat
12 DECSM 9 = DECINLM, interlace
23 DECSM 18 = DECPFF, print form feed
23 DECSM 19 = DECPEX, print extent
23 DECSM 42 = DECNRCM, national/multinational character

View File

@ -17,10 +17,11 @@ extern "C" {
// from stdint.h // from stdint.h
typedef unsigned char uint8_t; typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t; typedef unsigned int uint32_t;
#define VTERM_VERSION_MAJOR 0 #define VTERM_VERSION_MAJOR 0
#define VTERM_VERSION_MINOR 1 #define VTERM_VERSION_MINOR 2
#define VTERM_CHECK_VERSION \ #define VTERM_CHECK_VERSION \
vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR) vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR)
@ -267,6 +268,14 @@ enum {
VTERM_N_PROP_MOUSES VTERM_N_PROP_MOUSES
}; };
typedef enum {
VTERM_SELECTION_CLIPBOARD = (1<<0),
VTERM_SELECTION_PRIMARY = (1<<1),
VTERM_SELECTION_SECONDARY = (1<<2),
VTERM_SELECTION_SELECT = (1<<3),
VTERM_SELECTION_CUT0 = (1<<4), /* also CUT1 .. CUT7 by bitshifting */
} VTermSelectionMask;
typedef struct { typedef struct {
const uint32_t *chars; const uint32_t *chars;
int width; int width;
@ -375,6 +384,9 @@ typedef struct {
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)(int command, VTermStringFragment frag, void *user); int (*osc)(int command, VTermStringFragment frag, void *user);
int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
int (*apc)(VTermStringFragment frag, void *user);
int (*pm)(VTermStringFragment frag, void *user);
int (*sos)(VTermStringFragment frag, void *user);
int (*resize)(int rows, int cols, void *user); int (*resize)(int rows, int cols, void *user);
} VTermParserCallbacks; } VTermParserCallbacks;
@ -419,8 +431,16 @@ typedef struct {
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)(int command, VTermStringFragment frag, void *user); int (*osc)(int command, VTermStringFragment frag, void *user);
int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user); int (*dcs)(const char *command, size_t commandlen, VTermStringFragment frag, void *user);
int (*apc)(VTermStringFragment frag, void *user);
int (*pm)(VTermStringFragment frag, void *user);
int (*sos)(VTermStringFragment frag, void *user);
} VTermStateFallbacks; } VTermStateFallbacks;
typedef struct {
int (*set)(VTermSelectionMask mask, VTermStringFragment frag, void *user);
int (*query)(VTermSelectionMask mask, void *user);
} VTermSelectionCallbacks;
VTermState *vterm_obtain_state(VTerm *vt); VTermState *vterm_obtain_state(VTerm *vt);
void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user); void vterm_state_set_callbacks(VTermState *state, const VTermStateCallbacks *callbacks, void *user);
@ -457,6 +477,11 @@ const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row);
*/ */
void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col); void vterm_state_convert_color_to_rgb(const VTermState *state, VTermColor *col);
void vterm_state_set_selection_callbacks(VTermState *state, const VTermSelectionCallbacks *callbacks, void *user,
char *buffer, size_t buflen);
void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTermStringFragment frag);
// ------------ // ------------
// Screen layer // Screen layer
// ------------ // ------------

View File

@ -89,6 +89,9 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod)
if (!(state->mouse_flags & MOUSE_WANT_CLICK)) if (!(state->mouse_flags & MOUSE_WANT_CLICK))
return; return;
if(!state->mouse_flags)
return;
if(button < 4) { if(button < 4) {
output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row); output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);
} }

View File

@ -77,10 +77,25 @@ static void string_fragment(VTerm *vt, const char *str, size_t len, int final)
break; break;
case DCS: case DCS:
if(len && vt->parser.callbacks && vt->parser.callbacks->dcs) if(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); (*vt->parser.callbacks->dcs)(vt->parser.v.dcs.command, vt->parser.v.dcs.commandlen, frag, vt->parser.cbdata);
break; break;
case APC:
if(vt->parser.callbacks && vt->parser.callbacks->apc)
(*vt->parser.callbacks->apc)(frag, vt->parser.cbdata);
break;
case PM:
if(vt->parser.callbacks && vt->parser.callbacks->pm)
(*vt->parser.callbacks->pm)(frag, vt->parser.cbdata);
break;
case SOS:
if(vt->parser.callbacks && vt->parser.callbacks->sos)
(*vt->parser.callbacks->sos)(frag, vt->parser.cbdata);
break;
case NORMAL: case NORMAL:
case CSI_LEADER: case CSI_LEADER:
case CSI_ARGS: case CSI_ARGS:
@ -112,6 +127,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
break; break;
case OSC: case OSC:
case DCS: case DCS:
case APC:
case PM:
case SOS:
string_start = bytes; string_start = bytes;
break; break;
} }
@ -150,6 +168,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
// fallthrough // fallthrough
} }
else if(c < 0x20) { // other C0 else if(c < 0x20) { // other C0
if(vt->parser.state == SOS)
continue; // All other C0s permitted in SOS
if(vterm_get_special_pty_type() == 2) { if(vterm_get_special_pty_type() == 2) {
if(c == 0x08) // BS if(c == 0x08) // BS
// Set the trick for BS output after a sequence, to delay backspace // Set the trick for BS output after a sequence, to delay backspace
@ -176,7 +197,8 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
((!IS_STRING_STATE() || c == 0x5c))) { ((!IS_STRING_STATE() || c == 0x5c))) {
c += 0x40; c += 0x40;
c1_allowed = TRUE; c1_allowed = TRUE;
string_len -= 1; if(string_len)
string_len -= 1;
vt->parser.in_esc = FALSE; vt->parser.in_esc = FALSE;
} }
else { else {
@ -279,6 +301,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
string_state: string_state:
case OSC: case OSC:
case DCS: case DCS:
case APC:
case PM:
case SOS:
if(c == 0x07 || (c1_allowed && c == 0x9c)) { if(c == 0x07 || (c1_allowed && c == 0x9c)) {
string_fragment(vt, string_start, string_len, TRUE); string_fragment(vt, string_start, string_len, TRUE);
ENTER_NORMAL_STATE(); ENTER_NORMAL_STATE();
@ -308,6 +333,12 @@ string_state:
vt->parser.v.dcs.commandlen = 0; vt->parser.v.dcs.commandlen = 0;
ENTER_STATE(DCS_COMMAND); ENTER_STATE(DCS_COMMAND);
break; break;
case 0x98: // SOS
vt->parser.string_initial = TRUE;
ENTER_STATE(SOS);
string_start = bytes + pos + 1;
string_len = 0;
break;
case 0x9b: // CSI case 0x9b: // CSI
vt->parser.v.csi.leaderlen = 0; vt->parser.v.csi.leaderlen = 0;
ENTER_STATE(CSI_LEADER); ENTER_STATE(CSI_LEADER);
@ -318,6 +349,18 @@ string_state:
string_start = bytes + pos + 1; string_start = bytes + pos + 1;
ENTER_STATE(OSC_COMMAND); ENTER_STATE(OSC_COMMAND);
break; break;
case 0x9e: // PM
vt->parser.string_initial = TRUE;
ENTER_STATE(PM);
string_start = bytes + pos + 1;
string_len = 0;
break;
case 0x9f: // APC
vt->parser.string_initial = TRUE;
ENTER_STATE(APC);
string_start = bytes + pos + 1;
string_len = 0;
break;
default: default:
do_control(vt, c); do_control(vt, c);
break; break;
@ -340,8 +383,12 @@ string_state:
} }
} }
if(string_start) if(string_start) {
string_fragment(vt, string_start, bytes + pos - string_start, FALSE); size_t string_len = bytes + pos - string_start;
if(vt->parser.in_esc)
string_len -= 1;
string_fragment(vt, string_start, string_len, FALSE);
}
return len; return len;
} }

View File

@ -79,6 +79,10 @@ static VTermState *vterm_state_new(VTerm *vt)
state->callbacks = NULL; state->callbacks = NULL;
state->cbdata = NULL; state->cbdata = NULL;
state->selection.callbacks = NULL;
state->selection.user = NULL;
state->selection.buffer = NULL;
vterm_state_newpen(state); vterm_state_newpen(state);
state->bold_is_highbright = 0; state->bold_is_highbright = 0;
@ -1615,6 +1619,174 @@ static int on_csi(const char *leader, const long args[], int argcount, const cha
return 1; return 1;
} }
static char base64_one(uint8_t b)
{
if(b < 26)
return 'A' + b;
else if(b < 52)
return 'a' + b - 26;
else if(b < 62)
return '0' + b - 52;
else if(b == 62)
return '+';
else if(b == 63)
return '/';
return 0;
}
static uint8_t unbase64one(char c)
{
if(c >= 'A' && c <= 'Z')
return c - 'A';
else if(c >= 'a' && c <= 'z')
return c - 'a' + 26;
else if(c >= '0' && c <= '9')
return c - '0' + 52;
else if(c == '+')
return 62;
else if(c == '/')
return 63;
return 0xFF;
}
static void osc_selection(VTermState *state, VTermStringFragment frag)
{
if(frag.initial) {
state->tmp.selection.mask = 0;
state->tmp.selection.state = SELECTION_INITIAL;
}
while(!state->tmp.selection.state && frag.len) {
/* Parse selection parameter */
switch(frag.str[0]) {
case 'c':
state->tmp.selection.mask |= VTERM_SELECTION_CLIPBOARD;
break;
case 'p':
state->tmp.selection.mask |= VTERM_SELECTION_PRIMARY;
break;
case 'q':
state->tmp.selection.mask |= VTERM_SELECTION_SECONDARY;
break;
case 's':
state->tmp.selection.mask |= VTERM_SELECTION_SELECT;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
state->tmp.selection.mask |= (VTERM_SELECTION_CUT0 << (frag.str[0] - '0'));
break;
case ';':
state->tmp.selection.state = SELECTION_SELECTED;
if(!state->tmp.selection.mask)
state->tmp.selection.mask = VTERM_SELECTION_SELECT|VTERM_SELECTION_CUT0;
break;
}
frag.str++;
frag.len--;
}
if(!frag.len)
return;
if(state->tmp.selection.state == SELECTION_SELECTED) {
if(frag.str[0] == '?') {
state->tmp.selection.state = SELECTION_QUERY;
}
else {
state->tmp.selection.state = SELECTION_SET_INITIAL;
state->tmp.selection.recvpartial = 0;
}
}
if(state->tmp.selection.state == SELECTION_QUERY) {
if(state->selection.callbacks->query)
(*state->selection.callbacks->query)(state->tmp.selection.mask, state->selection.user);
return;
}
if(state->selection.callbacks->set) {
size_t bufcur = 0;
char *buffer = state->selection.buffer;
uint32_t x = 0; /* Current decoding value */
int n = 0; /* Number of sextets consumed */
if(state->tmp.selection.recvpartial) {
n = state->tmp.selection.recvpartial >> 24;
x = state->tmp.selection.recvpartial & 0x03FFFF; /* could be up to 18 bits of state in here */
state->tmp.selection.recvpartial = 0;
}
while((state->selection.buflen - bufcur) >= 3 && frag.len) {
if(frag.str[0] == '=') {
if(n == 2) {
buffer[0] = (x >> 4) & 0xFF;
buffer += 1, bufcur += 1;
}
if(n == 3) {
buffer[0] = (x >> 10) & 0xFF;
buffer[1] = (x >> 2) & 0xFF;
buffer += 2, bufcur += 2;
}
while(frag.len && frag.str[0] == '=')
frag.str++, frag.len--;
n = 0;
}
else {
uint8_t b = unbase64one(frag.str[0]);
if(b == 0xFF) {
DEBUG_LOG1("base64decode bad input %02X\n", (uint8_t)frag.str[0]);
}
else {
x = (x << 6) | b;
n++;
}
frag.str++, frag.len--;
if(n == 4) {
buffer[0] = (x >> 16) & 0xFF;
buffer[1] = (x >> 8) & 0xFF;
buffer[2] = (x >> 0) & 0xFF;
buffer += 3, bufcur += 3;
x = 0;
n = 0;
}
}
if(!frag.len || (state->selection.buflen - bufcur) < 3) {
if(bufcur) {
(*state->selection.callbacks->set)(state->tmp.selection.mask, (VTermStringFragment){
.str = state->selection.buffer,
.len = bufcur,
.initial = state->tmp.selection.state == SELECTION_SET_INITIAL,
.final = frag.final,
}, state->selection.user);
state->tmp.selection.state = SELECTION_SET;
}
buffer = state->selection.buffer;
bufcur = 0;
}
}
if(n)
state->tmp.selection.recvpartial = (n << 24) | x;
}
}
static int on_osc(int command, VTermStringFragment frag, void *user) static int on_osc(int command, VTermStringFragment frag, void *user)
{ {
VTermState *state = user; VTermState *state = user;
@ -1656,6 +1828,12 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
settermprop_string(state, VTERM_PROP_CURSORCOLOR, frag); settermprop_string(state, VTERM_PROP_CURSORCOLOR, frag);
return 1; return 1;
case 52:
if(state->selection.callbacks)
osc_selection(state, frag);
return 1;
default: default:
if(state->fallbacks && state->fallbacks->osc) if(state->fallbacks && state->fallbacks->osc)
if((*state->fallbacks->osc)(command, frag, state->fbdata)) if((*state->fallbacks->osc)(command, frag, state->fbdata))
@ -1718,12 +1896,14 @@ static void request_status_string(VTermState *state, VTermStringFragment frag)
case 'r': case 'r':
// Query DECSTBM // Query DECSTBM
vterm_push_output_sprintf_dcs(vt, "1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state)); vterm_push_output_sprintf_str(vt, C1_DCS, TRUE,
"1$r%d;%dr", state->scrollregion_top+1, SCROLLREGION_BOTTOM(state));
return; return;
case 's': case 's':
// Query DECSLRM // Query DECSLRM
vterm_push_output_sprintf_dcs(vt, "1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state)); vterm_push_output_sprintf_str(vt, C1_DCS, TRUE,
"1$r%d;%ds", SCROLLREGION_LEFT(state)+1, SCROLLREGION_RIGHT(state));
return; return;
case ' '|('q'<<8): { case ' '|('q'<<8): {
@ -1736,17 +1916,19 @@ static void request_status_string(VTermState *state, VTermStringFragment frag)
} }
if(state->mode.cursor_blink) if(state->mode.cursor_blink)
reply--; reply--;
vterm_push_output_sprintf_dcs(vt, "1$r%d q", reply); vterm_push_output_sprintf_str(vt, C1_DCS, TRUE,
"1$r%d q", reply);
return; return;
} }
case '\"'|('q'<<8): case '\"'|('q'<<8):
// Query DECSCA // Query DECSCA
vterm_push_output_sprintf_dcs(vt, "1$r%d\"q", state->protected_cell ? 1 : 2); vterm_push_output_sprintf_str(vt, C1_DCS, TRUE,
"1$r%d\"q", state->protected_cell ? 1 : 2);
return; return;
} }
vterm_push_output_sprintf_dcs(state->vt, "0$r%s", tmp); vterm_push_output_sprintf_str(state->vt, C1_DCS, TRUE, "0$r%s", tmp);
} }
static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user) static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
@ -1765,6 +1947,42 @@ static int on_dcs(const char *command, size_t commandlen, VTermStringFragment fr
return 0; return 0;
} }
static int on_apc(VTermStringFragment frag, void *user)
{
VTermState *state = user;
if(state->fallbacks && state->fallbacks->apc)
if((*state->fallbacks->apc)(frag, state->fbdata))
return 1;
/* No DEBUG_LOG because all APCs are unhandled */
return 0;
}
static int on_pm(VTermStringFragment frag, void *user)
{
VTermState *state = user;
if(state->fallbacks && state->fallbacks->pm)
if((*state->fallbacks->pm)(frag, state->fbdata))
return 1;
/* No DEBUG_LOG because all PMs are unhandled */
return 0;
}
static int on_sos(VTermStringFragment frag, void *user)
{
VTermState *state = user;
if(state->fallbacks && state->fallbacks->sos)
if((*state->fallbacks->sos)(frag, state->fbdata))
return 1;
/* No DEBUG_LOG because all SOSs are unhandled */
return 0;
}
static int on_resize(int rows, int cols, void *user) static int on_resize(int rows, int cols, void *user)
{ {
VTermState *state = user; VTermState *state = user;
@ -1866,6 +2084,9 @@ static const VTermParserCallbacks parser_callbacks = {
on_csi, // csi on_csi, // csi
on_osc, // osc on_osc, // osc
on_dcs, // dcs on_dcs, // dcs
on_apc, // apc
on_pm, // pm
on_sos, // sos
on_resize // resize on_resize // resize
}; };
@ -1909,6 +2130,8 @@ void vterm_state_reset(VTermState *state, int hard)
state->mode.bracketpaste = 0; state->mode.bracketpaste = 0;
state->mode.report_focus = 0; state->mode.report_focus = 0;
state->mouse_flags = 0;
state->vt->mode.ctrl8bit = 0; state->vt->mode.ctrl8bit = 0;
{ {
@ -2087,3 +2310,96 @@ const VTermLineInfo *vterm_state_get_lineinfo(const VTermState *state, int row)
{ {
return state->lineinfo + row; return state->lineinfo + row;
} }
void vterm_state_set_selection_callbacks(VTermState *state, const VTermSelectionCallbacks *callbacks, void *user,
char *buffer, size_t buflen)
{
if(buflen && !buffer)
buffer = vterm_allocator_malloc(state->vt, buflen);
state->selection.callbacks = callbacks;
state->selection.user = user;
state->selection.buffer = buffer;
state->selection.buflen = buflen;
}
void vterm_state_send_selection(VTermState *state, VTermSelectionMask mask, VTermStringFragment frag)
{
VTerm *vt = state->vt;
if(frag.initial) {
/* TODO: support sending more than one mask bit */
static char selection_chars[] = "cpqs";
int idx;
for(idx = 0; idx < 4; idx++)
if(mask & (1 << idx))
break;
vterm_push_output_sprintf_str(vt, C1_OSC, FALSE, "52;%c;", selection_chars[idx]);
state->tmp.selection.sendpartial = 0;
}
if(frag.len) {
size_t bufcur = 0;
char *buffer = state->selection.buffer;
uint32_t x = 0;
int n = 0;
if(state->tmp.selection.sendpartial) {
n = state->tmp.selection.sendpartial >> 24;
x = state->tmp.selection.sendpartial & 0xFFFFFF;
state->tmp.selection.sendpartial = 0;
}
while((state->selection.buflen - bufcur) >= 4 && frag.len) {
x = (x << 8) | frag.str[0];
n++;
frag.str++, frag.len--;
if(n == 3) {
buffer[0] = base64_one((x >> 18) & 0x3F);
buffer[1] = base64_one((x >> 12) & 0x3F);
buffer[2] = base64_one((x >> 6) & 0x3F);
buffer[3] = base64_one((x >> 0) & 0x3F);
buffer += 4, bufcur += 4;
x = 0;
n = 0;
}
if(!frag.len || (state->selection.buflen - bufcur) < 4) {
if(bufcur)
vterm_push_output_bytes(vt, state->selection.buffer, bufcur);
buffer = state->selection.buffer;
bufcur = 0;
}
}
if(n)
state->tmp.selection.sendpartial = (n << 24) | x;
}
if(frag.final) {
if(state->tmp.selection.sendpartial) {
int n = state->tmp.selection.sendpartial >> 24;
uint32_t x = state->tmp.selection.sendpartial & 0xFFFFFF;
char *buffer = state->selection.buffer;
/* n is either 1 or 2 now */
x <<= (n == 1) ? 16 : 8;
buffer[0] = base64_one((x >> 18) & 0x3F);
buffer[1] = base64_one((x >> 12) & 0x3F);
buffer[2] = (n == 1) ? '=' : base64_one((x >> 6) & 0x3F);
buffer[3] = '=';
vterm_push_output_sprintf_str(vt, 0, TRUE, "%.*s", 4, buffer);
}
else
vterm_push_output_sprintf_str(vt, 0, TRUE, "");
}
}

View File

@ -200,27 +200,35 @@ INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, cons
va_end(args); va_end(args);
} }
INTERNAL void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...) INTERNAL void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, int term, const char *fmt, ...)
{ {
size_t cur; size_t cur;
va_list args; va_list args;
cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, if(ctrl) {
vt->mode.ctrl8bit ? "\x90" : ESC_S "P"); // DCS if(ctrl >= 0x80 && !vt->mode.ctrl8bit)
cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len,
ESC_S "%c", ctrl - 0x40);
else
cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len,
"%c", ctrl);
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);
}
va_start(args, fmt); va_start(args, fmt);
vterm_push_output_vsprintf(vt, fmt, args); vterm_push_output_vsprintf(vt, fmt, args);
va_end(args); va_end(args);
cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len, if(term) {
vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len,
if(cur >= vt->tmpbuffer_len) vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST
return; if(cur >= vt->tmpbuffer_len)
vterm_push_output_bytes(vt, vt->tmpbuffer, cur); return;
vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
}
} }
size_t vterm_output_get_buffer_size(const VTerm *vt) size_t vterm_output_get_buffer_size(const VTerm *vt)

View File

@ -154,7 +154,26 @@ struct VTermState
/* Temporary state for DECRQSS parsing */ /* Temporary state for DECRQSS parsing */
union { union {
char decrqss[4]; char decrqss[4];
struct {
uint16_t mask;
enum {
SELECTION_INITIAL,
SELECTION_SELECTED,
SELECTION_QUERY,
SELECTION_SET_INITIAL,
SELECTION_SET,
} state : 8;
uint32_t recvpartial;
uint32_t sendpartial;
} selection;
} tmp; } tmp;
struct {
const VTermSelectionCallbacks *callbacks;
void *user;
char *buffer;
size_t buflen;
} selection;
}; };
struct VTerm struct VTerm
@ -181,6 +200,9 @@ struct VTerm
OSC_COMMAND, OSC_COMMAND,
OSC, OSC,
DCS, DCS,
APC,
PM,
SOS,
} state; } state;
unsigned int in_esc : 1; unsigned int in_esc : 1;
@ -248,7 +270,7 @@ void vterm_push_output_bytes(VTerm *vt, const char *bytes, size_t len);
void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args); void vterm_push_output_vsprintf(VTerm *vt, const char *format, va_list args);
void vterm_push_output_sprintf(VTerm *vt, const char *format, ...); void vterm_push_output_sprintf(VTerm *vt, const char *format, ...);
void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...); void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, const char *fmt, ...);
void vterm_push_output_sprintf_dcs(VTerm *vt, const char *fmt, ...); void vterm_push_output_sprintf_str(VTerm *vt, unsigned char ctrl, int term, const char *fmt, ...);
void vterm_state_free(VTermState *state); void vterm_state_free(VTermState *state);

View File

@ -17,15 +17,15 @@ PUSH "\x1f"
PUSH "\x83" PUSH "\x83"
control 0x83 control 0x83
PUSH "\x9f" PUSH "\x99"
control 0x9f control 0x99
!C1 7bit !C1 7bit
PUSH "\e\x43" PUSH "\e\x43"
control 0x83 control 0x83
PUSH "\e\x5f" PUSH "\e\x59"
control 0x9f control 0x99
!High bytes !High bytes
PUSH "\xa0\xcc\xfe" PUSH "\xa0\xcc\xfe"
@ -184,6 +184,12 @@ PUSH "\ePHello\e\\"
PUSH "\x{90}Hello\x9c" PUSH "\x{90}Hello\x9c"
dcs ["Hello"] dcs ["Hello"]
!Split write of 7bit ST
PUSH "\ePABC\e"
dcs ["ABC"
PUSH "\\"
dcs ]
!Escape cancels DCS, starts Escape !Escape cancels DCS, starts Escape
PUSH "\ePSomething\e9" PUSH "\ePSomething\e9"
escape "9" escape "9"
@ -198,6 +204,48 @@ PUSH "\ePBy\ne\x07"
control 10 control 10
dcs "e"] dcs "e"]
!APC BEL
PUSH "\e_Hello\x07"
apc ["Hello"]
!APC ST (7bit)
PUSH "\e_Hello\e\\"
apc ["Hello"]
!APC ST (8bit)
PUSH "\x{9f}Hello\x9c"
apc ["Hello"]
!PM BEL
PUSH "\e^Hello\x07"
pm ["Hello"]
!PM ST (7bit)
PUSH "\e^Hello\e\\"
pm ["Hello"]
!PM ST (8bit)
PUSH "\x{9e}Hello\x9c"
pm ["Hello"]
!SOS BEL
PUSH "\eXHello\x07"
sos ["Hello"]
!SOS ST (7bit)
PUSH "\eXHello\e\\"
sos ["Hello"]
!SOS ST (8bit)
PUSH "\x{98}Hello\x9c"
sos ["Hello"]
!SOS can contain any C0 or C1 code
PUSH "\eXABC\x01DEF\e\\"
sos ["ABC\x01DEF"]
PUSH "\eXABC\x99DEF\e\\"
sos ["ABC\x{99}DEF"]
!NUL ignored !NUL ignored
PUSH "\x{00}" PUSH "\x{00}"

View File

@ -170,3 +170,12 @@ PUSH "\e[?1006\$p"
output "\e[?1006;2\$y" output "\e[?1006;2\$y"
PUSH "\e[?1015\$p" PUSH "\e[?1015\$p"
output "\e[?1015;1\$y" output "\e[?1015;1\$y"
!Mouse disabled reports nothing
RESET
settermprop 1 true
settermprop 2 true
settermprop 7 1
MOUSEMOVE 0,0 0
MOUSEBTN d 1 0
MOUSEBTN u 1 0

View File

@ -17,3 +17,15 @@ PUSH "\e]27;Something\e\\"
!Unrecognised DCS !Unrecognised DCS
PUSH "\ePz123\e\\" PUSH "\ePz123\e\\"
dcs ["z123"] dcs ["z123"]
!Unrecognised APC
PUSH "\e_z123\e\\"
apc ["z123"]
!Unrecognised PM
PUSH "\e^z123\e\\"
pm ["z123"]
!Unrecognised SOS
PUSH "\eXz123\e\\"
sos ["z123"]

View File

@ -0,0 +1,55 @@
INIT
UTF8 1
WANTSTATE
!Set clipboard; final chunk len 4
PUSH "\e]52;c;SGVsbG8s\e\\"
selection-set mask=0001 ["Hello,"]
!Set clipboard; final chunk len 3
PUSH "\e]52;c;SGVsbG8sIHc=\e\\"
selection-set mask=0001 ["Hello, w"]
!Set clipboard; final chunk len 2
PUSH "\e]52;c;SGVsbG8sIHdvcmxkCg==\e\\"
selection-set mask=0001 ["Hello, world\n"]
!Set clipboard; split between chunks
PUSH "\e]52;c;SGVs"
selection-set mask=0001 ["Hel"
PUSH "bG8s\e\\"
selection-set mask=0001 "lo,"]
!Set clipboard; split within chunk
PUSH "\e]52;c;SGVsbG"
selection-set mask=0001 ["Hel"
PUSH "8s\e\\"
selection-set mask=0001 "lo,"]
!Query clipboard
PUSH "\e]52;c;?\e\\"
selection-query mask=0001
!Send clipboard; final chunk len 4
SELECTION 1 ["Hello,"]
output "\e]52;c;SGVsbG8s\e\\"
!Send clipboard; final chunk len 3
SELECTION 1 ["Hello, w"]
output "\e]52;c;SGVsbG8sIHc=\e\\"
!Send clipboard; final chunk len 2
SELECTION 1 ["Hello, world\n"]
output "\e]52;c;SGVsbG8sIHdvcmxkCg==\e\\"
!Send clipboard; split between chunks
SELECTION 1 ["Hel"
output "\e]52;c;SGVs"
SELECTION 1 "lo,"]
output "bG8s\e\\"
!Send clipboard; split within chunk
SELECTION 1 ["Hello"
output "\e]52;c;SGVs"
SELECTION 1 ","]
output "bG8s\e\\"

View File

@ -13,7 +13,8 @@ static size_t inplace_hex2bytes(char *s)
while(*inpos) { while(*inpos) {
unsigned int ch; unsigned int ch;
sscanf(inpos, "%2x", &ch); if(sscanf(inpos, "%2x", &ch) < 1)
break;
*outpos = ch; *outpos = ch;
outpos += 1; inpos += 2; outpos += 1; inpos += 2;
} }
@ -98,7 +99,7 @@ static void term_output(const char *s, size_t len, void *user UNUSED)
static void printhex(const char *s, size_t len) static void printhex(const char *s, size_t len)
{ {
while(len--) while(len--)
printf("%02x", (s++)[0]); printf("%02x", (uint8_t)(s++)[0]);
} }
static int parser_text(const char bytes[], size_t len, void *user UNUSED) static int parser_text(const char bytes[], size_t len, void *user UNUSED)
@ -216,6 +217,57 @@ static int parser_dcs(const char *command, size_t commandlen, VTermStringFragmen
return 1; return 1;
} }
static int parser_apc(VTermStringFragment frag, void *user UNUSED)
{
printf("apc ");
if(frag.initial)
printf("[");
printhex(frag.str, frag.len);
if(frag.final)
printf("]");
printf("\n");
return 1;
}
static int parser_pm(VTermStringFragment frag, void *user UNUSED)
{
printf("pm ");
if(frag.initial)
printf("[");
printhex(frag.str, frag.len);
if(frag.final)
printf("]");
printf("\n");
return 1;
}
static int parser_sos(VTermStringFragment frag, void *user UNUSED)
{
printf("sos ");
if(frag.initial)
printf("[");
printhex(frag.str, frag.len);
if(frag.final)
printf("]");
printf("\n");
return 1;
}
static VTermParserCallbacks parser_cbs = { static VTermParserCallbacks parser_cbs = {
parser_text, // text parser_text, // text
parser_control, // control parser_control, // control
@ -223,6 +275,9 @@ static VTermParserCallbacks parser_cbs = {
parser_csi, // csi parser_csi, // csi
parser_osc, // osc parser_osc, // osc
parser_dcs, // dcs parser_dcs, // dcs
parser_apc, // apc
parser_pm, // pm
parser_sos, // sos
NULL // resize NULL // resize
}; };
@ -230,7 +285,10 @@ static VTermStateFallbacks fallbacks = {
parser_control, // control parser_control, // control
parser_csi, // csi parser_csi, // csi
parser_osc, // osc parser_osc, // osc
parser_dcs // dcs parser_dcs, // dcs
parser_apc, // dcs
parser_pm, // pm
parser_sos // sos
}; };
/* These callbacks are shared by State and Screen */ /* These callbacks are shared by State and Screen */
@ -414,6 +472,31 @@ VTermStateCallbacks state_cbs = {
state_setlineinfo, // setlineinfo state_setlineinfo, // setlineinfo
}; };
static int selection_set(VTermSelectionMask mask, VTermStringFragment frag, void *user UNUSED)
{
printf("selection-set mask=%04X ", mask);
if(frag.initial)
printf("[");
printhex(frag.str, frag.len);
if(frag.final)
printf("]");
printf("\n");
return 1;
}
static int selection_query(VTermSelectionMask mask, void *user UNUSED)
{
printf("selection-query mask=%04X\n", mask);
return 1;
}
VTermSelectionCallbacks selection_cbs = {
.set = selection_set,
.query = selection_query,
};
static int want_screen_damage = 0; static int want_screen_damage = 0;
static int want_screen_damage_cells = 0; static int want_screen_damage_cells = 0;
static int screen_damage(VTermRect rect, void *user UNUSED) static int screen_damage(VTermRect rect, void *user UNUSED)
@ -555,6 +638,7 @@ int main(int argc UNUSED, char **argv UNUSED)
if(!state) { if(!state) {
state = vterm_obtain_state(vt); state = vterm_obtain_state(vt);
vterm_state_set_callbacks(state, &state_cbs, NULL); vterm_state_set_callbacks(state, &state_cbs, NULL);
vterm_state_set_selection_callbacks(state, &selection_cbs, NULL, NULL, 1024);
vterm_state_set_bold_highbright(state, 1); vterm_state_set_bold_highbright(state, 1);
vterm_state_reset(state, 1); vterm_state_reset(state, 1);
} }
@ -768,6 +852,32 @@ int main(int argc UNUSED, char **argv UNUSED)
vterm_mouse_button(vt, button, (press == 'd' || press == 'D'), mod); vterm_mouse_button(vt, button, (press == 'd' || press == 'D'), mod);
} }
else if(strstartswith(line, "SELECTION ")) {
char *linep = line + 10;
unsigned int mask;
int len;
VTermStringFragment frag = { 0 };
sscanf(linep, "%x%n", &mask, &len);
linep += len;
while(linep[0] == ' ')
linep++;
if(linep[0] == '[') {
frag.initial = TRUE;
linep++;
while(linep[0] == ' ')
linep++;
}
frag.len = inplace_hex2bytes(linep);
frag.str = linep;
linep += frag.len * 2;
while(linep[0] == ' ')
linep++;
if(linep[0] == ']') {
frag.final = TRUE;
}
vterm_state_send_selection(state, mask, frag);
}
else if(strstartswith(line, "DAMAGEMERGE ")) { else if(strstartswith(line, "DAMAGEMERGE ")) {
char *linep = line + 12; char *linep = line + 12;
while(linep[0] == ' ') while(linep[0] == ' ')

View File

@ -85,6 +85,11 @@ sub do_line
my $string = eval($2); my $string = eval($2);
$line = "$1 " . unpack "H*", $string; $line = "$1 " . unpack "H*", $string;
} }
elsif( $line =~ m/^(SELECTION \d+) +(\[?)(.*?)(\]?)$/ ) {
# we're evil
my $string = eval($3);
$line = "$1 $2 " . unpack( "H*", $string ) . " $4";
}
do_onetest if defined $command; do_onetest if defined $command;
@ -113,15 +118,18 @@ sub do_line
$line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final"; $line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final";
} }
elsif( $line =~ m/^(escape|dcs) (\[?)(.*?)(\]?)$/ ) { elsif( $line =~ m/^(escape|dcs|apc|pm|sos) (\[?)(.*?)(\]?)$/ ) {
$line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", eval($3) ) . "$4"; $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", length $3 ? 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";
} }
elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc) / ) { elsif( $line =~ m/^(?:movecursor|scrollrect|moverect|erase|damage|sb_pushline|sb_popline|settermprop|setmousefunc|selection-query) / ) {
# no conversion # no conversion
} }
elsif( $line =~ m/^(selection-set) (.*?) (\[?)(.*?)(\]?)$/ ) {
$line = "$1 $2 $3" . join( "", map sprintf("%02x", $_), unpack "C*", eval($4) ) . "$5";
}
else { else {
warn "Unrecognised test expectation '$line'\n"; warn "Unrecognised test expectation '$line'\n";
} }

View File

@ -1,6 +1,5 @@
prefix=@PREFIX@
libdir=@LIBDIR@ libdir=@LIBDIR@
includedir=${prefix}/include includedir=@INCDIR@
Name: vterm Name: vterm
Description: Abstract VT220/Xterm/ECMA-48 emulation library Description: Abstract VT220/Xterm/ECMA-48 emulation library

View File

@ -4526,7 +4526,10 @@ static VTermStateFallbacks state_fallbacks = {
NULL, // control NULL, // control
parse_csi, // csi parse_csi, // csi
parse_osc, // osc parse_osc, // osc
NULL // dcs NULL, // dcs
NULL, // apc
NULL, // pm
NULL // sos
}; };
/* /*

View File

@ -757,6 +757,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 */
/**/
3666,
/**/ /**/
3665, 3665,
/**/ /**/