summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2021-11-24 19:30:55 +0000
committerBram Moolenaar <Bram@vim.org>2021-11-24 19:30:55 +0000
commit7da341560ec8db7e81cd80092b046b60a482fbbe (patch)
treef730b64f0d74c28697b322dfe965a071170028c4
parent19916a8c8920b6a1fd737ffa6d4e363fc7a96319 (diff)
downloadvim-git-7da341560ec8db7e81cd80092b046b60a482fbbe.tar.gz
patch 8.2.3666: libvterm is outdatedv8.2.3666
Problem: Libvterm is outdated. Solution: Include patches from revision 769 to revision 789.
-rw-r--r--Filelist1
-rw-r--r--src/libvterm/Makefile4
-rw-r--r--src/libvterm/doc/seqs.txt483
-rw-r--r--src/libvterm/include/vterm.h27
-rw-r--r--src/libvterm/src/mouse.c3
-rw-r--r--src/libvterm/src/parser.c55
-rw-r--r--src/libvterm/src/state.c326
-rw-r--r--src/libvterm/src/vterm.c32
-rw-r--r--src/libvterm/src/vterm_internal.h24
-rw-r--r--src/libvterm/t/02parser.test56
-rw-r--r--src/libvterm/t/17state_mouse.test9
-rw-r--r--src/libvterm/t/29state_fallback.test12
-rw-r--r--src/libvterm/t/40state_selection.test55
-rw-r--r--src/libvterm/t/harness.c116
-rw-r--r--src/libvterm/t/run-test.pl14
-rw-r--r--src/libvterm/vterm.pc.in3
-rw-r--r--src/terminal.c5
-rw-r--r--src/version.c2
18 files changed, 971 insertions, 256 deletions
diff --git a/Filelist b/Filelist
index 1ab6e1b1c..f89289d18 100644
--- a/Filelist
+++ b/Filelist
@@ -377,6 +377,7 @@ SRC_ALL = \
src/libvterm/t/30state_pen.test \
src/libvterm/t/31state_rep.test \
src/libvterm/t/32state_flow.test \
+ src/libvterm/t/40state_selection.test \
src/libvterm/t/60screen_ascii.test \
src/libvterm/t/61screen_unicode.test \
src/libvterm/t/62screen_damage.test \
diff --git a/src/libvterm/Makefile b/src/libvterm/Makefile
index be01dd070..2f83e0d68 100644
--- a/src/libvterm/Makefile
+++ b/src/libvterm/Makefile
@@ -37,7 +37,7 @@ INCFILES=$(TBLFILES:.tbl=.inc)
HFILES_INT=$(sort $(wildcard src/*.h)) $(HFILES)
VERSION_MAJOR=0
-VERSION_MINOR=1
+VERSION_MINOR=2
VERSION_CURRENT=0
VERSION_REVISION=0
@@ -97,7 +97,7 @@ install-inc:
install -d $(DESTDIR)$(INCDIR)
install -m644 $(HFILES) $(DESTDIR)$(INCDIR)
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 -d $(DESTDIR)$(LIBDIR)
diff --git a/src/libvterm/doc/seqs.txt b/src/libvterm/doc/seqs.txt
index aa15fec3d..7f21367e9 100644
--- a/src/libvterm/doc/seqs.txt
+++ b/src/libvterm/doc/seqs.txt
@@ -4,228 +4,275 @@ between states.
1 = VT100
2 = VT220
3 = VT320
+x = xterm
- C0 controls
-
-123 0x00 = NUL
-123 0x07 = BEL
-123 0x08 = BS
-123 0x09 = HT
-123 0x0A = LF
-123 0x0B = VT
-123 0x0C = FF
-123 0x0D = CR
-123 0x0E = LS1
-123 0x0F = LS0
- (0x18 = CAN)
- (0x1A = SUB)
- (0x1B = ESC)
-
-123 0x7f = DEL (ignored)
-
- C1 controls
-
-123 0x84 = IND
-123 0x85 = NEL
-123 0x88 = HTS
-123 0x8D = RI
- 23 0x8e = SS2
- 23 0x8f = SS3
- (0x90 = DCS)
- (0x9B = CSI)
- (0x9C = ST)
- (0x9D = OSC)
-
- Escape sequences
- - excluding sequences that are C1 aliases
-
-123 ESC () = SCS, select character set (G0, G1)
- 23 ESC *+ = SCS, select character set (G2, G3)
-123 ESC 7 = DECSC - save cursor
-123 ESC 8 = DECRC - restore cursor
-123 ESC # 3 = DECDHL, double-height line (top half)
-123 ESC # 4 = DECDHL, double-height line (bottom half)
-123 ESC # 5 = DECSWL, single-width single-height line
-123 ESC # 6 = DECDWL, double-width single-height line
-123 ESC # 8 = DECALN
-123 ESC < = Ignored (used by VT100 to exit VT52 mode)
-123 ESC = = DECKPAM, keypad application mode
-123 ESC > = DECKPNM, keypad numeric mode
- 23 ESC Sp F = S7C1T
- 23 ESC Sp G = S8C1T
- (ESC P = DCS)
- (ESC [ = CSI)
- (ESC \ = ST)
- (ESC ] = OSC)
-123 ESC c = RIS, reset initial state
- 3 ESC n = LS2
- 3 ESC o = LS3
- 3 ESC ~ = LS1R
- 3 ESC } = LS2R
- 3 ESC | = LS3R
-
- DCSes
-
- 3 DCS $ q ST = DECRQSS
- 3 m = Request SGR
- Sp q = Request DECSCUSR
- 3 " q = Request DECSCA
- 3 r = Request DECSTBM
- s = Request DECSLRM
-
- CSIs
- 23 CSI @ = ICH
-123 CSI A = CUU
-123 CSI B = CUD
-123 CSI C = CUF
-123 CSI D = CUB
- CSI E = CNL
- CSI F = CPL
- CSI G = CHA
-123 CSI H = CUP
- CSI I = CHT
-123 CSI J = ED
- 23 CSI ? J = DECSED, selective erase in display
-123 CSI K = EL
- 23 CSI ? K = DECSEL, selective erase in line
- 23 CSI L = IL
- 23 CSI M = DL
- 23 CSI P = DCH
- CSI S = SU
- CSI T = SD
- 23 CSI X = ECH
- CSI Z = CBT
- CSI ` = HPA
- CSI a = HPR
- CSI b = REP
-123 CSI c = DA, device attributes
-123 0 = DA
- 23 CSI > c = DECSDA
- 23 0 = SDA
- CSI d = VPA
- CSI e = VPR
-123 CSI f = HVP
-123 CSI g = TBC
-123 CSI h = SM, Set mode
-123 CSI ? h = DECSM, DEC set mode
- CSI j = HPB
- CSI k = VPB
-123 CSI l = RM, Reset mode
-123 CSI ? l = DECRM, DEC reset mode
-123 CSI m = SGR, Set Graphic Rendition
-123 CSI n = DSR, Device Status Report
- 23 5 = operating status
- 23 6 = CPR = cursor position
- 23 CSI ? n = DECDSR; behaves as DSR but uses CSI ? instead of CSI to respond
- 23 CSI ! p = DECSTR, soft terminal reset
- 3 CSI ? $ p = DECRQM, request mode
- CSI Sp q = DECSCUSR (odd numbers blink, even numbers solid)
- 1 or 2 = block
- 3 or 4 = underline
- 5 or 6 = I-beam to left
- 23 CSI " q = DECSCA, select character attributes
-123 CSI r = DECSTBM
- CSI s = DECSLRM
- CSI ' } = DECIC
- CSI ' ~ = DECDC
-
- OSCs
-
- OSC 0; = Set icon name and title
- OSC 1; = Set icon name
- OSC 2; = Set title
-
- Standard modes
-
- 23 SM 4 = IRM
-123 SM 20 = NLM, linefeed/newline
-
- DEC modes
-
-123 DECSM 1 = DECCKM, cursor keys
-123 DECSM 5 = DECSCNM, screen
-123 DECSM 6 = DECOM, origin
-123 DECSM 7 = DECAWM, autowrap
- DECSM 12 = Cursor blink
- 23 DECSM 25 = DECTCEM, text cursor enable
- DECSM 69 = DECVSSM, vertical screen split
- DECSM 1000 = Mouse click/release tracking
- DECSM 1002 = Mouse click/release/drag tracking
- DECSM 1003 = Mouse all movements tracking
- DECSM 1004 = Focus in/out reporting
- DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended
- DECSM 1006 = Mouse protocol SGR
- DECSM 1015 = Mouse protocol rxvt
- DECSM 1047 = Altscreen
- DECSM 1048 = Save cursor
- DECSM 1049 = 1047 + 1048
- DECSM 2004 = Bracketed paste
-
- Graphic Renditions
-
-123 SGR 0 = Reset
-123 SGR 1 = Bold on
- SGR 3 = Italic on
-123 SGR 4 = Underline single
- SGR 4:x = Underline style
-123 SGR 5 = Blink on
-123 SGR 7 = Reverse on
- SGR 8 = Conceal on
- SGR 9 = Strikethrough on
- SGR 10-19 = Select font
- SGR 21 = Underline double
- 23 SGR 22 = Bold off
- SGR 23 = Italic off
- 23 SGR 24 = Underline off
- 23 SGR 25 = Blink off
- 23 SGR 27 = Reverse off
- SGR 28 = Conceal off
- SGR 29 = Strikethrough off
- SGR 30-37 = Foreground ANSI
- SGR 38 = Foreground alternative palette
- SGR 39 = Foreground default
- SGR 40-47 = Background ANSI
- SGR 48 = Background alternative palette
- SGR 49 = Background default
- SGR 90-97 = Foreground ANSI high-intensity
- SGR 100-107 = Background ANSI high-intensity
+ C0 controls
+
+123 0x00 = NUL
+123x 0x07 = BEL
+123x 0x08 = BS
+123x 0x09 = HT
+123x 0x0A = LF
+123x 0x0B = VT
+123x 0x0C = FF
+123x 0x0D = CR
+123x 0x0E = LS1
+123x 0x0F = LS0
+ (0x18 = CAN)
+ (0x1A = SUB)
+ (0x1B = ESC)
+
+123 0x7f = DEL (ignored)
+
+ C1 controls
+
+123x 0x84 = IND
+123x 0x85 = NEL
+123x 0x88 = HTS
+123x 0x8D = RI
+ 23x 0x8E = SS2
+ 23x 0x8F = SS3
+ (0x90 = DCS)
+ (0x98 = SOS)
+ (0x9B = CSI)
+ (0x9C = ST)
+ (0x9D = OSC)
+ (0x9E = PM)
+ (0x9F = APC)
+
+ Escape sequences
+ - excluding sequences that are C1 aliases
+
+123x ESC ( = SCS, select character set G0
+123x ESC ) = SCS, select character set G1
+ 23x ESC * = SCS, select character set G2
+ 23x ESC + = SCS, select character set G3
+123x ESC 7 = DECSC - save cursor
+123x ESC 8 = DECRC - restore cursor
+123x ESC # 3 = DECDHL, double-height line (top half)
+123x ESC # 4 = DECDHL, double-height line (bottom half)
+123x ESC # 5 = DECSWL, single-width single-height line
+123x ESC # 6 = DECDWL, double-width single-height line
+123x ESC # 8 = DECALN
+123 ESC < = Ignored (used by VT100 to exit VT52 mode)
+123x ESC = = DECKPAM, keypad application mode
+123x ESC > = DECKPNM, keypad numeric mode
+ 23x ESC Sp F = S7C1T
+ 23x ESC Sp G = S8C1T
+ (ESC P = DCS)
+ (ESC X = SOS)
+ (ESC [ = CSI)
+ (ESC \ = ST)
+ (ESC ] = OSC)
+ (ESC ^ = PM)
+ (ESC _ = APC)
+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
+
+ 3x DCS $ q ST = DECRQSS
+ 3x m = Request SGR
+ x Sp q = Request DECSCUSR
+ 3x " q = Request DECSCA
+ 3x r = Request DECSTBM
+ x s = Request DECSLRM
+
+ CSIs
+ 23x CSI @ = ICH
+123x CSI A = CUU
+123x CSI B = CUD
+123x CSI C = CUF
+123x CSI D = CUB
+ x CSI E = CNL
+ x CSI F = CPL
+ x CSI G = CHA
+123x CSI H = CUP
+ x CSI I = CHT
+123x CSI J = ED
+ 23x CSI ? J = DECSED, selective erase in display
+123x CSI K = EL
+ 23x CSI ? K = DECSEL, selective erase in line
+ 23x CSI L = IL
+ 23x CSI M = DL
+ 23x CSI P = DCH
+ x CSI S = SU
+ x CSI T = SD
+ 23x CSI X = ECH
+ x CSI Z = CBT
+ x CSI ` = HPA
+ x CSI a = HPR
+ x CSI b = REP
+123x CSI c = DA, device attributes
+123 0 = DA
+ 23x CSI > c = DECSDA
+ 23 0 = SDA
+ x CSI d = VPA
+ x CSI e = VPR
+123x CSI f = HVP
+123x CSI g = TBC
+123x CSI h = SM, Set mode
+123x CSI ? h = DECSM, DEC set mode
+ CSI j = HPB
+ CSI k = VPB
+123x CSI l = RM, Reset mode
+123x CSI ? l = DECRM, DEC reset mode
+123x CSI m = SGR, Set Graphic Rendition
+123x CSI n = DSR, Device Status Report
+ 23x 5 = operating status
+ 23x 6 = CPR = cursor position
+ 23x CSI ? n = DECDSR; behaves as DSR but uses CSI ? instead of CSI to respond
+ 23x CSI ! p = DECSTR, soft terminal reset
+ 3x CSI ? $ p = DECRQM, request private mode
+ x CSI Sp q = DECSCUSR (odd numbers blink, even numbers solid)
+ 1 or 2 = block
+ 3 or 4 = underline
+ 5 or 6 = I-beam to left
+ 23x CSI " q = DECSCA, select character attributes
+123x CSI r = DECSTBM
+ x CSI s = DECSLRM
+ x CSI ' } = DECIC
+ x CSI ' ~ = DECDC
+
+ OSCs
+
+ x OSC 0; = Set icon name and title
+ x OSC 1; = Set icon name
+ x OSC 2; = Set title
+ x OSC 52; = Selection management
+
+ Standard modes
+
+ 23x SM 4 = IRM
+123x SM 20 = NLM, linefeed/newline
+
+ DEC modes
+
+123x DECSM 1 = DECCKM, cursor keys
+123x DECSM 5 = DECSCNM, screen
+123x DECSM 6 = DECOM, origin
+123x DECSM 7 = DECAWM, autowrap
+ x DECSM 12 = Cursor blink
+ 23x DECSM 25 = DECTCEM, text cursor enable
+ x DECSM 69 = DECVSSM, vertical screen split
+ x DECSM 1000 = Mouse click/release tracking
+ x DECSM 1002 = Mouse click/release/drag tracking
+ x DECSM 1003 = Mouse all movements tracking
+ x DECSM 1004 = Focus in/out reporting
+ x DECSM 1005 = Mouse protocol extended (UTF-8) - not recommended
+ x DECSM 1006 = Mouse protocol SGR
+ x DECSM 1015 = Mouse protocol rxvt
+ x DECSM 1047 = Altscreen
+ x DECSM 1048 = Save cursor
+ x DECSM 1049 = 1047 + 1048
+ x DECSM 2004 = Bracketed paste
+
+ Graphic Renditions
+
+123x SGR 0 = Reset
+123x SGR 1 = Bold on
+ x SGR 3 = Italic on
+123x SGR 4 = Underline single
+ SGR 4:x = Underline style
+123x SGR 5 = Blink on
+123x SGR 7 = Reverse on
+ x SGR 8 = Conceal on
+ x SGR 9 = Strikethrough on
+ SGR 10-19 = Select font
+ x SGR 21 = Underline double
+ 23x SGR 22 = Bold off
+ x SGR 23 = Italic off
+ 23x SGR 24 = Underline off
+ 23x SGR 25 = Blink off
+ 23x SGR 27 = Reverse off
+ x SGR 28 = Conceal off
+ x SGR 29 = Strikethrough off
+ x SGR 30-37 = Foreground ANSI
+ x SGR 38 = Foreground alternative palette
+ x SGR 39 = Foreground default
+ x SGR 40-47 = Background ANSI
+ x SGR 48 = Background alternative palette
+ x SGR 49 = Background default
+ x SGR 90-97 = Foreground ANSI high-intensity
+ x SGR 100-107 = Background ANSI high-intensity
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.
-123 0x05 = ENQ
- 3 0x11 = DC1 (XON)
- 3 0x13 = DC3 (XOFF)
-12 ESC Z = DECID, identify terminal
- DCS $ q = [DECRQSS]
- 3 " p = Request DECSCL
- 3 $ } = Request DECSASD
- 3 $ ~ = Request DECSSDT
- 23 DCS { = DECDLD, down-line-loadable character set
- 23 DCS | = DECUDK, user-defined key
- 23 CSI i = DEC printer control
- 23 CSI " p = DECSCL, set compatibility level
-1 CSI q = DECLL, load LEDs
- 3 CSI $ u = DECRQTSR, request terminal state report
- 3 1 = terminal state report
- 3 CSI & u = DECRQUPSS, request user-preferred supplemental set
- 3 CSI $ w = DECRQPSR, request presentation state report
- 3 1 = cursor information report
- 3 2 = tab stop report
-1 CSI x = DECREQTPARM, request terminal parameters
-123 CSI y = DECTST, invoke confidence test
- 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
+123x 0x05 = ENQ
+ 3 0x11 = DC1 (XON)
+ 3 0x13 = DC3 (XOFF)
+ x ESC % @ = Select default character set
+ x ESC % G = Select UTF-8 character set
+ x ESC 6 = DECBI, Back Index
+12 ESC Z = DECID, identify terminal
+ x DCS + Q = XTGETXRES, Request resource values
+ DCS $ q = [DECRQSS]
+ 3x " p = Request DECSCL
+ x t = Request DECSLPP
+ x $ | = Request DECSCPP
+ x * | = Request DECSLNS
+ 3 $ } = Request DECSASD
+ 3 $ ~ = Request DECSSDT
+ x DCS + p = XTSETTCAP, set termcap/terminfo data
+ x DCS + q = XTGETTCAP, request termcap/terminfo
+ 23 DCS { = DECDLD, down-line-loadable character set
+ 23x DCS | = DECUDK, user-defined key
+ x CSI Sp @ = Shift left columns
+ x CSI Sp A = Shift right columns
+ x CSI # P = XTPUSHCOLORS, push current dynamic colours to stack
+ x CSI # Q = XTPOPCOLORS, pop dynamic colours from stack
+ x CSI # R = XTREPORTCOLORS, report current entry on palette stack
+ x CSI ? S = XTSMGRAPHICS, set/request graphics attribute
+ x CSI > T = XTRMTITLE, reset title mode features
+ 23x CSI i = DEC printer control
+ x CSI > m = XTMODKEYS, set key modifier options
+ x CSI > n = (XTMODKEYS), reset key modifier options
+ x CSI $ p = DECRQM, request ANSI mode
+ 23x CSI " p = DECSCL, set compatibility level
+ x CSI > p = XTSMPOINTER, set resource value pointer mode
+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
diff --git a/src/libvterm/include/vterm.h b/src/libvterm/include/vterm.h
index 9873b6d55..d553fbd51 100644
--- a/src/libvterm/include/vterm.h
+++ b/src/libvterm/include/vterm.h
@@ -17,10 +17,11 @@ extern "C" {
// from stdint.h
typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define VTERM_VERSION_MAJOR 0
-#define VTERM_VERSION_MINOR 1
+#define VTERM_VERSION_MINOR 2
#define VTERM_CHECK_VERSION \
vterm_check_version(VTERM_VERSION_MAJOR, VTERM_VERSION_MINOR)
@@ -267,6 +268,14 @@ enum {
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 {
const uint32_t *chars;
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 (*osc)(int command, 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);
} 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 (*osc)(int command, 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;
+typedef struct {
+ int (*set)(VTermSelectionMask mask, VTermStringFragment frag, void *user);
+ int (*query)(VTermSelectionMask mask, void *user);
+} VTermSelectionCallbacks;
+
VTermState *vterm_obtain_state(VTerm *vt);
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_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
// ------------
diff --git a/src/libvterm/src/mouse.c b/src/libvterm/src/mouse.c
index ed60b0147..5f35d5648 100644
--- a/src/libvterm/src/mouse.c
+++ b/src/libvterm/src/mouse.c
@@ -89,6 +89,9 @@ void vterm_mouse_button(VTerm *vt, int button, int pressed, VTermModifier mod)
if (!(state->mouse_flags & MOUSE_WANT_CLICK))
return;
+ if(!state->mouse_flags)
+ return;
+
if(button < 4) {
output_mouse(state, button-1, pressed, mod, state->mouse_col, state->mouse_row);
}
diff --git a/src/libvterm/src/parser.c b/src/libvterm/src/parser.c
index 490f5ce1b..0d4422cf4 100644
--- a/src/libvterm/src/parser.c
+++ b/src/libvterm/src/parser.c
@@ -77,10 +77,25 @@ static void string_fragment(VTerm *vt, const char *str, size_t len, int final)
break;
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);
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 CSI_LEADER:
case CSI_ARGS:
@@ -112,6 +127,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
break;
case OSC:
case DCS:
+ case APC:
+ case PM:
+ case SOS:
string_start = bytes;
break;
}
@@ -150,6 +168,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
// fallthrough
}
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(c == 0x08) // BS
// 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))) {
c += 0x40;
c1_allowed = TRUE;
- string_len -= 1;
+ if(string_len)
+ string_len -= 1;
vt->parser.in_esc = FALSE;
}
else {
@@ -279,6 +301,9 @@ size_t vterm_input_write(VTerm *vt, const char *bytes, size_t len)
string_state:
case OSC:
case DCS:
+ case APC:
+ case PM:
+ case SOS:
if(c == 0x07 || (c1_allowed && c == 0x9c)) {
string_fragment(vt, string_start, string_len, TRUE);
ENTER_NORMAL_STATE();
@@ -308,6 +333,12 @@ string_state:
vt->parser.v.dcs.commandlen = 0;
ENTER_STATE(DCS_COMMAND);
break;
+ case 0x98: // SOS
+ vt->parser.string_initial = TRUE;
+ ENTER_STATE(SOS);
+ string_start = bytes + pos + 1;
+ string_len = 0;
+ break;
case 0x9b: // CSI
vt->parser.v.csi.leaderlen = 0;
ENTER_STATE(CSI_LEADER);
@@ -318,6 +349,18 @@ string_state:
string_start = bytes + pos + 1;
ENTER_STATE(OSC_COMMAND);
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:
do_control(vt, c);
break;
@@ -340,8 +383,12 @@ string_state:
}
}
- if(string_start)
- string_fragment(vt, string_start, bytes + pos - string_start, FALSE);
+ if(string_start) {
+ 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;
}
diff --git a/src/libvterm/src/state.c b/src/libvterm/src/state.c
index afb188c7e..e3c76bc1a 100644
--- a/src/libvterm/src/state.c
+++ b/src/libvterm/src/state.c
@@ -79,6 +79,10 @@ static VTermState *vterm_state_new(VTerm *vt)
state->callbacks = NULL;
state->cbdata = NULL;
+ state->selection.callbacks = NULL;
+ state->selection.user = NULL;
+ state->selection.buffer = NULL;
+
vterm_state_newpen(state);
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;
}
+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)
{
VTermState *state = user;
@@ -1656,6 +1828,12 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
settermprop_string(state, VTERM_PROP_CURSORCOLOR, frag);
return 1;
+ case 52:
+ if(state->selection.callbacks)
+ osc_selection(state, frag);
+
+ return 1;
+
default:
if(state->fallbacks && state->fallbacks->osc)
if((*state->fallbacks->osc)(command, frag, state->fbdata))
@@ -1718,12 +1896,14 @@ static void request_status_string(VTermState *state, VTermStringFragment frag)
case 'r':
// 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;
case 's':
// 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;
case ' '|('q'<<8): {
@@ -1736,17 +1916,19 @@ static void request_status_string(VTermState *state, VTermStringFragment frag)
}
if(state->mode.cursor_blink)
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;
}
case '\"'|('q'<<8):
// 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;
}
- 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)
@@ -1765,6 +1947,42 @@ static int on_dcs(const char *command, size_t commandlen, VTermStringFragment fr
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)
{
VTermState *state = user;
@@ -1866,6 +2084,9 @@ static const VTermParserCallbacks parser_callbacks = {
on_csi, // csi
on_osc, // osc
on_dcs, // dcs
+ on_apc, // apc
+ on_pm, // pm
+ on_sos, // sos
on_resize // resize
};
@@ -1909,6 +2130,8 @@ void vterm_state_reset(VTermState *state, int hard)
state->mode.bracketpaste = 0;
state->mode.report_focus = 0;
+ state->mouse_flags = 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;
}
+
+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, "");
+ }
+}
diff --git a/src/libvterm/src/vterm.c b/src/libvterm/src/vterm.c
index 0211ea147..da026b9a6 100644
--- a/src/libvterm/src/vterm.c
+++ b/src/libvterm/src/vterm.c
@@ -200,27 +200,35 @@ INTERNAL void vterm_push_output_sprintf_ctrl(VTerm *vt, unsigned char ctrl, cons
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;
va_list args;
- cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len,
- vt->mode.ctrl8bit ? "\x90" : ESC_S "P"); // DCS
-
- if(cur >= vt->tmpbuffer_len)
- return;
- vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
+ if(ctrl) {
+ 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)
+ return;
+ vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
+ }
va_start(args, fmt);
vterm_push_output_vsprintf(vt, fmt, args);
va_end(args);
- cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len,
- vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST
- if(cur >= vt->tmpbuffer_len)
- return;
- vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
+ if(term) {
+ cur = SNPRINTF(vt->tmpbuffer, vt->tmpbuffer_len,
+ vt->mode.ctrl8bit ? "\x9C" : ESC_S "\\"); // ST
+ if(cur >= vt->tmpbuffer_len)
+ return;
+ vterm_push_output_bytes(vt, vt->tmpbuffer, cur);
+ }
}
size_t vterm_output_get_buffer_size(const VTerm *vt)
diff --git a/src/libvterm/src/vterm_internal.h b/src/libvterm/src/vterm_internal.h
index cc0c64d30..c4e408a37 100644
--- a/src/libvterm/src/vterm_internal.h
+++ b/src/libvterm/src/vterm_internal.h
@@ -154,7 +154,26 @@ struct VTermState
/* Temporary state for DECRQSS parsing */
union {
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;
+
+ struct {
+ const VTermSelectionCallbacks *callbacks;
+ void *user;
+ char *buffer;
+ size_t buflen;
+ } selection;
};
struct VTerm
@@ -181,6 +200,9 @@ struct VTerm
OSC_COMMAND,
OSC,
DCS,
+ APC,
+ PM,
+ SOS,
} state;
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_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_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);
diff --git a/src/libvterm/t/02parser.test b/src/libvterm/t/02parser.test
index 0a21b927e..2cc51dc20 100644
--- a/src/libvterm/t/02parser.test
+++ b/src/libvterm/t/02parser.test
@@ -17,15 +17,15 @@ PUSH "\x1f"
PUSH "\x83"
control 0x83
-PUSH "\x9f"
- control 0x9f
+PUSH "\x99"
+ control 0x99
!C1 7bit
PUSH "\e\x43"
control 0x83
-PUSH "\e\x5f"
- control 0x9f
+PUSH "\e\x59"
+ control 0x99
!High bytes
PUSH "\xa0\xcc\xfe"
@@ -184,6 +184,12 @@ PUSH "\ePHello\e\\"
PUSH "\x{90}Hello\x9c"
dcs ["Hello"]
+!Split write of 7bit ST
+PUSH "\ePABC\e"
+ dcs ["ABC"
+PUSH "\\"
+ dcs ]
+
!Escape cancels DCS, starts Escape
PUSH "\ePSomething\e9"
escape "9"
@@ -198,6 +204,48 @@ PUSH "\ePBy\ne\x07"
control 10
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
PUSH "\x{00}"
diff --git a/src/libvterm/t/17state_mouse.test b/src/libvterm/t/17state_mouse.test
index c39f56b82..e5ba29b4e 100644
--- a/src/libvterm/t/17state_mouse.test
+++ b/src/libvterm/t/17state_mouse.test
@@ -170,3 +170,12 @@ PUSH "\e[?1006\$p"
output "\e[?1006;2\$y"
PUSH "\e[?1015\$p"
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
diff --git a/src/libvterm/t/29state_fallback.test b/src/libvterm/t/29state_fallback.test
index 7995dd1b6..4ab2e1845 100644
--- a/src/libvterm/t/29state_fallback.test
+++ b/src/libvterm/t/29state_fallback.test
@@ -17,3 +17,15 @@ PUSH "\e]27;Something\e\\"
!Unrecognised DCS
PUSH "\ePz123\e\\"
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"]
diff --git a/src/libvterm/t/40state_selection.test b/src/libvterm/t/40state_selection.test
new file mode 100644
index 000000000..6ed8972fc
--- /dev/null
+++ b/src/libvterm/t/40state_selection.test
@@ -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\\"
diff --git a/src/libvterm/t/harness.c b/src/libvterm/t/harness.c
index 10afbfd76..07babb68c 100644
--- a/src/libvterm/t/harness.c
+++ b/src/libvterm/t/harness.c
@@ -13,7 +13,8 @@ static size_t inplace_hex2bytes(char *s)
while(*inpos) {
unsigned int ch;
- sscanf(inpos, "%2x", &ch);
+ if(sscanf(inpos, "%2x", &ch) < 1)
+ break;
*outpos = ch;
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)
{
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)
@@ -216,6 +217,57 @@ static int parser_dcs(const char *command, size_t commandlen, VTermStringFragmen
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 = {
parser_text, // text
parser_control, // control
@@ -223,6 +275,9 @@ static VTermParserCallbacks parser_cbs = {
parser_csi, // csi
parser_osc, // osc
parser_dcs, // dcs
+ parser_apc, // apc
+ parser_pm, // pm
+ parser_sos, // sos
NULL // resize
};
@@ -230,7 +285,10 @@ static VTermStateFallbacks fallbacks = {
parser_control, // control
parser_csi, // csi
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 */
@@ -414,6 +472,31 @@ VTermStateCallbacks state_cbs = {
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_cells = 0;
static int screen_damage(VTermRect rect, void *user UNUSED)
@@ -555,6 +638,7 @@ int main(int argc UNUSED, char **argv UNUSED)
if(!state) {
state = vterm_obtain_state(vt);
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_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);
}
+ 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 ")) {
char *linep = line + 12;
while(linep[0] == ' ')
diff --git a/src/libvterm/t/run-test.pl b/src/libvterm/t/run-test.pl
index 82abb291e..2e359cc84 100644
--- a/src/libvterm/t/run-test.pl
+++ b/src/libvterm/t/run-test.pl
@@ -85,6 +85,11 @@ sub do_line
my $string = eval($2);
$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;
@@ -113,15 +118,18 @@ sub do_line
$line = "$cmd $initial" . join( "", map sprintf("%02x", $_), unpack "C*", length $data ? eval($data) : "" ) . "$final";
}
- elsif( $line =~ m/^(escape|dcs) (\[?)(.*?)(\]?)$/ ) {
- $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", eval($3) ) . "$4";
+ elsif( $line =~ m/^(escape|dcs|apc|pm|sos) (\[?)(.*?)(\]?)$/ ) {
+ $line = "$1 $2" . join( "", map sprintf("%02x", $_), unpack "C*", length $3 ? eval($3) : "" ) . "$4";
}
elsif( $line =~ m/^putglyph (\S+) (.*)$/ ) {
$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
}
+ elsif( $line =~ m/^(selection-set) (.*?) (\[?)(.*?)(\]?)$/ ) {
+ $line = "$1 $2 $3" . join( "", map sprintf("%02x", $_), unpack "C*", eval($4) ) . "$5";
+ }
else {
warn "Unrecognised test expectation '$line'\n";
}
diff --git a/src/libvterm/vterm.pc.in b/src/libvterm/vterm.pc.in
index c64c72ddf..8d7e59a1e 100644
--- a/src/libvterm/vterm.pc.in
+++ b/src/libvterm/vterm.pc.in
@@ -1,6 +1,5 @@
-prefix=@PREFIX@
libdir=@LIBDIR@
-includedir=${prefix}/include
+includedir=@INCDIR@
Name: vterm
Description: Abstract VT220/Xterm/ECMA-48 emulation library
diff --git a/src/terminal.c b/src/terminal.c
index df1ca6990..4a95a3e3d 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -4526,7 +4526,10 @@ static VTermStateFallbacks state_fallbacks = {
NULL, // control
parse_csi, // csi
parse_osc, // osc
- NULL // dcs
+ NULL, // dcs
+ NULL, // apc
+ NULL, // pm
+ NULL // sos
};
/*
diff --git a/src/version.c b/src/version.c
index 7a29e4e0d..527691c92 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 3666,
+/**/
3665,
/**/
3664,