| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
2
|
|
|
|
|
|
|
#
|
|
3
|
|
|
|
|
|
|
# Termbox (Perl port)
|
|
4
|
|
|
|
|
|
|
#
|
|
5
|
|
|
|
|
|
|
# Implementation based on termbox2 v2.7.0-dev, 8. Feb 2026
|
|
6
|
|
|
|
|
|
|
#
|
|
7
|
|
|
|
|
|
|
# Copyright (C) 2015-2026 Adam Saponara
|
|
8
|
|
|
|
|
|
|
# 2010-2020 nsf
|
|
9
|
|
|
|
|
|
|
#
|
|
10
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
11
|
|
|
|
|
|
|
# Author: 2024-2026 J. Schneider
|
|
12
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
package Termbox;
|
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
17
|
|
|
|
|
|
|
# Boilerplate ------------------------------------------------------------
|
|
18
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
19
|
|
|
|
|
|
|
|
|
20
|
37
|
|
|
37
|
|
3150732
|
use 5.010;
|
|
|
37
|
|
|
|
|
120
|
|
|
21
|
37
|
|
|
37
|
|
164
|
use strict;
|
|
|
37
|
|
|
|
|
56
|
|
|
|
37
|
|
|
|
|
783
|
|
|
22
|
37
|
|
|
37
|
|
134
|
use warnings;
|
|
|
37
|
|
|
|
|
55
|
|
|
|
37
|
|
|
|
|
1665
|
|
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# version '...'
|
|
25
|
37
|
|
|
37
|
|
12457
|
use version;
|
|
|
37
|
|
|
|
|
54888
|
|
|
|
37
|
|
|
|
|
204
|
|
|
26
|
|
|
|
|
|
|
our $version = version->declare('v2.7.0_0');
|
|
27
|
|
|
|
|
|
|
our $VERSION = version->declare('v0.4.3');
|
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# authority '...'
|
|
30
|
|
|
|
|
|
|
our $authority = 'github:adsr';
|
|
31
|
|
|
|
|
|
|
our $AUTHORITY = 'github:brickpool';
|
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
34
|
|
|
|
|
|
|
# Imports ----------------------------------------------------------------
|
|
35
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
require bytes;
|
|
38
|
37
|
|
|
37
|
|
4295
|
use Carp ();
|
|
|
37
|
|
|
|
|
56
|
|
|
|
37
|
|
|
|
|
767
|
|
|
39
|
37
|
|
|
37
|
|
124
|
use Config;
|
|
|
37
|
|
|
|
|
46
|
|
|
|
37
|
|
|
|
|
1315
|
|
|
40
|
37
|
|
|
37
|
|
17193
|
use IO::File ();
|
|
|
37
|
|
|
|
|
272771
|
|
|
|
37
|
|
|
|
|
1087
|
|
|
41
|
37
|
|
|
37
|
|
15296
|
use Params::Check qw( check );
|
|
|
37
|
|
|
|
|
137305
|
|
|
|
37
|
|
|
|
|
2437
|
|
|
42
|
37
|
|
|
|
|
181
|
use POSIX qw(
|
|
43
|
|
|
|
|
|
|
:errno_h
|
|
44
|
|
|
|
|
|
|
:termios_h
|
|
45
|
37
|
|
|
37
|
|
15017
|
);
|
|
|
37
|
|
|
|
|
258898
|
|
|
46
|
37
|
|
|
|
|
1948
|
use Scalar::Util qw(
|
|
47
|
|
|
|
|
|
|
looks_like_number
|
|
48
|
|
|
|
|
|
|
blessed
|
|
49
|
37
|
|
|
37
|
|
62603
|
);
|
|
|
37
|
|
|
|
|
55
|
|
|
50
|
37
|
|
|
37
|
|
12419
|
use utf8;
|
|
|
37
|
|
|
|
|
7396
|
|
|
|
37
|
|
|
|
|
182
|
|
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
53
|
|
|
|
|
|
|
# Compile-time options ---------------------------------------------------
|
|
54
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
# use constant TB_VERSION_STR => $version->normal;
|
|
57
|
2
|
|
|
2
|
0
|
361
|
BEGIN { sub TB_VERSION_STR () { state $qv = $version->normal } }
|
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# STRICT is a global flag that enables strict argument checking.
|
|
60
|
37
|
100
|
|
|
|
71
|
use constant STRICT => !!grep { exists $ENV{$_} && $ENV{$_} } qw(
|
|
|
148
|
|
|
|
|
4555
|
|
|
61
|
|
|
|
|
|
|
PERL_STRICT
|
|
62
|
|
|
|
|
|
|
EXTENDED_TESTING
|
|
63
|
|
|
|
|
|
|
AUTHOR_TESTING
|
|
64
|
|
|
|
|
|
|
RELEASE_TESTING
|
|
65
|
37
|
|
|
37
|
|
4204
|
);
|
|
|
37
|
|
|
|
|
49
|
|
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# The following compile-time options are available for conditional code.
|
|
68
|
|
|
|
|
|
|
# They are set to the default values used in the C implementation, but can be
|
|
69
|
|
|
|
|
|
|
# overridden by setting the corresponding environment variables before loading
|
|
70
|
|
|
|
|
|
|
# this module.
|
|
71
|
|
|
|
|
|
|
|
|
72
|
37
|
50
|
|
37
|
|
214
|
use constant TB_OPT_EGC => exists $ENV{TB_OPT_EGC} ? !!$ENV{TB_OPT_EGC} : 1;
|
|
|
37
|
|
|
|
|
49
|
|
|
|
37
|
|
|
|
|
2417
|
|
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# Define this to set the string length used in 'tb_printf' and 'tb_sendf'.
|
|
75
|
|
|
|
|
|
|
use constant TB_OPT_PRINTF_BUF => exists $ENV{TB_OPT_PRINTF_BUF}
|
|
76
|
|
|
|
|
|
|
? 0+$ENV{TB_OPT_PRINTF_BUF}
|
|
77
|
37
|
50
|
|
37
|
|
169
|
: 4096;
|
|
|
37
|
|
|
|
|
53
|
|
|
|
37
|
|
|
|
|
2658
|
|
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
# Define this to set the size of the buffer used when reading from the tty.
|
|
80
|
|
|
|
|
|
|
use constant TB_OPT_READ_BUF => exists $ENV{TB_OPT_READ_BUF}
|
|
81
|
|
|
|
|
|
|
? 0+$ENV{TB_OPT_READ_BUF}
|
|
82
|
37
|
50
|
|
37
|
|
225
|
: 64;
|
|
|
37
|
|
|
|
|
118
|
|
|
|
37
|
|
|
|
|
2243
|
|
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# In this port, TB_OPT_LIBC_WCHAR selects the Unicode::UCD-based wcwidth backend
|
|
85
|
|
|
|
|
|
|
use constant TB_OPT_LIBC_WCHAR => exists $ENV{TB_OPT_LIBC_WCHAR}
|
|
86
|
|
|
|
|
|
|
? !!$ENV{TB_OPT_LIBC_WCHAR}
|
|
87
|
37
|
50
|
|
37
|
|
149
|
: 1;
|
|
|
37
|
|
|
|
|
67
|
|
|
|
37
|
|
|
|
|
2231
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
37
|
50
|
|
37
|
|
214
|
use constant TB_PATH_MAX => exists $ENV{PATH_MAX} ? $ENV{PATH_MAX} : 4096;
|
|
|
37
|
|
|
|
|
58
|
|
|
|
37
|
|
|
|
|
2766
|
|
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
use constant TB_TERMINFO_DIR => exists $ENV{TB_TERMINFO_DIR}
|
|
92
|
|
|
|
|
|
|
? ''.$ENV{TB_TERMINFO_DIR}
|
|
93
|
37
|
50
|
|
37
|
|
159
|
: undef;
|
|
|
37
|
|
|
|
|
50
|
|
|
|
37
|
|
|
|
|
2193
|
|
|
94
|
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
use constant TB_RESIZE_FALLBACK_MS => exists $ENV{TB_RESIZE_FALLBACK_MS}
|
|
96
|
|
|
|
|
|
|
? 0+$ENV{TB_RESIZE_FALLBACK_MS}
|
|
97
|
37
|
50
|
|
37
|
|
142
|
: 1000;
|
|
|
37
|
|
|
|
|
48
|
|
|
|
37
|
|
|
|
|
2328
|
|
|
98
|
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# Deprecated. Back-compat for old flag.
|
|
100
|
|
|
|
|
|
|
use constant TB_OPT_TRUECOLOR => exists $ENV{TB_OPT_TRUECOLOR}
|
|
101
|
|
|
|
|
|
|
? !!$ENV{TB_OPT_TRUECOLOR}
|
|
102
|
37
|
50
|
|
37
|
|
164
|
: undef;
|
|
|
37
|
|
|
|
|
66
|
|
|
|
37
|
|
|
|
|
4751
|
|
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# Ensure sane 'TB_OPT_ATTR_W' (16, 32, or 64)
|
|
105
|
|
|
|
|
|
|
use constant TB_OPT_ATTR_W =>
|
|
106
|
|
|
|
|
|
|
( exists $ENV{TB_OPT_ATTR_W}
|
|
107
|
|
|
|
|
|
|
&& $ENV{TB_OPT_ATTR_W} =~ /^(16|32|64)$/ ) ? $ENV{TB_OPT_ATTR_W} :
|
|
108
|
37
|
50
|
33
|
|
|
4919
|
( !defined TB_OPT_TRUECOLOR ) ? $Config{ivsize} * 8 :
|
|
|
|
50
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
( TB_OPT_TRUECOLOR ) ? 32 :
|
|
110
|
37
|
|
|
37
|
|
203
|
16 ;
|
|
|
37
|
|
|
|
|
66
|
|
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
113
|
|
|
|
|
|
|
# Exports ----------------------------------------------------------------
|
|
114
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
115
|
|
|
|
|
|
|
|
|
116
|
37
|
|
|
37
|
|
192
|
use Exporter qw( import );
|
|
|
37
|
|
|
|
|
83
|
|
|
|
37
|
|
|
|
|
15401
|
|
|
117
|
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
our @EXPORT_OK = qw(
|
|
119
|
|
|
|
|
|
|
);
|
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
our %EXPORT_TAGS = (
|
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
api => [qw(
|
|
124
|
|
|
|
|
|
|
tb_init
|
|
125
|
|
|
|
|
|
|
tb_init_file
|
|
126
|
|
|
|
|
|
|
tb_init_fd
|
|
127
|
|
|
|
|
|
|
tb_init_rwfd
|
|
128
|
|
|
|
|
|
|
tb_shutdown
|
|
129
|
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
tb_width
|
|
131
|
|
|
|
|
|
|
tb_height
|
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
tb_clear
|
|
134
|
|
|
|
|
|
|
tb_set_clear_attrs
|
|
135
|
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
tb_present
|
|
137
|
|
|
|
|
|
|
tb_invalidate
|
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
tb_set_cursor
|
|
140
|
|
|
|
|
|
|
tb_hide_cursor
|
|
141
|
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
tb_set_cell
|
|
143
|
|
|
|
|
|
|
tb_set_cell_ex
|
|
144
|
|
|
|
|
|
|
tb_extend_cell
|
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
tb_get_cell
|
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
tb_set_input_mode
|
|
149
|
|
|
|
|
|
|
tb_set_output_mode
|
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
tb_peek_event
|
|
152
|
|
|
|
|
|
|
tb_poll_event
|
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
tb_get_fds
|
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
tb_print
|
|
157
|
|
|
|
|
|
|
tb_printf
|
|
158
|
|
|
|
|
|
|
tb_print_ex
|
|
159
|
|
|
|
|
|
|
tb_printf_ex
|
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
tb_send
|
|
162
|
|
|
|
|
|
|
tb_sendf
|
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
tb_set_func
|
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
tb_utf8_char_length
|
|
167
|
|
|
|
|
|
|
tb_utf8_char_to_unicode
|
|
168
|
|
|
|
|
|
|
tb_utf8_unicode_to_char
|
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
tb_last_errno
|
|
171
|
|
|
|
|
|
|
tb_strerror
|
|
172
|
|
|
|
|
|
|
tb_cell_buffer
|
|
173
|
|
|
|
|
|
|
tb_has_truecolor
|
|
174
|
|
|
|
|
|
|
tb_has_egc
|
|
175
|
|
|
|
|
|
|
tb_attr_width
|
|
176
|
|
|
|
|
|
|
tb_version
|
|
177
|
|
|
|
|
|
|
)],
|
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
keys => [qw(
|
|
180
|
|
|
|
|
|
|
TB_KEY_CTRL_TILDE
|
|
181
|
|
|
|
|
|
|
TB_KEY_CTRL_2
|
|
182
|
|
|
|
|
|
|
TB_KEY_CTRL_A
|
|
183
|
|
|
|
|
|
|
TB_KEY_CTRL_B
|
|
184
|
|
|
|
|
|
|
TB_KEY_CTRL_C
|
|
185
|
|
|
|
|
|
|
TB_KEY_CTRL_D
|
|
186
|
|
|
|
|
|
|
TB_KEY_CTRL_E
|
|
187
|
|
|
|
|
|
|
TB_KEY_CTRL_F
|
|
188
|
|
|
|
|
|
|
TB_KEY_CTRL_G
|
|
189
|
|
|
|
|
|
|
TB_KEY_BACKSPACE
|
|
190
|
|
|
|
|
|
|
TB_KEY_CTRL_H
|
|
191
|
|
|
|
|
|
|
TB_KEY_TAB
|
|
192
|
|
|
|
|
|
|
TB_KEY_CTRL_I
|
|
193
|
|
|
|
|
|
|
TB_KEY_CTRL_J
|
|
194
|
|
|
|
|
|
|
TB_KEY_CTRL_K
|
|
195
|
|
|
|
|
|
|
TB_KEY_CTRL_L
|
|
196
|
|
|
|
|
|
|
TB_KEY_ENTER
|
|
197
|
|
|
|
|
|
|
TB_KEY_CTRL_M
|
|
198
|
|
|
|
|
|
|
TB_KEY_CTRL_N
|
|
199
|
|
|
|
|
|
|
TB_KEY_CTRL_O
|
|
200
|
|
|
|
|
|
|
TB_KEY_CTRL_P
|
|
201
|
|
|
|
|
|
|
TB_KEY_CTRL_Q
|
|
202
|
|
|
|
|
|
|
TB_KEY_CTRL_R
|
|
203
|
|
|
|
|
|
|
TB_KEY_CTRL_S
|
|
204
|
|
|
|
|
|
|
TB_KEY_CTRL_T
|
|
205
|
|
|
|
|
|
|
TB_KEY_CTRL_U
|
|
206
|
|
|
|
|
|
|
TB_KEY_CTRL_V
|
|
207
|
|
|
|
|
|
|
TB_KEY_CTRL_W
|
|
208
|
|
|
|
|
|
|
TB_KEY_CTRL_X
|
|
209
|
|
|
|
|
|
|
TB_KEY_CTRL_Y
|
|
210
|
|
|
|
|
|
|
TB_KEY_CTRL_Z
|
|
211
|
|
|
|
|
|
|
TB_KEY_ESC
|
|
212
|
|
|
|
|
|
|
TB_KEY_CTRL_LSQ_BRACKET
|
|
213
|
|
|
|
|
|
|
TB_KEY_CTRL_3
|
|
214
|
|
|
|
|
|
|
TB_KEY_CTRL_4
|
|
215
|
|
|
|
|
|
|
TB_KEY_CTRL_BACKSLASH
|
|
216
|
|
|
|
|
|
|
TB_KEY_CTRL_5
|
|
217
|
|
|
|
|
|
|
TB_KEY_CTRL_RSQ_BRACKET
|
|
218
|
|
|
|
|
|
|
TB_KEY_CTRL_6
|
|
219
|
|
|
|
|
|
|
TB_KEY_CTRL_7
|
|
220
|
|
|
|
|
|
|
TB_KEY_CTRL_SLASH
|
|
221
|
|
|
|
|
|
|
TB_KEY_CTRL_UNDERSCORE
|
|
222
|
|
|
|
|
|
|
TB_KEY_SPACE
|
|
223
|
|
|
|
|
|
|
TB_KEY_BACKSPACE2
|
|
224
|
|
|
|
|
|
|
TB_KEY_CTRL_8
|
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
TB_KEY_F1
|
|
227
|
|
|
|
|
|
|
TB_KEY_F2
|
|
228
|
|
|
|
|
|
|
TB_KEY_F3
|
|
229
|
|
|
|
|
|
|
TB_KEY_F4
|
|
230
|
|
|
|
|
|
|
TB_KEY_F5
|
|
231
|
|
|
|
|
|
|
TB_KEY_F6
|
|
232
|
|
|
|
|
|
|
TB_KEY_F7
|
|
233
|
|
|
|
|
|
|
TB_KEY_F8
|
|
234
|
|
|
|
|
|
|
TB_KEY_F9
|
|
235
|
|
|
|
|
|
|
TB_KEY_F10
|
|
236
|
|
|
|
|
|
|
TB_KEY_F11
|
|
237
|
|
|
|
|
|
|
TB_KEY_F12
|
|
238
|
|
|
|
|
|
|
TB_KEY_INSERT
|
|
239
|
|
|
|
|
|
|
TB_KEY_DELETE
|
|
240
|
|
|
|
|
|
|
TB_KEY_HOME
|
|
241
|
|
|
|
|
|
|
TB_KEY_END
|
|
242
|
|
|
|
|
|
|
TB_KEY_PGUP
|
|
243
|
|
|
|
|
|
|
TB_KEY_PGDN
|
|
244
|
|
|
|
|
|
|
TB_KEY_ARROW_UP
|
|
245
|
|
|
|
|
|
|
TB_KEY_ARROW_DOWN
|
|
246
|
|
|
|
|
|
|
TB_KEY_ARROW_LEFT
|
|
247
|
|
|
|
|
|
|
TB_KEY_ARROW_RIGHT
|
|
248
|
|
|
|
|
|
|
TB_KEY_BACK_TAB
|
|
249
|
|
|
|
|
|
|
TB_KEY_MOUSE_LEFT
|
|
250
|
|
|
|
|
|
|
TB_KEY_MOUSE_RIGHT
|
|
251
|
|
|
|
|
|
|
TB_KEY_MOUSE_MIDDLE
|
|
252
|
|
|
|
|
|
|
TB_KEY_MOUSE_RELEASE
|
|
253
|
|
|
|
|
|
|
TB_KEY_MOUSE_WHEEL_UP
|
|
254
|
|
|
|
|
|
|
TB_KEY_MOUSE_WHEEL_DOWN
|
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
TB_CAP_F1
|
|
257
|
|
|
|
|
|
|
TB_CAP_F2
|
|
258
|
|
|
|
|
|
|
TB_CAP_F3
|
|
259
|
|
|
|
|
|
|
TB_CAP_F4
|
|
260
|
|
|
|
|
|
|
TB_CAP_F5
|
|
261
|
|
|
|
|
|
|
TB_CAP_F6
|
|
262
|
|
|
|
|
|
|
TB_CAP_F7
|
|
263
|
|
|
|
|
|
|
TB_CAP_F8
|
|
264
|
|
|
|
|
|
|
TB_CAP_F9
|
|
265
|
|
|
|
|
|
|
TB_CAP_F10
|
|
266
|
|
|
|
|
|
|
TB_CAP_F11
|
|
267
|
|
|
|
|
|
|
TB_CAP_F12
|
|
268
|
|
|
|
|
|
|
TB_CAP_INSERT
|
|
269
|
|
|
|
|
|
|
TB_CAP_DELETE
|
|
270
|
|
|
|
|
|
|
TB_CAP_HOME
|
|
271
|
|
|
|
|
|
|
TB_CAP_END
|
|
272
|
|
|
|
|
|
|
TB_CAP_PGUP
|
|
273
|
|
|
|
|
|
|
TB_CAP_PGDN
|
|
274
|
|
|
|
|
|
|
TB_CAP_ARROW_UP
|
|
275
|
|
|
|
|
|
|
TB_CAP_ARROW_DOWN
|
|
276
|
|
|
|
|
|
|
TB_CAP_ARROW_LEFT
|
|
277
|
|
|
|
|
|
|
TB_CAP_ARROW_RIGHT
|
|
278
|
|
|
|
|
|
|
TB_CAP_BACK_TAB
|
|
279
|
|
|
|
|
|
|
TB_CAP__COUNT_KEYS
|
|
280
|
|
|
|
|
|
|
TB_CAP_ENTER_CA
|
|
281
|
|
|
|
|
|
|
TB_CAP_EXIT_CA
|
|
282
|
|
|
|
|
|
|
TB_CAP_SHOW_CURSOR
|
|
283
|
|
|
|
|
|
|
TB_CAP_HIDE_CURSOR
|
|
284
|
|
|
|
|
|
|
TB_CAP_CLEAR_SCREEN
|
|
285
|
|
|
|
|
|
|
TB_CAP_SGR0
|
|
286
|
|
|
|
|
|
|
TB_CAP_UNDERLINE
|
|
287
|
|
|
|
|
|
|
TB_CAP_BOLD
|
|
288
|
|
|
|
|
|
|
TB_CAP_BLINK
|
|
289
|
|
|
|
|
|
|
TB_CAP_ITALIC
|
|
290
|
|
|
|
|
|
|
TB_CAP_REVERSE
|
|
291
|
|
|
|
|
|
|
TB_CAP_ENTER_KEYPAD
|
|
292
|
|
|
|
|
|
|
TB_CAP_EXIT_KEYPAD
|
|
293
|
|
|
|
|
|
|
TB_CAP_DIM
|
|
294
|
|
|
|
|
|
|
TB_CAP_INVISIBLE
|
|
295
|
|
|
|
|
|
|
TB_CAP__COUNT
|
|
296
|
|
|
|
|
|
|
)],
|
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
color => [qw(
|
|
299
|
|
|
|
|
|
|
TB_DEFAULT
|
|
300
|
|
|
|
|
|
|
TB_BLACK
|
|
301
|
|
|
|
|
|
|
TB_RED
|
|
302
|
|
|
|
|
|
|
TB_GREEN
|
|
303
|
|
|
|
|
|
|
TB_YELLOW
|
|
304
|
|
|
|
|
|
|
TB_BLUE
|
|
305
|
|
|
|
|
|
|
TB_MAGENTA
|
|
306
|
|
|
|
|
|
|
TB_CYAN
|
|
307
|
|
|
|
|
|
|
TB_WHITE
|
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
TB_BOLD
|
|
310
|
|
|
|
|
|
|
TB_UNDERLINE
|
|
311
|
|
|
|
|
|
|
TB_REVERSE
|
|
312
|
|
|
|
|
|
|
TB_ITALIC
|
|
313
|
|
|
|
|
|
|
TB_BLINK
|
|
314
|
|
|
|
|
|
|
TB_HI_BLACK
|
|
315
|
|
|
|
|
|
|
TB_BRIGHT
|
|
316
|
|
|
|
|
|
|
TB_DIM
|
|
317
|
|
|
|
|
|
|
),
|
|
318
|
|
|
|
|
|
|
TB_OPT_ATTR_W == 32
|
|
319
|
|
|
|
|
|
|
? qw( TB_256_BLACK )
|
|
320
|
|
|
|
|
|
|
: qw( TB_TRUECOLOR_BOLD
|
|
321
|
|
|
|
|
|
|
TB_TRUECOLOR_UNDERLINE
|
|
322
|
|
|
|
|
|
|
TB_TRUECOLOR_REVERSE
|
|
323
|
|
|
|
|
|
|
TB_TRUECOLOR_ITALIC
|
|
324
|
|
|
|
|
|
|
TB_TRUECOLOR_BLINK
|
|
325
|
|
|
|
|
|
|
TB_TRUECOLOR_BLACK ),
|
|
326
|
|
|
|
|
|
|
TB_OPT_ATTR_W == 64
|
|
327
|
|
|
|
|
|
|
? qw( TB_STRIKEOUT
|
|
328
|
|
|
|
|
|
|
TB_UNDERLINE_2
|
|
329
|
|
|
|
|
|
|
TB_OVERLINE
|
|
330
|
|
|
|
|
|
|
TB_INVISIBLE )
|
|
331
|
|
|
|
|
|
|
: ()
|
|
332
|
|
|
|
|
|
|
],
|
|
333
|
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
event => [qw(
|
|
335
|
|
|
|
|
|
|
TB_EVENT_KEY
|
|
336
|
|
|
|
|
|
|
TB_EVENT_RESIZE
|
|
337
|
|
|
|
|
|
|
TB_EVENT_MOUSE
|
|
338
|
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
TB_MOD_ALT
|
|
340
|
|
|
|
|
|
|
TB_MOD_CTRL
|
|
341
|
|
|
|
|
|
|
TB_MOD_SHIFT
|
|
342
|
|
|
|
|
|
|
TB_MOD_MOTION
|
|
343
|
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
TB_INPUT_CURRENT
|
|
345
|
|
|
|
|
|
|
TB_INPUT_ESC
|
|
346
|
|
|
|
|
|
|
TB_INPUT_ALT
|
|
347
|
|
|
|
|
|
|
TB_INPUT_MOUSE
|
|
348
|
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
TB_OUTPUT_CURRENT
|
|
350
|
|
|
|
|
|
|
TB_OUTPUT_NORMAL
|
|
351
|
|
|
|
|
|
|
TB_OUTPUT_256
|
|
352
|
|
|
|
|
|
|
TB_OUTPUT_216
|
|
353
|
|
|
|
|
|
|
TB_OUTPUT_GRAYSCALE
|
|
354
|
|
|
|
|
|
|
),
|
|
355
|
|
|
|
|
|
|
TB_OPT_ATTR_W >= 32
|
|
356
|
|
|
|
|
|
|
? qw( TB_OUTPUT_TRUECOLOR )
|
|
357
|
|
|
|
|
|
|
: ()
|
|
358
|
|
|
|
|
|
|
],
|
|
359
|
|
|
|
|
|
|
|
|
360
|
|
|
|
|
|
|
return => [qw(
|
|
361
|
|
|
|
|
|
|
TB_OK
|
|
362
|
|
|
|
|
|
|
TB_ERR
|
|
363
|
|
|
|
|
|
|
TB_ERR_NEED_MORE
|
|
364
|
|
|
|
|
|
|
TB_ERR_INIT_ALREADY
|
|
365
|
|
|
|
|
|
|
TB_ERR_INIT_OPEN
|
|
366
|
|
|
|
|
|
|
TB_ERR_MEM
|
|
367
|
|
|
|
|
|
|
TB_ERR_NO_EVENT
|
|
368
|
|
|
|
|
|
|
TB_ERR_NO_TERM
|
|
369
|
|
|
|
|
|
|
TB_ERR_NOT_INIT
|
|
370
|
|
|
|
|
|
|
TB_ERR_OUT_OF_BOUNDS
|
|
371
|
|
|
|
|
|
|
TB_ERR_READ
|
|
372
|
|
|
|
|
|
|
TB_ERR_RESIZE_IOCTL
|
|
373
|
|
|
|
|
|
|
TB_ERR_RESIZE_PIPE
|
|
374
|
|
|
|
|
|
|
TB_ERR_RESIZE_SIGACTION
|
|
375
|
|
|
|
|
|
|
TB_ERR_POLL
|
|
376
|
|
|
|
|
|
|
TB_ERR_TCGETATTR
|
|
377
|
|
|
|
|
|
|
TB_ERR_TCSETATTR
|
|
378
|
|
|
|
|
|
|
TB_ERR_UNSUPPORTED_TERM
|
|
379
|
|
|
|
|
|
|
TB_ERR_RESIZE_WRITE
|
|
380
|
|
|
|
|
|
|
TB_ERR_RESIZE_POLL
|
|
381
|
|
|
|
|
|
|
TB_ERR_RESIZE_READ
|
|
382
|
|
|
|
|
|
|
TB_ERR_RESIZE_SSCANF
|
|
383
|
|
|
|
|
|
|
TB_ERR_CAP_COLLISION
|
|
384
|
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
TB_ERR_SELECT
|
|
386
|
|
|
|
|
|
|
TB_ERR_RESIZE_SELECT
|
|
387
|
|
|
|
|
|
|
)],
|
|
388
|
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
func => [qw(
|
|
390
|
|
|
|
|
|
|
TB_FUNC_EXTRACT_PRE
|
|
391
|
|
|
|
|
|
|
TB_FUNC_EXTRACT_POST
|
|
392
|
|
|
|
|
|
|
)],
|
|
393
|
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
);
|
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
# add all the other %EXPORT_TAGS ":class" tags to the ":all" class and
|
|
397
|
|
|
|
|
|
|
# @EXPORT_OK, deleting duplicates
|
|
398
|
|
|
|
|
|
|
{
|
|
399
|
|
|
|
|
|
|
my %seen;
|
|
400
|
|
|
|
|
|
|
push
|
|
401
|
|
|
|
|
|
|
@EXPORT_OK,
|
|
402
|
|
|
|
|
|
|
grep {!$seen{$_}++} @{$EXPORT_TAGS{$_}}
|
|
403
|
|
|
|
|
|
|
foreach keys %EXPORT_TAGS;
|
|
404
|
|
|
|
|
|
|
push
|
|
405
|
|
|
|
|
|
|
@{$EXPORT_TAGS{all}},
|
|
406
|
|
|
|
|
|
|
@EXPORT_OK;
|
|
407
|
|
|
|
|
|
|
}
|
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
410
|
|
|
|
|
|
|
# Constants --------------------------------------------------------------
|
|
411
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
412
|
|
|
|
|
|
|
|
|
413
|
37
|
|
|
37
|
|
231
|
use constant INT16_SIZE => $Config{shortsize};
|
|
|
37
|
|
|
|
|
44
|
|
|
|
37
|
|
|
|
|
6957
|
|
|
414
|
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# ASCII key constants ($tb_event->key)
|
|
416
|
|
|
|
|
|
|
use constant {
|
|
417
|
37
|
|
|
|
|
13529
|
TB_KEY_CTRL_TILDE => 0x00,
|
|
418
|
|
|
|
|
|
|
TB_KEY_CTRL_2 => 0x00, # clash with 'CTRL_TILDE'
|
|
419
|
|
|
|
|
|
|
TB_KEY_CTRL_A => 0x01,
|
|
420
|
|
|
|
|
|
|
TB_KEY_CTRL_B => 0x02,
|
|
421
|
|
|
|
|
|
|
TB_KEY_CTRL_C => 0x03,
|
|
422
|
|
|
|
|
|
|
TB_KEY_CTRL_D => 0x04,
|
|
423
|
|
|
|
|
|
|
TB_KEY_CTRL_E => 0x05,
|
|
424
|
|
|
|
|
|
|
TB_KEY_CTRL_F => 0x06,
|
|
425
|
|
|
|
|
|
|
TB_KEY_CTRL_G => 0x07,
|
|
426
|
|
|
|
|
|
|
TB_KEY_BACKSPACE => 0x08,
|
|
427
|
|
|
|
|
|
|
TB_KEY_CTRL_H => 0x08, # clash with 'BACKSPACE'
|
|
428
|
|
|
|
|
|
|
TB_KEY_TAB => 0x09,
|
|
429
|
|
|
|
|
|
|
TB_KEY_CTRL_I => 0x09, # clash with 'TAB'
|
|
430
|
|
|
|
|
|
|
TB_KEY_CTRL_J => 0x0a,
|
|
431
|
|
|
|
|
|
|
TB_KEY_CTRL_K => 0x0b,
|
|
432
|
|
|
|
|
|
|
TB_KEY_CTRL_L => 0x0c,
|
|
433
|
|
|
|
|
|
|
TB_KEY_ENTER => 0x0d,
|
|
434
|
|
|
|
|
|
|
TB_KEY_CTRL_M => 0x0d, # clash with 'ENTER'
|
|
435
|
|
|
|
|
|
|
TB_KEY_CTRL_N => 0x0e,
|
|
436
|
|
|
|
|
|
|
TB_KEY_CTRL_O => 0x0f,
|
|
437
|
|
|
|
|
|
|
TB_KEY_CTRL_P => 0x10,
|
|
438
|
|
|
|
|
|
|
TB_KEY_CTRL_Q => 0x11,
|
|
439
|
|
|
|
|
|
|
TB_KEY_CTRL_R => 0x12,
|
|
440
|
|
|
|
|
|
|
TB_KEY_CTRL_S => 0x13,
|
|
441
|
|
|
|
|
|
|
TB_KEY_CTRL_T => 0x14,
|
|
442
|
|
|
|
|
|
|
TB_KEY_CTRL_U => 0x15,
|
|
443
|
|
|
|
|
|
|
TB_KEY_CTRL_V => 0x16,
|
|
444
|
|
|
|
|
|
|
TB_KEY_CTRL_W => 0x17,
|
|
445
|
|
|
|
|
|
|
TB_KEY_CTRL_X => 0x18,
|
|
446
|
|
|
|
|
|
|
TB_KEY_CTRL_Y => 0x19,
|
|
447
|
|
|
|
|
|
|
TB_KEY_CTRL_Z => 0x1a,
|
|
448
|
|
|
|
|
|
|
TB_KEY_ESC => 0x1b,
|
|
449
|
|
|
|
|
|
|
TB_KEY_CTRL_LSQ_BRACKET => 0x1b, # clash with 'ESC'
|
|
450
|
|
|
|
|
|
|
TB_KEY_CTRL_3 => 0x1b, # clash with 'ESC'
|
|
451
|
|
|
|
|
|
|
TB_KEY_CTRL_4 => 0x1c,
|
|
452
|
|
|
|
|
|
|
TB_KEY_CTRL_BACKSLASH => 0x1c, # clash with 'CTRL_4'
|
|
453
|
|
|
|
|
|
|
TB_KEY_CTRL_5 => 0x1d,
|
|
454
|
|
|
|
|
|
|
TB_KEY_CTRL_RSQ_BRACKET => 0x1d, # clash with 'CTRL_5'
|
|
455
|
|
|
|
|
|
|
TB_KEY_CTRL_6 => 0x1e,
|
|
456
|
|
|
|
|
|
|
TB_KEY_CTRL_7 => 0x1f,
|
|
457
|
|
|
|
|
|
|
TB_KEY_CTRL_SLASH => 0x1f, # clash with 'CTRL_7'
|
|
458
|
|
|
|
|
|
|
TB_KEY_CTRL_UNDERSCORE => 0x1f, # clash with 'CTRL_7'
|
|
459
|
|
|
|
|
|
|
TB_KEY_SPACE => 0x20,
|
|
460
|
|
|
|
|
|
|
TB_KEY_BACKSPACE2 => 0x7f,
|
|
461
|
|
|
|
|
|
|
TB_KEY_CTRL_8 => 0x7f, # clash with 'BACKSPACE2'
|
|
462
|
37
|
|
|
37
|
|
217
|
};
|
|
|
37
|
|
|
|
|
44
|
|
|
463
|
|
|
|
|
|
|
|
|
464
|
0
|
|
|
0
|
0
|
0
|
sub tb_key_i($) { 0xFFFF - $_[0] }
|
|
465
|
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# Terminal-dependent key constants ($tb_event->key) and terminfo caps
|
|
467
|
|
|
|
|
|
|
use constant {
|
|
468
|
37
|
|
|
|
|
8523
|
TB_KEY_F1 => 0xFFFF - 0,
|
|
469
|
|
|
|
|
|
|
TB_KEY_F2 => 0xFFFF - 1,
|
|
470
|
|
|
|
|
|
|
TB_KEY_F3 => 0xFFFF - 2,
|
|
471
|
|
|
|
|
|
|
TB_KEY_F4 => 0xFFFF - 3,
|
|
472
|
|
|
|
|
|
|
TB_KEY_F5 => 0xFFFF - 4,
|
|
473
|
|
|
|
|
|
|
TB_KEY_F6 => 0xFFFF - 5,
|
|
474
|
|
|
|
|
|
|
TB_KEY_F7 => 0xFFFF - 6,
|
|
475
|
|
|
|
|
|
|
TB_KEY_F8 => 0xFFFF - 7,
|
|
476
|
|
|
|
|
|
|
TB_KEY_F9 => 0xFFFF - 8,
|
|
477
|
|
|
|
|
|
|
TB_KEY_F10 => 0xFFFF - 9,
|
|
478
|
|
|
|
|
|
|
TB_KEY_F11 => 0xFFFF - 10,
|
|
479
|
|
|
|
|
|
|
TB_KEY_F12 => 0xFFFF - 11,
|
|
480
|
|
|
|
|
|
|
TB_KEY_INSERT => 0xFFFF - 12,
|
|
481
|
|
|
|
|
|
|
TB_KEY_DELETE => 0xFFFF - 13,
|
|
482
|
|
|
|
|
|
|
TB_KEY_HOME => 0xFFFF - 14,
|
|
483
|
|
|
|
|
|
|
TB_KEY_END => 0xFFFF - 15,
|
|
484
|
|
|
|
|
|
|
TB_KEY_PGUP => 0xFFFF - 16,
|
|
485
|
|
|
|
|
|
|
TB_KEY_PGDN => 0xFFFF - 17,
|
|
486
|
|
|
|
|
|
|
TB_KEY_ARROW_UP => 0xFFFF - 18,
|
|
487
|
|
|
|
|
|
|
TB_KEY_ARROW_DOWN => 0xFFFF - 19,
|
|
488
|
|
|
|
|
|
|
TB_KEY_ARROW_LEFT => 0xFFFF - 20,
|
|
489
|
|
|
|
|
|
|
TB_KEY_ARROW_RIGHT => 0xFFFF - 21,
|
|
490
|
|
|
|
|
|
|
TB_KEY_BACK_TAB => 0xFFFF - 22,
|
|
491
|
|
|
|
|
|
|
TB_KEY_MOUSE_LEFT => 0xFFFF - 23,
|
|
492
|
|
|
|
|
|
|
TB_KEY_MOUSE_RIGHT => 0xFFFF - 24,
|
|
493
|
|
|
|
|
|
|
TB_KEY_MOUSE_MIDDLE => 0xFFFF - 25,
|
|
494
|
|
|
|
|
|
|
TB_KEY_MOUSE_RELEASE => 0xFFFF - 26,
|
|
495
|
|
|
|
|
|
|
TB_KEY_MOUSE_WHEEL_UP => 0xFFFF - 27,
|
|
496
|
|
|
|
|
|
|
TB_KEY_MOUSE_WHEEL_DOWN => 0xFFFF - 28,
|
|
497
|
37
|
|
|
37
|
|
195
|
};
|
|
|
37
|
|
|
|
|
50
|
|
|
498
|
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
use constant {
|
|
500
|
37
|
|
|
|
|
9746
|
TB_CAP_F1 => 0,
|
|
501
|
|
|
|
|
|
|
TB_CAP_F2 => 1,
|
|
502
|
|
|
|
|
|
|
TB_CAP_F3 => 2,
|
|
503
|
|
|
|
|
|
|
TB_CAP_F4 => 3,
|
|
504
|
|
|
|
|
|
|
TB_CAP_F5 => 4,
|
|
505
|
|
|
|
|
|
|
TB_CAP_F6 => 5,
|
|
506
|
|
|
|
|
|
|
TB_CAP_F7 => 6,
|
|
507
|
|
|
|
|
|
|
TB_CAP_F8 => 7,
|
|
508
|
|
|
|
|
|
|
TB_CAP_F9 => 8,
|
|
509
|
|
|
|
|
|
|
TB_CAP_F10 => 9,
|
|
510
|
|
|
|
|
|
|
TB_CAP_F11 => 10,
|
|
511
|
|
|
|
|
|
|
TB_CAP_F12 => 11,
|
|
512
|
|
|
|
|
|
|
TB_CAP_INSERT => 12,
|
|
513
|
|
|
|
|
|
|
TB_CAP_DELETE => 13,
|
|
514
|
|
|
|
|
|
|
TB_CAP_HOME => 14,
|
|
515
|
|
|
|
|
|
|
TB_CAP_END => 15,
|
|
516
|
|
|
|
|
|
|
TB_CAP_PGUP => 16,
|
|
517
|
|
|
|
|
|
|
TB_CAP_PGDN => 17,
|
|
518
|
|
|
|
|
|
|
TB_CAP_ARROW_UP => 18,
|
|
519
|
|
|
|
|
|
|
TB_CAP_ARROW_DOWN => 19,
|
|
520
|
|
|
|
|
|
|
TB_CAP_ARROW_LEFT => 20,
|
|
521
|
|
|
|
|
|
|
TB_CAP_ARROW_RIGHT => 21,
|
|
522
|
|
|
|
|
|
|
TB_CAP_BACK_TAB => 22,
|
|
523
|
|
|
|
|
|
|
TB_CAP__COUNT_KEYS => 23,
|
|
524
|
|
|
|
|
|
|
TB_CAP_ENTER_CA => 23,
|
|
525
|
|
|
|
|
|
|
TB_CAP_EXIT_CA => 24,
|
|
526
|
|
|
|
|
|
|
TB_CAP_SHOW_CURSOR => 25,
|
|
527
|
|
|
|
|
|
|
TB_CAP_HIDE_CURSOR => 26,
|
|
528
|
|
|
|
|
|
|
TB_CAP_CLEAR_SCREEN => 27,
|
|
529
|
|
|
|
|
|
|
TB_CAP_SGR0 => 28,
|
|
530
|
|
|
|
|
|
|
TB_CAP_UNDERLINE => 29,
|
|
531
|
|
|
|
|
|
|
TB_CAP_BOLD => 30,
|
|
532
|
|
|
|
|
|
|
TB_CAP_BLINK => 31,
|
|
533
|
|
|
|
|
|
|
TB_CAP_ITALIC => 32,
|
|
534
|
|
|
|
|
|
|
TB_CAP_REVERSE => 33,
|
|
535
|
|
|
|
|
|
|
TB_CAP_ENTER_KEYPAD => 34,
|
|
536
|
|
|
|
|
|
|
TB_CAP_EXIT_KEYPAD => 35,
|
|
537
|
|
|
|
|
|
|
TB_CAP_DIM => 36,
|
|
538
|
|
|
|
|
|
|
TB_CAP_INVISIBLE => 37,
|
|
539
|
|
|
|
|
|
|
TB_CAP__COUNT => 38,
|
|
540
|
37
|
|
|
37
|
|
190
|
};
|
|
|
37
|
|
|
|
|
63
|
|
|
541
|
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
# Some hard-coded caps
|
|
543
|
|
|
|
|
|
|
use constant {
|
|
544
|
37
|
|
|
|
|
2927
|
TB_HARDCAP_ENTER_MOUSE => "\x1b[?1000h\x1b[?1002h\x1b[?1015h\x1b[?1006h",
|
|
545
|
|
|
|
|
|
|
TB_HARDCAP_EXIT_MOUSE => "\x1b[?1006l\x1b[?1015l\x1b[?1002l\x1b[?1000l",
|
|
546
|
|
|
|
|
|
|
TB_HARDCAP_STRIKEOUT => "\x1b[9m",
|
|
547
|
|
|
|
|
|
|
TB_HARDCAP_UNDERLINE_2 => "\x1b[21m",
|
|
548
|
|
|
|
|
|
|
TB_HARDCAP_OVERLINE => "\x1b[53m",
|
|
549
|
37
|
|
|
37
|
|
225
|
};
|
|
|
37
|
|
|
|
|
48
|
|
|
550
|
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
# Colors (numeric) and attributes (bitwise) ($tb_cell->fg, $tb_cell->bg)
|
|
552
|
|
|
|
|
|
|
use constant {
|
|
553
|
37
|
|
|
|
|
3333
|
TB_DEFAULT => 0x0000,
|
|
554
|
|
|
|
|
|
|
TB_BLACK => 0x0001,
|
|
555
|
|
|
|
|
|
|
TB_RED => 0x0002,
|
|
556
|
|
|
|
|
|
|
TB_GREEN => 0x0003,
|
|
557
|
|
|
|
|
|
|
TB_YELLOW => 0x0004,
|
|
558
|
|
|
|
|
|
|
TB_BLUE => 0x0005,
|
|
559
|
|
|
|
|
|
|
TB_MAGENTA => 0x0006,
|
|
560
|
|
|
|
|
|
|
TB_CYAN => 0x0007,
|
|
561
|
|
|
|
|
|
|
TB_WHITE => 0x0008,
|
|
562
|
37
|
|
|
37
|
|
155
|
};
|
|
|
37
|
|
|
|
|
64
|
|
|
563
|
|
|
|
|
|
|
|
|
564
|
37
|
|
|
37
|
|
118
|
BEGIN { if (TB_OPT_ATTR_W == 16) {
|
|
565
|
37
|
|
|
37
|
|
449
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
222
|
|
|
|
37
|
|
|
|
|
7142
|
|
|
566
|
|
|
|
|
|
|
*TB_BOLD = sub () { 0x0100 };
|
|
567
|
|
|
|
|
|
|
*TB_UNDERLINE = sub () { 0x0200 };
|
|
568
|
|
|
|
|
|
|
*TB_REVERSE = sub () { 0x0400 };
|
|
569
|
|
|
|
|
|
|
*TB_ITALIC = sub () { 0x0800 };
|
|
570
|
|
|
|
|
|
|
*TB_BLINK = sub () { 0x1000 };
|
|
571
|
|
|
|
|
|
|
*TB_HI_BLACK = sub () { 0x2000 };
|
|
572
|
|
|
|
|
|
|
*TB_BRIGHT = sub () { 0x4000 };
|
|
573
|
|
|
|
|
|
|
*TB_DIM = sub () { 0x8000 };
|
|
574
|
|
|
|
|
|
|
*TB_256_BLACK = &TB_HI_BLACK; # TB_256_BLACK is deprecated
|
|
575
|
|
|
|
|
|
|
}
|
|
576
|
|
|
|
|
|
|
else {
|
|
577
|
37
|
|
|
37
|
|
224
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
70
|
|
|
|
37
|
|
|
|
|
6503
|
|
|
578
|
37
|
|
|
|
|
72
|
*TB_BOLD = sub () { 0x00010000 };
|
|
579
|
37
|
|
|
|
|
59
|
*TB_UNDERLINE = sub () { 0x00020000 };
|
|
580
|
37
|
|
|
|
|
55
|
*TB_REVERSE = sub () { 0x00040000 };
|
|
581
|
37
|
|
|
|
|
63
|
*TB_ITALIC = sub () { 0x00080000 };
|
|
582
|
37
|
|
|
|
|
53
|
*TB_BLINK = sub () { 0x00100000 };
|
|
583
|
37
|
|
|
|
|
48
|
*TB_HI_BLACK = sub () { 0x00200000 };
|
|
584
|
37
|
|
|
|
|
47
|
*TB_BRIGHT = sub () { 0x00400000 };
|
|
585
|
37
|
|
|
|
|
85
|
*TB_DIM = sub () { 0x00800000 };
|
|
586
|
37
|
|
|
|
|
228
|
*TB_TRUECOLOR_BOLD = &TB_BOLD; # TB_TRUECOLOR_BOLD is deprecated
|
|
587
|
37
|
|
|
|
|
124
|
*TB_TRUECOLOR_UNDERLINE = &TB_UNDERLINE;
|
|
588
|
37
|
|
|
|
|
94
|
*TB_TRUECOLOR_REVERSE = &TB_REVERSE;
|
|
589
|
37
|
|
|
|
|
99
|
*TB_TRUECOLOR_ITALIC = &TB_ITALIC;
|
|
590
|
37
|
|
|
|
|
121
|
*TB_TRUECOLOR_BLINK = &TB_BLINK;
|
|
591
|
37
|
|
|
|
|
1355
|
*TB_TRUECOLOR_BLACK = &TB_HI_BLACK;
|
|
592
|
|
|
|
|
|
|
}}
|
|
593
|
|
|
|
|
|
|
|
|
594
|
37
|
|
|
37
|
|
104
|
BEGIN { if (TB_OPT_ATTR_W == 64) {
|
|
595
|
37
|
|
|
37
|
|
151
|
no warnings;
|
|
|
37
|
|
|
|
|
40
|
|
|
|
37
|
|
|
|
|
3518
|
|
|
596
|
37
|
|
|
|
|
65
|
*TB_STRIKEOUT = sub () { 0x010000000000 };
|
|
597
|
37
|
|
|
|
|
67
|
*TB_UNDERLINE_2 = sub () { 0x020000000000 };
|
|
598
|
37
|
|
|
|
|
77
|
*TB_OVERLINE = sub () { 0x040000000000 };
|
|
599
|
37
|
|
|
|
|
1057
|
*TB_INVISIBLE = sub () { 0x080000000000 };
|
|
600
|
|
|
|
|
|
|
}}
|
|
601
|
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
# Event types ($tb_event->type)
|
|
603
|
|
|
|
|
|
|
use constant {
|
|
604
|
37
|
|
|
|
|
3763
|
TB_EVENT_KEY => 1,
|
|
605
|
|
|
|
|
|
|
TB_EVENT_RESIZE => 2,
|
|
606
|
|
|
|
|
|
|
TB_EVENT_MOUSE => 3,
|
|
607
|
37
|
|
|
37
|
|
145
|
};
|
|
|
37
|
|
|
|
|
67
|
|
|
608
|
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
# Key modifiers (bitwise) ($tb_event->mod)
|
|
610
|
|
|
|
|
|
|
use constant {
|
|
611
|
37
|
|
|
|
|
2269
|
TB_MOD_ALT => 1,
|
|
612
|
|
|
|
|
|
|
TB_MOD_CTRL => 2,
|
|
613
|
|
|
|
|
|
|
TB_MOD_SHIFT => 4,
|
|
614
|
|
|
|
|
|
|
TB_MOD_MOTION => 8,
|
|
615
|
37
|
|
|
37
|
|
163
|
};
|
|
|
37
|
|
|
|
|
41
|
|
|
616
|
|
|
|
|
|
|
|
|
617
|
|
|
|
|
|
|
# Input modes (bitwise) (tb_set_input_mode)
|
|
618
|
|
|
|
|
|
|
use constant {
|
|
619
|
37
|
|
|
|
|
1886
|
TB_INPUT_CURRENT => 0,
|
|
620
|
|
|
|
|
|
|
TB_INPUT_ESC => 1,
|
|
621
|
|
|
|
|
|
|
TB_INPUT_ALT => 2,
|
|
622
|
|
|
|
|
|
|
TB_INPUT_MOUSE => 4,
|
|
623
|
37
|
|
|
37
|
|
140
|
};
|
|
|
37
|
|
|
|
|
40
|
|
|
624
|
|
|
|
|
|
|
|
|
625
|
|
|
|
|
|
|
# Output modes (bitwise) (tb_set_output_mode)
|
|
626
|
|
|
|
|
|
|
use constant {
|
|
627
|
37
|
|
|
|
|
2669
|
TB_OUTPUT_CURRENT => 0,
|
|
628
|
|
|
|
|
|
|
TB_OUTPUT_NORMAL => 1,
|
|
629
|
|
|
|
|
|
|
TB_OUTPUT_256 => 2,
|
|
630
|
|
|
|
|
|
|
TB_OUTPUT_216 => 4,
|
|
631
|
|
|
|
|
|
|
TB_OUTPUT_GRAYSCALE => 8,
|
|
632
|
37
|
|
|
37
|
|
141
|
};
|
|
|
37
|
|
|
|
|
43
|
|
|
633
|
37
|
|
|
37
|
|
108
|
BEGIN { if (TB_OPT_ATTR_W >= 32) {
|
|
634
|
37
|
|
|
37
|
|
148
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
61
|
|
|
|
37
|
|
|
|
|
2130
|
|
|
635
|
37
|
|
|
|
|
2747
|
*TB_OUTPUT_TRUECOLOR = sub () { 5 };
|
|
636
|
|
|
|
|
|
|
}}
|
|
637
|
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
# Common function return values unless otherwise noted.
|
|
639
|
|
|
|
|
|
|
use constant {
|
|
640
|
37
|
|
|
|
|
5830
|
TB_OK => 0,
|
|
641
|
|
|
|
|
|
|
TB_ERR => -1,
|
|
642
|
|
|
|
|
|
|
TB_ERR_NEED_MORE => -2,
|
|
643
|
|
|
|
|
|
|
TB_ERR_INIT_ALREADY => -3,
|
|
644
|
|
|
|
|
|
|
TB_ERR_INIT_OPEN => -4,
|
|
645
|
|
|
|
|
|
|
TB_ERR_MEM => -5,
|
|
646
|
|
|
|
|
|
|
TB_ERR_NO_EVENT => -6,
|
|
647
|
|
|
|
|
|
|
TB_ERR_NO_TERM => -7,
|
|
648
|
|
|
|
|
|
|
TB_ERR_NOT_INIT => -8,
|
|
649
|
|
|
|
|
|
|
TB_ERR_OUT_OF_BOUNDS => -9,
|
|
650
|
|
|
|
|
|
|
TB_ERR_READ => -10,
|
|
651
|
|
|
|
|
|
|
TB_ERR_RESIZE_IOCTL => -11,
|
|
652
|
|
|
|
|
|
|
TB_ERR_RESIZE_PIPE => -12,
|
|
653
|
|
|
|
|
|
|
TB_ERR_RESIZE_SIGACTION => -13,
|
|
654
|
|
|
|
|
|
|
TB_ERR_POLL => -14,
|
|
655
|
|
|
|
|
|
|
TB_ERR_TCGETATTR => -15,
|
|
656
|
|
|
|
|
|
|
TB_ERR_TCSETATTR => -16,
|
|
657
|
|
|
|
|
|
|
TB_ERR_UNSUPPORTED_TERM => -17,
|
|
658
|
|
|
|
|
|
|
TB_ERR_RESIZE_WRITE => -18,
|
|
659
|
|
|
|
|
|
|
TB_ERR_RESIZE_POLL => -19,
|
|
660
|
|
|
|
|
|
|
TB_ERR_RESIZE_READ => -20,
|
|
661
|
|
|
|
|
|
|
TB_ERR_RESIZE_SSCANF => -21,
|
|
662
|
|
|
|
|
|
|
TB_ERR_CAP_COLLISION => -22,
|
|
663
|
37
|
|
|
37
|
|
144
|
};
|
|
|
37
|
|
|
|
|
50
|
|
|
664
|
37
|
|
|
37
|
|
168
|
use constant TB_ERR_SELECT => TB_ERR_POLL;
|
|
|
37
|
|
|
|
|
39
|
|
|
|
37
|
|
|
|
|
1670
|
|
|
665
|
37
|
|
|
37
|
|
159
|
use constant TB_ERR_RESIZE_SELECT => TB_ERR_RESIZE_POLL;
|
|
|
37
|
|
|
|
|
62
|
|
|
|
37
|
|
|
|
|
1608
|
|
|
666
|
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
# Deprecated. Function types to be used with 'tb_set_func'.
|
|
668
|
|
|
|
|
|
|
use constant {
|
|
669
|
37
|
|
|
|
|
1900
|
TB_FUNC_EXTRACT_PRE => 0,
|
|
670
|
|
|
|
|
|
|
TB_FUNC_EXTRACT_POST => 1,
|
|
671
|
37
|
|
|
37
|
|
185
|
};
|
|
|
37
|
|
|
|
|
64
|
|
|
672
|
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
# Mouse escape parser type tags (enum equivalent)
|
|
674
|
|
|
|
|
|
|
use constant {
|
|
675
|
37
|
|
|
|
|
2005
|
TYPE_VT200 => 0,
|
|
676
|
|
|
|
|
|
|
TYPE_1006 => 1,
|
|
677
|
|
|
|
|
|
|
TYPE_1015 => 2,
|
|
678
|
|
|
|
|
|
|
TYPE_MAX => 3,
|
|
679
|
37
|
|
|
37
|
|
150
|
};
|
|
|
37
|
|
|
|
|
47
|
|
|
680
|
|
|
|
|
|
|
|
|
681
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
682
|
|
|
|
|
|
|
# Globals ----------------------------------------------------------------
|
|
683
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
684
|
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
# Holds the current state of the terminal
|
|
686
|
37
|
|
|
37
|
|
149
|
use vars qw( $global );
|
|
|
37
|
|
|
|
|
40
|
|
|
|
37
|
|
|
|
|
2617
|
|
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
689
|
|
|
|
|
|
|
# Utility functions ------------------------------------------------------
|
|
690
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
691
|
|
|
|
|
|
|
|
|
692
|
37
|
|
|
37
|
|
86
|
BEGIN { if ( TB_OPT_LIBC_WCHAR ) {
|
|
693
|
37
|
|
|
|
|
36821
|
require Unicode::UCD;
|
|
694
|
|
|
|
|
|
|
} else {
|
|
695
|
|
|
|
|
|
|
require Termbox::PP::WCWidth;
|
|
696
|
|
|
|
|
|
|
}}
|
|
697
|
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
# Determine if the current locale is CJK, which affects the width of
|
|
699
|
|
|
|
|
|
|
# 'A' (Ambiguous) characters.
|
|
700
|
|
|
|
|
|
|
our $is_cjk = eval {
|
|
701
|
|
|
|
|
|
|
require Unicode::EastAsianWidth::Detect;
|
|
702
|
|
|
|
|
|
|
Unicode::EastAsianWidth::Detect::is_cjk_lang() ? 1 : 0;
|
|
703
|
|
|
|
|
|
|
} || 0;
|
|
704
|
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
sub wcwidth {
|
|
706
|
60
|
|
|
60
|
0
|
154611
|
my ($cp) = @_;
|
|
707
|
|
|
|
|
|
|
|
|
708
|
60
|
50
|
33
|
|
|
167
|
return -1 if $cp < 0 || $cp > 0x10FFFF;
|
|
709
|
60
|
50
|
66
|
|
|
109
|
return -1 if $cp >= 0xD800 && $cp <= 0xDFFF;
|
|
710
|
60
|
100
|
|
|
|
82
|
return 0 if $cp == 0;
|
|
711
|
58
|
100
|
66
|
|
|
215
|
return -1 if $cp < 0x20 || ($cp >= 0x7F && $cp < 0xA0);
|
|
|
|
|
66
|
|
|
|
|
|
712
|
54
|
100
|
66
|
|
|
184
|
return 1 if $cp <= 0x7E || ($cp >= 0xA0 && $cp <= 0xFF);
|
|
|
|
|
100
|
|
|
|
|
|
713
|
|
|
|
|
|
|
|
|
714
|
21
|
|
|
|
|
32
|
state $cat = [ Unicode::UCD::prop_invmap('General_Category') ];
|
|
715
|
21
|
|
|
|
|
271632
|
state $eaw = [ Unicode::UCD::prop_invmap('East_Asian_Width') ];
|
|
716
|
21
|
|
|
|
|
16285
|
state $dig = [ Unicode::UCD::prop_invmap('Default_Ignorable_Code_Point') ];
|
|
717
|
|
|
|
|
|
|
|
|
718
|
21
|
|
|
|
|
2155
|
my $i = Unicode::UCD::search_invlist($cat->[0], $cp);
|
|
719
|
21
|
50
|
|
|
|
1236
|
if (defined $i) {
|
|
720
|
21
|
|
50
|
|
|
43
|
my $v = $cat->[1]->[$i] // '';
|
|
721
|
21
|
50
|
33
|
|
|
85
|
return -1
|
|
|
|
|
33
|
|
|
|
|
|
722
|
|
|
|
|
|
|
if $v eq 'Cc' || $v eq 'Cs' || $v eq 'Cn';
|
|
723
|
21
|
50
|
100
|
|
|
102
|
return 0
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
724
|
|
|
|
|
|
|
if $v eq 'Mn' || $v eq 'Me' || $v eq 'Cf' || $v eq 'Zl' || $v eq 'Zp';
|
|
725
|
|
|
|
|
|
|
}
|
|
726
|
|
|
|
|
|
|
|
|
727
|
17
|
|
|
|
|
26
|
$i = Unicode::UCD::search_invlist($dig->[0], $cp);
|
|
728
|
17
|
50
|
|
|
|
463
|
if (defined $i) {
|
|
729
|
17
|
|
50
|
|
|
27
|
my $v = $dig->[1]->[$i] // '';
|
|
730
|
17
|
50
|
33
|
|
|
105
|
return 0
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
731
|
|
|
|
|
|
|
if $v eq 'Y' || $v eq 'Yes' || $v eq 'T' || $v eq 'True' || $v eq '1';
|
|
732
|
|
|
|
|
|
|
}
|
|
733
|
|
|
|
|
|
|
|
|
734
|
17
|
|
|
|
|
27
|
$i = Unicode::UCD::search_invlist($eaw->[0], $cp);
|
|
735
|
17
|
50
|
|
|
|
769
|
if (defined $i) {
|
|
736
|
17
|
|
50
|
|
|
29
|
my $v = $eaw->[1]->[$i] // '';
|
|
737
|
17
|
100
|
66
|
|
|
48
|
return 2 if $v eq 'W' || $v eq 'F';
|
|
738
|
5
|
50
|
|
|
|
11
|
return $is_cjk ? 2 : 1 if $v eq 'A';
|
|
|
|
100
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
}
|
|
740
|
|
|
|
|
|
|
|
|
741
|
4
|
|
|
|
|
8
|
return 1;
|
|
742
|
|
|
|
|
|
|
}
|
|
743
|
|
|
|
|
|
|
|
|
744
|
|
|
|
|
|
|
# Use NCCS (if supported); otherwise, read at least 32 fields.
|
|
745
|
37
|
50
|
|
37
|
|
1221887
|
BEGIN { if (eval { &POSIX::NCCS }) {
|
|
|
37
|
|
|
|
|
211
|
|
|
746
|
37
|
|
|
|
|
27938
|
*NCCS = \&POSIX::NCCS;
|
|
747
|
|
|
|
|
|
|
} else {
|
|
748
|
0
|
|
|
|
|
0
|
*NCCS = sub () { 32 };
|
|
749
|
|
|
|
|
|
|
}}
|
|
750
|
|
|
|
|
|
|
|
|
751
|
|
|
|
|
|
|
sub cfmakeraw { # void (\$tios)
|
|
752
|
0
|
|
|
0
|
0
|
0
|
my ($tios) = @_;
|
|
753
|
0
|
0
|
0
|
|
|
0
|
return unless blessed($tios) && $tios->isa('POSIX::Termios');
|
|
754
|
0
|
|
|
|
|
0
|
$tios->setiflag(
|
|
755
|
|
|
|
|
|
|
$tios->getiflag()
|
|
756
|
|
|
|
|
|
|
& ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON)
|
|
757
|
|
|
|
|
|
|
);
|
|
758
|
0
|
|
|
|
|
0
|
$tios->setoflag(
|
|
759
|
|
|
|
|
|
|
$tios->getoflag()
|
|
760
|
|
|
|
|
|
|
& ~OPOST
|
|
761
|
|
|
|
|
|
|
);
|
|
762
|
0
|
|
|
|
|
0
|
$tios->setlflag(
|
|
763
|
|
|
|
|
|
|
$tios->getlflag()
|
|
764
|
|
|
|
|
|
|
& ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN)
|
|
765
|
|
|
|
|
|
|
);
|
|
766
|
0
|
|
|
|
|
0
|
$tios->setcflag(
|
|
767
|
|
|
|
|
|
|
($tios->getcflag() & ~(CSIZE | PARENB)) | CS8
|
|
768
|
|
|
|
|
|
|
);
|
|
769
|
0
|
|
|
|
|
0
|
return;
|
|
770
|
|
|
|
|
|
|
}
|
|
771
|
|
|
|
|
|
|
|
|
772
|
|
|
|
|
|
|
my $clone = sub { # $clone ()
|
|
773
|
|
|
|
|
|
|
my ($src) = @_;
|
|
774
|
|
|
|
|
|
|
return undef unless blessed($src) && $src->isa('POSIX::Termios');
|
|
775
|
|
|
|
|
|
|
my $dst = POSIX::Termios->new();
|
|
776
|
|
|
|
|
|
|
$dst->setiflag($src->getiflag());
|
|
777
|
|
|
|
|
|
|
$dst->setoflag($src->getoflag());
|
|
778
|
|
|
|
|
|
|
$dst->setcflag($src->getcflag());
|
|
779
|
|
|
|
|
|
|
$dst->setlflag($src->getlflag());
|
|
780
|
|
|
|
|
|
|
$dst->setispeed($src->getispeed());
|
|
781
|
|
|
|
|
|
|
$dst->setospeed($src->getospeed());
|
|
782
|
|
|
|
|
|
|
for my $i (0 .. NCCS - 1) {
|
|
783
|
|
|
|
|
|
|
$dst->setcc($i, $src->getcc($i));
|
|
784
|
|
|
|
|
|
|
}
|
|
785
|
|
|
|
|
|
|
return $dst;
|
|
786
|
|
|
|
|
|
|
};
|
|
787
|
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
789
|
|
|
|
|
|
|
# Params Check -----------------------------------------------------------
|
|
790
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
# This sub is a wrapper around Params::Check::check that provides positional
|
|
793
|
|
|
|
|
|
|
# argument checking. It returns a coderef that can be used to check the
|
|
794
|
|
|
|
|
|
|
# arguments of a function. The coderef will return the original arguments if
|
|
795
|
|
|
|
|
|
|
# they pass the checks, or will die with an error message if they fail.
|
|
796
|
|
|
|
|
|
|
# See Type::Params::compile for the inspiration for this function.
|
|
797
|
|
|
|
|
|
|
sub compile {
|
|
798
|
0
|
|
|
0
|
0
|
0
|
return sub { @_ } unless STRICT;
|
|
|
261
|
|
|
261
|
|
399
|
|
|
799
|
|
|
|
|
|
|
|
|
800
|
261
|
100
|
|
|
|
658
|
unless (@_) {
|
|
801
|
|
|
|
|
|
|
return sub {
|
|
802
|
56
|
50
|
|
56
|
|
183
|
Carp::croak "Expected no arguments" if @_;
|
|
803
|
56
|
|
|
|
|
73
|
return @_;
|
|
804
|
39
|
|
|
|
|
190
|
};
|
|
805
|
|
|
|
|
|
|
}
|
|
806
|
|
|
|
|
|
|
|
|
807
|
222
|
|
|
|
|
314
|
my %tmpl;
|
|
808
|
222
|
|
|
|
|
928
|
@tmpl{1 .. @_} = @_;
|
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
return sub {
|
|
811
|
31702
|
|
|
31702
|
|
27251
|
my %in;
|
|
812
|
31702
|
|
|
|
|
51466
|
@in{1 .. @_} = @_;
|
|
813
|
|
|
|
|
|
|
|
|
814
|
31702
|
|
|
|
|
32187
|
local $Params::Check::STRIP_LEADING_DASHES = 0;
|
|
815
|
31702
|
|
|
|
|
27784
|
local $Params::Check::PRESERVE_CASE = 1;
|
|
816
|
31702
|
|
|
|
|
28337
|
local $Params::Check::CALLER_DEPTH
|
|
817
|
|
|
|
|
|
|
= $Params::Check::CALLER_DEPTH + 1;
|
|
818
|
|
|
|
|
|
|
|
|
819
|
31702
|
100
|
|
|
|
40281
|
Params::Check::check(\%tmpl, \%in, 0) or do {
|
|
820
|
16
|
|
|
|
|
1762
|
local $_ = Params::Check::last_error();
|
|
821
|
16
|
|
|
|
|
215
|
s/\bKey '(\d+)'/Argument #$1/g;
|
|
822
|
16
|
|
|
|
|
1944
|
Carp::croak $_;
|
|
823
|
|
|
|
|
|
|
};
|
|
824
|
|
|
|
|
|
|
|
|
825
|
31686
|
|
|
|
|
1952309
|
return @_;
|
|
826
|
222
|
|
|
|
|
1133
|
};
|
|
827
|
|
|
|
|
|
|
}
|
|
828
|
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
# Types::Standard like templates for Params::Check.
|
|
830
|
|
|
|
|
|
|
use constant {
|
|
831
|
|
|
|
|
|
|
_Bool => { required => 1, allow => qr/\A[01]?\z/ },
|
|
832
|
|
|
|
|
|
|
_Str => {
|
|
833
|
|
|
|
|
|
|
required => 1,
|
|
834
|
|
|
|
|
|
|
defined => 1, default => '', strict_type => 1
|
|
835
|
|
|
|
|
|
|
},
|
|
836
|
|
|
|
|
|
|
_Int => { required => 1, defined => 1, allow => qr/\A[-]?\d+\z/ },
|
|
837
|
|
|
|
|
|
|
_ClassName => { required => 1, defined => 1, allow => qr/\A\w+(::\w+)*\z/ },
|
|
838
|
|
|
|
|
|
|
_Ref => {
|
|
839
|
|
|
|
|
|
|
required => 1,
|
|
840
|
0
|
|
|
|
|
0
|
allow => ($] >= 5.016) ? \&CORE::ref : sub { ref($_[0]) }
|
|
841
|
|
|
|
|
|
|
},
|
|
842
|
|
|
|
|
|
|
_ScalarRef => {
|
|
843
|
|
|
|
|
|
|
required => 1, defined => 1, default => \undef,
|
|
844
|
|
|
|
|
|
|
strict_type => 1
|
|
845
|
|
|
|
|
|
|
},
|
|
846
|
|
|
|
|
|
|
_ArrayRef => { required => 1, defined => 1, default => [], strict_type => 1 },
|
|
847
|
|
|
|
|
|
|
_CodeRef => {
|
|
848
|
|
|
|
|
|
|
required => 1, defined => 1, default => sub { },
|
|
849
|
37
|
50
|
|
|
|
14137
|
strict_type => 1
|
|
850
|
|
|
|
|
|
|
},
|
|
851
|
|
|
|
|
|
|
_Object => { required => 1, allow => \&blessed },
|
|
852
|
37
|
|
|
37
|
|
345
|
};
|
|
|
37
|
|
|
|
|
59
|
|
|
853
|
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
sub _Maybe ($) {
|
|
855
|
7
|
|
|
7
|
|
14
|
my ($aref) = @_;
|
|
856
|
|
|
|
|
|
|
|
|
857
|
7
|
50
|
33
|
|
|
64
|
Carp::croak("_Maybe['a] expects exactly one template hashref")
|
|
|
|
|
33
|
|
|
|
|
|
858
|
|
|
|
|
|
|
unless ref($aref) eq 'ARRAY' && @$aref == 1 && ref($aref->[0]) eq 'HASH';
|
|
859
|
|
|
|
|
|
|
|
|
860
|
7
|
|
|
|
|
14
|
my ($t) = @$aref;
|
|
861
|
7
|
|
|
|
|
20
|
my %u = %$t;
|
|
862
|
|
|
|
|
|
|
|
|
863
|
7
|
|
|
|
|
16
|
my $allow = delete $u{allow};
|
|
864
|
7
|
|
|
|
|
23
|
my $strict_type = delete $u{strict_type};
|
|
865
|
7
|
|
|
|
|
11
|
my $default = $u{default};
|
|
866
|
|
|
|
|
|
|
|
|
867
|
7
|
|
|
|
|
10
|
$u{defined} = 0;
|
|
868
|
|
|
|
|
|
|
$u{allow} = sub {
|
|
869
|
35
|
|
|
35
|
|
3052
|
my ($v) = @_;
|
|
870
|
35
|
100
|
|
|
|
71
|
return 1 unless defined $v;
|
|
871
|
18
|
50
|
33
|
|
|
58
|
return 0 if $strict_type && ref($v) ne ref($default);
|
|
872
|
18
|
50
|
|
|
|
37
|
return 1 unless defined $allow;
|
|
873
|
0
|
0
|
|
|
|
0
|
return Params::Check::allow(
|
|
874
|
|
|
|
|
|
|
$v,
|
|
875
|
|
|
|
|
|
|
ref($allow) eq 'ARRAY' ? $allow : [ $allow ],
|
|
876
|
|
|
|
|
|
|
);
|
|
877
|
7
|
|
|
|
|
30
|
};
|
|
878
|
7
|
|
|
|
|
27
|
return \%u;
|
|
879
|
|
|
|
|
|
|
}
|
|
880
|
|
|
|
|
|
|
|
|
881
|
|
|
|
|
|
|
# Types::Common::Numeric like templates for Params::Check.
|
|
882
|
|
|
|
|
|
|
use constant {
|
|
883
|
37
|
|
|
|
|
7855
|
_PositiveInt => { required => 1, defined => 1, allow => qr/\A[1-9]\d*\z/ },
|
|
884
|
|
|
|
|
|
|
_PositiveOrZeroInt => { required => 1, defined => 1, allow => qr/\A\d+\z/ },
|
|
885
|
37
|
|
|
37
|
|
638
|
};
|
|
|
37
|
|
|
|
|
206
|
|
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
888
|
|
|
|
|
|
|
# Helper classes ---------------------------------------------------------
|
|
889
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
890
|
|
|
|
|
|
|
|
|
891
|
|
|
|
|
|
|
#
|
|
892
|
|
|
|
|
|
|
# The 'Termbox::Cell' class represents a single cell in the terminal.
|
|
893
|
|
|
|
|
|
|
#
|
|
894
|
|
|
|
|
|
|
|
|
895
|
|
|
|
|
|
|
sub Termbox::Cell::new { # $cell ()
|
|
896
|
11610
|
|
|
11610
|
|
369457
|
state $sig = compile(
|
|
897
|
|
|
|
|
|
|
_ClassName,
|
|
898
|
|
|
|
|
|
|
);
|
|
899
|
11610
|
|
|
|
|
11901
|
my ($class) = $sig->(@_);
|
|
900
|
11610
|
|
|
|
|
23407
|
return bless {
|
|
901
|
|
|
|
|
|
|
ch => '', # UFT8 string
|
|
902
|
|
|
|
|
|
|
fg => 0, # bitwise foreground attributes
|
|
903
|
|
|
|
|
|
|
bg => 0, # bitwise background attributes
|
|
904
|
|
|
|
|
|
|
}, $class;
|
|
905
|
|
|
|
|
|
|
}
|
|
906
|
|
|
|
|
|
|
|
|
907
|
1
|
|
|
1
|
|
2868
|
sub Termbox::Cell::ch { ord $_[0]->{ch} }
|
|
908
|
1
|
|
|
1
|
|
5
|
sub Termbox::Cell::fg { 0+ $_[0]->{fg} }
|
|
909
|
1
|
|
|
1
|
|
4
|
sub Termbox::Cell::bg { 0+ $_[0]->{bg} }
|
|
910
|
|
|
|
|
|
|
if (TB_OPT_EGC) {
|
|
911
|
37
|
|
|
37
|
|
291
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
87
|
|
|
|
37
|
|
|
|
|
210169
|
|
|
912
|
|
|
|
|
|
|
*Termbox::Cell::ech = sub {
|
|
913
|
2
|
|
|
2
|
|
6
|
my $ch = $_[0]->{ch};
|
|
914
|
2
|
50
|
|
|
|
16
|
length($ch) > 1 ? [ unpack('U*', $ch) ] : undef;
|
|
915
|
|
|
|
|
|
|
};
|
|
916
|
|
|
|
|
|
|
*Termbox::Cell::nech = sub {
|
|
917
|
1
|
|
|
1
|
|
1366
|
my $ch = $_[0]->{ch};
|
|
918
|
1
|
|
|
|
|
4
|
my $n = length($ch);
|
|
919
|
1
|
50
|
33
|
|
|
14
|
return ($ch =~ /\A\X\z/ && $n > 1) ? $n : 0;
|
|
920
|
|
|
|
|
|
|
};
|
|
921
|
|
|
|
|
|
|
*Termbox::Cell::cech = sub {
|
|
922
|
1
|
|
|
1
|
|
3
|
my $ech = $_[0]->ech;
|
|
923
|
1
|
50
|
|
|
|
6
|
$ech ? scalar(@$ech) : 0;
|
|
924
|
|
|
|
|
|
|
};
|
|
925
|
|
|
|
|
|
|
}
|
|
926
|
|
|
|
|
|
|
|
|
927
|
|
|
|
|
|
|
sub Termbox::Cell::set { # $int ($ch, $fg, $bg)
|
|
928
|
11584
|
|
|
11584
|
|
9870
|
state $sig = compile(
|
|
929
|
|
|
|
|
|
|
_Object,
|
|
930
|
|
|
|
|
|
|
_Str,
|
|
931
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
932
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
933
|
|
|
|
|
|
|
);
|
|
934
|
11584
|
|
|
|
|
11863
|
my ($cell, $ch, $fg, $bg) = $sig->(@_);
|
|
935
|
|
|
|
|
|
|
|
|
936
|
11584
|
100
|
|
|
|
15310
|
$ch = "\0" unless length($ch);
|
|
937
|
11584
|
|
|
|
|
13331
|
$cell->{ch} = TB_OPT_EGC ? $ch : substr($ch, 0, 1);
|
|
938
|
11584
|
|
|
|
|
10691
|
$cell->{fg} = $fg;
|
|
939
|
11584
|
|
|
|
|
10156
|
$cell->{bg} = $bg;
|
|
940
|
11584
|
|
|
|
|
15836
|
return TB_OK;
|
|
941
|
|
|
|
|
|
|
}
|
|
942
|
|
|
|
|
|
|
|
|
943
|
|
|
|
|
|
|
sub Termbox::Cell::equal { # $bool ($other)
|
|
944
|
6
|
|
|
6
|
|
19
|
state $sig = compile(
|
|
945
|
|
|
|
|
|
|
_Object,
|
|
946
|
|
|
|
|
|
|
_Object,
|
|
947
|
|
|
|
|
|
|
);
|
|
948
|
6
|
|
|
|
|
10
|
my ($a, $b) = $sig->(@_);
|
|
949
|
|
|
|
|
|
|
return 0
|
|
950
|
|
|
|
|
|
|
if !(ref $a && ref $b)
|
|
951
|
|
|
|
|
|
|
|| $a->{ch} ne $b->{ch}
|
|
952
|
|
|
|
|
|
|
|| $a->{fg} != $b->{fg}
|
|
953
|
6
|
100
|
33
|
|
|
67
|
|| $a->{bg} != $b->{bg};
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
954
|
3
|
|
|
|
|
14
|
return 1;
|
|
955
|
|
|
|
|
|
|
}
|
|
956
|
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
sub Termbox::Cell::copy { # $int ($src)
|
|
958
|
21
|
|
|
21
|
|
50
|
state $sig = compile(
|
|
959
|
|
|
|
|
|
|
_Object,
|
|
960
|
|
|
|
|
|
|
_Object,
|
|
961
|
|
|
|
|
|
|
);
|
|
962
|
21
|
|
|
|
|
43
|
my ($dst, $src) = $sig->(@_);
|
|
963
|
21
|
|
|
|
|
85
|
%$dst = %$src;
|
|
964
|
21
|
|
|
|
|
111
|
return TB_OK;
|
|
965
|
|
|
|
|
|
|
}
|
|
966
|
|
|
|
|
|
|
|
|
967
|
|
|
|
|
|
|
#
|
|
968
|
|
|
|
|
|
|
# The 'Termbox::Event' class represents an input event from the terminal.
|
|
969
|
|
|
|
|
|
|
#
|
|
970
|
|
|
|
|
|
|
|
|
971
|
|
|
|
|
|
|
sub Termbox::Event::new { # $event ()
|
|
972
|
17
|
|
|
17
|
|
528801
|
state $sig = compile(
|
|
973
|
|
|
|
|
|
|
_ClassName,
|
|
974
|
|
|
|
|
|
|
);
|
|
975
|
17
|
|
|
|
|
65
|
my ($class) = $sig->(@_);
|
|
976
|
17
|
|
|
|
|
138
|
return bless {
|
|
977
|
|
|
|
|
|
|
type => 0, # one of 'TB_EVENT_*' constants
|
|
978
|
|
|
|
|
|
|
mod => 0, # bitwise 'TB_MOD_*' constants
|
|
979
|
|
|
|
|
|
|
key => 0, # one of 'TB_KEY_*' constants
|
|
980
|
|
|
|
|
|
|
ch => 0, # a Unicode codepoint
|
|
981
|
|
|
|
|
|
|
w => 0, # resize height
|
|
982
|
|
|
|
|
|
|
h => 0, # resize height
|
|
983
|
|
|
|
|
|
|
x => 0, # mouse x
|
|
984
|
|
|
|
|
|
|
y => 0, # mouse y
|
|
985
|
|
|
|
|
|
|
}, $class;
|
|
986
|
|
|
|
|
|
|
};
|
|
987
|
|
|
|
|
|
|
|
|
988
|
1
|
|
|
1
|
|
14
|
sub Termbox::Event::type { $_[0]->{type} }
|
|
989
|
1
|
|
|
1
|
|
4
|
sub Termbox::Event::mod { $_[0]->{mod} }
|
|
990
|
1
|
|
|
1
|
|
4
|
sub Termbox::Event::key { $_[0]->{key} }
|
|
991
|
1
|
|
|
1
|
|
4
|
sub Termbox::Event::ch { $_[0]->{ch} }
|
|
992
|
1
|
|
|
1
|
|
4
|
sub Termbox::Event::w { $_[0]->{w} }
|
|
993
|
1
|
|
|
1
|
|
4
|
sub Termbox::Event::h { $_[0]->{h} }
|
|
994
|
1
|
|
|
1
|
|
4
|
sub Termbox::Event::x { $_[0]->{x} }
|
|
995
|
1
|
|
|
1
|
|
3
|
sub Termbox::Event::y { $_[0]->{y} }
|
|
996
|
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
#
|
|
998
|
|
|
|
|
|
|
# The 'cellbuf' class represents the cell buffer of the terminal,
|
|
999
|
|
|
|
|
|
|
# which holds the state of each cell on the screen.
|
|
1000
|
|
|
|
|
|
|
#
|
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
sub cellbuf::new { # $cellbuf ()
|
|
1003
|
106
|
|
|
106
|
|
542149
|
state $sig = compile(
|
|
1004
|
|
|
|
|
|
|
_ClassName,
|
|
1005
|
|
|
|
|
|
|
);
|
|
1006
|
106
|
|
|
|
|
199
|
my ($class) = $sig->(@_);
|
|
1007
|
106
|
|
|
|
|
1062
|
return bless {
|
|
1008
|
|
|
|
|
|
|
width => 0,
|
|
1009
|
|
|
|
|
|
|
height => 0,
|
|
1010
|
|
|
|
|
|
|
cells => [],
|
|
1011
|
|
|
|
|
|
|
}, $class;
|
|
1012
|
|
|
|
|
|
|
};
|
|
1013
|
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
sub cellbuf::init { # $int ($width, $height)
|
|
1015
|
21
|
|
|
21
|
|
6395
|
state $sig = compile(
|
|
1016
|
|
|
|
|
|
|
_Object,
|
|
1017
|
|
|
|
|
|
|
_PositiveInt,
|
|
1018
|
|
|
|
|
|
|
_PositiveInt,
|
|
1019
|
|
|
|
|
|
|
);
|
|
1020
|
21
|
|
|
|
|
45
|
my ($c, $w, $h) = $sig->(@_);
|
|
1021
|
21
|
|
|
|
|
53
|
$c->{width} = $w;
|
|
1022
|
21
|
|
|
|
|
32
|
$c->{height} = $h;
|
|
1023
|
21
|
|
|
|
|
508
|
$c->{cells} = [ map { Termbox::Cell->new() } 0 .. $w*$h-1 ];
|
|
|
11585
|
|
|
|
|
13533
|
|
|
1024
|
21
|
|
|
|
|
471
|
return TB_OK;
|
|
1025
|
|
|
|
|
|
|
}
|
|
1026
|
|
|
|
|
|
|
|
|
1027
|
|
|
|
|
|
|
sub cellbuf::clear { # $int ()
|
|
1028
|
14
|
|
|
14
|
|
4102
|
state $sig = compile(
|
|
1029
|
|
|
|
|
|
|
_Object,
|
|
1030
|
|
|
|
|
|
|
);
|
|
1031
|
14
|
|
|
|
|
37
|
my ($c) = $sig->(@_);
|
|
1032
|
14
|
|
|
|
|
42
|
my $rv;
|
|
1033
|
14
|
|
|
|
|
70
|
for my $i (0 .. $c->{width}*$c->{height}-1) {
|
|
1034
|
11557
|
50
|
|
|
|
17880
|
return $rv if $rv = $c->{cells}[$i]->set(' ', $global->{fg}, $global->{bg});
|
|
1035
|
|
|
|
|
|
|
}
|
|
1036
|
14
|
|
|
|
|
119
|
return TB_OK;
|
|
1037
|
|
|
|
|
|
|
}
|
|
1038
|
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
sub cellbuf::get { # $cell ($x, $y)
|
|
1040
|
32
|
|
|
32
|
|
95
|
state $sig = compile(
|
|
1041
|
|
|
|
|
|
|
_Object,
|
|
1042
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1043
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1044
|
|
|
|
|
|
|
);
|
|
1045
|
32
|
|
|
|
|
58
|
my ($c, $x, $y) = $sig->(@_);
|
|
1046
|
32
|
|
|
|
|
118
|
return $c->{cells}[ $x + $y * $c->{width} ];
|
|
1047
|
|
|
|
|
|
|
}
|
|
1048
|
|
|
|
|
|
|
|
|
1049
|
|
|
|
|
|
|
sub cellbuf::in_bounds { # $bool ($x, $y)
|
|
1050
|
46
|
|
|
46
|
|
86
|
state $sig = compile(
|
|
1051
|
|
|
|
|
|
|
_Object,
|
|
1052
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1053
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1054
|
|
|
|
|
|
|
);
|
|
1055
|
46
|
|
|
|
|
81
|
my ($c, $x, $y) = $sig->(@_);
|
|
1056
|
46
|
50
|
66
|
|
|
356
|
if ($x < 0 || $x >= $c->{width} || $y < 0 || $y >= $c->{height}) {
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
1057
|
3
|
|
|
|
|
16
|
return 0;
|
|
1058
|
|
|
|
|
|
|
}
|
|
1059
|
43
|
|
|
|
|
96
|
return 1;
|
|
1060
|
|
|
|
|
|
|
}
|
|
1061
|
|
|
|
|
|
|
|
|
1062
|
|
|
|
|
|
|
sub cellbuf::resize { # $int ($width, $height)
|
|
1063
|
5
|
|
|
5
|
|
22487
|
state $sig = compile(
|
|
1064
|
|
|
|
|
|
|
_Object,
|
|
1065
|
|
|
|
|
|
|
_PositiveInt,
|
|
1066
|
|
|
|
|
|
|
_PositiveInt,
|
|
1067
|
|
|
|
|
|
|
);
|
|
1068
|
5
|
|
|
|
|
17
|
my ($c, $w, $h) = $sig->(@_);
|
|
1069
|
5
|
|
|
|
|
10
|
my $rv;
|
|
1070
|
|
|
|
|
|
|
|
|
1071
|
5
|
|
|
|
|
9
|
my $ow = $c->{width};
|
|
1072
|
5
|
|
|
|
|
8
|
my $oh = $c->{height};
|
|
1073
|
|
|
|
|
|
|
|
|
1074
|
5
|
50
|
33
|
|
|
19
|
if ($ow == $w && $oh == $h) {
|
|
1075
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
1076
|
|
|
|
|
|
|
}
|
|
1077
|
|
|
|
|
|
|
|
|
1078
|
5
|
50
|
|
|
|
56
|
$w = $w < 1 ? 1 : $w;
|
|
1079
|
5
|
50
|
|
|
|
10
|
$h = $h < 1 ? 1 : $h;
|
|
1080
|
|
|
|
|
|
|
|
|
1081
|
5
|
100
|
|
|
|
11
|
my $minw = ($w < $ow) ? $w : $ow;
|
|
1082
|
5
|
100
|
|
|
|
10
|
my $minh = ($h < $oh) ? $h : $oh;
|
|
1083
|
|
|
|
|
|
|
|
|
1084
|
5
|
|
|
|
|
8
|
my $prev = $c->{cells};
|
|
1085
|
|
|
|
|
|
|
|
|
1086
|
5
|
|
|
|
|
16
|
$rv = $c->init($w, $h);
|
|
1087
|
5
|
50
|
|
|
|
14
|
return $rv if $rv != TB_OK;
|
|
1088
|
5
|
|
|
|
|
15
|
$rv = $c->clear();
|
|
1089
|
5
|
50
|
|
|
|
16
|
return $rv if $rv != TB_OK;
|
|
1090
|
|
|
|
|
|
|
|
|
1091
|
5
|
|
|
|
|
9
|
my ($x, $y);
|
|
1092
|
5
|
|
|
|
|
20
|
for ($x = 0; $x < $minw; $x++) {
|
|
1093
|
8
|
|
|
|
|
18
|
for ($y = 0; $y < $minh; $y++) {
|
|
1094
|
19
|
|
|
|
|
29
|
my ($src, $dst);
|
|
1095
|
19
|
|
|
|
|
37
|
$src = $prev->[($y * $ow) + $x];
|
|
1096
|
19
|
50
|
|
|
|
64
|
return TB_ERR_OUT_OF_BOUNDS unless $c->in_bounds($x, $y);
|
|
1097
|
19
|
|
|
|
|
53
|
$dst = $c->get($x, $y);
|
|
1098
|
19
|
50
|
|
|
|
40
|
return TB_ERR unless defined $dst;
|
|
1099
|
19
|
|
|
|
|
50
|
$rv = $dst->copy($src);
|
|
1100
|
19
|
50
|
|
|
|
70
|
return $rv if $rv != TB_OK;
|
|
1101
|
|
|
|
|
|
|
}
|
|
1102
|
|
|
|
|
|
|
}
|
|
1103
|
|
|
|
|
|
|
|
|
1104
|
5
|
|
|
|
|
40
|
return TB_OK;
|
|
1105
|
|
|
|
|
|
|
}
|
|
1106
|
|
|
|
|
|
|
|
|
1107
|
|
|
|
|
|
|
#
|
|
1108
|
|
|
|
|
|
|
# captrie class for terminal capability matching
|
|
1109
|
|
|
|
|
|
|
#
|
|
1110
|
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
sub captrie::new { # $captrie ()
|
|
1112
|
51
|
|
|
51
|
|
189582
|
state $sig = compile(
|
|
1113
|
|
|
|
|
|
|
_ClassName,
|
|
1114
|
|
|
|
|
|
|
);
|
|
1115
|
51
|
|
|
|
|
136
|
my ($class) = $sig->(@_);
|
|
1116
|
51
|
|
|
|
|
392
|
return bless {
|
|
1117
|
|
|
|
|
|
|
exact => {},
|
|
1118
|
|
|
|
|
|
|
prefixes => {},
|
|
1119
|
|
|
|
|
|
|
alt => undef,
|
|
1120
|
|
|
|
|
|
|
}, $class;
|
|
1121
|
|
|
|
|
|
|
}
|
|
1122
|
|
|
|
|
|
|
|
|
1123
|
|
|
|
|
|
|
sub captrie::clear { # $int ()
|
|
1124
|
5
|
|
|
5
|
|
11
|
state $sig = compile(
|
|
1125
|
|
|
|
|
|
|
_Object,
|
|
1126
|
|
|
|
|
|
|
);
|
|
1127
|
5
|
|
|
|
|
15
|
my ($self) = $sig->(@_);
|
|
1128
|
5
|
|
|
|
|
34
|
$self->{exact} = {};
|
|
1129
|
5
|
|
|
|
|
10
|
$self->{prefixes} = {};
|
|
1130
|
5
|
|
|
|
|
10
|
$self->{alt} = undef;
|
|
1131
|
5
|
|
|
|
|
7
|
return TB_OK;
|
|
1132
|
|
|
|
|
|
|
}
|
|
1133
|
|
|
|
|
|
|
|
|
1134
|
|
|
|
|
|
|
sub captrie::rebuild_alt { # $int ()
|
|
1135
|
3
|
|
|
3
|
|
4
|
state $sig = compile(
|
|
1136
|
|
|
|
|
|
|
_Object,
|
|
1137
|
|
|
|
|
|
|
);
|
|
1138
|
3
|
|
|
|
|
5
|
my ($self) = $sig->(@_);
|
|
1139
|
|
|
|
|
|
|
my @ordered = sort {
|
|
1140
|
0
|
0
|
|
|
|
0
|
length($b) <=> length($a)
|
|
1141
|
|
|
|
|
|
|
|| $a cmp $b
|
|
1142
|
3
|
|
|
|
|
6
|
} keys %{ $self->{exact} };
|
|
|
3
|
|
|
|
|
10
|
|
|
1143
|
3
|
50
|
|
|
|
10
|
$self->{alt} = @ordered ? join('|', map { quotemeta($_) } @ordered) : undef;
|
|
|
3
|
|
|
|
|
11
|
|
|
1144
|
3
|
|
|
|
|
14
|
return TB_OK;
|
|
1145
|
|
|
|
|
|
|
}
|
|
1146
|
|
|
|
|
|
|
|
|
1147
|
|
|
|
|
|
|
sub captrie::has_prefix { # $bool ($s)
|
|
1148
|
3
|
|
|
3
|
|
5
|
state $sig = compile(
|
|
1149
|
|
|
|
|
|
|
_Object,
|
|
1150
|
|
|
|
|
|
|
_Str,
|
|
1151
|
|
|
|
|
|
|
);
|
|
1152
|
3
|
|
|
|
|
6
|
my ($self, $s) = $sig->(@_);
|
|
1153
|
3
|
50
|
|
|
|
10
|
return 0 unless length($s);
|
|
1154
|
3
|
100
|
|
|
|
17
|
return exists $self->{prefixes}{$s} ? 1 : 0;
|
|
1155
|
|
|
|
|
|
|
}
|
|
1156
|
|
|
|
|
|
|
|
|
1157
|
|
|
|
|
|
|
sub captrie::best_match { # $s|undef ($buf)
|
|
1158
|
3
|
|
|
3
|
|
5
|
state $sig = compile(
|
|
1159
|
|
|
|
|
|
|
_Object,
|
|
1160
|
|
|
|
|
|
|
_Str,
|
|
1161
|
|
|
|
|
|
|
);
|
|
1162
|
3
|
|
|
|
|
10
|
my ($self, $buf) = $sig->(@_);
|
|
1163
|
3
|
50
|
|
|
|
8
|
return undef unless length($buf);
|
|
1164
|
3
|
|
|
|
|
4
|
my $alt = $self->{alt};
|
|
1165
|
3
|
50
|
|
|
|
7
|
return undef unless defined $alt;
|
|
1166
|
3
|
100
|
|
|
|
76
|
return $1 if $buf =~ /\A($alt)/s;
|
|
1167
|
1
|
|
|
|
|
5
|
return undef;
|
|
1168
|
|
|
|
|
|
|
}
|
|
1169
|
|
|
|
|
|
|
|
|
1170
|
|
|
|
|
|
|
sub captrie::add { # $int ($cap, $key, $mod)
|
|
1171
|
3
|
|
|
3
|
|
29
|
state $sig = compile(
|
|
1172
|
|
|
|
|
|
|
_Object,
|
|
1173
|
|
|
|
|
|
|
_Str,
|
|
1174
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1175
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1176
|
|
|
|
|
|
|
);
|
|
1177
|
3
|
|
|
|
|
8
|
my ($self, $cap, $key, $mod) = $sig->(@_);
|
|
1178
|
|
|
|
|
|
|
# Nothing to do for empty caps
|
|
1179
|
3
|
50
|
|
|
|
7
|
return TB_OK unless length($cap);
|
|
1180
|
3
|
50
|
|
|
|
13
|
return TB_ERR_CAP_COLLISION if exists $self->{exact}{$cap};
|
|
1181
|
|
|
|
|
|
|
|
|
1182
|
3
|
|
|
|
|
13
|
$self->{exact}{$cap} = {
|
|
1183
|
|
|
|
|
|
|
key => 0 + $key,
|
|
1184
|
|
|
|
|
|
|
mod => 0 + $mod,
|
|
1185
|
|
|
|
|
|
|
};
|
|
1186
|
|
|
|
|
|
|
|
|
1187
|
3
|
|
|
|
|
9
|
for my $i (1 .. length($cap) - 1) {
|
|
1188
|
8
|
|
|
|
|
13
|
my $p = substr($cap, 0, $i);
|
|
1189
|
8
|
|
|
|
|
14
|
$self->{prefixes}{$p} = 1;
|
|
1190
|
|
|
|
|
|
|
}
|
|
1191
|
|
|
|
|
|
|
|
|
1192
|
3
|
|
|
|
|
10
|
return $self->rebuild_alt();
|
|
1193
|
|
|
|
|
|
|
}
|
|
1194
|
|
|
|
|
|
|
|
|
1195
|
|
|
|
|
|
|
sub captrie::find { # $int ($buf, \$last, \$depth)
|
|
1196
|
3
|
|
|
3
|
|
4
|
state $sig = compile(
|
|
1197
|
|
|
|
|
|
|
_Object,
|
|
1198
|
|
|
|
|
|
|
_Str,
|
|
1199
|
|
|
|
|
|
|
_Ref,
|
|
1200
|
|
|
|
|
|
|
_Ref,
|
|
1201
|
|
|
|
|
|
|
);
|
|
1202
|
3
|
|
|
|
|
6
|
my ($self, $buf, $last, $depth) = $sig->(@_);
|
|
1203
|
|
|
|
|
|
|
my $node = {
|
|
1204
|
|
|
|
|
|
|
is_leaf => 0,
|
|
1205
|
|
|
|
|
|
|
key => 0,
|
|
1206
|
|
|
|
|
|
|
mod => 0,
|
|
1207
|
3
|
50
|
|
|
|
7
|
nchildren => scalar(keys %{ $self->{exact} }) ? 1 : 0,
|
|
|
3
|
|
|
|
|
15
|
|
|
1208
|
|
|
|
|
|
|
cap => '',
|
|
1209
|
|
|
|
|
|
|
};
|
|
1210
|
|
|
|
|
|
|
|
|
1211
|
3
|
100
|
|
|
|
8
|
if (defined(my $m = $self->best_match($buf))) {
|
|
|
|
50
|
|
|
|
|
|
|
1212
|
2
|
|
|
|
|
18
|
my $leaf = $self->{exact}{$m};
|
|
1213
|
|
|
|
|
|
|
$node = {
|
|
1214
|
|
|
|
|
|
|
is_leaf => 1,
|
|
1215
|
|
|
|
|
|
|
key => $leaf->{key},
|
|
1216
|
|
|
|
|
|
|
mod => $leaf->{mod},
|
|
1217
|
|
|
|
|
|
|
# Keep C-shape node contract; derive child-ness from prefix table.
|
|
1218
|
2
|
50
|
|
|
|
9
|
nchildren => ($self->has_prefix($m) ? 1 : 0),
|
|
1219
|
|
|
|
|
|
|
cap => $m,
|
|
1220
|
|
|
|
|
|
|
};
|
|
1221
|
2
|
|
|
|
|
5
|
$$depth = length($m);
|
|
1222
|
|
|
|
|
|
|
}
|
|
1223
|
|
|
|
|
|
|
elsif ($self->has_prefix($buf)) {
|
|
1224
|
1
|
|
|
|
|
2
|
$node->{nchildren} = 1;
|
|
1225
|
1
|
|
|
|
|
3
|
$node->{cap} = $buf;
|
|
1226
|
1
|
|
|
|
|
2
|
$$depth = length($buf);
|
|
1227
|
|
|
|
|
|
|
}
|
|
1228
|
|
|
|
|
|
|
else {
|
|
1229
|
0
|
|
|
|
|
0
|
$$depth = 0;
|
|
1230
|
|
|
|
|
|
|
}
|
|
1231
|
|
|
|
|
|
|
|
|
1232
|
3
|
|
|
|
|
5
|
$$last = $node;
|
|
1233
|
3
|
|
|
|
|
6
|
return TB_OK;
|
|
1234
|
|
|
|
|
|
|
}
|
|
1235
|
|
|
|
|
|
|
|
|
1236
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
1237
|
|
|
|
|
|
|
# Global state and initialization ----------------------------------------
|
|
1238
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
1239
|
|
|
|
|
|
|
|
|
1240
|
|
|
|
|
|
|
#
|
|
1241
|
|
|
|
|
|
|
# The 'tb_global' struct holds the global state of the terminal, including
|
|
1242
|
|
|
|
|
|
|
# filehandles, terminal state, colors, modes, parser state, buffers,
|
|
1243
|
|
|
|
|
|
|
#
|
|
1244
|
|
|
|
|
|
|
|
|
1245
|
|
|
|
|
|
|
$global = {
|
|
1246
|
|
|
|
|
|
|
# Filehandles
|
|
1247
|
|
|
|
|
|
|
ttyfd => -1,
|
|
1248
|
|
|
|
|
|
|
rfd => -1,
|
|
1249
|
|
|
|
|
|
|
wfd => -1,
|
|
1250
|
|
|
|
|
|
|
ttyfd_open => -1,
|
|
1251
|
|
|
|
|
|
|
resize_pipefd => [-1, -1],
|
|
1252
|
|
|
|
|
|
|
|
|
1253
|
|
|
|
|
|
|
# Terminal state
|
|
1254
|
|
|
|
|
|
|
width => -1,
|
|
1255
|
|
|
|
|
|
|
height => -1,
|
|
1256
|
|
|
|
|
|
|
cursor_x => -1,
|
|
1257
|
|
|
|
|
|
|
cursor_y => -1,
|
|
1258
|
|
|
|
|
|
|
last_x => -1,
|
|
1259
|
|
|
|
|
|
|
last_y => -1,
|
|
1260
|
|
|
|
|
|
|
|
|
1261
|
|
|
|
|
|
|
# Colors
|
|
1262
|
|
|
|
|
|
|
fg => TB_DEFAULT,
|
|
1263
|
|
|
|
|
|
|
bg => TB_DEFAULT,
|
|
1264
|
|
|
|
|
|
|
last_fg => ~TB_DEFAULT,
|
|
1265
|
|
|
|
|
|
|
last_bg => ~TB_DEFAULT,
|
|
1266
|
|
|
|
|
|
|
|
|
1267
|
|
|
|
|
|
|
# Modes
|
|
1268
|
|
|
|
|
|
|
input_mode => TB_INPUT_ESC,
|
|
1269
|
|
|
|
|
|
|
output_mode => TB_OUTPUT_NORMAL,
|
|
1270
|
|
|
|
|
|
|
|
|
1271
|
|
|
|
|
|
|
# Terminfo
|
|
1272
|
|
|
|
|
|
|
terminfo => '',
|
|
1273
|
|
|
|
|
|
|
# ->{nterminfo} is not needed
|
|
1274
|
|
|
|
|
|
|
|
|
1275
|
|
|
|
|
|
|
# Parser
|
|
1276
|
|
|
|
|
|
|
caps => [ (undef) x TB_CAP__COUNT ],
|
|
1277
|
|
|
|
|
|
|
cap_trie => captrie->new(),
|
|
1278
|
|
|
|
|
|
|
|
|
1279
|
|
|
|
|
|
|
# Buffers
|
|
1280
|
|
|
|
|
|
|
inbuf => '',
|
|
1281
|
|
|
|
|
|
|
outbuf => '',
|
|
1282
|
|
|
|
|
|
|
back => cellbuf->new(),
|
|
1283
|
|
|
|
|
|
|
front => cellbuf->new(),
|
|
1284
|
|
|
|
|
|
|
|
|
1285
|
|
|
|
|
|
|
# Termios
|
|
1286
|
|
|
|
|
|
|
orig_tios => undef,
|
|
1287
|
|
|
|
|
|
|
has_orig_tios => 0,
|
|
1288
|
|
|
|
|
|
|
|
|
1289
|
|
|
|
|
|
|
# (Error) state
|
|
1290
|
|
|
|
|
|
|
last_errno => 0,
|
|
1291
|
|
|
|
|
|
|
errbuf => "",
|
|
1292
|
|
|
|
|
|
|
initialized => 0,
|
|
1293
|
|
|
|
|
|
|
# ->{errbuf} is not needed
|
|
1294
|
|
|
|
|
|
|
|
|
1295
|
|
|
|
|
|
|
# Custom callbacks for escape sequence parsing
|
|
1296
|
|
|
|
|
|
|
fn_extract_esc_pre => undef,
|
|
1297
|
|
|
|
|
|
|
fn_extract_esc_post => undef,
|
|
1298
|
|
|
|
|
|
|
};
|
|
1299
|
|
|
|
|
|
|
|
|
1300
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
1301
|
|
|
|
|
|
|
# Implementation of the termbox2 API incl. helpers ----------------------
|
|
1302
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
1303
|
|
|
|
|
|
|
|
|
1304
|
|
|
|
|
|
|
#
|
|
1305
|
|
|
|
|
|
|
# Forwarding declarations of the public termbox API.
|
|
1306
|
|
|
|
|
|
|
#
|
|
1307
|
|
|
|
|
|
|
|
|
1308
|
|
|
|
|
|
|
# Initialize the termbox library
|
|
1309
|
|
|
|
|
|
|
sub tb_init;
|
|
1310
|
|
|
|
|
|
|
sub tb_init_file;
|
|
1311
|
|
|
|
|
|
|
sub tb_init_fd;
|
|
1312
|
|
|
|
|
|
|
sub tb_init_rwfd;
|
|
1313
|
|
|
|
|
|
|
sub tb_shutdown;
|
|
1314
|
|
|
|
|
|
|
|
|
1315
|
|
|
|
|
|
|
# Return the size of the internal back buffer
|
|
1316
|
|
|
|
|
|
|
sub tb_width;
|
|
1317
|
|
|
|
|
|
|
sub tb_height;
|
|
1318
|
|
|
|
|
|
|
|
|
1319
|
|
|
|
|
|
|
# Clear the internal back buffer
|
|
1320
|
|
|
|
|
|
|
sub tb_clear;
|
|
1321
|
|
|
|
|
|
|
sub tb_set_clear_attrs;
|
|
1322
|
|
|
|
|
|
|
|
|
1323
|
|
|
|
|
|
|
# Synchronize the internal back buffer with the terminal by writing to tty
|
|
1324
|
|
|
|
|
|
|
sub tb_present;
|
|
1325
|
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
# Clear the internal front buffer and force a complete re-render
|
|
1327
|
|
|
|
|
|
|
sub tb_invalidate;
|
|
1328
|
|
|
|
|
|
|
|
|
1329
|
|
|
|
|
|
|
# Set the position of the cursor
|
|
1330
|
|
|
|
|
|
|
sub tb_set_cursor;
|
|
1331
|
|
|
|
|
|
|
sub tb_hide_cursor;
|
|
1332
|
|
|
|
|
|
|
|
|
1333
|
|
|
|
|
|
|
# Set cell contents in the internal back buffer at the specified position
|
|
1334
|
|
|
|
|
|
|
sub tb_set_cell;
|
|
1335
|
|
|
|
|
|
|
sub tb_set_cell_ex;
|
|
1336
|
|
|
|
|
|
|
sub tb_extend_cell;
|
|
1337
|
|
|
|
|
|
|
|
|
1338
|
|
|
|
|
|
|
# Return a reference to the cell at the specified position
|
|
1339
|
|
|
|
|
|
|
sub tb_get_cell;
|
|
1340
|
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
# Set the input and output mode
|
|
1342
|
|
|
|
|
|
|
sub tb_set_input_mode;
|
|
1343
|
|
|
|
|
|
|
sub tb_set_output_mode;
|
|
1344
|
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
# Wait for an event
|
|
1346
|
|
|
|
|
|
|
sub tb_peek_event;
|
|
1347
|
|
|
|
|
|
|
sub tb_poll_event;
|
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
# Internal termbox fds that can be used with 'poll', 'select'
|
|
1350
|
|
|
|
|
|
|
sub tb_get_fds;
|
|
1351
|
|
|
|
|
|
|
|
|
1352
|
|
|
|
|
|
|
# Print and printf functions
|
|
1353
|
|
|
|
|
|
|
sub tb_print;
|
|
1354
|
|
|
|
|
|
|
sub tb_printf;
|
|
1355
|
|
|
|
|
|
|
sub tb_print_ex;
|
|
1356
|
|
|
|
|
|
|
sub tb_printf_ex;
|
|
1357
|
|
|
|
|
|
|
|
|
1358
|
|
|
|
|
|
|
# Send raw bytes to terminal
|
|
1359
|
|
|
|
|
|
|
sub tb_send;
|
|
1360
|
|
|
|
|
|
|
sub tb_sendf;
|
|
1361
|
|
|
|
|
|
|
|
|
1362
|
|
|
|
|
|
|
# Set custom callbacks for escape sequence parsing
|
|
1363
|
|
|
|
|
|
|
sub tb_set_func; # Deprecated
|
|
1364
|
|
|
|
|
|
|
|
|
1365
|
|
|
|
|
|
|
# UTF-8 utility functions
|
|
1366
|
|
|
|
|
|
|
sub tb_utf8_char_length;
|
|
1367
|
|
|
|
|
|
|
sub tb_utf8_char_to_unicode;
|
|
1368
|
|
|
|
|
|
|
sub tb_utf8_unicode_to_char;
|
|
1369
|
|
|
|
|
|
|
|
|
1370
|
|
|
|
|
|
|
# Library utility functions
|
|
1371
|
|
|
|
|
|
|
sub tb_last_errno;
|
|
1372
|
|
|
|
|
|
|
sub tb_strerror;
|
|
1373
|
|
|
|
|
|
|
sub tb_cell_buffer; # Deprecated
|
|
1374
|
|
|
|
|
|
|
sub tb_has_truecolor;
|
|
1375
|
|
|
|
|
|
|
sub tb_has_egc;
|
|
1376
|
|
|
|
|
|
|
sub tb_attr_width;
|
|
1377
|
|
|
|
|
|
|
sub tb_version;
|
|
1378
|
|
|
|
|
|
|
sub tb_iswprint;
|
|
1379
|
|
|
|
|
|
|
sub tb_wcwidth;
|
|
1380
|
|
|
|
|
|
|
|
|
1381
|
|
|
|
|
|
|
#
|
|
1382
|
|
|
|
|
|
|
# Forwarding declarations of internal helper functions.
|
|
1383
|
|
|
|
|
|
|
#
|
|
1384
|
|
|
|
|
|
|
|
|
1385
|
|
|
|
|
|
|
# Process management helpers
|
|
1386
|
|
|
|
|
|
|
sub tb_reset;
|
|
1387
|
|
|
|
|
|
|
sub tb_printf_inner;
|
|
1388
|
|
|
|
|
|
|
sub tb_deinit;
|
|
1389
|
|
|
|
|
|
|
sub tb_iswprint_ex;
|
|
1390
|
|
|
|
|
|
|
sub tb_cluster_width;
|
|
1391
|
|
|
|
|
|
|
|
|
1392
|
|
|
|
|
|
|
# Terminal initialization helpers
|
|
1393
|
|
|
|
|
|
|
sub init_term_attrs;
|
|
1394
|
|
|
|
|
|
|
sub init_term_caps;
|
|
1395
|
|
|
|
|
|
|
|
|
1396
|
|
|
|
|
|
|
# Terminfo parsing helpers
|
|
1397
|
|
|
|
|
|
|
sub load_terminfo;
|
|
1398
|
|
|
|
|
|
|
sub load_terminfo_from_path;
|
|
1399
|
|
|
|
|
|
|
sub read_terminfo_path;
|
|
1400
|
|
|
|
|
|
|
sub parse_terminfo_caps;
|
|
1401
|
|
|
|
|
|
|
sub load_builtin_caps;
|
|
1402
|
|
|
|
|
|
|
sub get_terminfo_string;
|
|
1403
|
|
|
|
|
|
|
sub get_terminfo_int16;
|
|
1404
|
|
|
|
|
|
|
|
|
1405
|
|
|
|
|
|
|
# Resize handling helpers
|
|
1406
|
|
|
|
|
|
|
sub init_resize_handler;
|
|
1407
|
|
|
|
|
|
|
sub resize_cellbufs;
|
|
1408
|
|
|
|
|
|
|
sub handle_resize;
|
|
1409
|
|
|
|
|
|
|
sub update_term_size;
|
|
1410
|
|
|
|
|
|
|
sub update_term_size_via_esc;
|
|
1411
|
|
|
|
|
|
|
|
|
1412
|
|
|
|
|
|
|
# Escape-cap parser helpers
|
|
1413
|
|
|
|
|
|
|
sub init_cap_trie;
|
|
1414
|
|
|
|
|
|
|
sub cap_trie_add;
|
|
1415
|
|
|
|
|
|
|
sub cap_trie_find;
|
|
1416
|
|
|
|
|
|
|
sub cap_trie_deinit;
|
|
1417
|
|
|
|
|
|
|
|
|
1418
|
|
|
|
|
|
|
# Event extraction helpers
|
|
1419
|
|
|
|
|
|
|
sub wait_event;
|
|
1420
|
|
|
|
|
|
|
sub extract_event;
|
|
1421
|
|
|
|
|
|
|
sub extract_esc;
|
|
1422
|
|
|
|
|
|
|
sub extract_esc_user;
|
|
1423
|
|
|
|
|
|
|
sub extract_esc_cap;
|
|
1424
|
|
|
|
|
|
|
sub extract_esc_mouse;
|
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
# Cell related helpers
|
|
1427
|
|
|
|
|
|
|
sub cell_cmp;
|
|
1428
|
|
|
|
|
|
|
sub cell_copy;
|
|
1429
|
|
|
|
|
|
|
sub cell_set;
|
|
1430
|
|
|
|
|
|
|
sub cell_reserve_ech;
|
|
1431
|
|
|
|
|
|
|
sub cell_free;
|
|
1432
|
|
|
|
|
|
|
|
|
1433
|
|
|
|
|
|
|
# Cell buffer related helpers
|
|
1434
|
|
|
|
|
|
|
sub init_cellbuf;
|
|
1435
|
|
|
|
|
|
|
sub cellbuf_init;
|
|
1436
|
|
|
|
|
|
|
sub cellbuf_free;
|
|
1437
|
|
|
|
|
|
|
sub cellbuf_clear;
|
|
1438
|
|
|
|
|
|
|
sub cellbuf_get;
|
|
1439
|
|
|
|
|
|
|
sub cellbuf_in_bounds;
|
|
1440
|
|
|
|
|
|
|
sub cellbuf_resize;
|
|
1441
|
|
|
|
|
|
|
|
|
1442
|
|
|
|
|
|
|
# Sending output helpers
|
|
1443
|
|
|
|
|
|
|
sub send_literal;
|
|
1444
|
|
|
|
|
|
|
sub send_num;
|
|
1445
|
|
|
|
|
|
|
sub send_init_escape_codes;
|
|
1446
|
|
|
|
|
|
|
sub send_clear;
|
|
1447
|
|
|
|
|
|
|
sub send_attr;
|
|
1448
|
|
|
|
|
|
|
sub send_sgr;
|
|
1449
|
|
|
|
|
|
|
sub send_cursor_if;
|
|
1450
|
|
|
|
|
|
|
sub send_char;
|
|
1451
|
|
|
|
|
|
|
sub send_cluster;
|
|
1452
|
|
|
|
|
|
|
sub convert_num;
|
|
1453
|
|
|
|
|
|
|
|
|
1454
|
|
|
|
|
|
|
# Byte buffer related helpers
|
|
1455
|
|
|
|
|
|
|
sub bytebuf_puts;
|
|
1456
|
|
|
|
|
|
|
sub bytebuf_nputs;
|
|
1457
|
|
|
|
|
|
|
sub bytebuf_shift;
|
|
1458
|
|
|
|
|
|
|
sub bytebuf_flush;
|
|
1459
|
|
|
|
|
|
|
sub bytebuf_reserve;
|
|
1460
|
|
|
|
|
|
|
sub bytebuf_free;
|
|
1461
|
|
|
|
|
|
|
|
|
1462
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
1463
|
|
|
|
|
|
|
# Public API implementation ----------------------------------------------
|
|
1464
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
1465
|
|
|
|
|
|
|
|
|
1466
|
|
|
|
|
|
|
#
|
|
1467
|
|
|
|
|
|
|
# Initialize the termbox library
|
|
1468
|
|
|
|
|
|
|
#
|
|
1469
|
|
|
|
|
|
|
|
|
1470
|
|
|
|
|
|
|
sub tb_init { # $int ()
|
|
1471
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile();
|
|
1472
|
0
|
|
|
|
|
0
|
$sig->(@_);
|
|
1473
|
0
|
|
|
|
|
0
|
return tb_init_file('/dev/tty');
|
|
1474
|
|
|
|
|
|
|
}
|
|
1475
|
|
|
|
|
|
|
|
|
1476
|
|
|
|
|
|
|
sub tb_init_file { # $int ($path)
|
|
1477
|
1
|
|
|
1
|
0
|
3931
|
state $sig = compile(
|
|
1478
|
|
|
|
|
|
|
_Str,
|
|
1479
|
|
|
|
|
|
|
);
|
|
1480
|
1
|
|
|
|
|
3
|
my ($path) =$sig->(@_);
|
|
1481
|
1
|
50
|
|
|
|
6
|
return TB_ERR_INIT_ALREADY if $global->{initialized};
|
|
1482
|
|
|
|
|
|
|
|
|
1483
|
0
|
|
|
|
|
0
|
my $ttyfd = POSIX::open($path, POSIX::O_RDWR);
|
|
1484
|
0
|
0
|
0
|
|
|
0
|
if (!defined $ttyfd || $ttyfd < 0) {
|
|
1485
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
1486
|
0
|
|
|
|
|
0
|
return TB_ERR_INIT_OPEN;
|
|
1487
|
|
|
|
|
|
|
}
|
|
1488
|
|
|
|
|
|
|
|
|
1489
|
0
|
|
|
|
|
0
|
$global->{ttyfd_open} = 1;
|
|
1490
|
0
|
|
|
|
|
0
|
return tb_init_fd($ttyfd);
|
|
1491
|
|
|
|
|
|
|
}
|
|
1492
|
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
sub tb_init_fd { # $int ($ttyfd)
|
|
1494
|
1
|
|
|
1
|
0
|
3972
|
state $sig = compile(
|
|
1495
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1496
|
|
|
|
|
|
|
);
|
|
1497
|
1
|
|
|
|
|
11
|
my ($ttyfd) = $sig->(@_);
|
|
1498
|
1
|
|
|
|
|
4
|
return tb_init_rwfd($ttyfd, $ttyfd);
|
|
1499
|
|
|
|
|
|
|
}
|
|
1500
|
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
sub tb_init_rwfd { # $int ($rfd, $wfd)
|
|
1502
|
2
|
|
|
2
|
0
|
150489
|
state $sig = compile(
|
|
1503
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1504
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1505
|
|
|
|
|
|
|
);
|
|
1506
|
2
|
|
|
|
|
4
|
my ($rfd, $wfd) = $sig->(@_);
|
|
1507
|
|
|
|
|
|
|
|
|
1508
|
2
|
|
|
|
|
7
|
tb_reset();
|
|
1509
|
|
|
|
|
|
|
$global->{ttyfd} =
|
|
1510
|
2
|
0
|
|
|
|
6
|
POSIX::isatty($rfd) ? $rfd :
|
|
|
|
50
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
POSIX::isatty($wfd) ? $wfd :
|
|
1512
|
|
|
|
|
|
|
-1;
|
|
1513
|
2
|
|
|
|
|
8
|
$global->{rfd} = $rfd;
|
|
1514
|
2
|
|
|
|
|
3
|
$global->{wfd} = $wfd;
|
|
1515
|
|
|
|
|
|
|
|
|
1516
|
2
|
|
|
|
|
3
|
my $rv;
|
|
1517
|
2
|
|
|
|
|
4
|
for (1) {
|
|
1518
|
2
|
50
|
|
|
|
4
|
$rv = init_term_attrs(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
7
|
|
|
1519
|
2
|
50
|
|
|
|
2
|
$rv = init_term_caps(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
6
|
|
|
1520
|
2
|
50
|
|
|
|
4
|
$rv = init_cap_trie(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
6
|
|
|
1521
|
2
|
50
|
|
|
|
5
|
$rv = init_resize_handler(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
5
|
|
|
1522
|
2
|
50
|
|
|
|
5
|
$rv = send_init_escape_codes(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
5
|
|
|
1523
|
2
|
50
|
|
|
|
14
|
$rv = send_clear(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
6
|
|
|
1524
|
2
|
50
|
|
|
|
2
|
$rv = update_term_size(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
7
|
|
|
1525
|
2
|
50
|
|
|
|
3
|
$rv = init_cellbuf(); last if $rv != TB_OK;
|
|
|
2
|
|
|
|
|
5
|
|
|
1526
|
|
|
|
|
|
|
|
|
1527
|
2
|
|
|
|
|
4
|
$global->{initialized} = 1;
|
|
1528
|
|
|
|
|
|
|
};
|
|
1529
|
|
|
|
|
|
|
|
|
1530
|
2
|
50
|
|
|
|
4
|
tb_deinit() if $rv != TB_OK;
|
|
1531
|
|
|
|
|
|
|
|
|
1532
|
2
|
|
|
|
|
7
|
return $rv;
|
|
1533
|
|
|
|
|
|
|
}
|
|
1534
|
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
sub tb_shutdown { # $int ()
|
|
1536
|
2
|
|
|
2
|
0
|
6755
|
state $sig = compile();
|
|
1537
|
2
|
|
|
|
|
5
|
$sig->(@_);
|
|
1538
|
2
|
100
|
|
|
|
9
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1539
|
1
|
|
|
|
|
4
|
tb_deinit();
|
|
1540
|
1
|
|
|
|
|
5
|
return TB_OK;
|
|
1541
|
|
|
|
|
|
|
}
|
|
1542
|
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
#
|
|
1544
|
|
|
|
|
|
|
# Return the size of the internal back buffer
|
|
1545
|
|
|
|
|
|
|
#
|
|
1546
|
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
sub tb_width { # $int ()
|
|
1548
|
1
|
|
|
1
|
0
|
139313
|
state $sig = compile();
|
|
1549
|
1
|
|
|
|
|
4
|
$sig->(@_);
|
|
1550
|
1
|
50
|
|
|
|
3
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1551
|
1
|
|
|
|
|
2
|
return $global->{width};
|
|
1552
|
|
|
|
|
|
|
}
|
|
1553
|
|
|
|
|
|
|
|
|
1554
|
|
|
|
|
|
|
sub tb_height { # $int ()
|
|
1555
|
1
|
|
|
1
|
0
|
356
|
state $sig = compile();
|
|
1556
|
1
|
|
|
|
|
2
|
$sig->(@_);
|
|
1557
|
1
|
50
|
|
|
|
3
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1558
|
1
|
|
|
|
|
3
|
return $global->{height};
|
|
1559
|
|
|
|
|
|
|
}
|
|
1560
|
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
#
|
|
1562
|
|
|
|
|
|
|
# Clear the internal back buffer
|
|
1563
|
|
|
|
|
|
|
#
|
|
1564
|
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
sub tb_clear { # $int ()
|
|
1566
|
2
|
|
|
2
|
0
|
146035
|
state $sig = compile();
|
|
1567
|
2
|
|
|
|
|
5
|
$sig->(@_);
|
|
1568
|
2
|
100
|
|
|
|
7
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1569
|
1
|
|
|
|
|
5
|
return cellbuf_clear($global->{back});
|
|
1570
|
|
|
|
|
|
|
}
|
|
1571
|
|
|
|
|
|
|
|
|
1572
|
|
|
|
|
|
|
sub tb_set_clear_attrs { # $int ($fg, $bg)
|
|
1573
|
2
|
|
|
2
|
0
|
3192
|
state $sig = compile(
|
|
1574
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1575
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1576
|
|
|
|
|
|
|
);
|
|
1577
|
2
|
|
|
|
|
5
|
my ($fg, $bg) = $sig->(@_);
|
|
1578
|
2
|
100
|
|
|
|
9
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1579
|
1
|
|
|
|
|
4
|
$global->{fg} = $fg;
|
|
1580
|
1
|
|
|
|
|
3
|
$global->{bg} = $bg;
|
|
1581
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
1582
|
|
|
|
|
|
|
}
|
|
1583
|
|
|
|
|
|
|
|
|
1584
|
|
|
|
|
|
|
#
|
|
1585
|
|
|
|
|
|
|
# Synchronize the internal back buffer with the terminal by writing to tty
|
|
1586
|
|
|
|
|
|
|
#
|
|
1587
|
|
|
|
|
|
|
|
|
1588
|
|
|
|
|
|
|
sub tb_present { # $int ()
|
|
1589
|
1
|
|
|
1
|
0
|
5
|
state $sig = compile();
|
|
1590
|
1
|
|
|
|
|
2
|
$sig->(@_);
|
|
1591
|
1
|
50
|
|
|
|
4
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1592
|
|
|
|
|
|
|
|
|
1593
|
1
|
|
|
|
|
1
|
my $rv;
|
|
1594
|
|
|
|
|
|
|
|
|
1595
|
|
|
|
|
|
|
# TODO: assert $global->{back}[width,height] == global->{front}[width,height]
|
|
1596
|
|
|
|
|
|
|
|
|
1597
|
1
|
|
|
|
|
2
|
$global->{last_x} = -1;
|
|
1598
|
1
|
|
|
|
|
2
|
$global->{last_y} = -1;
|
|
1599
|
|
|
|
|
|
|
|
|
1600
|
1
|
|
|
|
|
2
|
my ($x, $y, $i);
|
|
1601
|
1
|
|
|
|
|
4
|
for ($y = 0; $y < $global->{front}{height}; $y++) {
|
|
1602
|
1
|
|
|
|
|
10
|
for ($x = 0; $x < $global->{front}{width}; ) {
|
|
1603
|
1
|
|
|
|
|
1
|
my ($back, $front);
|
|
1604
|
1
|
|
|
|
|
4
|
$rv = cellbuf_get($global->{back}, $x, $y, \$back);
|
|
1605
|
1
|
50
|
|
|
|
9
|
return $rv if $rv != TB_OK;
|
|
1606
|
1
|
|
|
|
|
3
|
$rv = cellbuf_get($global->{front}, $x, $y, \$front);
|
|
1607
|
1
|
50
|
|
|
|
6
|
return $rv if $rv != TB_OK;
|
|
1608
|
|
|
|
|
|
|
|
|
1609
|
1
|
|
|
|
|
1
|
my $w;
|
|
1610
|
1
|
50
|
33
|
|
|
12
|
if (TB_OPT_EGC and
|
|
1611
|
|
|
|
|
|
|
$back->{ch} =~ /\A\X\z/ && length($back->{ch}) > 1
|
|
1612
|
|
|
|
|
|
|
) {
|
|
1613
|
1
|
|
|
|
|
11
|
my $ech = [ unpack 'U*', $back->{ch} ];
|
|
1614
|
1
|
|
|
|
|
4
|
$w = tb_cluster_width($ech, scalar @$ech);
|
|
1615
|
|
|
|
|
|
|
} else {
|
|
1616
|
0
|
|
|
|
|
0
|
$w = tb_wcwidth(ord($back->{ch}));
|
|
1617
|
|
|
|
|
|
|
}
|
|
1618
|
1
|
50
|
|
|
|
4
|
$w = 1 if $w < 1; # wcwidth returns -1 for invalid codepoints
|
|
1619
|
|
|
|
|
|
|
|
|
1620
|
1
|
50
|
|
|
|
3
|
if (cell_cmp($back, $front) != 0) {
|
|
1621
|
1
|
|
|
|
|
5
|
%$front = %$back;
|
|
1622
|
|
|
|
|
|
|
|
|
1623
|
1
|
|
|
|
|
4
|
send_attr($back->{fg}, $back->{bg});
|
|
1624
|
1
|
50
|
33
|
|
|
7
|
if ($w > 1 && $x >= $global->{front}{width} - ($w - 1)) {
|
|
1625
|
|
|
|
|
|
|
# Not enough room for wide char, send spaces
|
|
1626
|
0
|
|
|
|
|
0
|
for ($i = $x; $i < $global->{front}{width}; $i++) {
|
|
1627
|
0
|
|
|
|
|
0
|
send_char($i, $y, ord(' '));
|
|
1628
|
|
|
|
|
|
|
}
|
|
1629
|
|
|
|
|
|
|
} else {
|
|
1630
|
1
|
50
|
33
|
|
|
7
|
if (TB_OPT_EGC and
|
|
1631
|
|
|
|
|
|
|
$back->{ch} =~ /\A\X\z/ && length($back->{ch}) > 1
|
|
1632
|
|
|
|
|
|
|
) {
|
|
1633
|
1
|
|
|
|
|
3
|
my $ech = [ unpack 'U*', $back->{ch} ];
|
|
1634
|
1
|
|
|
|
|
3
|
send_cluster($x, $y, $ech, scalar @$ech);
|
|
1635
|
|
|
|
|
|
|
} else {
|
|
1636
|
0
|
|
|
|
|
0
|
send_char($x, $y, ord($back->{ch}));
|
|
1637
|
|
|
|
|
|
|
}
|
|
1638
|
|
|
|
|
|
|
|
|
1639
|
|
|
|
|
|
|
# When wcwidth>1, we need to advance the cursor by more
|
|
1640
|
|
|
|
|
|
|
# than 1, thereby skipping some cells. Set these skipped
|
|
1641
|
|
|
|
|
|
|
# cells to an invalid codepoint in the front buffer, so
|
|
1642
|
|
|
|
|
|
|
# that if this cell is later replaced by a wcwidth==1
|
|
1643
|
|
|
|
|
|
|
# char, we'll get a cell_cmp diff for the skipped cells
|
|
1644
|
|
|
|
|
|
|
# and properly re-render.
|
|
1645
|
1
|
|
|
|
|
5
|
for ($i = 1; $i < $w; $i++) {
|
|
1646
|
0
|
|
|
|
|
0
|
my $front_wide;
|
|
1647
|
0
|
|
|
|
|
0
|
$rv = cellbuf_get($global->{front}, $x + $i, $y, \$front_wide);
|
|
1648
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
1649
|
0
|
|
|
|
|
0
|
my $invalid = "\x{fffd}";
|
|
1650
|
0
|
|
|
|
|
0
|
$rv = $front_wide->set($invalid, -1, -1);
|
|
1651
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
1652
|
|
|
|
|
|
|
}
|
|
1653
|
|
|
|
|
|
|
}
|
|
1654
|
|
|
|
|
|
|
}
|
|
1655
|
1
|
|
|
|
|
5
|
$x += $w;
|
|
1656
|
|
|
|
|
|
|
}
|
|
1657
|
|
|
|
|
|
|
}
|
|
1658
|
|
|
|
|
|
|
|
|
1659
|
1
|
|
|
|
|
3
|
$rv = send_cursor_if($global->{cursor_x}, $global->{cursor_y});
|
|
1660
|
1
|
50
|
|
|
|
4
|
return $rv if $rv != TB_OK;
|
|
1661
|
1
|
|
|
|
|
13
|
$rv = bytebuf_flush(\$global->{out}, $global->{wfd});
|
|
1662
|
1
|
50
|
|
|
|
5
|
return $rv if $rv != TB_OK;
|
|
1663
|
|
|
|
|
|
|
|
|
1664
|
1
|
|
|
|
|
33
|
return TB_OK;
|
|
1665
|
|
|
|
|
|
|
}
|
|
1666
|
|
|
|
|
|
|
|
|
1667
|
|
|
|
|
|
|
#
|
|
1668
|
|
|
|
|
|
|
# Clear the internal front buffer and force a complete re-render
|
|
1669
|
|
|
|
|
|
|
#
|
|
1670
|
|
|
|
|
|
|
|
|
1671
|
|
|
|
|
|
|
sub tb_invalidate { # $int ()
|
|
1672
|
3
|
|
|
3
|
0
|
2750
|
state $sig = compile();
|
|
1673
|
3
|
|
|
|
|
27
|
$sig->(@_);
|
|
1674
|
3
|
100
|
|
|
|
9
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1675
|
2
|
|
|
|
|
3
|
my $rv = resize_cellbufs();
|
|
1676
|
2
|
100
|
|
|
|
11
|
return $rv if $rv != TB_OK;
|
|
1677
|
1
|
|
|
|
|
3
|
return TB_OK;
|
|
1678
|
|
|
|
|
|
|
}
|
|
1679
|
|
|
|
|
|
|
|
|
1680
|
|
|
|
|
|
|
#
|
|
1681
|
|
|
|
|
|
|
# Set the position of the cursor
|
|
1682
|
|
|
|
|
|
|
#
|
|
1683
|
|
|
|
|
|
|
|
|
1684
|
|
|
|
|
|
|
sub tb_set_cursor { # $int ($cx, $cy)
|
|
1685
|
2
|
|
|
2
|
0
|
161717
|
state $sig = compile(
|
|
1686
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1687
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1688
|
|
|
|
|
|
|
);
|
|
1689
|
2
|
|
|
|
|
5
|
my ($cx, $cy) = $sig->(@_);
|
|
1690
|
2
|
100
|
|
|
|
11
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1691
|
|
|
|
|
|
|
|
|
1692
|
1
|
50
|
|
|
|
4
|
$cx = 0 if $cx < 0;
|
|
1693
|
1
|
50
|
|
|
|
30
|
$cy = 0 if $cy < 0;
|
|
1694
|
|
|
|
|
|
|
|
|
1695
|
1
|
|
|
|
|
3
|
my $rv;
|
|
1696
|
1
|
50
|
|
|
|
3
|
if ($global->{cursor_x} == -1) {
|
|
1697
|
1
|
|
|
|
|
3
|
$rv = bytebuf_puts(\$global->{out}, $global->{caps}[TB_CAP_SHOW_CURSOR]);
|
|
1698
|
1
|
50
|
|
|
|
5
|
return $rv if $rv != TB_OK;
|
|
1699
|
|
|
|
|
|
|
}
|
|
1700
|
1
|
|
|
|
|
3
|
$rv = send_cursor_if($cx, $cy);
|
|
1701
|
1
|
50
|
|
|
|
4
|
return $rv if $rv != TB_OK;
|
|
1702
|
|
|
|
|
|
|
|
|
1703
|
1
|
|
|
|
|
2
|
$global->{cursor_x} = $cx;
|
|
1704
|
1
|
|
|
|
|
2
|
$global->{cursor_y} = $cy;
|
|
1705
|
|
|
|
|
|
|
|
|
1706
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
1707
|
|
|
|
|
|
|
}
|
|
1708
|
|
|
|
|
|
|
|
|
1709
|
|
|
|
|
|
|
sub tb_hide_cursor { # $int ()
|
|
1710
|
1
|
|
|
1
|
0
|
3234
|
state $sig = compile();
|
|
1711
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
1712
|
1
|
50
|
|
|
|
3
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1713
|
|
|
|
|
|
|
|
|
1714
|
1
|
50
|
|
|
|
3
|
if ($global->{cursor_x} >= 0) {
|
|
1715
|
1
|
|
|
|
|
3
|
my $rv = bytebuf_puts(\$global->{out}, $global->{caps}[TB_CAP_HIDE_CURSOR]);
|
|
1716
|
1
|
50
|
|
|
|
6
|
return $rv if $rv != TB_OK;
|
|
1717
|
|
|
|
|
|
|
}
|
|
1718
|
|
|
|
|
|
|
|
|
1719
|
1
|
|
|
|
|
1
|
$global->{cursor_x} = -1;
|
|
1720
|
1
|
|
|
|
|
1
|
$global->{cursor_y} = -1;
|
|
1721
|
|
|
|
|
|
|
|
|
1722
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
1723
|
|
|
|
|
|
|
}
|
|
1724
|
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
#
|
|
1726
|
|
|
|
|
|
|
# Set cell contents in the internal back buffer at the specified position
|
|
1727
|
|
|
|
|
|
|
#
|
|
1728
|
|
|
|
|
|
|
|
|
1729
|
|
|
|
|
|
|
sub tb_set_cell { # $int ($x, $y, $ch, $fg, $bg)
|
|
1730
|
8
|
|
|
8
|
0
|
143814
|
state $sig = compile(
|
|
1731
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1732
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1733
|
|
|
|
|
|
|
_Str,
|
|
1734
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1735
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1736
|
|
|
|
|
|
|
);
|
|
1737
|
8
|
|
|
|
|
16
|
my ($x, $y, $ch, $fg, $bg) = $sig->(@_);
|
|
1738
|
|
|
|
|
|
|
# Note: tb_set_cell stores only the first Perl character
|
|
1739
|
8
|
|
|
|
|
30
|
return tb_set_cell_ex($x, $y, substr($ch, 0, 1), 1, $fg, $bg);
|
|
1740
|
|
|
|
|
|
|
}
|
|
1741
|
|
|
|
|
|
|
|
|
1742
|
|
|
|
|
|
|
sub tb_set_cell_ex { # $int ($x, $y, $ch, $nch, $fg, $bg)
|
|
1743
|
12
|
|
|
12
|
0
|
2948
|
state $sig = compile(
|
|
1744
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1745
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1746
|
|
|
|
|
|
|
_Str,
|
|
1747
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1748
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1749
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1750
|
|
|
|
|
|
|
);
|
|
1751
|
12
|
|
|
|
|
22
|
my ($x, $y, $ch, $nch, $fg, $bg) = $sig->(@_);
|
|
1752
|
|
|
|
|
|
|
# Note: ch is a Perl string, not an array of codepoints
|
|
1753
|
|
|
|
|
|
|
# Note: nch is accepted for API compatibility but ignored in the Perl port
|
|
1754
|
12
|
100
|
|
|
|
52
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1755
|
9
|
|
|
|
|
11
|
my $rv;
|
|
1756
|
|
|
|
|
|
|
my $cell;
|
|
1757
|
9
|
|
|
|
|
27
|
$rv = cellbuf_get($global->{back}, $x, $y, \$cell);
|
|
1758
|
9
|
50
|
|
|
|
26
|
return $rv if $rv != TB_OK;
|
|
1759
|
9
|
|
|
|
|
24
|
$rv = $cell->set($ch, $fg, $bg);
|
|
1760
|
9
|
50
|
|
|
|
17
|
return $rv if $rv != TB_OK;
|
|
1761
|
9
|
|
|
|
|
18
|
return TB_OK;
|
|
1762
|
|
|
|
|
|
|
}
|
|
1763
|
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
sub tb_extend_cell { # $int ($x, $y, $ch)
|
|
1765
|
3
|
|
|
3
|
0
|
1719
|
state $sig = compile(
|
|
1766
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1767
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1768
|
|
|
|
|
|
|
_Str,
|
|
1769
|
|
|
|
|
|
|
);
|
|
1770
|
3
|
|
|
|
|
9
|
my ($x, $y, $ch) = $sig->(@_);
|
|
1771
|
3
|
100
|
|
|
|
12
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1772
|
2
|
|
|
|
|
2
|
return TB_ERR unless TB_OPT_EGC;
|
|
1773
|
|
|
|
|
|
|
# TODO: iswprint ch?
|
|
1774
|
2
|
|
|
|
|
5
|
my $rv;
|
|
1775
|
|
|
|
|
|
|
my $cell;
|
|
1776
|
2
|
|
|
|
|
10
|
$rv = cellbuf_get($global->{back}, $x, $y, \$cell);
|
|
1777
|
2
|
50
|
|
|
|
6
|
return $rv if $rv != TB_OK;
|
|
1778
|
|
|
|
|
|
|
# Note: tb_extend_cell appends only the first Perl character
|
|
1779
|
2
|
|
|
|
|
13
|
$cell->{ch} .= substr($ch, 0, 1);
|
|
1780
|
2
|
|
|
|
|
5
|
return TB_OK;
|
|
1781
|
|
|
|
|
|
|
}
|
|
1782
|
|
|
|
|
|
|
|
|
1783
|
|
|
|
|
|
|
#
|
|
1784
|
|
|
|
|
|
|
# Return a reference to the cell at the specified position
|
|
1785
|
|
|
|
|
|
|
#
|
|
1786
|
|
|
|
|
|
|
|
|
1787
|
|
|
|
|
|
|
sub tb_get_cell { # $cell ($x, $y, $back, $cell)
|
|
1788
|
3
|
|
|
3
|
0
|
4133
|
state $sig = compile(
|
|
1789
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1790
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1791
|
|
|
|
|
|
|
_Bool,
|
|
1792
|
|
|
|
|
|
|
_Ref,
|
|
1793
|
|
|
|
|
|
|
);
|
|
1794
|
3
|
|
|
|
|
5
|
my ($x, $y, $back, $cell) = $sig->(@_);
|
|
1795
|
3
|
100
|
|
|
|
13
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1796
|
2
|
50
|
|
|
|
9
|
return cellbuf_get($back ? $global->{back} : $global->{front}, $x, $y, $cell);
|
|
1797
|
|
|
|
|
|
|
}
|
|
1798
|
|
|
|
|
|
|
|
|
1799
|
|
|
|
|
|
|
#
|
|
1800
|
|
|
|
|
|
|
# Set the input and output mode
|
|
1801
|
|
|
|
|
|
|
#
|
|
1802
|
|
|
|
|
|
|
|
|
1803
|
|
|
|
|
|
|
sub tb_set_input_mode { # $int ($mode)
|
|
1804
|
2
|
|
|
2
|
0
|
139471
|
state $sig = compile(
|
|
1805
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1806
|
|
|
|
|
|
|
);
|
|
1807
|
2
|
|
|
|
|
4
|
my ($mode) = $sig->(@_);
|
|
1808
|
2
|
50
|
|
|
|
7
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1809
|
|
|
|
|
|
|
|
|
1810
|
2
|
100
|
|
|
|
4
|
if ($mode == TB_INPUT_CURRENT) {
|
|
1811
|
1
|
|
|
|
|
5
|
return $global->{input_mode};
|
|
1812
|
|
|
|
|
|
|
}
|
|
1813
|
|
|
|
|
|
|
|
|
1814
|
1
|
|
|
|
|
2
|
my $esc_or_alt = TB_INPUT_ESC | TB_INPUT_ALT;
|
|
1815
|
1
|
50
|
|
|
|
5
|
if (($mode & $esc_or_alt) == 0) {
|
|
|
|
0
|
|
|
|
|
|
|
1816
|
|
|
|
|
|
|
# neither specified; flip on ESC
|
|
1817
|
1
|
|
|
|
|
3
|
$mode |= TB_INPUT_ESC;
|
|
1818
|
|
|
|
|
|
|
} elsif (($mode & $esc_or_alt) == $esc_or_alt) {
|
|
1819
|
|
|
|
|
|
|
# both specified; flip off ALT
|
|
1820
|
0
|
|
|
|
|
0
|
$mode &= ~TB_INPUT_ALT;
|
|
1821
|
|
|
|
|
|
|
}
|
|
1822
|
|
|
|
|
|
|
|
|
1823
|
1
|
50
|
|
|
|
3
|
if ($mode & TB_INPUT_MOUSE) {
|
|
1824
|
1
|
|
|
|
|
4
|
bytebuf_puts(\$global->{outbuf}, TB_HARDCAP_ENTER_MOUSE);
|
|
1825
|
1
|
|
|
|
|
3
|
bytebuf_flush(\$global->{outbuf}, $global->{wfd});
|
|
1826
|
|
|
|
|
|
|
} else {
|
|
1827
|
0
|
|
|
|
|
0
|
bytebuf_puts(\$global->{outbuf}, TB_HARDCAP_EXIT_MOUSE);
|
|
1828
|
0
|
|
|
|
|
0
|
bytebuf_flush(\$global->{outbuf}, $global->{wfd});
|
|
1829
|
|
|
|
|
|
|
}
|
|
1830
|
|
|
|
|
|
|
|
|
1831
|
1
|
|
|
|
|
3
|
$global->{input_mode} = $mode;
|
|
1832
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
1833
|
|
|
|
|
|
|
}
|
|
1834
|
|
|
|
|
|
|
|
|
1835
|
|
|
|
|
|
|
sub tb_set_output_mode { # $int ($mode)
|
|
1836
|
3
|
|
|
3
|
0
|
3387
|
state $sig = compile(
|
|
1837
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1838
|
|
|
|
|
|
|
);
|
|
1839
|
3
|
|
|
|
|
7
|
my ($mode) = $sig->(@_);
|
|
1840
|
2
|
50
|
|
|
|
6
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1841
|
2
|
|
|
|
|
4
|
switch: for ($mode) {
|
|
1842
|
|
|
|
|
|
|
case: TB_OUTPUT_CURRENT == $_ and
|
|
1843
|
2
|
100
|
|
|
|
9
|
return $global->{output_mode};
|
|
1844
|
|
|
|
|
|
|
case: TB_OUTPUT_NORMAL == $_ ||
|
|
1845
|
|
|
|
|
|
|
TB_OUTPUT_256 == $_ ||
|
|
1846
|
|
|
|
|
|
|
TB_OUTPUT_216 == $_ ||
|
|
1847
|
|
|
|
|
|
|
TB_OUTPUT_GRAYSCALE == $_ ||
|
|
1848
|
|
|
|
|
|
|
(TB_OPT_ATTR_W >= 32 && TB_OUTPUT_TRUECOLOR == $_) and do
|
|
1849
|
1
|
0
|
33
|
|
|
9
|
{
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
1850
|
1
|
|
|
|
|
3
|
$global->{last_fg} = ~$global->{fg};
|
|
1851
|
1
|
|
|
|
|
2
|
$global->{last_bg} = ~$global->{bg};
|
|
1852
|
1
|
|
|
|
|
2
|
$global->{output_mode} = $mode;
|
|
1853
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
1854
|
|
|
|
|
|
|
}
|
|
1855
|
|
|
|
|
|
|
}
|
|
1856
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
1857
|
|
|
|
|
|
|
}
|
|
1858
|
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
#
|
|
1860
|
|
|
|
|
|
|
# Wait for an event
|
|
1861
|
|
|
|
|
|
|
#
|
|
1862
|
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
sub tb_peek_event { # $int ($event, $timeout_ms)
|
|
1864
|
2
|
|
|
2
|
0
|
10
|
state $sig = compile(
|
|
1865
|
|
|
|
|
|
|
_Object,
|
|
1866
|
|
|
|
|
|
|
_Int,
|
|
1867
|
|
|
|
|
|
|
);
|
|
1868
|
2
|
|
|
|
|
4
|
my ($event, $timeout_ms) = $sig->(@_);
|
|
1869
|
2
|
100
|
|
|
|
11
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1870
|
1
|
|
|
|
|
3
|
return wait_event($event, $timeout_ms);
|
|
1871
|
|
|
|
|
|
|
}
|
|
1872
|
|
|
|
|
|
|
|
|
1873
|
|
|
|
|
|
|
sub tb_poll_event { # $int ($event)
|
|
1874
|
2
|
|
|
2
|
0
|
9
|
state $sig = compile(
|
|
1875
|
|
|
|
|
|
|
_Object,
|
|
1876
|
|
|
|
|
|
|
);
|
|
1877
|
2
|
|
|
|
|
5
|
my ($event) = $sig->(@_);
|
|
1878
|
2
|
100
|
|
|
|
8
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1879
|
1
|
|
|
|
|
2
|
return wait_event($event, -1);
|
|
1880
|
|
|
|
|
|
|
}
|
|
1881
|
|
|
|
|
|
|
|
|
1882
|
|
|
|
|
|
|
#
|
|
1883
|
|
|
|
|
|
|
# Internal termbox fds that can be used with 'poll', 'select'
|
|
1884
|
|
|
|
|
|
|
#
|
|
1885
|
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
sub tb_get_fds { # $int (\$ttyfd, \$resizefd)
|
|
1887
|
2
|
|
|
2
|
0
|
162723
|
state $sig = compile(
|
|
1888
|
|
|
|
|
|
|
_ScalarRef,
|
|
1889
|
|
|
|
|
|
|
_ScalarRef,
|
|
1890
|
|
|
|
|
|
|
);
|
|
1891
|
2
|
|
|
|
|
6
|
my ($ttyfd, $resizefd) = $sig->(@_);
|
|
1892
|
2
|
100
|
|
|
|
10
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1893
|
|
|
|
|
|
|
|
|
1894
|
1
|
|
|
|
|
2
|
$$ttyfd = $global->{rfd};
|
|
1895
|
1
|
|
|
|
|
3
|
$$resizefd = $global->{resize_pipefd}[0];
|
|
1896
|
|
|
|
|
|
|
|
|
1897
|
1
|
|
|
|
|
3
|
return TB_OK;
|
|
1898
|
|
|
|
|
|
|
}
|
|
1899
|
|
|
|
|
|
|
|
|
1900
|
|
|
|
|
|
|
#
|
|
1901
|
|
|
|
|
|
|
# Print and printf functions
|
|
1902
|
|
|
|
|
|
|
#
|
|
1903
|
|
|
|
|
|
|
|
|
1904
|
|
|
|
|
|
|
sub tb_print { # $int ($x, $y, $fg, $bg, $str)
|
|
1905
|
1
|
|
|
1
|
0
|
141591
|
state $sig = compile(
|
|
1906
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1907
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1908
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1909
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1910
|
|
|
|
|
|
|
_Str,
|
|
1911
|
|
|
|
|
|
|
);
|
|
1912
|
1
|
|
|
|
|
3
|
my ($x, $y, $fg, $bg, $str) = $sig->(@_);
|
|
1913
|
1
|
|
|
|
|
5
|
return tb_print_ex($x, $y, $fg, $bg, undef, $str);
|
|
1914
|
|
|
|
|
|
|
}
|
|
1915
|
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
sub tb_print_ex { # $int ($x, $y, $fg, $bg, \$out_w|undef, $str)
|
|
1917
|
11
|
|
|
11
|
0
|
2557
|
state $sig = compile(
|
|
1918
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1919
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1920
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1921
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1922
|
|
|
|
|
|
|
_Maybe[_ScalarRef],
|
|
1923
|
|
|
|
|
|
|
_Str,
|
|
1924
|
|
|
|
|
|
|
);
|
|
1925
|
11
|
|
|
|
|
23
|
my ($x, $y, $fg, $bg, $out_w, $str) = $sig->(@_);
|
|
1926
|
|
|
|
|
|
|
|
|
1927
|
10
|
100
|
|
|
|
37
|
return TB_ERR_NOT_INIT unless $global->{initialized};
|
|
1928
|
|
|
|
|
|
|
|
|
1929
|
3
|
|
|
|
|
5
|
my $back = $global->{back};
|
|
1930
|
3
|
50
|
|
|
|
13
|
return TB_ERR_OUT_OF_BOUNDS unless $back->in_bounds($x, $y);
|
|
1931
|
|
|
|
|
|
|
|
|
1932
|
3
|
50
|
|
|
|
9
|
$$out_w = 0 if defined $out_w;
|
|
1933
|
|
|
|
|
|
|
|
|
1934
|
3
|
|
|
|
|
5
|
my $rv;
|
|
1935
|
|
|
|
|
|
|
my $w;
|
|
1936
|
3
|
|
|
|
|
4
|
my $ix = $x;
|
|
1937
|
3
|
|
|
|
|
4
|
my $x_prev = $x;
|
|
1938
|
3
|
|
|
|
|
3
|
my $uni;
|
|
1939
|
|
|
|
|
|
|
|
|
1940
|
3
|
|
|
|
|
9
|
while ($str) {
|
|
1941
|
7
|
|
|
|
|
22
|
$rv = tb_utf8_char_to_unicode(\$uni, $str);
|
|
1942
|
7
|
50
|
|
|
|
17
|
if ($rv < 0) {
|
|
|
|
50
|
|
|
|
|
|
|
1943
|
0
|
|
|
|
|
0
|
$uni = 0xfffd; # replace invalid UTF-8 char with U+FFFD
|
|
1944
|
0
|
|
|
|
|
0
|
bytes::substr($str, 0, -$rv, '');
|
|
1945
|
|
|
|
|
|
|
} elsif ($rv > 0) {
|
|
1946
|
7
|
|
|
|
|
16
|
bytes::substr($str, 0, $rv, '');
|
|
1947
|
|
|
|
|
|
|
} else {
|
|
1948
|
0
|
|
|
|
|
0
|
last; # shouldn't get here
|
|
1949
|
|
|
|
|
|
|
}
|
|
1950
|
|
|
|
|
|
|
|
|
1951
|
7
|
50
|
|
|
|
34
|
if ($uni eq ord("\n")) { # TODO: \r, \t, \v, \f, etc?
|
|
1952
|
0
|
|
|
|
|
0
|
$x = $ix;
|
|
1953
|
0
|
|
|
|
|
0
|
$x_prev = $x;
|
|
1954
|
0
|
|
|
|
|
0
|
$y++;
|
|
1955
|
0
|
|
|
|
|
0
|
next;
|
|
1956
|
|
|
|
|
|
|
}
|
|
1957
|
|
|
|
|
|
|
|
|
1958
|
7
|
50
|
|
|
|
17
|
if (!tb_iswprint_ex($uni, \$w)) {
|
|
1959
|
0
|
|
|
|
|
0
|
$uni = 0xfffd; # replace non-printable with U+FFFD
|
|
1960
|
0
|
|
|
|
|
0
|
$w = 1;
|
|
1961
|
|
|
|
|
|
|
}
|
|
1962
|
|
|
|
|
|
|
|
|
1963
|
7
|
50
|
|
|
|
21
|
if ($w < 0) {
|
|
|
|
100
|
|
|
|
|
|
|
1964
|
0
|
|
|
|
|
0
|
return TB_ERR; # shouldn't happen if iswprint
|
|
1965
|
|
|
|
|
|
|
}
|
|
1966
|
|
|
|
|
|
|
elsif ($w == 0) { # combining character
|
|
1967
|
1
|
50
|
|
|
|
7
|
if ($back->in_bounds($x_prev, $y)) {
|
|
1968
|
1
|
|
|
|
|
7
|
$rv = tb_extend_cell($x_prev, $y, chr $uni);
|
|
1969
|
1
|
50
|
|
|
|
6
|
return $rv if $rv != TB_OK;
|
|
1970
|
|
|
|
|
|
|
}
|
|
1971
|
|
|
|
|
|
|
}
|
|
1972
|
|
|
|
|
|
|
else {
|
|
1973
|
6
|
50
|
|
|
|
12
|
if ($back->in_bounds($x, $y)) {
|
|
1974
|
6
|
|
|
|
|
51
|
$rv = tb_set_cell($x, $y, chr $uni, $fg, $bg);
|
|
1975
|
6
|
50
|
|
|
|
14
|
return $rv if $rv != TB_OK;
|
|
1976
|
|
|
|
|
|
|
}
|
|
1977
|
6
|
|
|
|
|
7
|
$x_prev = $x;
|
|
1978
|
6
|
|
|
|
|
7
|
$x += $w;
|
|
1979
|
6
|
50
|
|
|
|
14
|
$$out_w += $w if defined $out_w;
|
|
1980
|
|
|
|
|
|
|
}
|
|
1981
|
|
|
|
|
|
|
}
|
|
1982
|
|
|
|
|
|
|
|
|
1983
|
3
|
|
|
|
|
10
|
return TB_OK;
|
|
1984
|
|
|
|
|
|
|
}
|
|
1985
|
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
sub tb_printf { # $int ($x, $y, $fg, $bg, $fmt, @args)
|
|
1987
|
1
|
|
|
1
|
0
|
5266
|
state $sig = compile(
|
|
1988
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1989
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1990
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1991
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
1992
|
|
|
|
|
|
|
_Str,
|
|
1993
|
|
|
|
|
|
|
);
|
|
1994
|
1
|
|
|
|
|
4
|
my ($x, $y, $fg, $bg, $fmt, @args) = ($sig->(@_[0..4]), @_[5..$#_]);
|
|
1995
|
1
|
|
|
|
|
5
|
return tb_print_ex($x, $y, $fg, $bg, undef, $fmt, @args);
|
|
1996
|
|
|
|
|
|
|
}
|
|
1997
|
|
|
|
|
|
|
|
|
1998
|
|
|
|
|
|
|
sub tb_printf_ex { # $int ($x, $y, $fg, $bg, \$out_w, $fmt, @args)
|
|
1999
|
2
|
|
|
2
|
0
|
1046
|
goto &tb_printf_inner;
|
|
2000
|
|
|
|
|
|
|
}
|
|
2001
|
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
#
|
|
2003
|
|
|
|
|
|
|
# Send raw bytes to terminal
|
|
2004
|
|
|
|
|
|
|
#
|
|
2005
|
|
|
|
|
|
|
|
|
2006
|
|
|
|
|
|
|
sub tb_send { # $int ($buf, $nbuf)
|
|
2007
|
2
|
|
|
2
|
0
|
138384
|
state $sig = compile(
|
|
2008
|
|
|
|
|
|
|
_Str,
|
|
2009
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2010
|
|
|
|
|
|
|
);
|
|
2011
|
2
|
|
|
|
|
6
|
my ($buf, $nbuf) = $sig->(@_);
|
|
2012
|
2
|
|
|
|
|
7
|
return bytebuf_nputs(\$global->{outbuf}, $buf, $nbuf);
|
|
2013
|
|
|
|
|
|
|
}
|
|
2014
|
|
|
|
|
|
|
|
|
2015
|
|
|
|
|
|
|
sub tb_sendf { # $int ($fmt, @args)
|
|
2016
|
1
|
|
|
1
|
0
|
1287
|
state $sig = compile(
|
|
2017
|
|
|
|
|
|
|
_Str,
|
|
2018
|
|
|
|
|
|
|
);
|
|
2019
|
1
|
|
|
|
|
3
|
my ($fmt, @args) = ($sig->(shift), @_);
|
|
2020
|
1
|
50
|
|
|
|
6
|
my $buf = @args ? sprintf($fmt, @args) : $fmt;
|
|
2021
|
1
|
|
|
|
|
4
|
my $len = bytes::length($buf);
|
|
2022
|
1
|
50
|
|
|
|
7
|
return TB_ERR if $len >= TB_OPT_PRINTF_BUF;
|
|
2023
|
1
|
|
|
|
|
3
|
return tb_send($buf, $len);
|
|
2024
|
|
|
|
|
|
|
}
|
|
2025
|
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
#
|
|
2027
|
|
|
|
|
|
|
# Set custom callbacks for escape sequence parsing
|
|
2028
|
|
|
|
|
|
|
#
|
|
2029
|
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
sub tb_set_func {
|
|
2031
|
3
|
|
|
3
|
0
|
137260
|
state $sig = compile(
|
|
2032
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2033
|
|
|
|
|
|
|
_CodeRef,
|
|
2034
|
|
|
|
|
|
|
);
|
|
2035
|
3
|
|
|
|
|
6
|
my ($fn_type, $fn) = $sig->(@_);
|
|
2036
|
|
|
|
|
|
|
|
|
2037
|
2
|
|
|
|
|
4
|
state $warned = 0;
|
|
2038
|
2
|
100
|
|
|
|
14
|
warn "tb_set_func() is deprecated and may be removed in a future release\n"
|
|
2039
|
|
|
|
|
|
|
unless $warned++;
|
|
2040
|
|
|
|
|
|
|
|
|
2041
|
2
|
|
|
|
|
8
|
switch: for ($fn_type) {
|
|
2042
|
2
|
100
|
|
|
|
5
|
case: TB_FUNC_EXTRACT_PRE == $_ and do {
|
|
2043
|
1
|
|
|
|
|
3
|
$global->{fn_extract_esc_pre} = $fn;
|
|
2044
|
1
|
|
|
|
|
5
|
return TB_OK;
|
|
2045
|
|
|
|
|
|
|
};
|
|
2046
|
1
|
50
|
|
|
|
3
|
case: TB_FUNC_EXTRACT_POST == $_ and do {
|
|
2047
|
1
|
|
|
|
|
2
|
$global->{fn_extract_esc_post} = $fn;
|
|
2048
|
1
|
|
|
|
|
5
|
return TB_OK;
|
|
2049
|
|
|
|
|
|
|
};
|
|
2050
|
|
|
|
|
|
|
}
|
|
2051
|
|
|
|
|
|
|
|
|
2052
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
2053
|
|
|
|
|
|
|
}
|
|
2054
|
|
|
|
|
|
|
|
|
2055
|
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
#
|
|
2057
|
|
|
|
|
|
|
# UTF-8 utility functions
|
|
2058
|
|
|
|
|
|
|
#
|
|
2059
|
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
sub tb_utf8_char_length { # $length ($c)
|
|
2061
|
24
|
|
|
24
|
0
|
153486
|
state $sig = compile(
|
|
2062
|
|
|
|
|
|
|
_Str,
|
|
2063
|
|
|
|
|
|
|
);
|
|
2064
|
24
|
|
|
|
|
35
|
my ($c) = $sig->(@_);
|
|
2065
|
24
|
50
|
|
|
|
42
|
return 0 if $c eq '';
|
|
2066
|
24
|
|
|
|
|
74
|
$c = bytes::substr($c, 0, 1);
|
|
2067
|
24
|
|
|
|
|
93
|
state $utf8_length = {};
|
|
2068
|
24
|
|
66
|
|
|
81
|
$utf8_length->{$c} //= do {
|
|
2069
|
17
|
|
|
|
|
43
|
my $b = unpack('C', $c);
|
|
2070
|
17
|
50
|
|
|
|
89
|
($b < 0xC0) ? 1
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
2071
|
|
|
|
|
|
|
: ($b < 0xE0) ? 2
|
|
2072
|
|
|
|
|
|
|
: ($b < 0xF0) ? 3
|
|
2073
|
|
|
|
|
|
|
: ($b < 0xF8) ? 4
|
|
2074
|
|
|
|
|
|
|
: ($b < 0xFC) ? 5
|
|
2075
|
|
|
|
|
|
|
: ($b < 0xFE) ? 6
|
|
2076
|
|
|
|
|
|
|
: 1;
|
|
2077
|
|
|
|
|
|
|
};
|
|
2078
|
|
|
|
|
|
|
}
|
|
2079
|
|
|
|
|
|
|
|
|
2080
|
|
|
|
|
|
|
sub tb_utf8_char_to_unicode { # $length (\$out, $c)
|
|
2081
|
19
|
|
|
19
|
0
|
16037
|
state $sig = compile(
|
|
2082
|
|
|
|
|
|
|
_ScalarRef,
|
|
2083
|
|
|
|
|
|
|
_Str,
|
|
2084
|
|
|
|
|
|
|
);
|
|
2085
|
19
|
|
|
|
|
37
|
my ($out, $c) = $sig->(@_);
|
|
2086
|
37
|
|
|
37
|
|
304
|
use bytes;
|
|
|
37
|
|
|
|
|
77
|
|
|
|
37
|
|
|
|
|
189
|
|
|
2087
|
|
|
|
|
|
|
|
|
2088
|
19
|
50
|
|
|
|
38
|
return 0 if $c eq '';
|
|
2089
|
19
|
|
|
|
|
35
|
my $b0 = substr($c, 0, 1);
|
|
2090
|
19
|
100
|
|
|
|
31
|
return 0 if $b0 eq "\0";
|
|
2091
|
18
|
|
|
|
|
38
|
my $len = tb_utf8_char_length($b0);
|
|
2092
|
|
|
|
|
|
|
|
|
2093
|
18
|
|
|
|
|
45
|
my @c = unpack('C*', substr($c, 0, $len));
|
|
2094
|
|
|
|
|
|
|
|
|
2095
|
18
|
|
|
|
|
22
|
state $utf8_mask = [0x7F, 0x1F, 0x0F, 0x07, 0x03, 0x01];
|
|
2096
|
18
|
|
50
|
|
|
52
|
my $mask = $utf8_mask->[$len - 1] // 0x7F;
|
|
2097
|
|
|
|
|
|
|
|
|
2098
|
18
|
|
|
|
|
22
|
my $result = $c[0] & $mask;
|
|
2099
|
|
|
|
|
|
|
|
|
2100
|
18
|
|
|
|
|
22
|
my $i;
|
|
2101
|
18
|
|
100
|
|
|
64
|
for ($i = 1; $i < @c && $c[$i] != 0; $i++) {
|
|
2102
|
14
|
|
|
|
|
15
|
$result <<= 6;
|
|
2103
|
14
|
|
|
|
|
31
|
$result |= $c[$i] & 0x3F;
|
|
2104
|
|
|
|
|
|
|
}
|
|
2105
|
|
|
|
|
|
|
|
|
2106
|
18
|
100
|
|
|
|
37
|
return -$i if $i != $len;
|
|
2107
|
|
|
|
|
|
|
|
|
2108
|
12
|
|
|
|
|
15
|
$$out = $result;
|
|
2109
|
12
|
|
|
|
|
21
|
return $len;
|
|
2110
|
|
|
|
|
|
|
}
|
|
2111
|
|
|
|
|
|
|
|
|
2112
|
|
|
|
|
|
|
sub tb_utf8_unicode_to_char { # $length (\$out, $c)
|
|
2113
|
5
|
|
|
5
|
0
|
11238
|
state $sig = compile(
|
|
2114
|
|
|
|
|
|
|
_ScalarRef,
|
|
2115
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2116
|
|
|
|
|
|
|
);
|
|
2117
|
5
|
|
|
|
|
13
|
my ($out, $c) = $sig->(@_);
|
|
2118
|
|
|
|
|
|
|
|
|
2119
|
|
|
|
|
|
|
# Fast path for real Unicode scalar values (<= 0x10FFFF)
|
|
2120
|
5
|
100
|
|
|
|
12
|
if ($c <= 0x10FFFF) {
|
|
2121
|
4
|
|
|
|
|
8
|
my $s = chr($c);
|
|
2122
|
4
|
|
|
|
|
10
|
utf8::encode($s);
|
|
2123
|
4
|
|
|
|
|
4
|
$$out = $s;
|
|
2124
|
4
|
|
|
|
|
15
|
return bytes::length($s);
|
|
2125
|
|
|
|
|
|
|
}
|
|
2126
|
|
|
|
|
|
|
|
|
2127
|
|
|
|
|
|
|
# Fallback for "extended UTF-8" (5/6-byte), C-compatible behavior
|
|
2128
|
1
|
|
|
|
|
2
|
my ($first, $len);
|
|
2129
|
|
|
|
|
|
|
|
|
2130
|
1
|
50
|
|
|
|
8
|
if ($c < 0x80) { $first = 0x00; $len = 1; }
|
|
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
2131
|
0
|
|
|
|
|
0
|
elsif ($c < 0x800) { $first = 0xC0; $len = 2; }
|
|
|
0
|
|
|
|
|
0
|
|
|
2132
|
0
|
|
|
|
|
0
|
elsif ($c < 0x10000) { $first = 0xE0; $len = 3; }
|
|
|
0
|
|
|
|
|
0
|
|
|
2133
|
1
|
|
|
|
|
2
|
elsif ($c < 0x200000) { $first = 0xF0; $len = 4; }
|
|
|
1
|
|
|
|
|
1
|
|
|
2134
|
0
|
|
|
|
|
0
|
elsif ($c < 0x4000000) { $first = 0xF8; $len = 5; }
|
|
|
0
|
|
|
|
|
0
|
|
|
2135
|
0
|
|
|
|
|
0
|
else { $first = 0xFC; $len = 6; }
|
|
|
0
|
|
|
|
|
0
|
|
|
2136
|
|
|
|
|
|
|
|
|
2137
|
1
|
|
|
|
|
3
|
my @out = (0) x $len;
|
|
2138
|
1
|
|
|
|
|
4
|
for (my $i = $len - 1; $i > 0; --$i) {
|
|
2139
|
3
|
|
|
|
|
6
|
$out[$i] = ($c & 0x3F) | 0x80;
|
|
2140
|
3
|
|
|
|
|
4
|
$c >>= 6;
|
|
2141
|
|
|
|
|
|
|
}
|
|
2142
|
1
|
|
|
|
|
2
|
$out[0] = $c | $first;
|
|
2143
|
1
|
|
|
|
|
5
|
$$out = pack('C*', @out);
|
|
2144
|
|
|
|
|
|
|
|
|
2145
|
1
|
|
|
|
|
3
|
return $len;
|
|
2146
|
|
|
|
|
|
|
}
|
|
2147
|
|
|
|
|
|
|
|
|
2148
|
|
|
|
|
|
|
#
|
|
2149
|
|
|
|
|
|
|
# Library utility functions
|
|
2150
|
|
|
|
|
|
|
#
|
|
2151
|
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
sub tb_last_errno { # $int ()
|
|
2153
|
2
|
|
|
2
|
0
|
2738
|
state $sig = compile();
|
|
2154
|
2
|
|
|
|
|
7
|
$sig->(@_);
|
|
2155
|
2
|
|
|
|
|
9
|
return 0+ $global->{last_errno};
|
|
2156
|
|
|
|
|
|
|
}
|
|
2157
|
|
|
|
|
|
|
|
|
2158
|
|
|
|
|
|
|
sub tb_strerror { # $str ($err)
|
|
2159
|
4
|
|
|
4
|
0
|
292
|
state $sig = compile(
|
|
2160
|
|
|
|
|
|
|
_Int,
|
|
2161
|
|
|
|
|
|
|
);
|
|
2162
|
4
|
|
|
|
|
9
|
my ($err) = $sig->(@_);
|
|
2163
|
4
|
|
|
|
|
8
|
switch: for (int($err)) {
|
|
2164
|
4
|
100
|
|
|
|
10
|
case: TB_OK == $_ and do {
|
|
2165
|
1
|
|
|
|
|
5
|
return "Success"
|
|
2166
|
|
|
|
|
|
|
};
|
|
2167
|
3
|
100
|
|
|
|
6
|
case: TB_ERR_NEED_MORE == $_ and do {
|
|
2168
|
1
|
|
|
|
|
4
|
return "Not enough input"
|
|
2169
|
|
|
|
|
|
|
};
|
|
2170
|
2
|
50
|
|
|
|
3
|
case: TB_ERR_INIT_ALREADY == $_ and do {
|
|
2171
|
0
|
|
|
|
|
0
|
return "Termbox initialized already"
|
|
2172
|
|
|
|
|
|
|
};
|
|
2173
|
2
|
50
|
|
|
|
5
|
case: TB_ERR_MEM == $_ and do {
|
|
2174
|
0
|
|
|
|
|
0
|
return "Out of memory"
|
|
2175
|
|
|
|
|
|
|
};
|
|
2176
|
2
|
50
|
|
|
|
5
|
case: TB_ERR_NO_EVENT == $_ and do {
|
|
2177
|
0
|
|
|
|
|
0
|
return "No event"
|
|
2178
|
|
|
|
|
|
|
};
|
|
2179
|
2
|
50
|
|
|
|
3
|
case: TB_ERR_NO_TERM == $_ and do {
|
|
2180
|
0
|
|
|
|
|
0
|
return "No TERM in environment"
|
|
2181
|
|
|
|
|
|
|
};
|
|
2182
|
2
|
50
|
|
|
|
4
|
case: TB_ERR_NOT_INIT == $_ and do {
|
|
2183
|
0
|
|
|
|
|
0
|
return "Termbox not initialized"
|
|
2184
|
|
|
|
|
|
|
};
|
|
2185
|
2
|
50
|
|
|
|
5
|
case: TB_ERR_OUT_OF_BOUNDS == $_ and do {
|
|
2186
|
0
|
|
|
|
|
0
|
return "Out of bounds"
|
|
2187
|
|
|
|
|
|
|
};
|
|
2188
|
2
|
50
|
|
|
|
4
|
case: TB_ERR_UNSUPPORTED_TERM == $_ and do {
|
|
2189
|
0
|
|
|
|
|
0
|
return "Unsupported terminal"
|
|
2190
|
|
|
|
|
|
|
};
|
|
2191
|
2
|
50
|
|
|
|
4
|
case: TB_ERR_CAP_COLLISION == $_ and do {
|
|
2192
|
0
|
|
|
|
|
0
|
return "Termcaps collision"
|
|
2193
|
|
|
|
|
|
|
};
|
|
2194
|
2
|
50
|
|
|
|
3
|
case: TB_ERR_RESIZE_SSCANF == $_ and do {
|
|
2195
|
0
|
|
|
|
|
0
|
return "Terminal width/height not received by sscanf() after resize"
|
|
2196
|
|
|
|
|
|
|
};
|
|
2197
|
|
|
|
|
|
|
case:
|
|
2198
|
|
|
|
|
|
|
TB_ERR == $_ ||
|
|
2199
|
|
|
|
|
|
|
TB_ERR_INIT_OPEN == $_ ||
|
|
2200
|
|
|
|
|
|
|
TB_ERR_READ == $_ ||
|
|
2201
|
|
|
|
|
|
|
TB_ERR_RESIZE_IOCTL == $_ ||
|
|
2202
|
|
|
|
|
|
|
TB_ERR_RESIZE_PIPE == $_ ||
|
|
2203
|
|
|
|
|
|
|
TB_ERR_RESIZE_SIGACTION == $_ ||
|
|
2204
|
|
|
|
|
|
|
TB_ERR_POLL == $_ ||
|
|
2205
|
|
|
|
|
|
|
TB_ERR_TCGETATTR == $_ ||
|
|
2206
|
|
|
|
|
|
|
TB_ERR_TCSETATTR == $_ ||
|
|
2207
|
|
|
|
|
|
|
TB_ERR_RESIZE_WRITE == $_ ||
|
|
2208
|
|
|
|
|
|
|
TB_ERR_RESIZE_POLL == $_ ||
|
|
2209
|
|
|
|
|
|
|
TB_ERR_RESIZE_READ == $_ and do
|
|
2210
|
2
|
50
|
66
|
|
|
24
|
{
|
|
|
|
|
66
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
2211
|
1
|
|
|
|
|
2
|
$! = $global->{last_errno};
|
|
2212
|
1
|
|
|
|
|
4
|
return "$!";
|
|
2213
|
|
|
|
|
|
|
};
|
|
2214
|
|
|
|
|
|
|
default: {
|
|
2215
|
1
|
|
|
|
|
2
|
$! = $global->{last_errno};
|
|
|
1
|
|
|
|
|
2
|
|
|
2216
|
1
|
|
|
|
|
3
|
return "$!";
|
|
2217
|
|
|
|
|
|
|
}
|
|
2218
|
|
|
|
|
|
|
}
|
|
2219
|
|
|
|
|
|
|
}
|
|
2220
|
|
|
|
|
|
|
|
|
2221
|
|
|
|
|
|
|
sub tb_cell_buffer { # \@ ()
|
|
2222
|
4
|
|
|
4
|
0
|
5889
|
state $sig = compile();
|
|
2223
|
4
|
|
|
|
|
11
|
$sig->(@_);
|
|
2224
|
|
|
|
|
|
|
|
|
2225
|
4
|
|
|
|
|
6
|
state $warned = 0;
|
|
2226
|
4
|
100
|
|
|
|
35
|
warn "tb_cell_buffer() is deprecated; ".
|
|
2227
|
|
|
|
|
|
|
"use tb_get_cell() and related APIs instead\n"
|
|
2228
|
|
|
|
|
|
|
unless $warned++;
|
|
2229
|
|
|
|
|
|
|
|
|
2230
|
4
|
|
|
|
|
16
|
my $back = $global->{back};
|
|
2231
|
4
|
50
|
33
|
|
|
30
|
return [] unless ref($back) eq 'cellbuf' && ref($back->{cells}) eq 'ARRAY';
|
|
2232
|
4
|
|
|
|
|
15
|
return $back->{cells};
|
|
2233
|
|
|
|
|
|
|
}
|
|
2234
|
|
|
|
|
|
|
|
|
2235
|
|
|
|
|
|
|
sub tb_has_truecolor { # $int ()
|
|
2236
|
1
|
|
|
1
|
0
|
3
|
state $sig = compile();
|
|
2237
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
2238
|
1
|
|
|
|
|
2
|
return TB_OPT_ATTR_W >= 32 ? 1 : 0;
|
|
2239
|
|
|
|
|
|
|
}
|
|
2240
|
|
|
|
|
|
|
|
|
2241
|
|
|
|
|
|
|
sub tb_has_egc { # $int ()
|
|
2242
|
1
|
|
|
1
|
0
|
315
|
state $sig = compile();
|
|
2243
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
2244
|
1
|
|
|
|
|
2
|
return TB_OPT_EGC ? 1 : 0;
|
|
2245
|
|
|
|
|
|
|
}
|
|
2246
|
|
|
|
|
|
|
|
|
2247
|
|
|
|
|
|
|
sub tb_attr_width { # $int ()
|
|
2248
|
1
|
|
|
1
|
0
|
301
|
state $sig = compile();
|
|
2249
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
2250
|
1
|
|
|
|
|
2
|
return TB_OPT_ATTR_W;
|
|
2251
|
|
|
|
|
|
|
}
|
|
2252
|
|
|
|
|
|
|
|
|
2253
|
|
|
|
|
|
|
sub tb_version { # $str ()
|
|
2254
|
1
|
|
|
1
|
0
|
138619
|
state $sig = compile();
|
|
2255
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
2256
|
1
|
|
|
|
|
5
|
return TB_VERSION_STR;
|
|
2257
|
|
|
|
|
|
|
}
|
|
2258
|
|
|
|
|
|
|
|
|
2259
|
|
|
|
|
|
|
sub tb_iswprint { # $int ($codepoint)
|
|
2260
|
12
|
|
|
12
|
0
|
146155
|
state $sig = compile(
|
|
2261
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2262
|
|
|
|
|
|
|
);
|
|
2263
|
12
|
|
|
|
|
20
|
my ($codepoint) = $sig->(@_);
|
|
2264
|
12
|
|
|
|
|
29
|
return tb_iswprint_ex($codepoint, undef);
|
|
2265
|
|
|
|
|
|
|
}
|
|
2266
|
|
|
|
|
|
|
|
|
2267
|
|
|
|
|
|
|
sub tb_wcwidth { # $int ($codepoint)
|
|
2268
|
8
|
|
|
8
|
0
|
9
|
state $sig = compile(
|
|
2269
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2270
|
|
|
|
|
|
|
);
|
|
2271
|
8
|
|
|
|
|
15
|
my ($codepoint) = $sig->(@_);
|
|
2272
|
8
|
|
|
|
|
10
|
if (TB_OPT_LIBC_WCHAR) {
|
|
2273
|
8
|
|
|
|
|
16
|
return wcwidth($codepoint);
|
|
2274
|
|
|
|
|
|
|
} else {
|
|
2275
|
|
|
|
|
|
|
return Termbox::PP::WCWidth::wcwidth($codepoint);
|
|
2276
|
|
|
|
|
|
|
}
|
|
2277
|
|
|
|
|
|
|
}
|
|
2278
|
|
|
|
|
|
|
|
|
2279
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
2280
|
|
|
|
|
|
|
# Internal helper implementation -----------------------------------------
|
|
2281
|
|
|
|
|
|
|
# ------------------------------------------------------------------------
|
|
2282
|
|
|
|
|
|
|
|
|
2283
|
|
|
|
|
|
|
#
|
|
2284
|
|
|
|
|
|
|
# Process Management Helpers
|
|
2285
|
|
|
|
|
|
|
#
|
|
2286
|
|
|
|
|
|
|
|
|
2287
|
|
|
|
|
|
|
sub tb_reset { # $int ()
|
|
2288
|
11
|
|
|
11
|
0
|
211728
|
state $sig = compile();
|
|
2289
|
11
|
|
|
|
|
29
|
$sig->(@_);
|
|
2290
|
|
|
|
|
|
|
|
|
2291
|
|
|
|
|
|
|
# Keep tty ownership flag, reset everything else like termbox2.
|
|
2292
|
11
|
|
50
|
|
|
36
|
my $ttyfd_open = $global->{ttyfd_open} // -1;
|
|
2293
|
11
|
|
|
|
|
118
|
$global = {
|
|
2294
|
|
|
|
|
|
|
ttyfd => -1,
|
|
2295
|
|
|
|
|
|
|
rfd => -1,
|
|
2296
|
|
|
|
|
|
|
wfd => -1,
|
|
2297
|
|
|
|
|
|
|
ttyfd_open => $ttyfd_open,
|
|
2298
|
|
|
|
|
|
|
resize_pipefd => [-1, -1],
|
|
2299
|
|
|
|
|
|
|
|
|
2300
|
|
|
|
|
|
|
width => -1,
|
|
2301
|
|
|
|
|
|
|
height => -1,
|
|
2302
|
|
|
|
|
|
|
cursor_x => -1,
|
|
2303
|
|
|
|
|
|
|
cursor_y => -1,
|
|
2304
|
|
|
|
|
|
|
last_x => -1,
|
|
2305
|
|
|
|
|
|
|
last_y => -1,
|
|
2306
|
|
|
|
|
|
|
|
|
2307
|
|
|
|
|
|
|
fg => TB_DEFAULT,
|
|
2308
|
|
|
|
|
|
|
bg => TB_DEFAULT,
|
|
2309
|
|
|
|
|
|
|
last_fg => ~TB_DEFAULT,
|
|
2310
|
|
|
|
|
|
|
last_bg => ~TB_DEFAULT,
|
|
2311
|
|
|
|
|
|
|
|
|
2312
|
|
|
|
|
|
|
input_mode => TB_INPUT_ESC,
|
|
2313
|
|
|
|
|
|
|
output_mode => TB_OUTPUT_NORMAL,
|
|
2314
|
|
|
|
|
|
|
|
|
2315
|
|
|
|
|
|
|
terminfo => '',
|
|
2316
|
|
|
|
|
|
|
|
|
2317
|
|
|
|
|
|
|
caps => [ (undef) x TB_CAP__COUNT ],
|
|
2318
|
|
|
|
|
|
|
cap_trie => captrie->new(),
|
|
2319
|
|
|
|
|
|
|
|
|
2320
|
|
|
|
|
|
|
inbuf => '',
|
|
2321
|
|
|
|
|
|
|
outbuf => '',
|
|
2322
|
|
|
|
|
|
|
back => cellbuf->new(),
|
|
2323
|
|
|
|
|
|
|
front => cellbuf->new(),
|
|
2324
|
|
|
|
|
|
|
|
|
2325
|
|
|
|
|
|
|
orig_tios => undef,
|
|
2326
|
|
|
|
|
|
|
has_orig_tios => 0,
|
|
2327
|
|
|
|
|
|
|
|
|
2328
|
|
|
|
|
|
|
last_errno => 0,
|
|
2329
|
|
|
|
|
|
|
errbuf => '',
|
|
2330
|
|
|
|
|
|
|
initialized => 0,
|
|
2331
|
|
|
|
|
|
|
|
|
2332
|
|
|
|
|
|
|
fn_extract_esc_pre => undef,
|
|
2333
|
|
|
|
|
|
|
fn_extract_esc_post => undef,
|
|
2334
|
|
|
|
|
|
|
};
|
|
2335
|
|
|
|
|
|
|
|
|
2336
|
11
|
|
|
|
|
56
|
return TB_OK;
|
|
2337
|
|
|
|
|
|
|
}
|
|
2338
|
|
|
|
|
|
|
|
|
2339
|
|
|
|
|
|
|
sub tb_printf_inner { # $int ($x, $y, $fg, $bg, \$out_w, $fmt, @args)
|
|
2340
|
5
|
|
|
5
|
0
|
1973
|
state $sig = compile(
|
|
2341
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2342
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2343
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2344
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2345
|
|
|
|
|
|
|
_Maybe[_ScalarRef],
|
|
2346
|
|
|
|
|
|
|
_Str,
|
|
2347
|
|
|
|
|
|
|
);
|
|
2348
|
5
|
|
|
|
|
17
|
my ($x, $y, $fg, $bg, $out_w, $fmt, @args) = ($sig->(@_[0..5]), @_[6..$#_]);
|
|
2349
|
|
|
|
|
|
|
|
|
2350
|
4
|
100
|
|
|
|
15
|
my $str = @args ? sprintf($fmt, @args) : $fmt;
|
|
2351
|
4
|
50
|
33
|
|
|
118
|
return TB_ERR
|
|
2352
|
|
|
|
|
|
|
if !defined($str)
|
|
2353
|
|
|
|
|
|
|
|| length($str) >= TB_OPT_PRINTF_BUF;
|
|
2354
|
|
|
|
|
|
|
|
|
2355
|
4
|
|
|
|
|
13
|
return tb_print_ex($x, $y, $fg, $bg, $out_w, $str);
|
|
2356
|
|
|
|
|
|
|
}
|
|
2357
|
|
|
|
|
|
|
|
|
2358
|
|
|
|
|
|
|
sub tb_deinit { # $int ()
|
|
2359
|
5
|
|
|
5
|
0
|
6461
|
state $sig = compile();
|
|
2360
|
5
|
|
|
|
|
16
|
$sig->(@_);
|
|
2361
|
|
|
|
|
|
|
|
|
2362
|
5
|
50
|
33
|
|
|
21
|
if (defined($global->{caps}[0]) && $global->{wfd} >= 0) {
|
|
2363
|
0
|
|
|
|
|
0
|
bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_SHOW_CURSOR]);
|
|
2364
|
0
|
|
|
|
|
0
|
bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_SGR0]);
|
|
2365
|
0
|
|
|
|
|
0
|
bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_CLEAR_SCREEN]);
|
|
2366
|
0
|
|
|
|
|
0
|
bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_EXIT_CA]);
|
|
2367
|
0
|
|
|
|
|
0
|
bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_EXIT_KEYPAD]);
|
|
2368
|
0
|
|
|
|
|
0
|
bytebuf_puts(\$global->{outbuf}, TB_HARDCAP_EXIT_MOUSE);
|
|
2369
|
0
|
|
|
|
|
0
|
bytebuf_flush(\$global->{outbuf}, $global->{wfd});
|
|
2370
|
|
|
|
|
|
|
}
|
|
2371
|
|
|
|
|
|
|
|
|
2372
|
5
|
50
|
|
|
|
15
|
if ($global->{ttyfd} >= 0) {
|
|
2373
|
0
|
0
|
|
|
|
0
|
if ($global->{has_orig_tios}) {
|
|
2374
|
0
|
|
|
|
|
0
|
$global->{orig_tios}->setattr($global->{ttyfd}, TCSAFLUSH);
|
|
2375
|
|
|
|
|
|
|
}
|
|
2376
|
0
|
0
|
|
|
|
0
|
if ($global->{ttyfd_open}) {
|
|
2377
|
0
|
|
|
|
|
0
|
POSIX::close($global->{ttyfd});
|
|
2378
|
0
|
|
|
|
|
0
|
$global->{ttyfd_open} = 0;
|
|
2379
|
0
|
|
|
|
|
0
|
$global->{ttyfd} = -1;
|
|
2380
|
|
|
|
|
|
|
}
|
|
2381
|
|
|
|
|
|
|
}
|
|
2382
|
|
|
|
|
|
|
|
|
2383
|
5
|
50
|
|
|
|
61
|
$SIG{WINCH} = 'DEFAULT' if exists $SIG{WINCH};
|
|
2384
|
5
|
|
|
|
|
8
|
foreach my $fd (@{ $global->{resize_pipefd}}) {
|
|
|
5
|
|
|
|
|
16
|
|
|
2385
|
10
|
50
|
|
|
|
20
|
POSIX::close($fd) if $fd >= 0;
|
|
2386
|
|
|
|
|
|
|
}
|
|
2387
|
|
|
|
|
|
|
|
|
2388
|
5
|
|
|
|
|
18
|
cellbuf_free($global->{back});
|
|
2389
|
5
|
|
|
|
|
18
|
cellbuf_free($global->{front});
|
|
2390
|
5
|
|
|
|
|
23
|
bytebuf_free(\$global->{inbuf});
|
|
2391
|
5
|
|
|
|
|
11
|
bytebuf_free(\$global->{outbuf});
|
|
2392
|
|
|
|
|
|
|
|
|
2393
|
5
|
50
|
|
|
|
13
|
$global->{terminfo} = '' if $global->{terminfo};
|
|
2394
|
|
|
|
|
|
|
|
|
2395
|
5
|
50
|
|
|
|
49
|
my $rv = $global->{cap_trie}->clear() if $global->{cap_trie};
|
|
2396
|
5
|
50
|
|
|
|
13
|
return $rv if $rv != TB_OK;
|
|
2397
|
|
|
|
|
|
|
|
|
2398
|
5
|
|
|
|
|
18
|
tb_reset();
|
|
2399
|
5
|
|
|
|
|
20
|
return TB_OK;
|
|
2400
|
|
|
|
|
|
|
}
|
|
2401
|
|
|
|
|
|
|
|
|
2402
|
|
|
|
|
|
|
sub tb_iswprint_ex { # $bool ($ch, \$width|undef)
|
|
2403
|
19
|
|
|
19
|
0
|
28
|
state $sig = compile(
|
|
2404
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2405
|
|
|
|
|
|
|
_Maybe[_ScalarRef],
|
|
2406
|
|
|
|
|
|
|
);
|
|
2407
|
19
|
|
|
|
|
28
|
my ($ch, $width) = $sig->(@_);
|
|
2408
|
|
|
|
|
|
|
|
|
2409
|
19
|
|
|
|
|
21
|
if (TB_OPT_LIBC_WCHAR) {
|
|
2410
|
19
|
|
|
|
|
43
|
my $w = wcwidth($ch);
|
|
2411
|
19
|
100
|
|
|
|
36
|
$$width = $w if defined $width;
|
|
2412
|
|
|
|
|
|
|
|
|
2413
|
|
|
|
|
|
|
# NUL is not printable even though width is 0.
|
|
2414
|
19
|
100
|
100
|
|
|
133
|
return $ch != 0 && $w >= 0 ? 1 : 0;
|
|
2415
|
|
|
|
|
|
|
} else {
|
|
2416
|
|
|
|
|
|
|
|
|
2417
|
|
|
|
|
|
|
# Fast path for 1-byte codepoints
|
|
2418
|
|
|
|
|
|
|
if (($ch >= 0x20 && $ch <= 0x7e) || ($ch >= 0xa0 && $ch <= 0xff)) {
|
|
2419
|
|
|
|
|
|
|
$$width = 1 if defined $width;
|
|
2420
|
|
|
|
|
|
|
return 1;
|
|
2421
|
|
|
|
|
|
|
}
|
|
2422
|
|
|
|
|
|
|
if ($ch <= 0xff) {
|
|
2423
|
|
|
|
|
|
|
$$width = ($ch == 0 ? 0 : -1) if defined $width;
|
|
2424
|
|
|
|
|
|
|
return 0;
|
|
2425
|
|
|
|
|
|
|
}
|
|
2426
|
|
|
|
|
|
|
|
|
2427
|
|
|
|
|
|
|
my $w = Termbox::PP::WCWidth::wcwidth($ch);
|
|
2428
|
|
|
|
|
|
|
$$width = $w if defined $width;
|
|
2429
|
|
|
|
|
|
|
return $w >= 0 ? 1 : 0;
|
|
2430
|
|
|
|
|
|
|
}
|
|
2431
|
|
|
|
|
|
|
}
|
|
2432
|
|
|
|
|
|
|
|
|
2433
|
|
|
|
|
|
|
sub tb_cluster_width { # $int (\@cluster, $nch)
|
|
2434
|
9
|
|
|
9
|
0
|
7057
|
state $sig = compile(
|
|
2435
|
|
|
|
|
|
|
_ArrayRef,
|
|
2436
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2437
|
|
|
|
|
|
|
);
|
|
2438
|
9
|
|
|
|
|
19
|
my ($cluster, $nch) = $sig->(@_);
|
|
2439
|
|
|
|
|
|
|
|
|
2440
|
9
|
|
|
|
|
13
|
my $wmax = -1;
|
|
2441
|
9
|
|
|
|
|
13
|
my ($vs15, $vs16, $ri, $zwj) = (0, 0, 0, 0);
|
|
2442
|
|
|
|
|
|
|
|
|
2443
|
9
|
|
|
|
|
22
|
for my $i (0 .. $nch-1) {
|
|
2444
|
10
|
|
50
|
|
|
21
|
my $c = $cluster->[$i] // return -1;
|
|
2445
|
10
|
50
|
33
|
|
|
49
|
if ($c == 0xfe0e) { $vs15++ }
|
|
|
0
|
50
|
|
|
|
0
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
2446
|
0
|
|
|
|
|
0
|
elsif ($c == 0xfe0f) { $vs16++ }
|
|
2447
|
0
|
|
|
|
|
0
|
elsif ($c == 0x200d) { $zwj++ }
|
|
2448
|
0
|
|
|
|
|
0
|
elsif ($c >= 0x1f1e6 && $c <= 0x1f1ff) { $ri++ }
|
|
2449
|
|
|
|
|
|
|
|
|
2450
|
10
|
|
|
|
|
51
|
my $w = tb_wcwidth($c);
|
|
2451
|
10
|
50
|
|
|
|
19
|
$w = -1 unless defined $w;
|
|
2452
|
10
|
100
|
|
|
|
23
|
$wmax = $w if $w > $wmax;
|
|
2453
|
|
|
|
|
|
|
}
|
|
2454
|
|
|
|
|
|
|
|
|
2455
|
9
|
100
|
|
|
|
15
|
if ($wmax >= 1) {
|
|
2456
|
8
|
50
|
|
|
|
15
|
return 1 if $vs15;
|
|
2457
|
8
|
50
|
33
|
|
|
36
|
return 2 if $vs16 || $zwj || $ri >= 2;
|
|
|
|
|
33
|
|
|
|
|
|
2458
|
|
|
|
|
|
|
}
|
|
2459
|
|
|
|
|
|
|
|
|
2460
|
9
|
|
|
|
|
25
|
return $wmax;
|
|
2461
|
|
|
|
|
|
|
}
|
|
2462
|
|
|
|
|
|
|
|
|
2463
|
|
|
|
|
|
|
#
|
|
2464
|
|
|
|
|
|
|
# Terminal initialization helpers
|
|
2465
|
|
|
|
|
|
|
#
|
|
2466
|
|
|
|
|
|
|
|
|
2467
|
|
|
|
|
|
|
sub init_term_attrs { # $int ()
|
|
2468
|
1
|
|
|
1
|
0
|
141422
|
state $sig = compile();
|
|
2469
|
1
|
|
|
|
|
4
|
$sig->(@_);
|
|
2470
|
|
|
|
|
|
|
|
|
2471
|
1
|
50
|
|
|
|
9
|
return TB_OK if $global->{ttyfd} < 0;
|
|
2472
|
|
|
|
|
|
|
|
|
2473
|
0
|
|
0
|
|
|
0
|
$global->{orig_tios} = POSIX::Termios->new() // return TB_ERR_TCGETATTR;
|
|
2474
|
|
|
|
|
|
|
|
|
2475
|
0
|
0
|
|
|
|
0
|
if (!defined $global->{orig_tios}->getattr($global->{ttyfd})) {
|
|
2476
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
2477
|
0
|
|
|
|
|
0
|
return TB_ERR_TCGETATTR;
|
|
2478
|
|
|
|
|
|
|
}
|
|
2479
|
|
|
|
|
|
|
|
|
2480
|
0
|
|
0
|
|
|
0
|
my $tios = $global->{orig_tios}->$clone() // return TB_ERR_TCSETATTR;
|
|
2481
|
0
|
|
|
|
|
0
|
$global->{has_orig_tios} = 1;
|
|
2482
|
|
|
|
|
|
|
|
|
2483
|
0
|
|
|
|
|
0
|
cfmakeraw($tios);
|
|
2484
|
0
|
|
|
|
|
0
|
$tios->setcc(VMIN, 1);
|
|
2485
|
0
|
|
|
|
|
0
|
$tios->setcc(VTIME, 0);
|
|
2486
|
|
|
|
|
|
|
|
|
2487
|
0
|
0
|
|
|
|
0
|
if (!defined $tios->setattr($global->{ttyfd}, TCSAFLUSH)) {
|
|
2488
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
2489
|
0
|
|
|
|
|
0
|
return TB_ERR_TCSETATTR;
|
|
2490
|
|
|
|
|
|
|
}
|
|
2491
|
|
|
|
|
|
|
|
|
2492
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
2493
|
|
|
|
|
|
|
}
|
|
2494
|
|
|
|
|
|
|
|
|
2495
|
|
|
|
|
|
|
sub init_term_caps { # $int ()
|
|
2496
|
1
|
|
|
1
|
0
|
3105
|
state $sig = compile();
|
|
2497
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
2498
|
1
|
50
|
|
|
|
3
|
if (load_terminfo() == TB_OK) {
|
|
2499
|
1
|
|
|
|
|
3
|
return parse_terminfo_caps();
|
|
2500
|
|
|
|
|
|
|
}
|
|
2501
|
0
|
|
|
|
|
0
|
return load_builtin_caps();
|
|
2502
|
|
|
|
|
|
|
}
|
|
2503
|
|
|
|
|
|
|
|
|
2504
|
|
|
|
|
|
|
#
|
|
2505
|
|
|
|
|
|
|
# Terminfo parsing helpers
|
|
2506
|
|
|
|
|
|
|
#
|
|
2507
|
|
|
|
|
|
|
|
|
2508
|
|
|
|
|
|
|
sub load_terminfo { # $int ()
|
|
2509
|
3
|
|
|
3
|
0
|
6479
|
state $sig = compile();
|
|
2510
|
3
|
|
|
|
|
9
|
$sig->(@_);
|
|
2511
|
|
|
|
|
|
|
|
|
2512
|
3
|
|
|
|
|
6
|
my $rv;
|
|
2513
|
|
|
|
|
|
|
|
|
2514
|
|
|
|
|
|
|
# See terminfo(5) "Fetching Compiled Descriptions" for a description of
|
|
2515
|
|
|
|
|
|
|
# this behavior. Some of these paths are compile-time ncurses options, so
|
|
2516
|
|
|
|
|
|
|
# best guesses are used here.
|
|
2517
|
3
|
|
|
|
|
6
|
my $term = $ENV{TERM};
|
|
2518
|
3
|
50
|
|
|
|
9
|
return TB_ERR unless $term;
|
|
2519
|
|
|
|
|
|
|
|
|
2520
|
|
|
|
|
|
|
# If TERMINFO is set, try that directory first
|
|
2521
|
3
|
50
|
|
|
|
82
|
if (defined(my $terminfo = $ENV{"TERMINFO"})) {
|
|
2522
|
0
|
|
|
|
|
0
|
$rv = load_terminfo_from_path($terminfo, $term);
|
|
2523
|
0
|
0
|
|
|
|
0
|
return $rv if $rv == TB_OK;
|
|
2524
|
|
|
|
|
|
|
}
|
|
2525
|
|
|
|
|
|
|
|
|
2526
|
|
|
|
|
|
|
# Next try ~/.terminfo
|
|
2527
|
3
|
50
|
|
|
|
13
|
if (defined(my $home = $ENV{"HOME"})) {
|
|
2528
|
3
|
|
|
|
|
7
|
my $tmp = "$home/.terminfo";
|
|
2529
|
|
|
|
|
|
|
|
|
2530
|
3
|
50
|
|
|
|
8
|
return TB_ERR if length($tmp) >= TB_PATH_MAX;
|
|
2531
|
|
|
|
|
|
|
|
|
2532
|
3
|
|
|
|
|
9
|
$rv = load_terminfo_from_path($tmp, $term);
|
|
2533
|
3
|
50
|
|
|
|
8
|
return $rv if $rv == TB_OK;
|
|
2534
|
|
|
|
|
|
|
}
|
|
2535
|
|
|
|
|
|
|
|
|
2536
|
|
|
|
|
|
|
# Next try TERMINFO_DIRS
|
|
2537
|
|
|
|
|
|
|
#
|
|
2538
|
|
|
|
|
|
|
# Note, empty entries are supposed to be interpretted as the "compiled-in
|
|
2539
|
|
|
|
|
|
|
# default", which is of course system-dependent. Previously /etc/terminfo
|
|
2540
|
|
|
|
|
|
|
# was used here. Let's skip empty entries altogether rather than give
|
|
2541
|
|
|
|
|
|
|
# precedence to a guess, and check common paths after this loop.
|
|
2542
|
3
|
50
|
|
|
|
19
|
if (defined(my $dirs = $ENV{"TERMINFO_DIRS"})) {
|
|
2543
|
0
|
0
|
|
|
|
0
|
return TB_ERR if length($dirs) >= TB_PATH_MAX;
|
|
2544
|
0
|
|
|
|
|
0
|
foreach my $dir (split /:/, $dirs, -1) {
|
|
2545
|
0
|
0
|
|
|
|
0
|
next if $dir eq '';
|
|
2546
|
0
|
|
|
|
|
0
|
$rv = load_terminfo_from_path($dir, $term);
|
|
2547
|
0
|
0
|
|
|
|
0
|
return $rv if $rv == TB_OK;
|
|
2548
|
|
|
|
|
|
|
}
|
|
2549
|
|
|
|
|
|
|
}
|
|
2550
|
|
|
|
|
|
|
|
|
2551
|
|
|
|
|
|
|
# Try compile-time terminfo directory if available
|
|
2552
|
3
|
50
|
|
|
|
39
|
if (defined TB_TERMINFO_DIR) {
|
|
2553
|
0
|
|
|
|
|
0
|
$rv = load_terminfo_from_path(TB_TERMINFO_DIR, $term);
|
|
2554
|
0
|
0
|
|
|
|
0
|
return $rv if $rv == TB_OK;
|
|
2555
|
|
|
|
|
|
|
}
|
|
2556
|
|
|
|
|
|
|
|
|
2557
|
3
|
|
|
|
|
10
|
foreach my $dir (qw(
|
|
2558
|
|
|
|
|
|
|
/usr/local/etc/terminfo
|
|
2559
|
|
|
|
|
|
|
/usr/local/share/terminfo
|
|
2560
|
|
|
|
|
|
|
/usr/local/lib/terminfo
|
|
2561
|
|
|
|
|
|
|
/etc/terminfo
|
|
2562
|
|
|
|
|
|
|
/usr/share/terminfo
|
|
2563
|
|
|
|
|
|
|
/usr/lib/terminfo
|
|
2564
|
|
|
|
|
|
|
/usr/share/lib/terminfo
|
|
2565
|
|
|
|
|
|
|
/lib/terminfo
|
|
2566
|
|
|
|
|
|
|
)) {
|
|
2567
|
15
|
|
|
|
|
20
|
$rv = load_terminfo_from_path($dir, $term);
|
|
2568
|
15
|
100
|
|
|
|
37
|
return $rv if $rv == TB_OK;
|
|
2569
|
|
|
|
|
|
|
}
|
|
2570
|
|
|
|
|
|
|
|
|
2571
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
2572
|
|
|
|
|
|
|
}
|
|
2573
|
|
|
|
|
|
|
|
|
2574
|
|
|
|
|
|
|
sub load_terminfo_from_path { # $int ($path, $term)
|
|
2575
|
19
|
|
|
19
|
0
|
3893
|
state $sig = compile(
|
|
2576
|
|
|
|
|
|
|
_Str,
|
|
2577
|
|
|
|
|
|
|
_Str,
|
|
2578
|
|
|
|
|
|
|
);
|
|
2579
|
19
|
|
|
|
|
31
|
my ($path, $term) = $sig->(@_);
|
|
2580
|
19
|
|
|
|
|
24
|
my $rv;
|
|
2581
|
|
|
|
|
|
|
my $tmp;
|
|
2582
|
|
|
|
|
|
|
|
|
2583
|
|
|
|
|
|
|
# Look for term at this terminfo location, e.g., /x/xterm
|
|
2584
|
19
|
|
|
|
|
35
|
$tmp = "$path/" . substr($term, 0, 1) . "/$term";
|
|
2585
|
19
|
50
|
|
|
|
27
|
return TB_ERR if length($tmp) >= TB_PATH_MAX;
|
|
2586
|
|
|
|
|
|
|
|
|
2587
|
19
|
|
|
|
|
27
|
$rv = read_terminfo_path($tmp);
|
|
2588
|
19
|
100
|
|
|
|
53
|
return $rv if $rv == TB_OK;
|
|
2589
|
|
|
|
|
|
|
|
|
2590
|
15
|
50
|
|
|
|
39
|
if ($^O eq 'darwin') {
|
|
2591
|
|
|
|
|
|
|
# Try the Darwin equivalent path, e.g., /78/xterm
|
|
2592
|
0
|
|
|
|
|
0
|
$tmp = "$path/" . sprintf('%x', ord(substr($term, 0, 1))) . "/$term";
|
|
2593
|
0
|
0
|
|
|
|
0
|
return TB_ERR if length($tmp) >= TB_PATH_MAX;
|
|
2594
|
|
|
|
|
|
|
|
|
2595
|
0
|
|
|
|
|
0
|
return read_terminfo_path($tmp);
|
|
2596
|
|
|
|
|
|
|
}
|
|
2597
|
|
|
|
|
|
|
|
|
2598
|
15
|
|
|
|
|
18
|
return TB_ERR;
|
|
2599
|
|
|
|
|
|
|
}
|
|
2600
|
|
|
|
|
|
|
|
|
2601
|
|
|
|
|
|
|
sub read_terminfo_path { # $int ($path)
|
|
2602
|
19
|
|
|
19
|
0
|
23
|
state $sig = compile(
|
|
2603
|
|
|
|
|
|
|
_Str,
|
|
2604
|
|
|
|
|
|
|
);
|
|
2605
|
19
|
|
|
|
|
26
|
my ($path) = $sig->(@_);
|
|
2606
|
|
|
|
|
|
|
|
|
2607
|
19
|
100
|
|
|
|
1042
|
open(my $fp, '<:raw', $path)
|
|
2608
|
|
|
|
|
|
|
or return TB_ERR;
|
|
2609
|
|
|
|
|
|
|
|
|
2610
|
4
|
|
|
|
|
28
|
my @st = stat($fp);
|
|
2611
|
4
|
50
|
|
|
|
10
|
if (!@st) {
|
|
2612
|
0
|
|
|
|
|
0
|
close($fp);
|
|
2613
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
2614
|
|
|
|
|
|
|
}
|
|
2615
|
|
|
|
|
|
|
|
|
2616
|
4
|
|
|
|
|
6
|
my $fsize = $st[7];
|
|
2617
|
|
|
|
|
|
|
|
|
2618
|
4
|
|
|
|
|
6
|
my $data = '';
|
|
2619
|
4
|
|
|
|
|
98
|
my $nread = sysread($fp, $data, $fsize);
|
|
2620
|
|
|
|
|
|
|
|
|
2621
|
4
|
50
|
33
|
|
|
23
|
if (!defined($nread) || $nread != $fsize) {
|
|
2622
|
0
|
|
|
|
|
0
|
close($fp);
|
|
2623
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
2624
|
|
|
|
|
|
|
}
|
|
2625
|
|
|
|
|
|
|
|
|
2626
|
4
|
|
|
|
|
11
|
$global->{terminfo} = $data;
|
|
2627
|
|
|
|
|
|
|
|
|
2628
|
4
|
|
|
|
|
38
|
close($fp);
|
|
2629
|
4
|
|
|
|
|
25
|
return TB_OK;
|
|
2630
|
|
|
|
|
|
|
}
|
|
2631
|
|
|
|
|
|
|
|
|
2632
|
|
|
|
|
|
|
sub parse_terminfo_caps { # $int ()
|
|
2633
|
2
|
|
|
2
|
0
|
22
|
state $sig = compile();
|
|
2634
|
2
|
|
|
|
|
5
|
$sig->(@_);
|
|
2635
|
|
|
|
|
|
|
|
|
2636
|
2
|
|
|
|
|
4
|
my $terminfo = $global->{terminfo};
|
|
2637
|
2
|
|
50
|
|
|
7
|
my $nterminfo = length($terminfo) // 0;
|
|
2638
|
|
|
|
|
|
|
|
|
2639
|
|
|
|
|
|
|
# Ensure there's at least a header's worth of data
|
|
2640
|
2
|
50
|
|
|
|
7
|
return TB_ERR if $nterminfo < 6 * INT16_SIZE;
|
|
2641
|
|
|
|
|
|
|
|
|
2642
|
2
|
50
|
|
|
|
2
|
my $terminfo_cap_indexes = eval {
|
|
2643
|
37
|
|
|
37
|
|
108977
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
60
|
|
|
|
37
|
|
|
|
|
12521
|
|
|
2644
|
2
|
|
|
|
|
1141
|
require Termbox::PP::Terminfo::Builtin;
|
|
2645
|
2
|
|
|
|
|
12
|
\@Termbox::PP::Terminfo::Builtin::terminfo_cap_indexes;
|
|
2646
|
|
|
|
|
|
|
} or return TB_ERR;
|
|
2647
|
|
|
|
|
|
|
|
|
2648
|
2
|
|
|
|
|
5
|
my ($magic_number, $nbytes_names, $nbytes_bools, $num_ints, $num_offsets,
|
|
2649
|
|
|
|
|
|
|
$nbytes_strings);
|
|
2650
|
|
|
|
|
|
|
|
|
2651
|
|
|
|
|
|
|
# header[0] the magic number (octal 0432 or 01036)
|
|
2652
|
|
|
|
|
|
|
# header[1] the size, in bytes, of the names section
|
|
2653
|
|
|
|
|
|
|
# header[2] the number of bytes in the boolean section
|
|
2654
|
|
|
|
|
|
|
# header[3] the number of short integers in the numbers section
|
|
2655
|
|
|
|
|
|
|
# header[4] the number of offsets (short integers) in the strings section
|
|
2656
|
|
|
|
|
|
|
# header[5] the size, in bytes, of the string table
|
|
2657
|
2
|
|
|
|
|
46
|
get_terminfo_int16(0 * INT16_SIZE, \$magic_number);
|
|
2658
|
2
|
|
|
|
|
5
|
get_terminfo_int16(1 * INT16_SIZE, \$nbytes_names);
|
|
2659
|
2
|
|
|
|
|
5
|
get_terminfo_int16(2 * INT16_SIZE, \$nbytes_bools);
|
|
2660
|
2
|
|
|
|
|
6
|
get_terminfo_int16(3 * INT16_SIZE, \$num_ints);
|
|
2661
|
2
|
|
|
|
|
4
|
get_terminfo_int16(4 * INT16_SIZE, \$num_offsets);
|
|
2662
|
2
|
|
|
|
|
5
|
get_terminfo_int16(5 * INT16_SIZE, \$nbytes_strings);
|
|
2663
|
|
|
|
|
|
|
|
|
2664
|
|
|
|
|
|
|
# Legacy ints are 16-bit, extended ints are 32-bit
|
|
2665
|
2
|
50
|
|
|
|
6
|
my $bytes_per_int = $magic_number == 01036 ? 4 # 32-bit
|
|
2666
|
|
|
|
|
|
|
: 2; # 16-bit
|
|
2667
|
|
|
|
|
|
|
|
|
2668
|
|
|
|
|
|
|
# Between the boolean section and the number section, a null byte will be
|
|
2669
|
|
|
|
|
|
|
# inserted, if necessary, to ensure that the number section begins on
|
|
2670
|
|
|
|
|
|
|
# an even byte
|
|
2671
|
2
|
50
|
|
|
|
7
|
my $align_offset = (($nbytes_names + $nbytes_bools) % 2 != 0) ? 1 : 0;
|
|
2672
|
|
|
|
|
|
|
|
|
2673
|
2
|
|
|
|
|
3
|
my $nbytes_header = 6 * INT16_SIZE;
|
|
2674
|
2
|
|
|
|
|
5
|
my $pos_str_offsets =
|
|
2675
|
|
|
|
|
|
|
$nbytes_header # header (12 bytes)
|
|
2676
|
|
|
|
|
|
|
+ $nbytes_names # length of names section
|
|
2677
|
|
|
|
|
|
|
+ $nbytes_bools # length of boolean section
|
|
2678
|
|
|
|
|
|
|
+ $align_offset
|
|
2679
|
|
|
|
|
|
|
+ ($num_ints * $bytes_per_int); # length of string offsets section
|
|
2680
|
|
|
|
|
|
|
|
|
2681
|
2
|
|
|
|
|
3
|
my $pos_str_table =
|
|
2682
|
|
|
|
|
|
|
$pos_str_offsets
|
|
2683
|
|
|
|
|
|
|
+ ($num_offsets * INT16_SIZE); # length of string offsets table
|
|
2684
|
|
|
|
|
|
|
|
|
2685
|
2
|
|
50
|
|
|
6
|
$global->{caps} ||= [];
|
|
2686
|
|
|
|
|
|
|
|
|
2687
|
|
|
|
|
|
|
# Load caps
|
|
2688
|
2
|
|
|
|
|
7
|
for (my $i = 0; $i < TB_CAP__COUNT; $i++) {
|
|
2689
|
76
|
|
|
|
|
113
|
my $cap = get_terminfo_string($pos_str_offsets, $num_offsets,
|
|
2690
|
|
|
|
|
|
|
$pos_str_table, $nbytes_strings, $terminfo_cap_indexes->[$i]);
|
|
2691
|
|
|
|
|
|
|
# Something is not right
|
|
2692
|
76
|
50
|
|
|
|
103
|
return TB_ERR unless defined $cap;
|
|
2693
|
76
|
|
|
|
|
136
|
$global->{caps}->[$i] = $cap;
|
|
2694
|
|
|
|
|
|
|
}
|
|
2695
|
|
|
|
|
|
|
|
|
2696
|
2
|
|
|
|
|
11
|
return TB_OK;
|
|
2697
|
|
|
|
|
|
|
}
|
|
2698
|
|
|
|
|
|
|
|
|
2699
|
|
|
|
|
|
|
sub load_builtin_caps { # $int ()
|
|
2700
|
1
|
|
|
1
|
0
|
157651
|
state $sig = compile();
|
|
2701
|
1
|
|
|
|
|
4
|
$sig->(@_);
|
|
2702
|
1
|
|
|
|
|
2
|
my $term = $ENV{"TERM"};
|
|
2703
|
|
|
|
|
|
|
|
|
2704
|
1
|
50
|
|
|
|
3
|
return TB_ERR_NO_TERM unless $term;
|
|
2705
|
|
|
|
|
|
|
|
|
2706
|
1
|
50
|
|
|
|
2
|
my $builtin_terms = do {
|
|
2707
|
1
|
|
|
|
|
7
|
require Termbox::PP::Terminfo::Builtin;
|
|
2708
|
37
|
|
|
37
|
|
243
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
223
|
|
|
|
37
|
|
|
|
|
3028
|
|
|
2709
|
1
|
|
|
|
|
3
|
\%Termbox::PP::Terminfo::Builtin::builtin_terms;
|
|
2710
|
|
|
|
|
|
|
} or return TB_ERR;
|
|
2711
|
1
|
50
|
|
|
|
1
|
my $builtin_terms_orders = do {
|
|
2712
|
1
|
|
|
|
|
3
|
require Termbox::PP::Terminfo::Builtin;
|
|
2713
|
37
|
|
|
37
|
|
375
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
78
|
|
|
|
37
|
|
|
|
|
49866
|
|
|
2714
|
1
|
|
|
|
|
3
|
\@Termbox::PP::Terminfo::Builtin::builtin_terms_orders;
|
|
2715
|
|
|
|
|
|
|
} or return TB_ERR;
|
|
2716
|
|
|
|
|
|
|
|
|
2717
|
|
|
|
|
|
|
# Check for exact TERM match
|
|
2718
|
1
|
50
|
|
|
|
2
|
if (exists $builtin_terms->{$term}) {
|
|
2719
|
1
|
|
|
|
|
2
|
my $caps = $builtin_terms->{$term};
|
|
2720
|
1
|
|
|
|
|
3
|
@{ $global->{caps} } = @$caps[0 .. TB_CAP__COUNT - 1];
|
|
|
1
|
|
|
|
|
10
|
|
|
2721
|
1
|
|
|
|
|
2
|
return TB_OK;
|
|
2722
|
|
|
|
|
|
|
}
|
|
2723
|
|
|
|
|
|
|
|
|
2724
|
|
|
|
|
|
|
# Check for partial TERM or alias match
|
|
2725
|
0
|
|
|
|
|
0
|
foreach my $name (@$builtin_terms_orders) {
|
|
2726
|
0
|
0
|
|
|
|
0
|
next if index($term, $name) < 0;
|
|
2727
|
0
|
0
|
|
|
|
0
|
next unless exists $builtin_terms->{$name};
|
|
2728
|
|
|
|
|
|
|
|
|
2729
|
0
|
|
|
|
|
0
|
my $caps = $builtin_terms->{$name};
|
|
2730
|
0
|
|
|
|
|
0
|
@{ $global->{caps} } = @$caps[0 .. TB_CAP__COUNT - 1];
|
|
|
0
|
|
|
|
|
0
|
|
|
2731
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
2732
|
|
|
|
|
|
|
}
|
|
2733
|
|
|
|
|
|
|
|
|
2734
|
0
|
|
|
|
|
0
|
return TB_ERR_UNSUPPORTED_TERM;
|
|
2735
|
|
|
|
|
|
|
}
|
|
2736
|
|
|
|
|
|
|
|
|
2737
|
|
|
|
|
|
|
sub get_terminfo_string { # $str|undef ($offsets_pos, $offsets_len, $table_pos, $table_size, $index)
|
|
2738
|
80
|
|
|
80
|
0
|
148640
|
state $sig = compile(
|
|
2739
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2740
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2741
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2742
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2743
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2744
|
|
|
|
|
|
|
);
|
|
2745
|
80
|
|
|
|
|
98
|
my ($offsets_pos, $offsets_len, $table_pos, $table_size, $index) = $sig->(@_);
|
|
2746
|
|
|
|
|
|
|
|
|
2747
|
80
|
100
|
|
|
|
139
|
if ($index >= $offsets_len) {
|
|
2748
|
|
|
|
|
|
|
# An index beyond the offset table indicates absent
|
|
2749
|
|
|
|
|
|
|
# See 'convert_strings' in tinfo 'read_entry.c'
|
|
2750
|
1
|
|
|
|
|
4
|
return '';
|
|
2751
|
|
|
|
|
|
|
}
|
|
2752
|
|
|
|
|
|
|
|
|
2753
|
79
|
|
|
|
|
75
|
my $table_offset;
|
|
2754
|
79
|
|
|
|
|
78
|
my $table_offset_offset = $offsets_pos + ($index * INT16_SIZE);
|
|
2755
|
79
|
50
|
|
|
|
101
|
if (get_terminfo_int16($table_offset_offset, \$table_offset) != TB_OK) {
|
|
2756
|
|
|
|
|
|
|
# offset beyond end of terminfo entry
|
|
2757
|
|
|
|
|
|
|
# Truncated/corrupt terminfo entry?
|
|
2758
|
0
|
|
|
|
|
0
|
return undef;
|
|
2759
|
|
|
|
|
|
|
}
|
|
2760
|
|
|
|
|
|
|
|
|
2761
|
79
|
50
|
33
|
|
|
239
|
if ($table_offset < 0 || $table_offset >= $table_size) {
|
|
2762
|
|
|
|
|
|
|
# A negative offset indicates absent
|
|
2763
|
|
|
|
|
|
|
# An offset beyond the string table indicates absent
|
|
2764
|
|
|
|
|
|
|
# See 'convert_strings' in tinfo 'read_entry.c'
|
|
2765
|
0
|
|
|
|
|
0
|
return '';
|
|
2766
|
|
|
|
|
|
|
}
|
|
2767
|
|
|
|
|
|
|
|
|
2768
|
79
|
|
|
|
|
79
|
my $str_offset = $table_pos + $table_offset;
|
|
2769
|
79
|
50
|
|
|
|
113
|
if ($str_offset >= length($global->{terminfo})) {
|
|
2770
|
|
|
|
|
|
|
# string beyond end of terminfo entry
|
|
2771
|
|
|
|
|
|
|
# Truncated/corrupt terminfo entry?
|
|
2772
|
0
|
|
|
|
|
0
|
return undef;
|
|
2773
|
|
|
|
|
|
|
}
|
|
2774
|
|
|
|
|
|
|
|
|
2775
|
79
|
|
|
|
|
217
|
my $str = substr($global->{terminfo}, $str_offset);
|
|
2776
|
79
|
|
|
|
|
87
|
my $len = index($str, "\0");
|
|
2777
|
79
|
50
|
|
|
|
152
|
return $len >= 0 ? substr($str, 0, $len) : undef;
|
|
2778
|
|
|
|
|
|
|
}
|
|
2779
|
|
|
|
|
|
|
|
|
2780
|
|
|
|
|
|
|
sub get_terminfo_int16 { # $int ($offset, \$val)
|
|
2781
|
95
|
|
|
95
|
0
|
94
|
state $sig = compile(
|
|
2782
|
|
|
|
|
|
|
_Int,
|
|
2783
|
|
|
|
|
|
|
_ScalarRef,
|
|
2784
|
|
|
|
|
|
|
);
|
|
2785
|
95
|
|
|
|
|
109
|
my ($offset, $val) = $sig->(@_);
|
|
2786
|
95
|
100
|
66
|
|
|
275
|
if ($offset < 0 || $offset + INT16_SIZE > length($global->{terminfo})) {
|
|
2787
|
1
|
|
|
|
|
2
|
$$val = -1;
|
|
2788
|
1
|
|
|
|
|
3
|
return TB_ERR;
|
|
2789
|
|
|
|
|
|
|
}
|
|
2790
|
94
|
|
|
|
|
186
|
$$val = unpack('s<', substr($global->{terminfo}, $offset, INT16_SIZE));
|
|
2791
|
94
|
|
|
|
|
132
|
return TB_OK;
|
|
2792
|
|
|
|
|
|
|
}
|
|
2793
|
|
|
|
|
|
|
|
|
2794
|
|
|
|
|
|
|
#
|
|
2795
|
|
|
|
|
|
|
# Resize handling helpers
|
|
2796
|
|
|
|
|
|
|
#
|
|
2797
|
|
|
|
|
|
|
|
|
2798
|
|
|
|
|
|
|
sub init_resize_handler { # $int ()
|
|
2799
|
1
|
|
|
1
|
0
|
3278
|
state $sig = compile();
|
|
2800
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
2801
|
1
|
|
|
|
|
2
|
my ($rfd, $wfd);
|
|
2802
|
1
|
50
|
|
|
|
24
|
unless (($rfd, $wfd) = POSIX::pipe()) {
|
|
2803
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
2804
|
0
|
|
|
|
|
0
|
return TB_ERR_RESIZE_PIPE;
|
|
2805
|
|
|
|
|
|
|
}
|
|
2806
|
|
|
|
|
|
|
|
|
2807
|
1
|
|
|
|
|
4
|
$global->{resize_pipefd} = [$rfd, $wfd];
|
|
2808
|
|
|
|
|
|
|
|
|
2809
|
1
|
50
|
|
|
|
11
|
$SIG{WINCH} = \&handle_resize if exists $SIG{WINCH};
|
|
2810
|
1
|
|
|
|
|
3
|
return TB_OK;
|
|
2811
|
|
|
|
|
|
|
}
|
|
2812
|
|
|
|
|
|
|
|
|
2813
|
|
|
|
|
|
|
sub resize_cellbufs { # $int ()
|
|
2814
|
2
|
|
|
2
|
0
|
7125
|
state $sig = compile();
|
|
2815
|
2
|
|
|
|
|
6
|
$sig->(@_);
|
|
2816
|
2
|
|
|
|
|
2
|
my $rv;
|
|
2817
|
2
|
|
|
|
|
9
|
$rv = cellbuf_resize($global->{back}, $global->{width}, $global->{height});
|
|
2818
|
2
|
100
|
|
|
|
12
|
return $rv if $rv != TB_OK;
|
|
2819
|
1
|
|
|
|
|
4
|
$rv = cellbuf_resize($global->{front}, $global->{width}, $global->{height});
|
|
2820
|
1
|
50
|
|
|
|
4
|
return $rv if $rv != TB_OK;
|
|
2821
|
1
|
|
|
|
|
4
|
$rv = cellbuf_clear($global->{front});
|
|
2822
|
1
|
50
|
|
|
|
4
|
return $rv if $rv != TB_OK;
|
|
2823
|
1
|
|
|
|
|
2
|
$rv = send_clear();
|
|
2824
|
1
|
50
|
|
|
|
3
|
return $rv if $rv != TB_OK;
|
|
2825
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
2826
|
|
|
|
|
|
|
}
|
|
2827
|
|
|
|
|
|
|
|
|
2828
|
|
|
|
|
|
|
sub handle_resize { # void ($sig)
|
|
2829
|
1
|
|
|
1
|
0
|
5250
|
state $sig = compile(
|
|
2830
|
|
|
|
|
|
|
_Int,
|
|
2831
|
|
|
|
|
|
|
);
|
|
2832
|
1
|
|
|
|
|
2
|
my ($signo) = $sig->(@_);
|
|
2833
|
1
|
|
|
|
|
4
|
local $! = $!;
|
|
2834
|
1
|
|
|
|
|
4
|
my $payload = pack('i', $signo);
|
|
2835
|
1
|
|
|
|
|
24
|
POSIX::write($global->{resize_pipefd}[1], $payload, length($payload));
|
|
2836
|
1
|
|
|
|
|
4
|
return;
|
|
2837
|
|
|
|
|
|
|
}
|
|
2838
|
|
|
|
|
|
|
|
|
2839
|
|
|
|
|
|
|
sub update_term_size { # $int ()
|
|
2840
|
1
|
|
|
1
|
0
|
4590
|
state $sig = compile();
|
|
2841
|
1
|
|
|
|
|
2
|
$sig->(@_);
|
|
2842
|
1
|
|
|
|
|
2
|
my ($rv, $ioctl_errno);
|
|
2843
|
|
|
|
|
|
|
|
|
2844
|
1
|
50
|
|
|
|
5
|
return TB_OK if $global->{ttyfd} < 0;
|
|
2845
|
|
|
|
|
|
|
|
|
2846
|
0
|
|
|
|
|
0
|
my $fh = IO::File->new_from_fd($global->{ttyfd}, 'w');
|
|
2847
|
0
|
0
|
|
|
|
0
|
return TB_OK if !$fh;
|
|
2848
|
|
|
|
|
|
|
|
|
2849
|
0
|
|
|
|
|
0
|
my $sz = pack('S4', 0, 0, 0, 0);
|
|
2850
|
|
|
|
|
|
|
|
|
2851
|
|
|
|
|
|
|
# Try ioctl TIOCGWINSZ
|
|
2852
|
0
|
0
|
0
|
|
|
0
|
if (eval { require 'sys/ioctl.ph'; 1 } && ioctl($fh, &TIOCGWINSZ, $sz)) {
|
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
2853
|
0
|
|
|
|
|
0
|
my ($row, $col) = unpack('S4', $sz);
|
|
2854
|
0
|
|
|
|
|
0
|
$global->{width} = $col;
|
|
2855
|
0
|
|
|
|
|
0
|
$global->{height} = $row;
|
|
2856
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
2857
|
|
|
|
|
|
|
}
|
|
2858
|
0
|
|
|
|
|
0
|
$ioctl_errno = 0+ $!;
|
|
2859
|
|
|
|
|
|
|
|
|
2860
|
|
|
|
|
|
|
# Try >cursor(9999,9999), >u7,
|
|
2861
|
0
|
|
|
|
|
0
|
$rv = update_term_size_via_esc();
|
|
2862
|
0
|
0
|
|
|
|
0
|
return TB_OK if $rv == TB_OK;
|
|
2863
|
|
|
|
|
|
|
|
|
2864
|
0
|
|
|
|
|
0
|
$global->{last_errno} = $ioctl_errno;
|
|
2865
|
0
|
|
|
|
|
0
|
return TB_ERR_RESIZE_IOCTL;
|
|
2866
|
|
|
|
|
|
|
}
|
|
2867
|
|
|
|
|
|
|
|
|
2868
|
|
|
|
|
|
|
sub update_term_size_via_esc { # $int ()
|
|
2869
|
1
|
|
|
1
|
0
|
3301
|
state $sig = compile();
|
|
2870
|
1
|
|
|
|
|
12
|
$sig->(@_);
|
|
2871
|
|
|
|
|
|
|
|
|
2872
|
1
|
|
|
|
|
2
|
my $move_and_report = "\e[9999;9999H\e[6n";
|
|
2873
|
|
|
|
|
|
|
|
|
2874
|
|
|
|
|
|
|
my $write_rv = POSIX::write(
|
|
2875
|
|
|
|
|
|
|
$global->{wfd},
|
|
2876
|
1
|
|
|
|
|
5
|
$move_and_report,
|
|
2877
|
|
|
|
|
|
|
length($move_and_report),
|
|
2878
|
|
|
|
|
|
|
);
|
|
2879
|
1
|
50
|
33
|
|
|
8
|
return TB_ERR_RESIZE_WRITE
|
|
2880
|
|
|
|
|
|
|
if !defined($write_rv)
|
|
2881
|
|
|
|
|
|
|
|| $write_rv != length($move_and_report);
|
|
2882
|
|
|
|
|
|
|
|
|
2883
|
1
|
|
|
|
|
2
|
my $rin = '';
|
|
2884
|
1
|
|
|
|
|
5
|
vec($rin, $global->{rfd}, 1) = 1;
|
|
2885
|
|
|
|
|
|
|
|
|
2886
|
1
|
|
|
|
|
2
|
my $timeout = TB_RESIZE_FALLBACK_MS / 1000;
|
|
2887
|
1
|
|
|
|
|
7
|
my $select_rv = select($rin, undef, undef, $timeout);
|
|
2888
|
1
|
50
|
|
|
|
4
|
if ($select_rv != 1) {
|
|
2889
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
2890
|
0
|
|
|
|
|
0
|
return TB_ERR_RESIZE_POLL;
|
|
2891
|
|
|
|
|
|
|
}
|
|
2892
|
|
|
|
|
|
|
|
|
2893
|
1
|
|
|
|
|
2
|
my $buf = '';
|
|
2894
|
1
|
|
|
|
|
7
|
my $read_rv = POSIX::read($global->{rfd}, $buf, TB_OPT_READ_BUF);
|
|
2895
|
1
|
50
|
33
|
|
|
4
|
if (!defined($read_rv) || $read_rv < 1) {
|
|
2896
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
2897
|
0
|
|
|
|
|
0
|
return TB_ERR_RESIZE_READ;
|
|
2898
|
|
|
|
|
|
|
}
|
|
2899
|
|
|
|
|
|
|
|
|
2900
|
1
|
50
|
|
|
|
7
|
if ($buf !~ /\e\[(\d+);(\d+)R/) {
|
|
2901
|
0
|
|
|
|
|
0
|
return TB_ERR_RESIZE_SSCANF;
|
|
2902
|
|
|
|
|
|
|
}
|
|
2903
|
1
|
|
|
|
|
4
|
my ($rh, $rw) = ($1, $2);
|
|
2904
|
|
|
|
|
|
|
|
|
2905
|
1
|
|
|
|
|
3
|
$global->{width} = $rw;
|
|
2906
|
1
|
|
|
|
|
2
|
$global->{height} = $rh;
|
|
2907
|
1
|
|
|
|
|
3
|
return TB_OK;
|
|
2908
|
|
|
|
|
|
|
}
|
|
2909
|
|
|
|
|
|
|
|
|
2910
|
|
|
|
|
|
|
#
|
|
2911
|
|
|
|
|
|
|
# Escape-cap parser helpers
|
|
2912
|
|
|
|
|
|
|
#
|
|
2913
|
|
|
|
|
|
|
|
|
2914
|
|
|
|
|
|
|
sub init_cap_trie { # $int ()
|
|
2915
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile();
|
|
2916
|
0
|
|
|
|
|
0
|
$sig->(@_);
|
|
2917
|
|
|
|
|
|
|
|
|
2918
|
0
|
|
0
|
|
|
0
|
my $trie = $global->{cap_trie} //= captrie->new();
|
|
2919
|
0
|
|
|
|
|
0
|
my $rv = $trie->clear();
|
|
2920
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
2921
|
|
|
|
|
|
|
|
|
2922
|
0
|
0
|
|
|
|
0
|
my $builtin_mod_caps = eval {
|
|
2923
|
37
|
|
|
37
|
|
271
|
no warnings 'once';
|
|
|
37
|
|
|
|
|
48
|
|
|
|
37
|
|
|
|
|
32450
|
|
|
2924
|
0
|
|
|
|
|
0
|
require Termbox::PP::Terminfo::Builtin;
|
|
2925
|
0
|
|
|
|
|
0
|
\%Termbox::PP::Terminfo::Builtin::builtin_mod_caps;
|
|
2926
|
|
|
|
|
|
|
} or return TB_ERR;
|
|
2927
|
|
|
|
|
|
|
|
|
2928
|
|
|
|
|
|
|
# Add caps from terminfo or built-in
|
|
2929
|
|
|
|
|
|
|
# Collisions are expected as some terminfo entries have dupes. (For
|
|
2930
|
|
|
|
|
|
|
# example, att605-pc collides on TB_CAP_F4 and TB_CAP_DELETE.) First cap
|
|
2931
|
|
|
|
|
|
|
# in TB_CAP_* index order will win.
|
|
2932
|
|
|
|
|
|
|
#
|
|
2933
|
|
|
|
|
|
|
# TODO: Reorder TB_CAP_* so more critical caps come first.
|
|
2934
|
0
|
|
|
|
|
0
|
for my $i (0 .. TB_CAP__COUNT_KEYS - 1) {
|
|
2935
|
0
|
|
|
|
|
0
|
$rv = $trie->add($global->{caps}[$i], tb_key_i($i), 0);
|
|
2936
|
0
|
0
|
0
|
|
|
0
|
return $rv if $rv != TB_OK && $rv != TB_ERR_CAP_COLLISION;
|
|
2937
|
|
|
|
|
|
|
}
|
|
2938
|
|
|
|
|
|
|
|
|
2939
|
|
|
|
|
|
|
# Add built-in mod caps
|
|
2940
|
|
|
|
|
|
|
#
|
|
2941
|
|
|
|
|
|
|
# Collisions are OK here as well. This can happen if $global->{caps} collides
|
|
2942
|
|
|
|
|
|
|
# with builtin_mod_caps. It is desirable to give precedence to $global->{caps}
|
|
2943
|
|
|
|
|
|
|
# here.
|
|
2944
|
0
|
|
|
|
|
0
|
while (my ($cap, $entry) = each %$builtin_mod_caps) {
|
|
2945
|
0
|
|
0
|
|
|
0
|
my $key = $entry->{key} // next;
|
|
2946
|
0
|
|
0
|
|
|
0
|
my $mod = $entry->{mod} // next;
|
|
2947
|
0
|
|
|
|
|
0
|
$rv = $trie->add($cap, $key, $mod);
|
|
2948
|
0
|
0
|
0
|
|
|
0
|
return $rv if $rv != TB_OK && $rv != TB_ERR_CAP_COLLISION;
|
|
2949
|
|
|
|
|
|
|
}
|
|
2950
|
|
|
|
|
|
|
|
|
2951
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
2952
|
|
|
|
|
|
|
}
|
|
2953
|
|
|
|
|
|
|
|
|
2954
|
|
|
|
|
|
|
# Regex/prefix equivalent of termbox2's cap_trie_add.
|
|
2955
|
|
|
|
|
|
|
sub cap_trie_add { # $int ($cap|undef, $key, $mod)
|
|
2956
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile(
|
|
2957
|
|
|
|
|
|
|
_Maybe[_Str],
|
|
2958
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2959
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2960
|
|
|
|
|
|
|
);
|
|
2961
|
0
|
|
|
|
|
0
|
my ($cap, $key, $mod) = $sig->(@_);
|
|
2962
|
0
|
0
|
|
|
|
0
|
my $trie = $global->{cap_trie} or return TB_ERR;
|
|
2963
|
0
|
|
|
|
|
0
|
return $trie->add($cap, $key, $mod);
|
|
2964
|
|
|
|
|
|
|
}
|
|
2965
|
|
|
|
|
|
|
|
|
2966
|
|
|
|
|
|
|
# Regex/prefix equivalent of termbox2's cap_trie_find.
|
|
2967
|
|
|
|
|
|
|
# Returns a hash-ref node in $$last with {is_leaf,key,mod,nchildren,cap}.
|
|
2968
|
|
|
|
|
|
|
sub cap_trie_find { # $int ($buf|undef, $nbuf, \$last, \$depth)
|
|
2969
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile(
|
|
2970
|
|
|
|
|
|
|
_Maybe[_Str],
|
|
2971
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
2972
|
|
|
|
|
|
|
_ScalarRef,
|
|
2973
|
|
|
|
|
|
|
_ScalarRef,
|
|
2974
|
|
|
|
|
|
|
);
|
|
2975
|
0
|
|
|
|
|
0
|
my ($buf, $nbuf, $last, $depth) = $sig->(@_);
|
|
2976
|
0
|
0
|
|
|
|
0
|
my $trie = $global->{cap_trie} or return TB_ERR;
|
|
2977
|
0
|
|
|
|
|
0
|
return $trie->find($buf, $last, $depth); # Perl does not need nbuf
|
|
2978
|
|
|
|
|
|
|
}
|
|
2979
|
|
|
|
|
|
|
|
|
2980
|
|
|
|
|
|
|
sub cap_trie_deinit { # $int ($node)
|
|
2981
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile(
|
|
2982
|
|
|
|
|
|
|
_Object,
|
|
2983
|
|
|
|
|
|
|
);
|
|
2984
|
0
|
|
|
|
|
0
|
my ($node) = $sig->(@_);
|
|
2985
|
0
|
|
|
|
|
0
|
return $node->clear();
|
|
2986
|
|
|
|
|
|
|
}
|
|
2987
|
|
|
|
|
|
|
|
|
2988
|
|
|
|
|
|
|
#
|
|
2989
|
|
|
|
|
|
|
# Event extraction helpers
|
|
2990
|
|
|
|
|
|
|
#
|
|
2991
|
|
|
|
|
|
|
|
|
2992
|
|
|
|
|
|
|
sub wait_event {
|
|
2993
|
2
|
|
|
2
|
0
|
9
|
state $sig = compile(
|
|
2994
|
|
|
|
|
|
|
_Object,
|
|
2995
|
|
|
|
|
|
|
_Int,
|
|
2996
|
|
|
|
|
|
|
);
|
|
2997
|
2
|
|
|
|
|
5
|
my ($event, $timeout) = $sig->(@_);
|
|
2998
|
|
|
|
|
|
|
|
|
2999
|
2
|
|
|
|
|
3
|
my $rv;
|
|
3000
|
2
|
|
|
|
|
4
|
my $buf = '';
|
|
3001
|
2
|
|
|
|
|
5
|
state $empty_event = Termbox::Event->new();
|
|
3002
|
|
|
|
|
|
|
|
|
3003
|
2
|
|
|
|
|
3
|
alias: for ($event) {
|
|
3004
|
2
|
|
|
|
|
8
|
%$event = %$empty_event;
|
|
3005
|
|
|
|
|
|
|
|
|
3006
|
|
|
|
|
|
|
# Fast path: buffered input already yields a full event
|
|
3007
|
2
|
|
|
|
|
6
|
$rv = extract_event($event);
|
|
3008
|
2
|
100
|
|
|
|
7
|
return TB_OK if $rv == TB_OK;
|
|
3009
|
|
|
|
|
|
|
|
|
3010
|
1
|
|
|
|
|
2
|
my $rfd = $global->{rfd};
|
|
3011
|
1
|
|
|
|
|
2
|
my $resizefd = $global->{resize_pipefd}[0];
|
|
3012
|
|
|
|
|
|
|
|
|
3013
|
|
|
|
|
|
|
# Perl select timeout is seconds as float; undef means block forever
|
|
3014
|
1
|
50
|
|
|
|
6
|
my $timeout_sec = ($timeout < 0) ? undef : ($timeout / 1000);
|
|
3015
|
|
|
|
|
|
|
|
|
3016
|
1
|
|
|
|
|
1
|
do {
|
|
3017
|
1
|
|
|
|
|
2
|
my $rin = '';
|
|
3018
|
1
|
|
|
|
|
4
|
vec($rin, $rfd, 1) = 1;
|
|
3019
|
1
|
|
|
|
|
3
|
vec($rin, $resizefd, 1) = 1;
|
|
3020
|
|
|
|
|
|
|
|
|
3021
|
1
|
|
|
|
|
2
|
my $rout = $rin;
|
|
3022
|
|
|
|
|
|
|
|
|
3023
|
1
|
|
|
|
|
10
|
my $select_rv = select($rout, undef, undef, $timeout_sec);
|
|
3024
|
|
|
|
|
|
|
|
|
3025
|
1
|
50
|
|
|
|
3
|
if ($select_rv < 0) {
|
|
3026
|
|
|
|
|
|
|
# Let EINTR/EAGAIN bubble up
|
|
3027
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
3028
|
0
|
|
|
|
|
0
|
return TB_ERR_POLL;
|
|
3029
|
|
|
|
|
|
|
}
|
|
3030
|
1
|
50
|
|
|
|
4
|
if ($select_rv == 0) {
|
|
3031
|
0
|
|
|
|
|
0
|
return TB_ERR_NO_EVENT;
|
|
3032
|
|
|
|
|
|
|
}
|
|
3033
|
|
|
|
|
|
|
|
|
3034
|
1
|
|
|
|
|
3
|
my $tty_has_events = vec($rout, $rfd, 1);
|
|
3035
|
1
|
|
|
|
|
2
|
my $resize_has_events = vec($rout, $resizefd, 1);
|
|
3036
|
|
|
|
|
|
|
|
|
3037
|
1
|
50
|
|
|
|
2
|
if ($tty_has_events) {
|
|
3038
|
0
|
|
|
|
|
0
|
my $buf = '';
|
|
3039
|
0
|
|
|
|
|
0
|
my $read_rv = POSIX::read($rfd, $buf, TB_OPT_READ_BUF);
|
|
3040
|
0
|
0
|
0
|
|
|
0
|
if (!defined($read_rv) || $read_rv < 0) {
|
|
|
|
0
|
|
|
|
|
|
|
3041
|
0
|
|
|
|
|
0
|
$global->{last_errno} = 0+ $!;
|
|
3042
|
0
|
|
|
|
|
0
|
return TB_ERR_READ;
|
|
3043
|
|
|
|
|
|
|
} elsif ($read_rv > 0) {
|
|
3044
|
0
|
|
|
|
|
0
|
bytebuf_nputs(\$global->{inbuf}, $buf, $read_rv);
|
|
3045
|
|
|
|
|
|
|
}
|
|
3046
|
|
|
|
|
|
|
}
|
|
3047
|
|
|
|
|
|
|
|
|
3048
|
1
|
50
|
|
|
|
3
|
if ($resize_has_events) {
|
|
3049
|
1
|
|
|
|
|
1
|
my $ignore = pack('i', 0);
|
|
3050
|
1
|
|
|
|
|
14
|
POSIX::read($resizefd, $ignore, length($ignore));
|
|
3051
|
|
|
|
|
|
|
# TODO: Harden against errors encountered mid-resize
|
|
3052
|
1
|
|
|
|
|
4
|
$rv = update_term_size();
|
|
3053
|
1
|
50
|
|
|
|
4
|
return $rv if $rv != TB_OK;
|
|
3054
|
1
|
|
|
|
|
2
|
$rv = resize_cellbufs();
|
|
3055
|
1
|
50
|
|
|
|
4
|
return $rv if $rv != TB_OK;
|
|
3056
|
|
|
|
|
|
|
|
|
3057
|
1
|
|
|
|
|
2
|
$event->{type} = TB_EVENT_RESIZE;
|
|
3058
|
1
|
|
|
|
|
3
|
$event->{w} = $global->{width};
|
|
3059
|
1
|
|
|
|
|
2
|
$event->{h} = $global->{height};
|
|
3060
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
3061
|
|
|
|
|
|
|
}
|
|
3062
|
|
|
|
|
|
|
|
|
3063
|
|
|
|
|
|
|
# Try to extract an event after consuming input / handling resize
|
|
3064
|
0
|
|
|
|
|
0
|
%$event = %$empty_event;
|
|
3065
|
0
|
|
|
|
|
0
|
$rv = extract_event($event);
|
|
3066
|
0
|
0
|
|
|
|
0
|
return TB_OK if $rv == TB_OK;
|
|
3067
|
|
|
|
|
|
|
|
|
3068
|
|
|
|
|
|
|
} while ($timeout < 0);
|
|
3069
|
|
|
|
|
|
|
|
|
3070
|
0
|
|
|
|
|
0
|
return $rv;
|
|
3071
|
|
|
|
|
|
|
} #/ alias:
|
|
3072
|
|
|
|
|
|
|
}
|
|
3073
|
|
|
|
|
|
|
|
|
3074
|
|
|
|
|
|
|
sub extract_event { # $int ($event)
|
|
3075
|
3
|
|
|
3
|
0
|
8
|
state $sig = compile(
|
|
3076
|
|
|
|
|
|
|
_Object,
|
|
3077
|
|
|
|
|
|
|
);
|
|
3078
|
3
|
|
|
|
|
5
|
my ($event) = $sig->(@_);
|
|
3079
|
3
|
|
|
|
|
4
|
my $trie = $global->{cap_trie};
|
|
3080
|
3
|
|
|
|
|
5
|
alias: for my $in ($global->{inbuf}) {
|
|
3081
|
|
|
|
|
|
|
|
|
3082
|
3
|
100
|
|
|
|
7
|
return TB_ERR unless length($in);
|
|
3083
|
|
|
|
|
|
|
|
|
3084
|
37
|
|
|
37
|
|
271
|
use bytes;
|
|
|
37
|
|
|
|
|
65
|
|
|
|
37
|
|
|
|
|
171
|
|
|
3085
|
2
|
|
|
|
|
5
|
my $b0 = substr($in, 0, 1);
|
|
3086
|
2
|
50
|
|
|
|
5
|
if ($b0 eq "\e") {
|
|
3087
|
|
|
|
|
|
|
# Escape sequence?
|
|
3088
|
|
|
|
|
|
|
# In TB_INPUT_ESC, skip if the buffer is a single escape char
|
|
3089
|
0
|
0
|
0
|
|
|
0
|
unless (($global->{input_mode} & TB_INPUT_ESC) && length($in) == 1) {
|
|
3090
|
0
|
|
|
|
|
0
|
my $rv = extract_esc($event);
|
|
3091
|
0
|
0
|
0
|
|
|
0
|
return $rv if $rv != TB_OK && $rv != TB_ERR_NEED_MORE;
|
|
3092
|
|
|
|
|
|
|
}
|
|
3093
|
|
|
|
|
|
|
|
|
3094
|
|
|
|
|
|
|
# Escape key?
|
|
3095
|
0
|
0
|
|
|
|
0
|
if ($global->{input_mode} & TB_INPUT_ESC) {
|
|
3096
|
0
|
|
|
|
|
0
|
$event->{type} = TB_EVENT_KEY;
|
|
3097
|
0
|
|
|
|
|
0
|
$event->{ch} = 0;
|
|
3098
|
0
|
|
|
|
|
0
|
$event->{key} = TB_KEY_ESC;
|
|
3099
|
0
|
|
|
|
|
0
|
$event->{mod} = 0;
|
|
3100
|
0
|
|
|
|
|
0
|
substr($in, 0, 1, '');
|
|
3101
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
3102
|
|
|
|
|
|
|
}
|
|
3103
|
|
|
|
|
|
|
|
|
3104
|
|
|
|
|
|
|
# Recurse for alt key
|
|
3105
|
0
|
|
|
|
|
0
|
$event->{mod} |= TB_MOD_ALT;
|
|
3106
|
0
|
|
|
|
|
0
|
substr($in, 0, 1, '');
|
|
3107
|
0
|
|
|
|
|
0
|
return extract_event($event);
|
|
3108
|
|
|
|
|
|
|
}
|
|
3109
|
|
|
|
|
|
|
|
|
3110
|
|
|
|
|
|
|
# ASCII control key?
|
|
3111
|
2
|
|
33
|
|
|
8
|
my $is_ctrl = ord($b0) < TB_KEY_SPACE || ord($b0) == TB_KEY_BACKSPACE2;
|
|
3112
|
2
|
50
|
|
|
|
5
|
if ($is_ctrl) {
|
|
3113
|
0
|
|
|
|
|
0
|
$event->{type} = TB_EVENT_KEY;
|
|
3114
|
0
|
|
|
|
|
0
|
$event->{ch} = 0;
|
|
3115
|
0
|
|
|
|
|
0
|
$event->{key} = ord($in);
|
|
3116
|
0
|
|
|
|
|
0
|
$event->{mod} |= TB_MOD_CTRL;
|
|
3117
|
0
|
|
|
|
|
0
|
substr($in, 0, 1, '');
|
|
3118
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
3119
|
|
|
|
|
|
|
}
|
|
3120
|
|
|
|
|
|
|
|
|
3121
|
|
|
|
|
|
|
# UTF-8?
|
|
3122
|
2
|
|
|
|
|
4
|
my $need = tb_utf8_char_length($b0);
|
|
3123
|
2
|
50
|
|
|
|
20
|
if (length($in) >= $need) {
|
|
3124
|
2
|
|
|
|
|
7
|
$event->{type} = TB_EVENT_KEY;
|
|
3125
|
2
|
|
|
|
|
7
|
tb_utf8_char_to_unicode(\$event->{ch}, $in);
|
|
3126
|
2
|
|
|
|
|
9
|
$event->{key} = 0;
|
|
3127
|
2
|
|
|
|
|
5
|
substr($in, 0, $need, '');
|
|
3128
|
2
|
|
|
|
|
6
|
return TB_OK;
|
|
3129
|
|
|
|
|
|
|
}
|
|
3130
|
|
|
|
|
|
|
|
|
3131
|
|
|
|
|
|
|
# Need more input
|
|
3132
|
0
|
|
|
|
|
0
|
return TB_ERR
|
|
3133
|
|
|
|
|
|
|
} #/ alias:
|
|
3134
|
|
|
|
|
|
|
}
|
|
3135
|
|
|
|
|
|
|
|
|
3136
|
|
|
|
|
|
|
sub extract_esc { # $int ($event)
|
|
3137
|
2
|
|
|
2
|
0
|
12
|
state $sig = compile(
|
|
3138
|
|
|
|
|
|
|
_Object,
|
|
3139
|
|
|
|
|
|
|
);
|
|
3140
|
2
|
|
|
|
|
5
|
my ($event) = $sig->(@_);
|
|
3141
|
|
|
|
|
|
|
|
|
3142
|
2
|
|
|
|
|
4
|
my $rv;
|
|
3143
|
|
|
|
|
|
|
|
|
3144
|
2
|
|
|
|
|
6
|
$rv = extract_esc_user($event, 0);
|
|
3145
|
2
|
100
|
66
|
|
|
11
|
return $rv if $rv == TB_OK || $rv == TB_ERR_NEED_MORE;
|
|
3146
|
|
|
|
|
|
|
|
|
3147
|
1
|
|
|
|
|
3
|
$rv = extract_esc_cap($event);
|
|
3148
|
1
|
50
|
33
|
|
|
7
|
return $rv if $rv == TB_OK || $rv == TB_ERR_NEED_MORE;
|
|
3149
|
|
|
|
|
|
|
|
|
3150
|
0
|
|
|
|
|
0
|
$rv = extract_esc_mouse($event);
|
|
3151
|
0
|
0
|
0
|
|
|
0
|
return $rv if $rv == TB_OK || $rv == TB_ERR_NEED_MORE;
|
|
3152
|
|
|
|
|
|
|
|
|
3153
|
0
|
|
|
|
|
0
|
$rv = extract_esc_user($event, 1);
|
|
3154
|
0
|
0
|
0
|
|
|
0
|
return $rv if $rv == TB_OK || $rv == TB_ERR_NEED_MORE;
|
|
3155
|
|
|
|
|
|
|
|
|
3156
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
3157
|
|
|
|
|
|
|
}
|
|
3158
|
|
|
|
|
|
|
|
|
3159
|
|
|
|
|
|
|
sub extract_esc_user { # $int ($event, $is_post)
|
|
3160
|
3
|
|
|
3
|
0
|
5
|
state $sig = compile(
|
|
3161
|
|
|
|
|
|
|
_Object,
|
|
3162
|
|
|
|
|
|
|
_Bool,
|
|
3163
|
|
|
|
|
|
|
);
|
|
3164
|
3
|
|
|
|
|
6
|
my ($event, $is_post) = $sig->(@_);
|
|
3165
|
|
|
|
|
|
|
|
|
3166
|
|
|
|
|
|
|
my $fn = $is_post ? $global->{fn_extract_esc_post}
|
|
3167
|
3
|
100
|
|
|
|
9
|
: $global->{fn_extract_esc_pre};
|
|
3168
|
3
|
100
|
|
|
|
15
|
return TB_ERR unless ref($fn) eq 'CODE';
|
|
3169
|
|
|
|
|
|
|
|
|
3170
|
1
|
|
|
|
|
2
|
my $consumed = 0;
|
|
3171
|
1
|
|
|
|
|
3
|
my $rv = $fn->($event, \$consumed);
|
|
3172
|
|
|
|
|
|
|
|
|
3173
|
1
|
50
|
|
|
|
9
|
if ($rv == TB_OK) {
|
|
3174
|
1
|
|
|
|
|
5
|
bytebuf_shift(\$global->{inbuf}, $consumed);
|
|
3175
|
|
|
|
|
|
|
}
|
|
3176
|
|
|
|
|
|
|
|
|
3177
|
1
|
50
|
33
|
|
|
3
|
return $rv if $rv == TB_OK || $rv == TB_ERR_NEED_MORE;
|
|
3178
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
3179
|
|
|
|
|
|
|
}
|
|
3180
|
|
|
|
|
|
|
|
|
3181
|
|
|
|
|
|
|
sub extract_esc_mouse { # $int ($event)
|
|
3182
|
3
|
|
|
3
|
0
|
19
|
state $sig = compile(
|
|
3183
|
|
|
|
|
|
|
_Object,
|
|
3184
|
|
|
|
|
|
|
);
|
|
3185
|
3
|
|
|
|
|
10
|
my ($event) = $sig->(@_);
|
|
3186
|
|
|
|
|
|
|
|
|
3187
|
37
|
|
|
37
|
|
22750
|
use bytes;
|
|
|
37
|
|
|
|
|
60
|
|
|
|
37
|
|
|
|
|
127
|
|
|
3188
|
3
|
|
|
|
|
9
|
alias: for my $in ($global->{inbuf}) {
|
|
3189
|
3
|
|
|
|
|
19
|
my @in = unpack('C*', $in);
|
|
3190
|
|
|
|
|
|
|
|
|
3191
|
|
|
|
|
|
|
# Bail if not enough to determine type
|
|
3192
|
3
|
50
|
|
|
|
18
|
if (@in < 2) {
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
3193
|
0
|
|
|
|
|
0
|
return TB_ERR_NEED_MORE;
|
|
3194
|
|
|
|
|
|
|
} elsif ($in[1] != ord('[')) {
|
|
3195
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
3196
|
|
|
|
|
|
|
} elsif (@in < 3) {
|
|
3197
|
0
|
|
|
|
|
0
|
return TB_ERR_NEED_MORE;
|
|
3198
|
|
|
|
|
|
|
}
|
|
3199
|
|
|
|
|
|
|
|
|
3200
|
|
|
|
|
|
|
# Discern type of mouse event from 3rd byte
|
|
3201
|
3
|
|
|
|
|
7
|
my $type = TYPE_VT200;
|
|
3202
|
3
|
100
|
|
|
|
12
|
if ($in[2] == ord('M')) {
|
|
|
|
100
|
|
|
|
|
|
|
3203
|
|
|
|
|
|
|
# X10 mouse encoding, the simplest one: \x1b [ M Cb Cx Cy
|
|
3204
|
1
|
|
|
|
|
3
|
$type = TYPE_VT200;
|
|
3205
|
|
|
|
|
|
|
}
|
|
3206
|
|
|
|
|
|
|
elsif ($in[2] == ord('<')) {
|
|
3207
|
|
|
|
|
|
|
# xterm 1006 extended mode or urxvt 1015 extended mode
|
|
3208
|
|
|
|
|
|
|
# xterm: \x1b [ < Cb ; Cx ; Cy (M or m)
|
|
3209
|
1
|
|
|
|
|
5
|
$type = TYPE_1006;
|
|
3210
|
|
|
|
|
|
|
}
|
|
3211
|
|
|
|
|
|
|
else {
|
|
3212
|
|
|
|
|
|
|
# urxvt: \x1b [ Cb ; Cx ; Cy M
|
|
3213
|
1
|
|
|
|
|
2
|
$type = TYPE_1015;
|
|
3214
|
|
|
|
|
|
|
}
|
|
3215
|
|
|
|
|
|
|
|
|
3216
|
3
|
|
|
|
|
5
|
my $buf_shift = 0;
|
|
3217
|
|
|
|
|
|
|
|
|
3218
|
3
|
|
|
|
|
21
|
switch_parse: for ($type) {
|
|
3219
|
3
|
100
|
|
|
|
6
|
case: TYPE_VT200 == $_ and do {
|
|
3220
|
|
|
|
|
|
|
# In this mode, we need 6 bytes
|
|
3221
|
1
|
50
|
|
|
|
4
|
return TB_ERR_NEED_MORE if @in < 6;
|
|
3222
|
|
|
|
|
|
|
|
|
3223
|
1
|
|
|
|
|
3
|
my $b = $in[3] - 0x20;
|
|
3224
|
|
|
|
|
|
|
|
|
3225
|
1
|
|
|
|
|
2
|
local $_;
|
|
3226
|
1
|
|
|
|
|
4
|
switch: for ($b & 3) {
|
|
3227
|
1
|
50
|
|
|
|
3
|
case: 0 == $_ and do {
|
|
3228
|
1
|
50
|
|
|
|
5
|
$event->{key} = ($b & 64) ? TB_KEY_MOUSE_WHEEL_UP
|
|
3229
|
|
|
|
|
|
|
: TB_KEY_MOUSE_LEFT;
|
|
3230
|
1
|
|
|
|
|
4
|
last;
|
|
3231
|
|
|
|
|
|
|
};
|
|
3232
|
0
|
0
|
|
|
|
0
|
case: 1 == $_ and do {
|
|
3233
|
0
|
0
|
|
|
|
0
|
$event->{key} = ($b & 64) ? TB_KEY_MOUSE_WHEEL_DOWN
|
|
3234
|
|
|
|
|
|
|
: TB_KEY_MOUSE_MIDDLE;
|
|
3235
|
0
|
|
|
|
|
0
|
last;
|
|
3236
|
|
|
|
|
|
|
};
|
|
3237
|
0
|
0
|
|
|
|
0
|
case: 2 == $_ and do {
|
|
3238
|
0
|
|
|
|
|
0
|
$event->{key} = TB_KEY_MOUSE_RIGHT;
|
|
3239
|
0
|
|
|
|
|
0
|
last;
|
|
3240
|
|
|
|
|
|
|
};
|
|
3241
|
0
|
0
|
|
|
|
0
|
case: 3 == $_ and do {
|
|
3242
|
0
|
|
|
|
|
0
|
$event->{key} = TB_KEY_MOUSE_RELEASE;
|
|
3243
|
0
|
|
|
|
|
0
|
last;
|
|
3244
|
|
|
|
|
|
|
};
|
|
3245
|
|
|
|
|
|
|
default: {
|
|
3246
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
|
0
|
|
|
|
|
0
|
|
|
3247
|
|
|
|
|
|
|
};
|
|
3248
|
|
|
|
|
|
|
}
|
|
3249
|
|
|
|
|
|
|
|
|
3250
|
1
|
50
|
|
|
|
4
|
if (($b & 32) != 0) {
|
|
3251
|
0
|
|
|
|
|
0
|
$event->{mod} |= TB_MOD_MOTION;
|
|
3252
|
|
|
|
|
|
|
}
|
|
3253
|
|
|
|
|
|
|
|
|
3254
|
|
|
|
|
|
|
# The coord is 1,1 for upper left
|
|
3255
|
1
|
|
|
|
|
2
|
$event->{x} = $in[4] - 0x21;
|
|
3256
|
1
|
|
|
|
|
3
|
$event->{y} = $in[5] - 0x21;
|
|
3257
|
|
|
|
|
|
|
|
|
3258
|
|
|
|
|
|
|
# Eat 6 bytes
|
|
3259
|
1
|
|
|
|
|
2
|
$buf_shift = 6;
|
|
3260
|
1
|
|
|
|
|
3
|
last;
|
|
3261
|
|
|
|
|
|
|
};
|
|
3262
|
|
|
|
|
|
|
|
|
3263
|
|
|
|
|
|
|
case: TYPE_1006 == $_ || # fallthrough
|
|
3264
|
|
|
|
|
|
|
TYPE_1015 == $_ and do
|
|
3265
|
2
|
50
|
66
|
|
|
11
|
{
|
|
3266
|
2
|
|
|
|
|
5
|
my @num = (-1, -1, -1);
|
|
3267
|
2
|
|
|
|
|
42
|
my $num_i = 0;
|
|
3268
|
2
|
|
|
|
|
24
|
my $cur_num = -1;
|
|
3269
|
2
|
|
|
|
|
4
|
my $trail = ord(' ');
|
|
3270
|
|
|
|
|
|
|
|
|
3271
|
2
|
|
|
|
|
5
|
my $i = 2;
|
|
3272
|
2
|
100
|
|
|
|
7
|
++$i if $type == TYPE_1006; # skip '<'
|
|
3273
|
|
|
|
|
|
|
|
|
3274
|
|
|
|
|
|
|
# Parse %d;%d;%d[mM] into @num
|
|
3275
|
2
|
|
66
|
|
|
13
|
while ($i < @in && $num_i < 3) {
|
|
3276
|
19
|
|
|
|
|
27
|
my $c = $in[$i];
|
|
3277
|
|
|
|
|
|
|
|
|
3278
|
19
|
100
|
66
|
|
|
50
|
if ($c >= ord('0') && $c <= ord('9')) {
|
|
3279
|
|
|
|
|
|
|
# Digit
|
|
3280
|
13
|
100
|
|
|
|
24
|
$cur_num = 0 if $cur_num == -1;
|
|
3281
|
13
|
|
|
|
|
16
|
$cur_num *= 10;
|
|
3282
|
13
|
|
|
|
|
15
|
$cur_num += $c - ord('0');
|
|
3283
|
13
|
|
|
|
|
17
|
++$i;
|
|
3284
|
13
|
|
|
|
|
93
|
next;
|
|
3285
|
|
|
|
|
|
|
}
|
|
3286
|
|
|
|
|
|
|
|
|
3287
|
6
|
50
|
66
|
|
|
97
|
if ($cur_num != -1
|
|
|
|
|
33
|
|
|
|
|
|
3288
|
|
|
|
|
|
|
&& (($num_i < 2 && $c == ord(';'))
|
|
3289
|
|
|
|
|
|
|
|| ($num_i == 2 && ($c == ord('m') || $c == ord('M')))))
|
|
3290
|
|
|
|
|
|
|
{
|
|
3291
|
|
|
|
|
|
|
# We're at a semi-colon, 'm', or 'M' and we have a number
|
|
3292
|
6
|
|
|
|
|
10
|
$num[$num_i] = $cur_num;
|
|
3293
|
6
|
|
|
|
|
8
|
++$num_i;
|
|
3294
|
6
|
|
|
|
|
8
|
$cur_num = -1;
|
|
3295
|
6
|
|
|
|
|
6
|
$trail = $c;
|
|
3296
|
6
|
|
|
|
|
9
|
++$i;
|
|
3297
|
6
|
|
|
|
|
18
|
next;
|
|
3298
|
|
|
|
|
|
|
}
|
|
3299
|
|
|
|
|
|
|
|
|
3300
|
|
|
|
|
|
|
# Something else; not a mouse event
|
|
3301
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
3302
|
|
|
|
|
|
|
}
|
|
3303
|
|
|
|
|
|
|
|
|
3304
|
|
|
|
|
|
|
# If we didn't get to the 3rd number, we need more
|
|
3305
|
2
|
50
|
|
|
|
5
|
return TB_ERR_NEED_MORE if $num[2] == -1;
|
|
3306
|
|
|
|
|
|
|
|
|
3307
|
|
|
|
|
|
|
# We have a valid mouse event, eat i bytes from the buffer
|
|
3308
|
2
|
|
|
|
|
3
|
$buf_shift = $i;
|
|
3309
|
|
|
|
|
|
|
|
|
3310
|
2
|
100
|
|
|
|
6
|
$num[0] -= 0x20 if $type == TYPE_1015;
|
|
3311
|
|
|
|
|
|
|
|
|
3312
|
2
|
|
|
|
|
4
|
local $_;
|
|
3313
|
2
|
|
|
|
|
7
|
switch: for ($num[0] & 3) {
|
|
3314
|
2
|
50
|
|
|
|
5
|
case: 0 == $_ and do {
|
|
3315
|
0
|
0
|
|
|
|
0
|
$event->{key} = ($num[0] & 64) ? TB_KEY_MOUSE_WHEEL_UP
|
|
3316
|
|
|
|
|
|
|
: TB_KEY_MOUSE_LEFT;
|
|
3317
|
0
|
|
|
|
|
0
|
last;
|
|
3318
|
|
|
|
|
|
|
};
|
|
3319
|
2
|
100
|
|
|
|
4
|
case: 1 == $_ and do {
|
|
3320
|
1
|
50
|
|
|
|
5
|
$event->{key} = ($num[0] & 64) ? TB_KEY_MOUSE_WHEEL_DOWN
|
|
3321
|
|
|
|
|
|
|
: TB_KEY_MOUSE_MIDDLE;
|
|
3322
|
1
|
|
|
|
|
2
|
last;
|
|
3323
|
|
|
|
|
|
|
};
|
|
3324
|
1
|
50
|
|
|
|
4
|
case: 2 == $_ and do {
|
|
3325
|
0
|
|
|
|
|
0
|
$event->{key} = TB_KEY_MOUSE_RIGHT;
|
|
3326
|
0
|
|
|
|
|
0
|
last;
|
|
3327
|
|
|
|
|
|
|
};
|
|
3328
|
1
|
50
|
|
|
|
4
|
case: 3 == $_ and do {
|
|
3329
|
1
|
|
|
|
|
2
|
$event->{key} = TB_KEY_MOUSE_RELEASE;
|
|
3330
|
1
|
|
|
|
|
3
|
last;
|
|
3331
|
|
|
|
|
|
|
};
|
|
3332
|
|
|
|
|
|
|
default: {
|
|
3333
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
|
0
|
|
|
|
|
0
|
|
|
3334
|
|
|
|
|
|
|
};
|
|
3335
|
|
|
|
|
|
|
}
|
|
3336
|
|
|
|
|
|
|
|
|
3337
|
|
|
|
|
|
|
# On xterm mouse release is signaled by lowercase m
|
|
3338
|
2
|
50
|
|
|
|
5
|
if ($trail == ord('m')) {
|
|
3339
|
0
|
|
|
|
|
0
|
$event->{key} = TB_KEY_MOUSE_RELEASE;
|
|
3340
|
|
|
|
|
|
|
}
|
|
3341
|
|
|
|
|
|
|
|
|
3342
|
2
|
100
|
|
|
|
6
|
if (($num[0] & 32) != 0) {
|
|
3343
|
1
|
|
|
|
|
4
|
$event->{mod} |= TB_MOD_MOTION;
|
|
3344
|
|
|
|
|
|
|
}
|
|
3345
|
|
|
|
|
|
|
|
|
3346
|
2
|
50
|
|
|
|
8
|
$event->{x} = ($num[1] - 1 < 0) ? 0 : $num[1] - 1;
|
|
3347
|
2
|
50
|
|
|
|
5
|
$event->{y} = ($num[2] - 1 < 0) ? 0 : $num[2] - 1;
|
|
3348
|
2
|
|
|
|
|
4
|
last;
|
|
3349
|
|
|
|
|
|
|
};
|
|
3350
|
|
|
|
|
|
|
}
|
|
3351
|
|
|
|
|
|
|
|
|
3352
|
3
|
50
|
|
|
|
11
|
substr($in, 0, $buf_shift, '') if $buf_shift > 0;
|
|
3353
|
|
|
|
|
|
|
|
|
3354
|
3
|
|
|
|
|
7
|
$event->{type} = TB_EVENT_MOUSE;
|
|
3355
|
|
|
|
|
|
|
|
|
3356
|
3
|
|
|
|
|
47
|
return TB_OK;
|
|
3357
|
|
|
|
|
|
|
} #/ alias:
|
|
3358
|
|
|
|
|
|
|
}
|
|
3359
|
|
|
|
|
|
|
|
|
3360
|
|
|
|
|
|
|
sub extract_esc_cap {
|
|
3361
|
3
|
|
|
3
|
0
|
11
|
state $sig = compile(
|
|
3362
|
|
|
|
|
|
|
_Object,
|
|
3363
|
|
|
|
|
|
|
);
|
|
3364
|
3
|
|
|
|
|
8
|
my ($event) = $sig->(@_);
|
|
3365
|
3
|
|
|
|
|
5
|
my $trie = $global->{cap_trie};
|
|
3366
|
3
|
|
|
|
|
7
|
alias: for my $in ($global->{inbuf}) {
|
|
3367
|
3
|
|
|
|
|
5
|
my $node;
|
|
3368
|
|
|
|
|
|
|
my $depth;
|
|
3369
|
|
|
|
|
|
|
|
|
3370
|
3
|
|
|
|
|
10
|
my $rv = $trie->find($in, \$node, \$depth);
|
|
3371
|
3
|
50
|
|
|
|
6
|
return $rv if $rv != TB_OK;
|
|
3372
|
|
|
|
|
|
|
|
|
3373
|
3
|
100
|
33
|
|
|
12
|
if ($node->{is_leaf}) {
|
|
|
|
50
|
|
|
|
|
|
|
3374
|
|
|
|
|
|
|
# Found a leaf node
|
|
3375
|
2
|
|
|
|
|
9
|
$event->{type} = TB_EVENT_KEY;
|
|
3376
|
2
|
|
|
|
|
3
|
$event->{ch} = 0;
|
|
3377
|
2
|
|
|
|
|
7
|
$event->{key} = $node->{key};
|
|
3378
|
2
|
|
|
|
|
4
|
$event->{mod} = $node->{mod};
|
|
3379
|
2
|
|
|
|
|
4
|
substr($in, 0, $depth, '');
|
|
3380
|
2
|
|
|
|
|
8
|
return TB_OK;
|
|
3381
|
|
|
|
|
|
|
}
|
|
3382
|
|
|
|
|
|
|
elsif ($node->{nchildren} > 0 && length($in) <= $depth) {
|
|
3383
|
|
|
|
|
|
|
# Found a branch node (not enough input)
|
|
3384
|
1
|
|
|
|
|
5
|
return TB_ERR_NEED_MORE;
|
|
3385
|
|
|
|
|
|
|
}
|
|
3386
|
|
|
|
|
|
|
|
|
3387
|
0
|
|
|
|
|
0
|
return TB_ERR;
|
|
3388
|
|
|
|
|
|
|
} #/ alias:
|
|
3389
|
|
|
|
|
|
|
}
|
|
3390
|
|
|
|
|
|
|
|
|
3391
|
|
|
|
|
|
|
#
|
|
3392
|
|
|
|
|
|
|
# Cell related helpers
|
|
3393
|
|
|
|
|
|
|
#
|
|
3394
|
|
|
|
|
|
|
|
|
3395
|
|
|
|
|
|
|
sub cell_cmp { # $int ($a, $b)
|
|
3396
|
2
|
|
|
2
|
0
|
11
|
state $sig = compile(
|
|
3397
|
|
|
|
|
|
|
_Object,
|
|
3398
|
|
|
|
|
|
|
_Object,
|
|
3399
|
|
|
|
|
|
|
);
|
|
3400
|
2
|
|
|
|
|
8
|
my ($a, $b) = $sig->(@_);
|
|
3401
|
2
|
50
|
|
|
|
9
|
return $a->equal($b) ? 0 : 1;
|
|
3402
|
|
|
|
|
|
|
}
|
|
3403
|
|
|
|
|
|
|
|
|
3404
|
|
|
|
|
|
|
sub cell_copy { # $int ($dst, $src)
|
|
3405
|
1
|
|
|
1
|
0
|
6
|
goto &Termbox::Cell::copy;
|
|
3406
|
|
|
|
|
|
|
}
|
|
3407
|
|
|
|
|
|
|
|
|
3408
|
|
|
|
|
|
|
sub cell_set { # $int ($cell, \@ch, $nch, $fg, $bg)
|
|
3409
|
10
|
|
|
10
|
0
|
872
|
state $sig = compile(
|
|
3410
|
|
|
|
|
|
|
_Object,
|
|
3411
|
|
|
|
|
|
|
_ArrayRef,
|
|
3412
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3413
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3414
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3415
|
|
|
|
|
|
|
);
|
|
3416
|
10
|
|
|
|
|
25
|
my ($cell, $ch, $nch, $fg, $bg) = $sig->(@_);
|
|
3417
|
8
|
|
|
|
|
88
|
return $cell->set(pack('U*', @$ch), $fg, $bg);
|
|
3418
|
|
|
|
|
|
|
}
|
|
3419
|
|
|
|
|
|
|
|
|
3420
|
|
|
|
|
|
|
sub cell_reserve_ech { # $int ($cell, $n)
|
|
3421
|
1
|
|
|
1
|
0
|
6
|
state $sig = compile(
|
|
3422
|
|
|
|
|
|
|
_Object,
|
|
3423
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3424
|
|
|
|
|
|
|
);
|
|
3425
|
1
|
|
|
|
|
4
|
my ($cell, $n) = $sig->(@_);
|
|
3426
|
1
|
|
|
|
|
3
|
return TB_OPT_EGC ? TB_OK : TB_ERR;
|
|
3427
|
|
|
|
|
|
|
}
|
|
3428
|
|
|
|
|
|
|
|
|
3429
|
|
|
|
|
|
|
sub cell_free { # $int ($cell)
|
|
3430
|
7685
|
|
|
7685
|
0
|
6159
|
state $sig = compile(
|
|
3431
|
|
|
|
|
|
|
_Object,
|
|
3432
|
|
|
|
|
|
|
);
|
|
3433
|
7685
|
|
|
|
|
7649
|
my ($cell) = $sig->(@_);
|
|
3434
|
7685
|
|
|
|
|
9003
|
$cell->{ch} = "\0";
|
|
3435
|
7685
|
|
|
|
|
7332
|
$cell->{fg} = 0;
|
|
3436
|
7685
|
|
|
|
|
6977
|
$cell->{bg} = 0;
|
|
3437
|
7685
|
|
|
|
|
7099
|
return TB_OK;
|
|
3438
|
|
|
|
|
|
|
}
|
|
3439
|
|
|
|
|
|
|
|
|
3440
|
|
|
|
|
|
|
#
|
|
3441
|
|
|
|
|
|
|
# Cell buffer related helpers
|
|
3442
|
|
|
|
|
|
|
#
|
|
3443
|
|
|
|
|
|
|
|
|
3444
|
|
|
|
|
|
|
sub init_cellbuf { # $int ()
|
|
3445
|
3
|
|
|
3
|
0
|
146897
|
state $sig = compile();
|
|
3446
|
3
|
|
|
|
|
8
|
$sig->(@_);
|
|
3447
|
3
|
|
|
|
|
3
|
my $rv;
|
|
3448
|
|
|
|
|
|
|
|
|
3449
|
3
|
|
33
|
|
|
23
|
$global->{back} ||= cellbuf->new();
|
|
3450
|
3
|
|
33
|
|
|
9
|
$global->{front} ||= cellbuf->new();
|
|
3451
|
|
|
|
|
|
|
|
|
3452
|
3
|
|
|
|
|
15
|
$rv = $global->{back}->init($global->{width}, $global->{height});
|
|
3453
|
3
|
50
|
|
|
|
18
|
return $rv if $rv != TB_OK;
|
|
3454
|
3
|
|
|
|
|
20
|
$rv = $global->{front}->init($global->{width}, $global->{height});
|
|
3455
|
3
|
50
|
|
|
|
25
|
return $rv if $rv != TB_OK;
|
|
3456
|
3
|
|
|
|
|
44
|
$rv = $global->{back}->clear();
|
|
3457
|
3
|
50
|
|
|
|
35
|
return $rv if $rv != TB_OK;
|
|
3458
|
3
|
|
|
|
|
20
|
$rv = $global->{front}->clear();
|
|
3459
|
3
|
50
|
|
|
|
19
|
return $rv if $rv != TB_OK;
|
|
3460
|
|
|
|
|
|
|
|
|
3461
|
3
|
|
|
|
|
17
|
return TB_OK;
|
|
3462
|
|
|
|
|
|
|
}
|
|
3463
|
|
|
|
|
|
|
|
|
3464
|
|
|
|
|
|
|
sub cellbuf_init { # $int ($c, $w, $h)
|
|
3465
|
5
|
|
|
5
|
0
|
38
|
goto &cellbuf::init;
|
|
3466
|
|
|
|
|
|
|
}
|
|
3467
|
|
|
|
|
|
|
|
|
3468
|
|
|
|
|
|
|
sub cellbuf_free { # $int ($c)
|
|
3469
|
11
|
|
|
11
|
0
|
21
|
state $sig = compile(
|
|
3470
|
|
|
|
|
|
|
_Object,
|
|
3471
|
|
|
|
|
|
|
);
|
|
3472
|
11
|
|
|
|
|
23
|
my ($c) = $sig->(@_);
|
|
3473
|
11
|
50
|
|
|
|
14
|
for my $cell (@{ $c->{cells} || [] }) {
|
|
|
11
|
|
|
|
|
37
|
|
|
3474
|
7684
|
|
|
|
|
7718
|
my $rv = cell_free($cell);
|
|
3475
|
7684
|
50
|
|
|
|
9384
|
return $rv if $rv != TB_OK;
|
|
3476
|
|
|
|
|
|
|
}
|
|
3477
|
|
|
|
|
|
|
|
|
3478
|
11
|
|
|
|
|
23
|
$c->{width} = 0;
|
|
3479
|
11
|
|
|
|
|
20
|
$c->{height} = 0;
|
|
3480
|
11
|
|
|
|
|
1013
|
$c->{cells} = [];
|
|
3481
|
11
|
|
|
|
|
23
|
return TB_OK;
|
|
3482
|
|
|
|
|
|
|
}
|
|
3483
|
|
|
|
|
|
|
|
|
3484
|
|
|
|
|
|
|
sub cellbuf_clear { # $int ($c)
|
|
3485
|
2
|
|
|
2
|
0
|
10
|
goto &cellbuf::clear;
|
|
3486
|
|
|
|
|
|
|
}
|
|
3487
|
|
|
|
|
|
|
|
|
3488
|
|
|
|
|
|
|
sub cellbuf_get { # $int ($c, $x, $y, \$out)
|
|
3489
|
15
|
|
|
15
|
0
|
29
|
state $sig = compile(
|
|
3490
|
|
|
|
|
|
|
_Object,
|
|
3491
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3492
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3493
|
|
|
|
|
|
|
_Ref,
|
|
3494
|
|
|
|
|
|
|
);
|
|
3495
|
15
|
|
|
|
|
29
|
my ($c, $x, $y, $out) = $sig->(@_);
|
|
3496
|
15
|
100
|
|
|
|
43
|
return TB_ERR_OUT_OF_BOUNDS unless $c->in_bounds($x, $y);
|
|
3497
|
13
|
|
|
|
|
42
|
$$out = $c->get($x, $y);
|
|
3498
|
13
|
50
|
|
|
|
40
|
return defined $$out ? TB_OK : TB_ERR;
|
|
3499
|
|
|
|
|
|
|
}
|
|
3500
|
|
|
|
|
|
|
|
|
3501
|
|
|
|
|
|
|
sub cellbuf_in_bounds { # $int ($c, $x, $y)
|
|
3502
|
2
|
|
|
2
|
0
|
30
|
goto &cellbuf::in_bounds;
|
|
3503
|
|
|
|
|
|
|
}
|
|
3504
|
|
|
|
|
|
|
|
|
3505
|
|
|
|
|
|
|
sub cellbuf_resize { # $int ($c, $w, $h)
|
|
3506
|
1
|
|
|
1
|
0
|
7
|
goto &cellbuf::resize;
|
|
3507
|
|
|
|
|
|
|
}
|
|
3508
|
|
|
|
|
|
|
|
|
3509
|
|
|
|
|
|
|
#
|
|
3510
|
|
|
|
|
|
|
# Sending output helpers
|
|
3511
|
|
|
|
|
|
|
#
|
|
3512
|
|
|
|
|
|
|
|
|
3513
|
|
|
|
|
|
|
sub send_literal { # $int ($rv, $a)
|
|
3514
|
6
|
|
|
6
|
0
|
140514
|
state $sig = compile(
|
|
3515
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3516
|
|
|
|
|
|
|
_Str,
|
|
3517
|
|
|
|
|
|
|
);
|
|
3518
|
6
|
|
|
|
|
9
|
my ($rv, $a) = $sig->(@_);
|
|
3519
|
2
|
|
|
|
|
5
|
$global->{outbuf} .= $a;
|
|
3520
|
2
|
|
|
|
|
5
|
return TB_OK;
|
|
3521
|
|
|
|
|
|
|
}
|
|
3522
|
|
|
|
|
|
|
|
|
3523
|
|
|
|
|
|
|
sub send_num { # $int ($rv, \$buf, $n)
|
|
3524
|
2
|
|
|
2
|
0
|
1593
|
state $sig = compile(
|
|
3525
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3526
|
|
|
|
|
|
|
_ScalarRef,
|
|
3527
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3528
|
|
|
|
|
|
|
);
|
|
3529
|
2
|
|
|
|
|
4
|
my ($rv, $buf, $n) = $sig->(@_);
|
|
3530
|
2
|
|
|
|
|
9
|
$global->{outbuf} .= sprintf('%u', $n);
|
|
3531
|
2
|
|
|
|
|
4
|
return TB_OK;
|
|
3532
|
|
|
|
|
|
|
}
|
|
3533
|
|
|
|
|
|
|
|
|
3534
|
|
|
|
|
|
|
sub send_init_escape_codes { # $int ()
|
|
3535
|
2
|
|
|
2
|
0
|
1439
|
state $sig = compile();
|
|
3536
|
2
|
|
|
|
|
4
|
$sig->(@_);
|
|
3537
|
2
|
|
|
|
|
3
|
my $rv;
|
|
3538
|
2
|
|
|
|
|
9
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_ENTER_CA]);
|
|
3539
|
1
|
50
|
|
|
|
3
|
return $rv if $rv != TB_OK;
|
|
3540
|
1
|
|
|
|
|
3
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_ENTER_KEYPAD]);
|
|
3541
|
1
|
50
|
|
|
|
2
|
return $rv if $rv != TB_OK;
|
|
3542
|
1
|
|
|
|
|
3
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_HIDE_CURSOR]);
|
|
3543
|
1
|
50
|
|
|
|
3
|
return $rv if $rv != TB_OK;
|
|
3544
|
1
|
|
|
|
|
3
|
return TB_OK;
|
|
3545
|
|
|
|
|
|
|
}
|
|
3546
|
|
|
|
|
|
|
|
|
3547
|
|
|
|
|
|
|
sub send_clear { # $int ()
|
|
3548
|
1
|
|
|
1
|
0
|
358
|
state $sig = compile();
|
|
3549
|
1
|
|
|
|
|
2
|
$sig->(@_);
|
|
3550
|
1
|
|
|
|
|
1
|
my $rv;
|
|
3551
|
|
|
|
|
|
|
|
|
3552
|
1
|
|
|
|
|
3
|
$rv = send_attr($global->{fg}, $global->{bg});
|
|
3553
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3554
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_CLEAR_SCREEN]);
|
|
3555
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3556
|
|
|
|
|
|
|
|
|
3557
|
0
|
|
|
|
|
0
|
$rv = send_cursor_if($global->{cursor_x}, $global->{cursor_y});
|
|
3558
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3559
|
0
|
|
|
|
|
0
|
$rv = bytebuf_flush(\$global->{outbuf}, $global->{wfd});
|
|
3560
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3561
|
|
|
|
|
|
|
|
|
3562
|
0
|
|
|
|
|
0
|
$global->{last_x} = -1;
|
|
3563
|
0
|
|
|
|
|
0
|
$global->{last_y} = -1;
|
|
3564
|
|
|
|
|
|
|
|
|
3565
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
3566
|
|
|
|
|
|
|
}
|
|
3567
|
|
|
|
|
|
|
|
|
3568
|
|
|
|
|
|
|
sub send_attr { # $int ($fg, $bg)
|
|
3569
|
3
|
|
|
3
|
0
|
943
|
state $sig = compile(
|
|
3570
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3571
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3572
|
|
|
|
|
|
|
);
|
|
3573
|
3
|
|
|
|
|
8
|
my ($fg, $bg) = $sig->(@_);
|
|
3574
|
3
|
|
|
|
|
5
|
my $rv;
|
|
3575
|
|
|
|
|
|
|
|
|
3576
|
3
|
100
|
66
|
|
|
32
|
if ($fg == $global->{last_fg} && $bg == $global->{last_bg}) {
|
|
3577
|
1
|
|
|
|
|
3
|
return TB_OK;
|
|
3578
|
|
|
|
|
|
|
}
|
|
3579
|
|
|
|
|
|
|
|
|
3580
|
2
|
|
|
|
|
5
|
$rv = bytebuf_puts($global->{outbuf}, $global->{caps}[TB_CAP_SGR0]);
|
|
3581
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3582
|
|
|
|
|
|
|
|
|
3583
|
0
|
|
|
|
|
0
|
my ($cfg, $cbg);
|
|
3584
|
0
|
|
|
|
|
0
|
switch: for ($global->{output_mode}) {
|
|
3585
|
|
|
|
|
|
|
DEFAULT:
|
|
3586
|
0
|
0
|
|
|
|
0
|
case: TB_OUTPUT_NORMAL == $_ and do {
|
|
3587
|
|
|
|
|
|
|
# The minus 1 below is because our colors are 1-indexed starting
|
|
3588
|
|
|
|
|
|
|
# from black. Black is represented by a 30, 40, 90, or 100 for fg,
|
|
3589
|
|
|
|
|
|
|
# bg, bright fg, or bright bg respectively. Red is 31, 41, 91,
|
|
3590
|
|
|
|
|
|
|
# 101, etc.
|
|
3591
|
0
|
0
|
|
|
|
0
|
$cfg = ($fg & TB_BRIGHT ? 90 : 30) + ($fg & 0x0f) - 1;
|
|
3592
|
0
|
0
|
|
|
|
0
|
$cbg = ($bg & TB_BRIGHT ? 100 : 40) + ($bg & 0x0f) - 1;
|
|
3593
|
0
|
|
|
|
|
0
|
last;
|
|
3594
|
0
|
|
|
|
|
0
|
};
|
|
3595
|
0
|
0
|
|
|
|
0
|
case: TB_OUTPUT_256 == $_ and do {
|
|
3596
|
0
|
|
|
|
|
0
|
$cfg = $fg & 0xff;
|
|
3597
|
0
|
|
|
|
|
0
|
$cbg = $bg & 0xff;
|
|
3598
|
0
|
0
|
|
|
|
0
|
$cfg = 0 if $fg & TB_HI_BLACK;
|
|
3599
|
0
|
0
|
|
|
|
0
|
$cbg = 0 if $bg & TB_HI_BLACK;
|
|
3600
|
0
|
|
|
|
|
0
|
last;
|
|
3601
|
|
|
|
|
|
|
};
|
|
3602
|
0
|
0
|
|
|
|
0
|
case: TB_OUTPUT_216 == $_ and do {
|
|
3603
|
0
|
|
|
|
|
0
|
$cfg = $fg & 0xff;
|
|
3604
|
0
|
|
|
|
|
0
|
$cbg = $bg & 0xff;
|
|
3605
|
0
|
0
|
|
|
|
0
|
$cfg = 216 if $cfg > 216;
|
|
3606
|
0
|
0
|
|
|
|
0
|
$cbg = 216 if $cbg > 216;
|
|
3607
|
0
|
|
|
|
|
0
|
$cfg += 0x0f;
|
|
3608
|
0
|
|
|
|
|
0
|
$cbg += 0x0f;
|
|
3609
|
0
|
|
|
|
|
0
|
last;
|
|
3610
|
|
|
|
|
|
|
};
|
|
3611
|
0
|
0
|
|
|
|
0
|
case: TB_OUTPUT_GRAYSCALE == $_ and do {
|
|
3612
|
0
|
|
|
|
|
0
|
$cfg = $fg & 0xff;
|
|
3613
|
0
|
|
|
|
|
0
|
$cbg = $bg & 0xff;
|
|
3614
|
0
|
0
|
|
|
|
0
|
$cfg = 24 if $cfg > 24;
|
|
3615
|
0
|
0
|
|
|
|
0
|
$cbg = 24 if $cbg > 24;
|
|
3616
|
0
|
|
|
|
|
0
|
$cfg += 0xe7;
|
|
3617
|
0
|
|
|
|
|
0
|
$cbg += 0xe7;
|
|
3618
|
0
|
|
|
|
|
0
|
last;
|
|
3619
|
|
|
|
|
|
|
};
|
|
3620
|
0
|
0
|
|
|
|
0
|
case: TB_OPT_ATTR_W >= 32 && TB_OUTPUT_TRUECOLOR == $_ and do {
|
|
3621
|
0
|
|
|
|
|
0
|
$cfg = $fg & 0xffffff;
|
|
3622
|
0
|
|
|
|
|
0
|
$cbg = $bg & 0xffffff;
|
|
3623
|
0
|
0
|
|
|
|
0
|
$cfg = 0 if $fg & TB_HI_BLACK;
|
|
3624
|
0
|
0
|
|
|
|
0
|
$cbg = 0 if $bg & TB_HI_BLACK;
|
|
3625
|
0
|
|
|
|
|
0
|
last;
|
|
3626
|
|
|
|
|
|
|
};
|
|
3627
|
|
|
|
|
|
|
default: {
|
|
3628
|
0
|
|
|
|
|
0
|
$_ = TB_OUTPUT_NORMAL;
|
|
|
0
|
|
|
|
|
0
|
|
|
3629
|
0
|
|
|
|
|
0
|
goto DEFAULT;
|
|
3630
|
|
|
|
|
|
|
};
|
|
3631
|
|
|
|
|
|
|
}
|
|
3632
|
|
|
|
|
|
|
|
|
3633
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_BOLD) {
|
|
3634
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_BOLD]);
|
|
3635
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3636
|
|
|
|
|
|
|
}
|
|
3637
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_BLINK) {
|
|
3638
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_BLINK]);
|
|
3639
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3640
|
|
|
|
|
|
|
}
|
|
3641
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_UNDERLINE) {
|
|
3642
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_UNDERLINE]);
|
|
3643
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3644
|
|
|
|
|
|
|
}
|
|
3645
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_ITALIC) {
|
|
3646
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_ITALIC]);
|
|
3647
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3648
|
|
|
|
|
|
|
}
|
|
3649
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_DIM) {
|
|
3650
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_DIM]);
|
|
3651
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3652
|
|
|
|
|
|
|
}
|
|
3653
|
0
|
|
|
|
|
0
|
if (TB_OPT_ATTR_W == 64) {
|
|
3654
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_STRIKEOUT) {
|
|
3655
|
|
|
|
|
|
|
$rv = bytebuf_puts(\$global->{outbuf},
|
|
3656
|
0
|
|
|
|
|
0
|
$global->{caps}[TB_HARDCAP_STRIKEOUT]);
|
|
3657
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3658
|
|
|
|
|
|
|
}
|
|
3659
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_UNDERLINE_2) {
|
|
3660
|
|
|
|
|
|
|
$rv = bytebuf_puts(\$global->{outbuf},
|
|
3661
|
0
|
|
|
|
|
0
|
$global->{caps}[TB_HARDCAP_UNDERLINE_2]);
|
|
3662
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3663
|
|
|
|
|
|
|
}
|
|
3664
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_OVERLINE) {
|
|
3665
|
|
|
|
|
|
|
$rv = bytebuf_puts(\$global->{outbuf},
|
|
3666
|
0
|
|
|
|
|
0
|
$global->{caps}[TB_HARDCAP_OVERLINE]);
|
|
3667
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3668
|
|
|
|
|
|
|
}
|
|
3669
|
0
|
0
|
|
|
|
0
|
if ($fg & TB_INVISIBLE) {
|
|
3670
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_INVISIBLE]);
|
|
3671
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3672
|
|
|
|
|
|
|
}
|
|
3673
|
|
|
|
|
|
|
}
|
|
3674
|
|
|
|
|
|
|
|
|
3675
|
0
|
0
|
0
|
|
|
0
|
if (($fg & TB_REVERSE) || ($bg & TB_REVERSE)) {
|
|
3676
|
0
|
|
|
|
|
0
|
$rv = bytebuf_puts(\$global->{outbuf}, $global->{caps}[TB_CAP_REVERSE]);
|
|
3677
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3678
|
|
|
|
|
|
|
}
|
|
3679
|
0
|
|
|
|
|
0
|
my $fg_is_default = ($fg & 0xff) == 0;
|
|
3680
|
0
|
|
|
|
|
0
|
my $bg_is_default = ($bg & 0xff) == 0;
|
|
3681
|
0
|
0
|
|
|
|
0
|
if ($global->{output_mode} == TB_OUTPUT_256) {
|
|
3682
|
0
|
0
|
|
|
|
0
|
$fg_is_default = 0 if $fg & TB_HI_BLACK;
|
|
3683
|
0
|
0
|
|
|
|
0
|
$bg_is_default = 0 if $bg & TB_HI_BLACK;
|
|
3684
|
|
|
|
|
|
|
}
|
|
3685
|
0
|
|
|
|
|
0
|
if (TB_OPT_ATTR_W >= 32) {
|
|
3686
|
0
|
0
|
|
|
|
0
|
if ($global->{output_mode} == TB_OUTPUT_TRUECOLOR) {
|
|
3687
|
0
|
|
0
|
|
|
0
|
$fg_is_default = (($fg & 0xffffff) == 0) && (($fg & TB_HI_BLACK) == 0);
|
|
3688
|
0
|
|
0
|
|
|
0
|
$bg_is_default = (($bg & 0xffffff) == 0) && (($bg & TB_HI_BLACK) == 0);
|
|
3689
|
|
|
|
|
|
|
}
|
|
3690
|
|
|
|
|
|
|
}
|
|
3691
|
|
|
|
|
|
|
|
|
3692
|
0
|
|
|
|
|
0
|
$rv = send_sgr($cfg, $cbg, $fg_is_default, $bg_is_default);
|
|
3693
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3694
|
|
|
|
|
|
|
|
|
3695
|
0
|
|
|
|
|
0
|
$global->{last_fg} = $fg;
|
|
3696
|
0
|
|
|
|
|
0
|
$global->{last_bg} = $bg;
|
|
3697
|
|
|
|
|
|
|
|
|
3698
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
3699
|
|
|
|
|
|
|
}
|
|
3700
|
|
|
|
|
|
|
|
|
3701
|
|
|
|
|
|
|
sub send_sgr { # $int ($cfg, $cbg, $fg_is_default, $bg_is_default)
|
|
3702
|
2
|
|
|
2
|
0
|
944
|
state $sig = compile(
|
|
3703
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3704
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3705
|
|
|
|
|
|
|
_Bool,
|
|
3706
|
|
|
|
|
|
|
_Bool,
|
|
3707
|
|
|
|
|
|
|
);
|
|
3708
|
2
|
|
|
|
|
6
|
my ($cfg, $cbg, $fg_is_default, $bg_is_default) = $sig->(@_);
|
|
3709
|
2
|
|
|
|
|
3
|
my $rv;
|
|
3710
|
2
|
|
|
|
|
3
|
my $nbuf = '';
|
|
3711
|
|
|
|
|
|
|
|
|
3712
|
2
|
50
|
33
|
|
|
8
|
return TB_OK if $fg_is_default && $bg_is_default;
|
|
3713
|
|
|
|
|
|
|
|
|
3714
|
2
|
|
|
|
|
5
|
switch: for ($global->{output_mode}) {
|
|
3715
|
|
|
|
|
|
|
DEFAULT:
|
|
3716
|
3
|
100
|
|
|
|
34
|
case: TB_OUTPUT_NORMAL == $_ and do {
|
|
3717
|
2
|
|
|
|
|
5
|
send_literal($rv, "\x1b[");
|
|
3718
|
0
|
0
|
|
|
|
0
|
if (!$fg_is_default) {
|
|
3719
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $cfg);
|
|
3720
|
0
|
0
|
|
|
|
0
|
if (!$bg_is_default) {
|
|
3721
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3722
|
|
|
|
|
|
|
}
|
|
3723
|
|
|
|
|
|
|
}
|
|
3724
|
0
|
0
|
|
|
|
0
|
if (!$bg_is_default) {
|
|
3725
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $cbg);
|
|
3726
|
|
|
|
|
|
|
}
|
|
3727
|
0
|
|
|
|
|
0
|
send_literal($rv, "m");
|
|
3728
|
0
|
|
|
|
|
0
|
last;
|
|
3729
|
3
|
|
|
|
|
3
|
};
|
|
3730
|
|
|
|
|
|
|
case: TB_OUTPUT_256 == $_ ||
|
|
3731
|
|
|
|
|
|
|
TB_OUTPUT_216 == $_ ||
|
|
3732
|
|
|
|
|
|
|
TB_OUTPUT_GRAYSCALE == $_ and do
|
|
3733
|
1
|
50
|
33
|
|
|
7
|
{
|
|
|
|
|
33
|
|
|
|
|
|
3734
|
0
|
|
|
|
|
0
|
send_literal($rv, "\x1b[");
|
|
3735
|
0
|
0
|
|
|
|
0
|
if (!$fg_is_default) {
|
|
3736
|
0
|
|
|
|
|
0
|
send_literal($rv, "38;5;");
|
|
3737
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $cfg);
|
|
3738
|
0
|
0
|
|
|
|
0
|
if (!$bg_is_default) {
|
|
3739
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3740
|
|
|
|
|
|
|
}
|
|
3741
|
|
|
|
|
|
|
}
|
|
3742
|
0
|
0
|
|
|
|
0
|
if (!$bg_is_default) {
|
|
3743
|
0
|
|
|
|
|
0
|
send_literal($rv, "48;5;");
|
|
3744
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $cbg);
|
|
3745
|
|
|
|
|
|
|
}
|
|
3746
|
0
|
|
|
|
|
0
|
send_literal($rv, "m");
|
|
3747
|
0
|
|
|
|
|
0
|
last;
|
|
3748
|
|
|
|
|
|
|
};
|
|
3749
|
1
|
50
|
|
|
|
3
|
case: TB_OPT_ATTR_W >= 32 && TB_OUTPUT_TRUECOLOR == $_ and do {
|
|
3750
|
0
|
|
|
|
|
0
|
send_literal($rv, "\x1b[");
|
|
3751
|
0
|
0
|
|
|
|
0
|
if (!$fg_is_default) {
|
|
3752
|
0
|
|
|
|
|
0
|
send_literal($rv, "38;2;");
|
|
3753
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, ($cfg >> 16) & 0xff);
|
|
3754
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3755
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, ($cfg >> 8) & 0xff);
|
|
3756
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3757
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $cfg & 0xff);
|
|
3758
|
0
|
0
|
|
|
|
0
|
if (!$bg_is_default) {
|
|
3759
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3760
|
|
|
|
|
|
|
}
|
|
3761
|
|
|
|
|
|
|
}
|
|
3762
|
0
|
0
|
|
|
|
0
|
if (!$bg_is_default) {
|
|
3763
|
0
|
|
|
|
|
0
|
send_literal($rv, "48;2;");
|
|
3764
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, ($cbg >> 16) & 0xff);
|
|
3765
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3766
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, ($cbg >> 8) & 0xff);
|
|
3767
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3768
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $cbg & 0xff);
|
|
3769
|
|
|
|
|
|
|
}
|
|
3770
|
0
|
|
|
|
|
0
|
send_literal($rv, "m");
|
|
3771
|
0
|
|
|
|
|
0
|
last;
|
|
3772
|
|
|
|
|
|
|
};
|
|
3773
|
|
|
|
|
|
|
default: {
|
|
3774
|
1
|
|
|
|
|
2
|
$_ = TB_OUTPUT_NORMAL;
|
|
|
1
|
|
|
|
|
1
|
|
|
3775
|
1
|
|
|
|
|
46
|
goto DEFAULT;
|
|
3776
|
|
|
|
|
|
|
};
|
|
3777
|
|
|
|
|
|
|
}
|
|
3778
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
3779
|
|
|
|
|
|
|
}
|
|
3780
|
|
|
|
|
|
|
|
|
3781
|
|
|
|
|
|
|
sub send_cursor_if { # $int ($x, $y)
|
|
3782
|
2
|
|
|
2
|
0
|
975
|
state $sig = compile(
|
|
3783
|
|
|
|
|
|
|
_Int,
|
|
3784
|
|
|
|
|
|
|
_Int,
|
|
3785
|
|
|
|
|
|
|
);
|
|
3786
|
2
|
|
|
|
|
6
|
my ($x, $y) = $sig->(@_);
|
|
3787
|
2
|
|
|
|
|
3
|
my $rv;
|
|
3788
|
2
|
|
|
|
|
4
|
my $nbuf = '';
|
|
3789
|
2
|
50
|
33
|
|
|
10
|
return TB_OK if $x < 0 || $y < 0;
|
|
3790
|
2
|
|
|
|
|
4
|
send_literal($rv, "\x1b[");
|
|
3791
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $y + 1);
|
|
3792
|
0
|
|
|
|
|
0
|
send_literal($rv, ";");
|
|
3793
|
0
|
|
|
|
|
0
|
send_num($rv, \$nbuf, $x + 1);
|
|
3794
|
0
|
|
|
|
|
0
|
send_literal($rv, "H");
|
|
3795
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
3796
|
|
|
|
|
|
|
}
|
|
3797
|
|
|
|
|
|
|
|
|
3798
|
|
|
|
|
|
|
sub send_char { # $int ($x, $y, $ch)
|
|
3799
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile(
|
|
3800
|
|
|
|
|
|
|
_Int,
|
|
3801
|
|
|
|
|
|
|
_Int,
|
|
3802
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3803
|
|
|
|
|
|
|
);
|
|
3804
|
0
|
|
|
|
|
0
|
my ($x, $y, $ch) = $sig->(@_);
|
|
3805
|
0
|
|
|
|
|
0
|
return send_cluster($x, $y, [$ch], 1);
|
|
3806
|
|
|
|
|
|
|
}
|
|
3807
|
|
|
|
|
|
|
|
|
3808
|
|
|
|
|
|
|
sub send_cluster { # $int ($x, $y, \@ch, $nch)
|
|
3809
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile(
|
|
3810
|
|
|
|
|
|
|
_Int,
|
|
3811
|
|
|
|
|
|
|
_Int,
|
|
3812
|
|
|
|
|
|
|
_ArrayRef,
|
|
3813
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3814
|
|
|
|
|
|
|
);
|
|
3815
|
0
|
|
|
|
|
0
|
my ($x, $y, $ch, $nch) = $sig->(@_);
|
|
3816
|
|
|
|
|
|
|
|
|
3817
|
0
|
0
|
0
|
|
|
0
|
if ($global->{last_x} != $x - 1 || $global->{last_y} != $y) {
|
|
3818
|
0
|
|
|
|
|
0
|
my $rv = send_cursor_if($x, $y);
|
|
3819
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3820
|
|
|
|
|
|
|
}
|
|
3821
|
0
|
|
|
|
|
0
|
$global->{last_x} = $x;
|
|
3822
|
0
|
|
|
|
|
0
|
$global->{last_y} = $y;
|
|
3823
|
|
|
|
|
|
|
|
|
3824
|
0
|
|
|
|
|
0
|
foreach my $ch32 (@$ch) {
|
|
3825
|
0
|
0
|
|
|
|
0
|
if (!tb_iswprint_ex($ch32, undef)) {
|
|
3826
|
0
|
|
|
|
|
0
|
$ch32 = 0xfffd; # replace non-printable codepoints with U+FFFD
|
|
3827
|
|
|
|
|
|
|
}
|
|
3828
|
0
|
|
|
|
|
0
|
my $cu8_len = tb_utf8_unicode_to_char(\my $chu8, $ch32);
|
|
3829
|
0
|
|
|
|
|
0
|
my $rv = bytebuf_nputs(\$global->{outbuf}, $chu8, $cu8_len);
|
|
3830
|
0
|
0
|
|
|
|
0
|
return $rv if $rv != TB_OK;
|
|
3831
|
|
|
|
|
|
|
}
|
|
3832
|
|
|
|
|
|
|
|
|
3833
|
0
|
|
|
|
|
0
|
return TB_OK;
|
|
3834
|
|
|
|
|
|
|
}
|
|
3835
|
|
|
|
|
|
|
|
|
3836
|
|
|
|
|
|
|
sub convert_num { # $len ($num, \$buf)
|
|
3837
|
0
|
|
|
0
|
0
|
0
|
state $sig = compile(
|
|
3838
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3839
|
|
|
|
|
|
|
_ScalarRef,
|
|
3840
|
|
|
|
|
|
|
);
|
|
3841
|
0
|
|
|
|
|
0
|
my ($num, $buf) = $sig->(@_);
|
|
3842
|
0
|
|
|
|
|
0
|
$$buf = sprintf('%u', $num);
|
|
3843
|
0
|
|
|
|
|
0
|
return bytes::length($$buf);
|
|
3844
|
|
|
|
|
|
|
}
|
|
3845
|
|
|
|
|
|
|
|
|
3846
|
|
|
|
|
|
|
#
|
|
3847
|
|
|
|
|
|
|
# Byte buffer related helpers
|
|
3848
|
|
|
|
|
|
|
#
|
|
3849
|
|
|
|
|
|
|
|
|
3850
|
|
|
|
|
|
|
sub bytebuf_puts { # $int (\$buf, $str)
|
|
3851
|
10
|
|
|
10
|
0
|
153731
|
state $sig = compile(
|
|
3852
|
|
|
|
|
|
|
_ScalarRef,
|
|
3853
|
|
|
|
|
|
|
_Str,
|
|
3854
|
|
|
|
|
|
|
);
|
|
3855
|
10
|
|
|
|
|
18
|
my ($b, $str) = $sig->(@_);
|
|
3856
|
|
|
|
|
|
|
# Nothing to do for empty caps
|
|
3857
|
5
|
100
|
|
|
|
17
|
$$b .= $str if bytes::length($str);
|
|
3858
|
5
|
|
|
|
|
45
|
return TB_OK
|
|
3859
|
|
|
|
|
|
|
}
|
|
3860
|
|
|
|
|
|
|
|
|
3861
|
|
|
|
|
|
|
sub bytebuf_nputs { # $int (\$buf, $str, $nstr)
|
|
3862
|
1
|
|
|
1
|
0
|
4
|
state $sig = compile(
|
|
3863
|
|
|
|
|
|
|
_ScalarRef,
|
|
3864
|
|
|
|
|
|
|
_Str,
|
|
3865
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3866
|
|
|
|
|
|
|
);
|
|
3867
|
1
|
|
|
|
|
4
|
my ($b, $str, $nstr) = $sig->(@_);
|
|
3868
|
1
|
|
|
|
|
5
|
$$b .= bytes::substr($str, 0, $nstr);
|
|
3869
|
1
|
|
|
|
|
8
|
return TB_OK;
|
|
3870
|
|
|
|
|
|
|
}
|
|
3871
|
|
|
|
|
|
|
|
|
3872
|
|
|
|
|
|
|
sub bytebuf_shift { # $int (\$buf, $n)
|
|
3873
|
3
|
|
|
3
|
0
|
3491
|
state $sig = compile(
|
|
3874
|
|
|
|
|
|
|
_ScalarRef,
|
|
3875
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3876
|
|
|
|
|
|
|
);
|
|
3877
|
3
|
|
|
|
|
8
|
my ($b, $n) = $sig->(@_);
|
|
3878
|
37
|
|
|
37
|
|
127309
|
use bytes;
|
|
|
37
|
|
|
|
|
58
|
|
|
|
37
|
|
|
|
|
126
|
|
|
3879
|
3
|
100
|
|
|
|
10
|
$n = length($$b) if $n > length($$b);
|
|
3880
|
3
|
|
|
|
|
9
|
substr($$b, 0, $n, '');
|
|
3881
|
3
|
|
|
|
|
9
|
return TB_OK;
|
|
3882
|
|
|
|
|
|
|
}
|
|
3883
|
|
|
|
|
|
|
|
|
3884
|
|
|
|
|
|
|
sub bytebuf_flush { # $int (\$buf, $fd)
|
|
3885
|
4
|
|
|
4
|
0
|
11080
|
state $sig = compile(
|
|
3886
|
|
|
|
|
|
|
_ScalarRef,
|
|
3887
|
|
|
|
|
|
|
_Int,
|
|
3888
|
|
|
|
|
|
|
);
|
|
3889
|
4
|
|
|
|
|
9
|
my ($b, $fd) = $sig->(@_);
|
|
3890
|
37
|
|
|
37
|
|
3396
|
use bytes;
|
|
|
37
|
|
|
|
|
52
|
|
|
|
37
|
|
|
|
|
106
|
|
|
3891
|
4
|
100
|
|
|
|
18
|
return TB_OK unless length($$b);
|
|
3892
|
2
|
|
|
|
|
4
|
my $want = length($$b);
|
|
3893
|
2
|
|
50
|
|
|
88
|
my $wrote = POSIX::write($fd // -1, $$b, $want);
|
|
3894
|
2
|
100
|
66
|
|
|
16
|
if (!defined($wrote) || $wrote != $want) {
|
|
3895
|
1
|
|
|
|
|
7
|
$global->{last_errno} = 0+ $!;
|
|
3896
|
1
|
|
|
|
|
4
|
return TB_ERR;
|
|
3897
|
|
|
|
|
|
|
}
|
|
3898
|
1
|
|
|
|
|
3
|
$$b = '';
|
|
3899
|
1
|
|
|
|
|
6
|
return TB_OK;
|
|
3900
|
|
|
|
|
|
|
}
|
|
3901
|
|
|
|
|
|
|
|
|
3902
|
|
|
|
|
|
|
sub bytebuf_reserve { # $int (\$buf, $sz)
|
|
3903
|
1
|
|
|
1
|
0
|
3099
|
state $sig = compile(
|
|
3904
|
|
|
|
|
|
|
_ScalarRef,
|
|
3905
|
|
|
|
|
|
|
_PositiveOrZeroInt,
|
|
3906
|
|
|
|
|
|
|
);
|
|
3907
|
1
|
|
|
|
|
3
|
$sig->(@_);
|
|
3908
|
1
|
|
|
|
|
4
|
return TB_OK;
|
|
3909
|
|
|
|
|
|
|
}
|
|
3910
|
|
|
|
|
|
|
|
|
3911
|
|
|
|
|
|
|
sub bytebuf_free { # $int (\$buf)
|
|
3912
|
12
|
|
|
12
|
0
|
760
|
state $sig = compile(
|
|
3913
|
|
|
|
|
|
|
_ScalarRef,
|
|
3914
|
|
|
|
|
|
|
);
|
|
3915
|
12
|
|
|
|
|
24
|
my ($b) = $sig->(@_);
|
|
3916
|
11
|
|
|
|
|
21
|
$$b = '';
|
|
3917
|
11
|
|
|
|
|
115
|
return TB_OK;
|
|
3918
|
|
|
|
|
|
|
}
|
|
3919
|
|
|
|
|
|
|
|
|
3920
|
|
|
|
|
|
|
# Hack to make 'use Termbox' work without an actual Termbox.pm file.
|
|
3921
|
|
|
|
|
|
|
$INC{"Termbox.pm"} = __FILE__;
|