rich-ruby 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -0
- data/LICENSE +21 -21
- data/README.md +547 -547
- data/docs/architecture.md +43 -0
- data/docs/cheat-sheet.md +52 -0
- data/docs/customization.md +53 -0
- data/docs/how-to-use.md +96 -0
- data/docs/test-report.md +112 -0
- data/docs/troubleshooting.md +36 -0
- data/docs/windows-notes.md +30 -0
- data/examples/demo.rb +106 -106
- data/examples/showcase.rb +420 -420
- data/examples/smoke_test.rb +41 -41
- data/examples/stress_test.rb +604 -604
- data/examples/syntax_markdown_demo.rb +166 -166
- data/examples/verify.rb +216 -215
- data/examples/visual_demo.rb +145 -145
- data/lib/rich/_palettes.rb +148 -148
- data/lib/rich/box.rb +342 -342
- data/lib/rich/cells.rb +524 -512
- data/lib/rich/color.rb +631 -628
- data/lib/rich/color_triplet.rb +227 -220
- data/lib/rich/console.rb +604 -549
- data/lib/rich/control.rb +332 -332
- data/lib/rich/json.rb +260 -254
- data/lib/rich/layout.rb +314 -314
- data/lib/rich/markdown.rb +531 -509
- data/lib/rich/markup.rb +186 -175
- data/lib/rich/panel.rb +318 -311
- data/lib/rich/progress.rb +430 -430
- data/lib/rich/segment.rb +387 -387
- data/lib/rich/style.rb +464 -433
- data/lib/rich/syntax.rb +1220 -1145
- data/lib/rich/table.rb +547 -525
- data/lib/rich/terminal_theme.rb +126 -126
- data/lib/rich/text.rb +460 -433
- data/lib/rich/tree.rb +220 -220
- data/lib/rich/version.rb +5 -5
- data/lib/rich/win32_console.rb +620 -582
- data/lib/rich.rb +108 -108
- metadata +15 -5
data/lib/rich/cells.rb
CHANGED
|
@@ -1,512 +1,524 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Rich
|
|
4
|
-
# Cell width calculation for Unicode characters.
|
|
5
|
-
# Handles East Asian Width and emoji character widths for proper terminal alignment.
|
|
6
|
-
module Cells
|
|
7
|
-
# Zero-width character categories (based on Unicode East Asian Width)
|
|
8
|
-
# These characters do not take up any visual space
|
|
9
|
-
ZERO_WIDTH_RANGES = [
|
|
10
|
-
0x0000..0x001F, # C0 control codes
|
|
11
|
-
0x007F..0x009F, # C1 control codes
|
|
12
|
-
0x00AD..0x00AD, # Soft hyphen
|
|
13
|
-
0x0300..0x036F, # Combining diacritical marks
|
|
14
|
-
0x0483..0x0489, # Combining Cyrillic marks
|
|
15
|
-
0x0591..0x05BD, # Hebrew combining marks
|
|
16
|
-
0x05BF..0x05BF,
|
|
17
|
-
0x05C1..0x05C2,
|
|
18
|
-
0x05C4..0x05C5,
|
|
19
|
-
0x05C7..0x05C7,
|
|
20
|
-
0x0600..0x0605, # Arabic marks
|
|
21
|
-
0x0610..0x061A,
|
|
22
|
-
0x061C..0x061C,
|
|
23
|
-
0x064B..0x065F,
|
|
24
|
-
0x0670..0x0670,
|
|
25
|
-
0x06D6..0x06DC,
|
|
26
|
-
0x06DF..0x06E4,
|
|
27
|
-
0x06E7..0x06E8,
|
|
28
|
-
0x06EA..0x06ED,
|
|
29
|
-
0x070F..0x070F,
|
|
30
|
-
0x0711..0x0711,
|
|
31
|
-
0x0730..0x074A,
|
|
32
|
-
0x07A6..0x07B0,
|
|
33
|
-
0x07EB..0x07F3,
|
|
34
|
-
0x0816..0x0819,
|
|
35
|
-
0x081B..0x0823,
|
|
36
|
-
0x0825..0x0827,
|
|
37
|
-
0x0829..0x082D,
|
|
38
|
-
0x0859..0x085B,
|
|
39
|
-
0x08D4..0x08E1,
|
|
40
|
-
0x08E3..0x0902,
|
|
41
|
-
0x093A..0x093A,
|
|
42
|
-
0x093C..0x093C,
|
|
43
|
-
0x0941..0x0948,
|
|
44
|
-
0x094D..0x094D,
|
|
45
|
-
0x0951..0x0957,
|
|
46
|
-
0x0962..0x0963,
|
|
47
|
-
0x0981..0x0981,
|
|
48
|
-
0x09BC..0x09BC,
|
|
49
|
-
0x09C1..0x09C4,
|
|
50
|
-
0x09CD..0x09CD,
|
|
51
|
-
0x09E2..0x09E3,
|
|
52
|
-
0x0A01..0x0A02,
|
|
53
|
-
0x0A3C..0x0A3C,
|
|
54
|
-
0x0A41..0x0A42,
|
|
55
|
-
0x0A47..0x0A48,
|
|
56
|
-
0x0A4B..0x0A4D,
|
|
57
|
-
0x0A51..0x0A51,
|
|
58
|
-
0x0A70..0x0A71,
|
|
59
|
-
0x0A75..0x0A75,
|
|
60
|
-
0x0A81..0x0A82,
|
|
61
|
-
0x0ABC..0x0ABC,
|
|
62
|
-
0x0AC1..0x0AC5,
|
|
63
|
-
0x0AC7..0x0AC8,
|
|
64
|
-
0x0ACD..0x0ACD,
|
|
65
|
-
0x0AE2..0x0AE3,
|
|
66
|
-
0x0B01..0x0B01,
|
|
67
|
-
0x0B3C..0x0B3C,
|
|
68
|
-
0x0B3F..0x0B3F,
|
|
69
|
-
0x0B41..0x0B44,
|
|
70
|
-
0x0B4D..0x0B4D,
|
|
71
|
-
0x0B56..0x0B56,
|
|
72
|
-
0x0B62..0x0B63,
|
|
73
|
-
0x0B82..0x0B82,
|
|
74
|
-
0x0BC0..0x0BC0,
|
|
75
|
-
0x0BCD..0x0BCD,
|
|
76
|
-
0x0C00..0x0C00,
|
|
77
|
-
0x0C3E..0x0C40,
|
|
78
|
-
0x0C46..0x0C48,
|
|
79
|
-
0x0C4A..0x0C4D,
|
|
80
|
-
0x0C55..0x0C56,
|
|
81
|
-
0x0C62..0x0C63,
|
|
82
|
-
0x0C81..0x0C81,
|
|
83
|
-
0x0CBC..0x0CBC,
|
|
84
|
-
0x0CBF..0x0CBF,
|
|
85
|
-
0x0CC6..0x0CC6,
|
|
86
|
-
0x0CCC..0x0CCD,
|
|
87
|
-
0x0CE2..0x0CE3,
|
|
88
|
-
0x0D01..0x0D01,
|
|
89
|
-
0x0D41..0x0D44,
|
|
90
|
-
0x0D4D..0x0D4D,
|
|
91
|
-
0x0D62..0x0D63,
|
|
92
|
-
0x0DCA..0x0DCA,
|
|
93
|
-
0x0DD2..0x0DD4,
|
|
94
|
-
0x0DD6..0x0DD6,
|
|
95
|
-
0x0E31..0x0E31,
|
|
96
|
-
0x0E34..0x0E3A,
|
|
97
|
-
0x0E47..0x0E4E,
|
|
98
|
-
0x0EB1..0x0EB1,
|
|
99
|
-
0x0EB4..0x0EB9,
|
|
100
|
-
0x0EBB..0x0EBC,
|
|
101
|
-
0x0EC8..0x0ECD,
|
|
102
|
-
0x0F18..0x0F19,
|
|
103
|
-
0x0F35..0x0F35,
|
|
104
|
-
0x0F37..0x0F37,
|
|
105
|
-
0x0F39..0x0F39,
|
|
106
|
-
0x0F71..0x0F7E,
|
|
107
|
-
0x0F80..0x0F84,
|
|
108
|
-
0x0F86..0x0F87,
|
|
109
|
-
0x0F8D..0x0F97,
|
|
110
|
-
0x0F99..0x0FBC,
|
|
111
|
-
0x0FC6..0x0FC6,
|
|
112
|
-
0x102D..0x1030,
|
|
113
|
-
0x1032..0x1037,
|
|
114
|
-
0x1039..0x103A,
|
|
115
|
-
0x103D..0x103E,
|
|
116
|
-
0x1058..0x1059,
|
|
117
|
-
0x105E..0x1060,
|
|
118
|
-
0x1071..0x1074,
|
|
119
|
-
0x1082..0x1082,
|
|
120
|
-
0x1085..0x1086,
|
|
121
|
-
0x108D..0x108D,
|
|
122
|
-
0x109D..0x109D,
|
|
123
|
-
0x1160..0x11FF, # Hangul Jungseong/Jongseong
|
|
124
|
-
0x135D..0x135F,
|
|
125
|
-
0x1712..0x1714,
|
|
126
|
-
0x1732..0x1734,
|
|
127
|
-
0x1752..0x1753,
|
|
128
|
-
0x1772..0x1773,
|
|
129
|
-
0x17B4..0x17B5,
|
|
130
|
-
0x17B7..0x17BD,
|
|
131
|
-
0x17C6..0x17C6,
|
|
132
|
-
0x17C9..0x17D3,
|
|
133
|
-
0x17DD..0x17DD,
|
|
134
|
-
0x180B..0x180D,
|
|
135
|
-
0x1885..0x1886,
|
|
136
|
-
0x18A9..0x18A9,
|
|
137
|
-
0x1920..0x1922,
|
|
138
|
-
0x1927..0x1928,
|
|
139
|
-
0x1932..0x1932,
|
|
140
|
-
0x1939..0x193B,
|
|
141
|
-
0x1A17..0x1A18,
|
|
142
|
-
0x1A1B..0x1A1B,
|
|
143
|
-
0x1A56..0x1A56,
|
|
144
|
-
0x1A58..0x1A5E,
|
|
145
|
-
0x1A60..0x1A60,
|
|
146
|
-
0x1A62..0x1A62,
|
|
147
|
-
0x1A65..0x1A6C,
|
|
148
|
-
0x1A73..0x1A7C,
|
|
149
|
-
0x1A7F..0x1A7F,
|
|
150
|
-
0x1AB0..0x1ABE,
|
|
151
|
-
0x1B00..0x1B03,
|
|
152
|
-
0x1B34..0x1B34,
|
|
153
|
-
0x1B36..0x1B3A,
|
|
154
|
-
0x1B3C..0x1B3C,
|
|
155
|
-
0x1B42..0x1B42,
|
|
156
|
-
0x1B6B..0x1B73,
|
|
157
|
-
0x1B80..0x1B81,
|
|
158
|
-
0x1BA2..0x1BA5,
|
|
159
|
-
0x1BA8..0x1BA9,
|
|
160
|
-
0x1BAB..0x1BAD,
|
|
161
|
-
0x1BE6..0x1BE6,
|
|
162
|
-
0x1BE8..0x1BE9,
|
|
163
|
-
0x1BED..0x1BED,
|
|
164
|
-
0x1BEF..0x1BF1,
|
|
165
|
-
0x1C2C..0x1C33,
|
|
166
|
-
0x1C36..0x1C37,
|
|
167
|
-
0x1CD0..0x1CD2,
|
|
168
|
-
0x1CD4..0x1CE0,
|
|
169
|
-
0x1CE2..0x1CE8,
|
|
170
|
-
0x1CED..0x1CED,
|
|
171
|
-
0x1CF4..0x1CF4,
|
|
172
|
-
0x1CF8..0x1CF9,
|
|
173
|
-
0x1DC0..0x1DF5,
|
|
174
|
-
0x1DFC..0x1DFF,
|
|
175
|
-
0x200B..0x200F, # Zero-width spaces and direction marks
|
|
176
|
-
0x202A..0x202E,
|
|
177
|
-
0x2060..0x2064,
|
|
178
|
-
0x2066..0x206F,
|
|
179
|
-
0x20D0..0x20F0, # Combining marks for symbols
|
|
180
|
-
0x2CEF..0x2CF1,
|
|
181
|
-
0x2D7F..0x2D7F,
|
|
182
|
-
0x2DE0..0x2DFF,
|
|
183
|
-
0x302A..0x302D,
|
|
184
|
-
0x3099..0x309A,
|
|
185
|
-
0xA66F..0xA672,
|
|
186
|
-
0xA674..0xA67D,
|
|
187
|
-
0xA69E..0xA69F,
|
|
188
|
-
0xA6F0..0xA6F1,
|
|
189
|
-
0xA802..0xA802,
|
|
190
|
-
0xA806..0xA806,
|
|
191
|
-
0xA80B..0xA80B,
|
|
192
|
-
0xA825..0xA826,
|
|
193
|
-
0xA8C4..0xA8C4,
|
|
194
|
-
0xA8E0..0xA8F1,
|
|
195
|
-
0xA926..0xA92D,
|
|
196
|
-
0xA947..0xA951,
|
|
197
|
-
0xA980..0xA982,
|
|
198
|
-
0xA9B3..0xA9B3,
|
|
199
|
-
0xA9B6..0xA9B9,
|
|
200
|
-
0xA9BC..0xA9BC,
|
|
201
|
-
0xA9E5..0xA9E5,
|
|
202
|
-
0xAA29..0xAA2E,
|
|
203
|
-
0xAA31..0xAA32,
|
|
204
|
-
0xAA35..0xAA36,
|
|
205
|
-
0xAA43..0xAA43,
|
|
206
|
-
0xAA4C..0xAA4C,
|
|
207
|
-
0xAA7C..0xAA7C,
|
|
208
|
-
0xAAB0..0xAAB0,
|
|
209
|
-
0xAAB2..0xAAB4,
|
|
210
|
-
0xAAB7..0xAAB8,
|
|
211
|
-
0xAABE..0xAABF,
|
|
212
|
-
0xAAC1..0xAAC1,
|
|
213
|
-
0xAAEC..0xAAED,
|
|
214
|
-
0xAAF6..0xAAF6,
|
|
215
|
-
0xABE5..0xABE5,
|
|
216
|
-
0xABE8..0xABE8,
|
|
217
|
-
0xABED..0xABED,
|
|
218
|
-
0xFB1E..0xFB1E,
|
|
219
|
-
0xFE00..0xFE0F, # Variation selectors
|
|
220
|
-
0xFE20..0xFE2F,
|
|
221
|
-
0xFEFF..0xFEFF, # BOM/ZWNBSP
|
|
222
|
-
0xFFF9..0xFFFB,
|
|
223
|
-
0x101FD..0x101FD,
|
|
224
|
-
0x102E0..0x102E0,
|
|
225
|
-
0x10376..0x1037A,
|
|
226
|
-
0x10A01..0x10A03,
|
|
227
|
-
0x10A05..0x10A06,
|
|
228
|
-
0x10A0C..0x10A0F,
|
|
229
|
-
0x10A38..0x10A3A,
|
|
230
|
-
0x10A3F..0x10A3F,
|
|
231
|
-
0x10AE5..0x10AE6,
|
|
232
|
-
0x11001..0x11001,
|
|
233
|
-
0x11038..0x11046,
|
|
234
|
-
0x1107F..0x11081,
|
|
235
|
-
0x110B3..0x110B6,
|
|
236
|
-
0x110B9..0x110BA,
|
|
237
|
-
0x11100..0x11102,
|
|
238
|
-
0x11127..0x1112B,
|
|
239
|
-
0x1112D..0x11134,
|
|
240
|
-
0x11173..0x11173,
|
|
241
|
-
0x11180..0x11181,
|
|
242
|
-
0x111B6..0x111BE,
|
|
243
|
-
0x111CA..0x111CC,
|
|
244
|
-
0x1122F..0x11231,
|
|
245
|
-
0x11234..0x11234,
|
|
246
|
-
0x11236..0x11237,
|
|
247
|
-
0x1123E..0x1123E,
|
|
248
|
-
0x112DF..0x112DF,
|
|
249
|
-
0x112E3..0x112EA,
|
|
250
|
-
0x11300..0x11301,
|
|
251
|
-
0x1133C..0x1133C,
|
|
252
|
-
0x11340..0x11340,
|
|
253
|
-
0x11366..0x1136C,
|
|
254
|
-
0x11370..0x11374,
|
|
255
|
-
0x11438..0x1143F,
|
|
256
|
-
0x11442..0x11444,
|
|
257
|
-
0x11446..0x11446,
|
|
258
|
-
0x114B3..0x114B8,
|
|
259
|
-
0x114BA..0x114BA,
|
|
260
|
-
0x114BF..0x114C0,
|
|
261
|
-
0x114C2..0x114C3,
|
|
262
|
-
0x115B2..0x115B5,
|
|
263
|
-
0x115BC..0x115BD,
|
|
264
|
-
0x115BF..0x115C0,
|
|
265
|
-
0x115DC..0x115DD,
|
|
266
|
-
0x11633..0x1163A,
|
|
267
|
-
0x1163D..0x1163D,
|
|
268
|
-
0x1163F..0x11640,
|
|
269
|
-
0x116AB..0x116AB,
|
|
270
|
-
0x116AD..0x116AD,
|
|
271
|
-
0x116B0..0x116B5,
|
|
272
|
-
0x116B7..0x116B7,
|
|
273
|
-
0x1171D..0x1171F,
|
|
274
|
-
0x11722..0x11725,
|
|
275
|
-
0x11727..0x1172B,
|
|
276
|
-
0x11C30..0x11C36,
|
|
277
|
-
0x11C38..0x11C3D,
|
|
278
|
-
0x11C3F..0x11C3F,
|
|
279
|
-
0x11C92..0x11CA7,
|
|
280
|
-
0x11CAA..0x11CB0,
|
|
281
|
-
0x11CB2..0x11CB3,
|
|
282
|
-
0x11CB5..0x11CB6,
|
|
283
|
-
0x16AF0..0x16AF4,
|
|
284
|
-
0x16B30..0x16B36,
|
|
285
|
-
0x16F8F..0x16F92,
|
|
286
|
-
0x1BC9D..0x1BC9E,
|
|
287
|
-
0x1D167..0x1D169,
|
|
288
|
-
0x1D173..0x1D182,
|
|
289
|
-
0x1D185..0x1D18B,
|
|
290
|
-
0x1D1AA..0x1D1AD,
|
|
291
|
-
0x1D242..0x1D244,
|
|
292
|
-
0x1DA00..0x1DA36,
|
|
293
|
-
0x1DA3B..0x1DA6C,
|
|
294
|
-
0x1DA75..0x1DA75,
|
|
295
|
-
0x1DA84..0x1DA84,
|
|
296
|
-
0x1DA9B..0x1DA9F,
|
|
297
|
-
0x1DAA1..0x1DAAF,
|
|
298
|
-
0x1E000..0x1E006,
|
|
299
|
-
0x1E008..0x1E018,
|
|
300
|
-
0x1E01B..0x1E021,
|
|
301
|
-
0x1E023..0x1E024,
|
|
302
|
-
0x1E026..0x1E02A,
|
|
303
|
-
0x1E8D0..0x1E8D6,
|
|
304
|
-
0x1E944..0x1E94A,
|
|
305
|
-
0xE0001..0xE0001,
|
|
306
|
-
0xE0020..0xE007F,
|
|
307
|
-
0xE0100..0xE01EF
|
|
308
|
-
].freeze
|
|
309
|
-
|
|
310
|
-
# Wide (double-width) character ranges (CJK, etc.)
|
|
311
|
-
WIDE_RANGES = [
|
|
312
|
-
0x1100..0x115F, # Hangul Jamo
|
|
313
|
-
0x231A..0x231B, # Watch, Hourglass
|
|
314
|
-
0x2329..0x232A, # Angle brackets
|
|
315
|
-
0x23E9..0x23F3, # Media controls
|
|
316
|
-
0x23F8..0x23FA,
|
|
317
|
-
0x25FD..0x25FE, # Squares
|
|
318
|
-
0x2614..0x2615, # Umbrella, Hot beverage
|
|
319
|
-
0x2648..0x2653, # Zodiac
|
|
320
|
-
0x267F..0x267F, # Wheelchair
|
|
321
|
-
0x2693..0x2693, # Anchor
|
|
322
|
-
0x26A1..0x26A1, # Lightning
|
|
323
|
-
0x26AA..0x26AB, # Circles
|
|
324
|
-
0x26BD..0x26BE, # Sports
|
|
325
|
-
0x26C4..0x26C5, # Weather
|
|
326
|
-
0x26CE..0x26CE, # Ophiuchus
|
|
327
|
-
0x26D4..0x26D4, # No entry
|
|
328
|
-
0x26EA..0x26EA, # Church
|
|
329
|
-
0x26F2..0x26F3, # Fountain, Golf
|
|
330
|
-
0x26F5..0x26F5, # Sailboat
|
|
331
|
-
0x26FA..0x26FA, # Tent
|
|
332
|
-
0x26FD..0x26FD, # Fuel pump
|
|
333
|
-
0x2702..0x2702, # Scissors
|
|
334
|
-
0x2705..0x2705, # Check mark
|
|
335
|
-
0x2708..0x270D, # Various
|
|
336
|
-
0x270F..0x270F, # Pencil
|
|
337
|
-
0x2712..0x2712, # Black nib
|
|
338
|
-
0x2714..0x2714, # Check mark
|
|
339
|
-
0x2716..0x2716, # X mark
|
|
340
|
-
0x271D..0x271D, # Cross
|
|
341
|
-
0x2721..0x2721, # Star of David
|
|
342
|
-
0x2728..0x2728, # Sparkles
|
|
343
|
-
0x2733..0x2734, # Asterisks
|
|
344
|
-
0x2744..0x2744, # Snowflake
|
|
345
|
-
0x2747..0x2747, # Sparkle
|
|
346
|
-
0x274C..0x274C, # Cross mark
|
|
347
|
-
0x274E..0x274E,
|
|
348
|
-
0x2753..0x2755, # Question marks
|
|
349
|
-
0x2757..0x2757, # Exclamation
|
|
350
|
-
0x2763..0x2764, # Heart
|
|
351
|
-
0x2795..0x2797, # Math symbols
|
|
352
|
-
0x27A1..0x27A1, # Arrow
|
|
353
|
-
0x27B0..0x27B0, # Loop
|
|
354
|
-
0x27BF..0x27BF, # Loop
|
|
355
|
-
0x2934..0x2935, # Arrows
|
|
356
|
-
0x2B05..0x2B07, # Arrows
|
|
357
|
-
0x2B1B..0x2B1C, # Squares
|
|
358
|
-
0x2B50..0x2B50, # Star
|
|
359
|
-
0x2B55..0x2B55, # Circle
|
|
360
|
-
0x2E80..0x2E99, # CJK radicals
|
|
361
|
-
0x2E9B..0x2EF3,
|
|
362
|
-
0x2F00..0x2FD5, # Kangxi radicals
|
|
363
|
-
0x2FF0..0x2FFB, # Ideographic description
|
|
364
|
-
0x3000..0x303E, # CJK punctuation
|
|
365
|
-
0x3041..0x3096, # Hiragana
|
|
366
|
-
0x3099..0x30FF, # Katakana
|
|
367
|
-
0x3105..0x312D, # Bopomofo
|
|
368
|
-
0x3131..0x318E, # Hangul compatibility
|
|
369
|
-
0x3190..0x31BA, # Kanbun
|
|
370
|
-
0x31C0..0x31E3, # CJK strokes
|
|
371
|
-
0x31F0..0x321E, # Katakana extensions
|
|
372
|
-
0x3220..0x3247, # Enclosed CJK
|
|
373
|
-
0x3250..0x32FE,
|
|
374
|
-
0x3300..0x4DBF, # CJK unified
|
|
375
|
-
0x4E00..0x9FFF, # CJK unified ideographs
|
|
376
|
-
0xA000..0xA48C, # Yi syllables
|
|
377
|
-
0xA490..0xA4C6, # Yi radicals
|
|
378
|
-
0xA960..0xA97C, # Hangul Jamo extended
|
|
379
|
-
0xAC00..0xD7A3, # Hangul syllables
|
|
380
|
-
0xF900..0xFAFF, # CJK compatibility ideographs
|
|
381
|
-
0xFE10..0xFE19, # Vertical forms
|
|
382
|
-
0xFE30..0xFE52, # CJK compatibility forms
|
|
383
|
-
0xFE54..0xFE66,
|
|
384
|
-
0xFE68..0xFE6B,
|
|
385
|
-
0xFF01..0xFF60, # Fullwidth forms
|
|
386
|
-
0xFFE0..0xFFE6,
|
|
387
|
-
0x16FE0..0x16FE1, # Various
|
|
388
|
-
0x17000..0x187EC, # Tangut
|
|
389
|
-
0x18800..0x18AF2,
|
|
390
|
-
0x1B000..0x1B11E, # Kana supplement
|
|
391
|
-
0x1B170..0x1B2FB,
|
|
392
|
-
0x1F004..0x1F004, # Mahjong
|
|
393
|
-
0x1F0CF..0x1F0CF, # Playing card
|
|
394
|
-
0x1F18E..0x1F18E, # Squared AB
|
|
395
|
-
0x1F191..0x1F19A, # Squared
|
|
396
|
-
0x1F200..0x1F202,
|
|
397
|
-
0x1F210..0x1F23B,
|
|
398
|
-
0x1F240..0x1F248,
|
|
399
|
-
0x1F250..0x1F251,
|
|
400
|
-
0x1F260..0x1F265,
|
|
401
|
-
0x1F300..0x1F64F, # Emoji
|
|
402
|
-
0x1F680..0x1F6C5,
|
|
403
|
-
0x1F6CC..0x1F6CC,
|
|
404
|
-
0x1F6D0..0x1F6D2,
|
|
405
|
-
0x1F6EB..0x1F6EC,
|
|
406
|
-
0x1F6F4..0x1F6F8,
|
|
407
|
-
0x1F910..0x1F93E,
|
|
408
|
-
0x1F940..0x1F94C,
|
|
409
|
-
0x1F950..0x1F96B,
|
|
410
|
-
0x1F980..0x1F997,
|
|
411
|
-
0x1F9C0..0x1F9C0,
|
|
412
|
-
0x1F9D0..0x1F9E6,
|
|
413
|
-
0x20000..0x2FFFD, # CJK extension B
|
|
414
|
-
0x30000..0x3FFFD # CJK extension G
|
|
415
|
-
].freeze
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
#
|
|
441
|
-
1
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
return 0 if text.nil? || text.empty?
|
|
466
|
-
|
|
467
|
-
#
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
@
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
#
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
end
|
|
503
|
-
|
|
504
|
-
#
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rich
|
|
4
|
+
# Cell width calculation for Unicode characters.
|
|
5
|
+
# Handles East Asian Width and emoji character widths for proper terminal alignment.
|
|
6
|
+
module Cells
|
|
7
|
+
# Zero-width character categories (based on Unicode East Asian Width)
|
|
8
|
+
# These characters do not take up any visual space
|
|
9
|
+
ZERO_WIDTH_RANGES = [
|
|
10
|
+
0x0000..0x001F, # C0 control codes
|
|
11
|
+
0x007F..0x009F, # C1 control codes
|
|
12
|
+
0x00AD..0x00AD, # Soft hyphen
|
|
13
|
+
0x0300..0x036F, # Combining diacritical marks
|
|
14
|
+
0x0483..0x0489, # Combining Cyrillic marks
|
|
15
|
+
0x0591..0x05BD, # Hebrew combining marks
|
|
16
|
+
0x05BF..0x05BF,
|
|
17
|
+
0x05C1..0x05C2,
|
|
18
|
+
0x05C4..0x05C5,
|
|
19
|
+
0x05C7..0x05C7,
|
|
20
|
+
0x0600..0x0605, # Arabic marks
|
|
21
|
+
0x0610..0x061A,
|
|
22
|
+
0x061C..0x061C,
|
|
23
|
+
0x064B..0x065F,
|
|
24
|
+
0x0670..0x0670,
|
|
25
|
+
0x06D6..0x06DC,
|
|
26
|
+
0x06DF..0x06E4,
|
|
27
|
+
0x06E7..0x06E8,
|
|
28
|
+
0x06EA..0x06ED,
|
|
29
|
+
0x070F..0x070F,
|
|
30
|
+
0x0711..0x0711,
|
|
31
|
+
0x0730..0x074A,
|
|
32
|
+
0x07A6..0x07B0,
|
|
33
|
+
0x07EB..0x07F3,
|
|
34
|
+
0x0816..0x0819,
|
|
35
|
+
0x081B..0x0823,
|
|
36
|
+
0x0825..0x0827,
|
|
37
|
+
0x0829..0x082D,
|
|
38
|
+
0x0859..0x085B,
|
|
39
|
+
0x08D4..0x08E1,
|
|
40
|
+
0x08E3..0x0902,
|
|
41
|
+
0x093A..0x093A,
|
|
42
|
+
0x093C..0x093C,
|
|
43
|
+
0x0941..0x0948,
|
|
44
|
+
0x094D..0x094D,
|
|
45
|
+
0x0951..0x0957,
|
|
46
|
+
0x0962..0x0963,
|
|
47
|
+
0x0981..0x0981,
|
|
48
|
+
0x09BC..0x09BC,
|
|
49
|
+
0x09C1..0x09C4,
|
|
50
|
+
0x09CD..0x09CD,
|
|
51
|
+
0x09E2..0x09E3,
|
|
52
|
+
0x0A01..0x0A02,
|
|
53
|
+
0x0A3C..0x0A3C,
|
|
54
|
+
0x0A41..0x0A42,
|
|
55
|
+
0x0A47..0x0A48,
|
|
56
|
+
0x0A4B..0x0A4D,
|
|
57
|
+
0x0A51..0x0A51,
|
|
58
|
+
0x0A70..0x0A71,
|
|
59
|
+
0x0A75..0x0A75,
|
|
60
|
+
0x0A81..0x0A82,
|
|
61
|
+
0x0ABC..0x0ABC,
|
|
62
|
+
0x0AC1..0x0AC5,
|
|
63
|
+
0x0AC7..0x0AC8,
|
|
64
|
+
0x0ACD..0x0ACD,
|
|
65
|
+
0x0AE2..0x0AE3,
|
|
66
|
+
0x0B01..0x0B01,
|
|
67
|
+
0x0B3C..0x0B3C,
|
|
68
|
+
0x0B3F..0x0B3F,
|
|
69
|
+
0x0B41..0x0B44,
|
|
70
|
+
0x0B4D..0x0B4D,
|
|
71
|
+
0x0B56..0x0B56,
|
|
72
|
+
0x0B62..0x0B63,
|
|
73
|
+
0x0B82..0x0B82,
|
|
74
|
+
0x0BC0..0x0BC0,
|
|
75
|
+
0x0BCD..0x0BCD,
|
|
76
|
+
0x0C00..0x0C00,
|
|
77
|
+
0x0C3E..0x0C40,
|
|
78
|
+
0x0C46..0x0C48,
|
|
79
|
+
0x0C4A..0x0C4D,
|
|
80
|
+
0x0C55..0x0C56,
|
|
81
|
+
0x0C62..0x0C63,
|
|
82
|
+
0x0C81..0x0C81,
|
|
83
|
+
0x0CBC..0x0CBC,
|
|
84
|
+
0x0CBF..0x0CBF,
|
|
85
|
+
0x0CC6..0x0CC6,
|
|
86
|
+
0x0CCC..0x0CCD,
|
|
87
|
+
0x0CE2..0x0CE3,
|
|
88
|
+
0x0D01..0x0D01,
|
|
89
|
+
0x0D41..0x0D44,
|
|
90
|
+
0x0D4D..0x0D4D,
|
|
91
|
+
0x0D62..0x0D63,
|
|
92
|
+
0x0DCA..0x0DCA,
|
|
93
|
+
0x0DD2..0x0DD4,
|
|
94
|
+
0x0DD6..0x0DD6,
|
|
95
|
+
0x0E31..0x0E31,
|
|
96
|
+
0x0E34..0x0E3A,
|
|
97
|
+
0x0E47..0x0E4E,
|
|
98
|
+
0x0EB1..0x0EB1,
|
|
99
|
+
0x0EB4..0x0EB9,
|
|
100
|
+
0x0EBB..0x0EBC,
|
|
101
|
+
0x0EC8..0x0ECD,
|
|
102
|
+
0x0F18..0x0F19,
|
|
103
|
+
0x0F35..0x0F35,
|
|
104
|
+
0x0F37..0x0F37,
|
|
105
|
+
0x0F39..0x0F39,
|
|
106
|
+
0x0F71..0x0F7E,
|
|
107
|
+
0x0F80..0x0F84,
|
|
108
|
+
0x0F86..0x0F87,
|
|
109
|
+
0x0F8D..0x0F97,
|
|
110
|
+
0x0F99..0x0FBC,
|
|
111
|
+
0x0FC6..0x0FC6,
|
|
112
|
+
0x102D..0x1030,
|
|
113
|
+
0x1032..0x1037,
|
|
114
|
+
0x1039..0x103A,
|
|
115
|
+
0x103D..0x103E,
|
|
116
|
+
0x1058..0x1059,
|
|
117
|
+
0x105E..0x1060,
|
|
118
|
+
0x1071..0x1074,
|
|
119
|
+
0x1082..0x1082,
|
|
120
|
+
0x1085..0x1086,
|
|
121
|
+
0x108D..0x108D,
|
|
122
|
+
0x109D..0x109D,
|
|
123
|
+
0x1160..0x11FF, # Hangul Jungseong/Jongseong
|
|
124
|
+
0x135D..0x135F,
|
|
125
|
+
0x1712..0x1714,
|
|
126
|
+
0x1732..0x1734,
|
|
127
|
+
0x1752..0x1753,
|
|
128
|
+
0x1772..0x1773,
|
|
129
|
+
0x17B4..0x17B5,
|
|
130
|
+
0x17B7..0x17BD,
|
|
131
|
+
0x17C6..0x17C6,
|
|
132
|
+
0x17C9..0x17D3,
|
|
133
|
+
0x17DD..0x17DD,
|
|
134
|
+
0x180B..0x180D,
|
|
135
|
+
0x1885..0x1886,
|
|
136
|
+
0x18A9..0x18A9,
|
|
137
|
+
0x1920..0x1922,
|
|
138
|
+
0x1927..0x1928,
|
|
139
|
+
0x1932..0x1932,
|
|
140
|
+
0x1939..0x193B,
|
|
141
|
+
0x1A17..0x1A18,
|
|
142
|
+
0x1A1B..0x1A1B,
|
|
143
|
+
0x1A56..0x1A56,
|
|
144
|
+
0x1A58..0x1A5E,
|
|
145
|
+
0x1A60..0x1A60,
|
|
146
|
+
0x1A62..0x1A62,
|
|
147
|
+
0x1A65..0x1A6C,
|
|
148
|
+
0x1A73..0x1A7C,
|
|
149
|
+
0x1A7F..0x1A7F,
|
|
150
|
+
0x1AB0..0x1ABE,
|
|
151
|
+
0x1B00..0x1B03,
|
|
152
|
+
0x1B34..0x1B34,
|
|
153
|
+
0x1B36..0x1B3A,
|
|
154
|
+
0x1B3C..0x1B3C,
|
|
155
|
+
0x1B42..0x1B42,
|
|
156
|
+
0x1B6B..0x1B73,
|
|
157
|
+
0x1B80..0x1B81,
|
|
158
|
+
0x1BA2..0x1BA5,
|
|
159
|
+
0x1BA8..0x1BA9,
|
|
160
|
+
0x1BAB..0x1BAD,
|
|
161
|
+
0x1BE6..0x1BE6,
|
|
162
|
+
0x1BE8..0x1BE9,
|
|
163
|
+
0x1BED..0x1BED,
|
|
164
|
+
0x1BEF..0x1BF1,
|
|
165
|
+
0x1C2C..0x1C33,
|
|
166
|
+
0x1C36..0x1C37,
|
|
167
|
+
0x1CD0..0x1CD2,
|
|
168
|
+
0x1CD4..0x1CE0,
|
|
169
|
+
0x1CE2..0x1CE8,
|
|
170
|
+
0x1CED..0x1CED,
|
|
171
|
+
0x1CF4..0x1CF4,
|
|
172
|
+
0x1CF8..0x1CF9,
|
|
173
|
+
0x1DC0..0x1DF5,
|
|
174
|
+
0x1DFC..0x1DFF,
|
|
175
|
+
0x200B..0x200F, # Zero-width spaces and direction marks
|
|
176
|
+
0x202A..0x202E,
|
|
177
|
+
0x2060..0x2064,
|
|
178
|
+
0x2066..0x206F,
|
|
179
|
+
0x20D0..0x20F0, # Combining marks for symbols
|
|
180
|
+
0x2CEF..0x2CF1,
|
|
181
|
+
0x2D7F..0x2D7F,
|
|
182
|
+
0x2DE0..0x2DFF,
|
|
183
|
+
0x302A..0x302D,
|
|
184
|
+
0x3099..0x309A,
|
|
185
|
+
0xA66F..0xA672,
|
|
186
|
+
0xA674..0xA67D,
|
|
187
|
+
0xA69E..0xA69F,
|
|
188
|
+
0xA6F0..0xA6F1,
|
|
189
|
+
0xA802..0xA802,
|
|
190
|
+
0xA806..0xA806,
|
|
191
|
+
0xA80B..0xA80B,
|
|
192
|
+
0xA825..0xA826,
|
|
193
|
+
0xA8C4..0xA8C4,
|
|
194
|
+
0xA8E0..0xA8F1,
|
|
195
|
+
0xA926..0xA92D,
|
|
196
|
+
0xA947..0xA951,
|
|
197
|
+
0xA980..0xA982,
|
|
198
|
+
0xA9B3..0xA9B3,
|
|
199
|
+
0xA9B6..0xA9B9,
|
|
200
|
+
0xA9BC..0xA9BC,
|
|
201
|
+
0xA9E5..0xA9E5,
|
|
202
|
+
0xAA29..0xAA2E,
|
|
203
|
+
0xAA31..0xAA32,
|
|
204
|
+
0xAA35..0xAA36,
|
|
205
|
+
0xAA43..0xAA43,
|
|
206
|
+
0xAA4C..0xAA4C,
|
|
207
|
+
0xAA7C..0xAA7C,
|
|
208
|
+
0xAAB0..0xAAB0,
|
|
209
|
+
0xAAB2..0xAAB4,
|
|
210
|
+
0xAAB7..0xAAB8,
|
|
211
|
+
0xAABE..0xAABF,
|
|
212
|
+
0xAAC1..0xAAC1,
|
|
213
|
+
0xAAEC..0xAAED,
|
|
214
|
+
0xAAF6..0xAAF6,
|
|
215
|
+
0xABE5..0xABE5,
|
|
216
|
+
0xABE8..0xABE8,
|
|
217
|
+
0xABED..0xABED,
|
|
218
|
+
0xFB1E..0xFB1E,
|
|
219
|
+
0xFE00..0xFE0F, # Variation selectors
|
|
220
|
+
0xFE20..0xFE2F,
|
|
221
|
+
0xFEFF..0xFEFF, # BOM/ZWNBSP
|
|
222
|
+
0xFFF9..0xFFFB,
|
|
223
|
+
0x101FD..0x101FD,
|
|
224
|
+
0x102E0..0x102E0,
|
|
225
|
+
0x10376..0x1037A,
|
|
226
|
+
0x10A01..0x10A03,
|
|
227
|
+
0x10A05..0x10A06,
|
|
228
|
+
0x10A0C..0x10A0F,
|
|
229
|
+
0x10A38..0x10A3A,
|
|
230
|
+
0x10A3F..0x10A3F,
|
|
231
|
+
0x10AE5..0x10AE6,
|
|
232
|
+
0x11001..0x11001,
|
|
233
|
+
0x11038..0x11046,
|
|
234
|
+
0x1107F..0x11081,
|
|
235
|
+
0x110B3..0x110B6,
|
|
236
|
+
0x110B9..0x110BA,
|
|
237
|
+
0x11100..0x11102,
|
|
238
|
+
0x11127..0x1112B,
|
|
239
|
+
0x1112D..0x11134,
|
|
240
|
+
0x11173..0x11173,
|
|
241
|
+
0x11180..0x11181,
|
|
242
|
+
0x111B6..0x111BE,
|
|
243
|
+
0x111CA..0x111CC,
|
|
244
|
+
0x1122F..0x11231,
|
|
245
|
+
0x11234..0x11234,
|
|
246
|
+
0x11236..0x11237,
|
|
247
|
+
0x1123E..0x1123E,
|
|
248
|
+
0x112DF..0x112DF,
|
|
249
|
+
0x112E3..0x112EA,
|
|
250
|
+
0x11300..0x11301,
|
|
251
|
+
0x1133C..0x1133C,
|
|
252
|
+
0x11340..0x11340,
|
|
253
|
+
0x11366..0x1136C,
|
|
254
|
+
0x11370..0x11374,
|
|
255
|
+
0x11438..0x1143F,
|
|
256
|
+
0x11442..0x11444,
|
|
257
|
+
0x11446..0x11446,
|
|
258
|
+
0x114B3..0x114B8,
|
|
259
|
+
0x114BA..0x114BA,
|
|
260
|
+
0x114BF..0x114C0,
|
|
261
|
+
0x114C2..0x114C3,
|
|
262
|
+
0x115B2..0x115B5,
|
|
263
|
+
0x115BC..0x115BD,
|
|
264
|
+
0x115BF..0x115C0,
|
|
265
|
+
0x115DC..0x115DD,
|
|
266
|
+
0x11633..0x1163A,
|
|
267
|
+
0x1163D..0x1163D,
|
|
268
|
+
0x1163F..0x11640,
|
|
269
|
+
0x116AB..0x116AB,
|
|
270
|
+
0x116AD..0x116AD,
|
|
271
|
+
0x116B0..0x116B5,
|
|
272
|
+
0x116B7..0x116B7,
|
|
273
|
+
0x1171D..0x1171F,
|
|
274
|
+
0x11722..0x11725,
|
|
275
|
+
0x11727..0x1172B,
|
|
276
|
+
0x11C30..0x11C36,
|
|
277
|
+
0x11C38..0x11C3D,
|
|
278
|
+
0x11C3F..0x11C3F,
|
|
279
|
+
0x11C92..0x11CA7,
|
|
280
|
+
0x11CAA..0x11CB0,
|
|
281
|
+
0x11CB2..0x11CB3,
|
|
282
|
+
0x11CB5..0x11CB6,
|
|
283
|
+
0x16AF0..0x16AF4,
|
|
284
|
+
0x16B30..0x16B36,
|
|
285
|
+
0x16F8F..0x16F92,
|
|
286
|
+
0x1BC9D..0x1BC9E,
|
|
287
|
+
0x1D167..0x1D169,
|
|
288
|
+
0x1D173..0x1D182,
|
|
289
|
+
0x1D185..0x1D18B,
|
|
290
|
+
0x1D1AA..0x1D1AD,
|
|
291
|
+
0x1D242..0x1D244,
|
|
292
|
+
0x1DA00..0x1DA36,
|
|
293
|
+
0x1DA3B..0x1DA6C,
|
|
294
|
+
0x1DA75..0x1DA75,
|
|
295
|
+
0x1DA84..0x1DA84,
|
|
296
|
+
0x1DA9B..0x1DA9F,
|
|
297
|
+
0x1DAA1..0x1DAAF,
|
|
298
|
+
0x1E000..0x1E006,
|
|
299
|
+
0x1E008..0x1E018,
|
|
300
|
+
0x1E01B..0x1E021,
|
|
301
|
+
0x1E023..0x1E024,
|
|
302
|
+
0x1E026..0x1E02A,
|
|
303
|
+
0x1E8D0..0x1E8D6,
|
|
304
|
+
0x1E944..0x1E94A,
|
|
305
|
+
0xE0001..0xE0001,
|
|
306
|
+
0xE0020..0xE007F,
|
|
307
|
+
0xE0100..0xE01EF
|
|
308
|
+
].freeze
|
|
309
|
+
|
|
310
|
+
# Wide (double-width) character ranges (CJK, etc.)
|
|
311
|
+
WIDE_RANGES = [
|
|
312
|
+
0x1100..0x115F, # Hangul Jamo
|
|
313
|
+
0x231A..0x231B, # Watch, Hourglass
|
|
314
|
+
0x2329..0x232A, # Angle brackets
|
|
315
|
+
0x23E9..0x23F3, # Media controls
|
|
316
|
+
0x23F8..0x23FA,
|
|
317
|
+
0x25FD..0x25FE, # Squares
|
|
318
|
+
0x2614..0x2615, # Umbrella, Hot beverage
|
|
319
|
+
0x2648..0x2653, # Zodiac
|
|
320
|
+
0x267F..0x267F, # Wheelchair
|
|
321
|
+
0x2693..0x2693, # Anchor
|
|
322
|
+
0x26A1..0x26A1, # Lightning
|
|
323
|
+
0x26AA..0x26AB, # Circles
|
|
324
|
+
0x26BD..0x26BE, # Sports
|
|
325
|
+
0x26C4..0x26C5, # Weather
|
|
326
|
+
0x26CE..0x26CE, # Ophiuchus
|
|
327
|
+
0x26D4..0x26D4, # No entry
|
|
328
|
+
0x26EA..0x26EA, # Church
|
|
329
|
+
0x26F2..0x26F3, # Fountain, Golf
|
|
330
|
+
0x26F5..0x26F5, # Sailboat
|
|
331
|
+
0x26FA..0x26FA, # Tent
|
|
332
|
+
0x26FD..0x26FD, # Fuel pump
|
|
333
|
+
0x2702..0x2702, # Scissors
|
|
334
|
+
0x2705..0x2705, # Check mark
|
|
335
|
+
0x2708..0x270D, # Various
|
|
336
|
+
0x270F..0x270F, # Pencil
|
|
337
|
+
0x2712..0x2712, # Black nib
|
|
338
|
+
0x2714..0x2714, # Check mark
|
|
339
|
+
0x2716..0x2716, # X mark
|
|
340
|
+
0x271D..0x271D, # Cross
|
|
341
|
+
0x2721..0x2721, # Star of David
|
|
342
|
+
0x2728..0x2728, # Sparkles
|
|
343
|
+
0x2733..0x2734, # Asterisks
|
|
344
|
+
0x2744..0x2744, # Snowflake
|
|
345
|
+
0x2747..0x2747, # Sparkle
|
|
346
|
+
0x274C..0x274C, # Cross mark
|
|
347
|
+
0x274E..0x274E,
|
|
348
|
+
0x2753..0x2755, # Question marks
|
|
349
|
+
0x2757..0x2757, # Exclamation
|
|
350
|
+
0x2763..0x2764, # Heart
|
|
351
|
+
0x2795..0x2797, # Math symbols
|
|
352
|
+
0x27A1..0x27A1, # Arrow
|
|
353
|
+
0x27B0..0x27B0, # Loop
|
|
354
|
+
0x27BF..0x27BF, # Loop
|
|
355
|
+
0x2934..0x2935, # Arrows
|
|
356
|
+
0x2B05..0x2B07, # Arrows
|
|
357
|
+
0x2B1B..0x2B1C, # Squares
|
|
358
|
+
0x2B50..0x2B50, # Star
|
|
359
|
+
0x2B55..0x2B55, # Circle
|
|
360
|
+
0x2E80..0x2E99, # CJK radicals
|
|
361
|
+
0x2E9B..0x2EF3,
|
|
362
|
+
0x2F00..0x2FD5, # Kangxi radicals
|
|
363
|
+
0x2FF0..0x2FFB, # Ideographic description
|
|
364
|
+
0x3000..0x303E, # CJK punctuation
|
|
365
|
+
0x3041..0x3096, # Hiragana
|
|
366
|
+
0x3099..0x30FF, # Katakana
|
|
367
|
+
0x3105..0x312D, # Bopomofo
|
|
368
|
+
0x3131..0x318E, # Hangul compatibility
|
|
369
|
+
0x3190..0x31BA, # Kanbun
|
|
370
|
+
0x31C0..0x31E3, # CJK strokes
|
|
371
|
+
0x31F0..0x321E, # Katakana extensions
|
|
372
|
+
0x3220..0x3247, # Enclosed CJK
|
|
373
|
+
0x3250..0x32FE,
|
|
374
|
+
0x3300..0x4DBF, # CJK unified
|
|
375
|
+
0x4E00..0x9FFF, # CJK unified ideographs
|
|
376
|
+
0xA000..0xA48C, # Yi syllables
|
|
377
|
+
0xA490..0xA4C6, # Yi radicals
|
|
378
|
+
0xA960..0xA97C, # Hangul Jamo extended
|
|
379
|
+
0xAC00..0xD7A3, # Hangul syllables
|
|
380
|
+
0xF900..0xFAFF, # CJK compatibility ideographs
|
|
381
|
+
0xFE10..0xFE19, # Vertical forms
|
|
382
|
+
0xFE30..0xFE52, # CJK compatibility forms
|
|
383
|
+
0xFE54..0xFE66,
|
|
384
|
+
0xFE68..0xFE6B,
|
|
385
|
+
0xFF01..0xFF60, # Fullwidth forms
|
|
386
|
+
0xFFE0..0xFFE6,
|
|
387
|
+
0x16FE0..0x16FE1, # Various
|
|
388
|
+
0x17000..0x187EC, # Tangut
|
|
389
|
+
0x18800..0x18AF2,
|
|
390
|
+
0x1B000..0x1B11E, # Kana supplement
|
|
391
|
+
0x1B170..0x1B2FB,
|
|
392
|
+
0x1F004..0x1F004, # Mahjong
|
|
393
|
+
0x1F0CF..0x1F0CF, # Playing card
|
|
394
|
+
0x1F18E..0x1F18E, # Squared AB
|
|
395
|
+
0x1F191..0x1F19A, # Squared
|
|
396
|
+
0x1F200..0x1F202,
|
|
397
|
+
0x1F210..0x1F23B,
|
|
398
|
+
0x1F240..0x1F248,
|
|
399
|
+
0x1F250..0x1F251,
|
|
400
|
+
0x1F260..0x1F265,
|
|
401
|
+
0x1F300..0x1F64F, # Emoji
|
|
402
|
+
0x1F680..0x1F6C5,
|
|
403
|
+
0x1F6CC..0x1F6CC,
|
|
404
|
+
0x1F6D0..0x1F6D2,
|
|
405
|
+
0x1F6EB..0x1F6EC,
|
|
406
|
+
0x1F6F4..0x1F6F8,
|
|
407
|
+
0x1F910..0x1F93E,
|
|
408
|
+
0x1F940..0x1F94C,
|
|
409
|
+
0x1F950..0x1F96B,
|
|
410
|
+
0x1F980..0x1F997,
|
|
411
|
+
0x1F9C0..0x1F9C0,
|
|
412
|
+
0x1F9D0..0x1F9E6,
|
|
413
|
+
0x20000..0x2FFFD, # CJK extension B
|
|
414
|
+
0x30000..0x3FFFD # CJK extension G
|
|
415
|
+
].freeze
|
|
416
|
+
|
|
417
|
+
# Eagerly initialize the shared width cache and its lock so the mutex is a
|
|
418
|
+
# stable singleton before any thread calls in. Lazy `@mutex ||= Mutex.new`
|
|
419
|
+
# inside the method could let two racing callers create distinct locks and
|
|
420
|
+
# leave the cache Hash effectively unguarded.
|
|
421
|
+
@cache = {}
|
|
422
|
+
@cache_mutex = Mutex.new
|
|
423
|
+
@overrides = {}
|
|
424
|
+
|
|
425
|
+
class << self
|
|
426
|
+
# Get the display width of a single character
|
|
427
|
+
# @param char [String] Single character
|
|
428
|
+
# @return [Integer] Width (0, 1, or 2)
|
|
429
|
+
def char_width(char)
|
|
430
|
+
return 0 if char.nil? || char.empty?
|
|
431
|
+
|
|
432
|
+
# Honor explicit per-character overrides registered via set_cell_size.
|
|
433
|
+
if defined?(@overrides) && @overrides && (override = @overrides[char])
|
|
434
|
+
return override
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
codepoint = char.ord
|
|
438
|
+
|
|
439
|
+
# Tab, newline, and carriage return should have width 1 for measurement
|
|
440
|
+
# (even though they may have different visual behavior)
|
|
441
|
+
return 1 if codepoint == 0x09 || codepoint == 0x0A || codepoint == 0x0D
|
|
442
|
+
|
|
443
|
+
# Fast path: printable ASCII is always width 1. This is the overwhelming
|
|
444
|
+
# common case and avoids scanning the ~340 zero-width/wide ranges below.
|
|
445
|
+
return 1 if codepoint >= 0x20 && codepoint <= 0x7E
|
|
446
|
+
|
|
447
|
+
# Check zero-width first (most common for combining marks)
|
|
448
|
+
ZERO_WIDTH_RANGES.each do |range|
|
|
449
|
+
return 0 if range.cover?(codepoint)
|
|
450
|
+
end
|
|
451
|
+
|
|
452
|
+
# Check wide characters
|
|
453
|
+
WIDE_RANGES.each do |range|
|
|
454
|
+
return 2 if range.cover?(codepoint)
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
# Default to single width
|
|
458
|
+
1
|
|
459
|
+
end
|
|
460
|
+
|
|
461
|
+
# Get the display width of a string
|
|
462
|
+
# @param text [String] Text to measure
|
|
463
|
+
# @return [Integer] Total display width in cells
|
|
464
|
+
def cell_len(text)
|
|
465
|
+
return 0 if text.nil? || text.empty?
|
|
466
|
+
|
|
467
|
+
# Display width is the sum of per-character cell widths. This is correct
|
|
468
|
+
# on every platform: legacy Windows consoles still render a CJK glyph as
|
|
469
|
+
# 2 cells and ASCII as 1 — UTF-8 byte count is NOT a display width.
|
|
470
|
+
text.each_char.sum { |c| char_width(c) }
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# Get the display width of a string, with cache
|
|
474
|
+
# @param text [String] Text to measure
|
|
475
|
+
# @return [Integer] Total display width
|
|
476
|
+
def cached_cell_len(text)
|
|
477
|
+
return 0 if text.nil? || text.empty?
|
|
478
|
+
|
|
479
|
+
# Lock-free read of the common cache-hit path (Hash reads are safe under
|
|
480
|
+
# MRI's GVL); only take the lock to populate. A 0 width is truthy in
|
|
481
|
+
# Ruby, so a cached zero-width string still short-circuits correctly.
|
|
482
|
+
hit = @cache[text]
|
|
483
|
+
return hit if hit
|
|
484
|
+
|
|
485
|
+
result = cell_len(text)
|
|
486
|
+
@cache_mutex.synchronize do
|
|
487
|
+
# Bulk-clear once over the cap rather than shifting one entry per
|
|
488
|
+
# insert while permanently parked at the boundary.
|
|
489
|
+
@cache.clear if @cache.size > 10_000
|
|
490
|
+
@cache[text] = result
|
|
491
|
+
end
|
|
492
|
+
result
|
|
493
|
+
end
|
|
494
|
+
|
|
495
|
+
# Set the cell size for a specific character (override)
|
|
496
|
+
# @param char [String] Character to override
|
|
497
|
+
# @param size [Integer] Width to use
|
|
498
|
+
def set_cell_size(char, size)
|
|
499
|
+
@overrides[char] = size
|
|
500
|
+
# Existing cached widths may include this character; invalidate them.
|
|
501
|
+
clear_cache
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Clear the cell width cache
|
|
505
|
+
def clear_cache
|
|
506
|
+
@cache_mutex.synchronize { @cache.clear }
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
# Check if a character is a zero-width character
|
|
510
|
+
# @param char [String] Character to check
|
|
511
|
+
# @return [Boolean]
|
|
512
|
+
def zero_width?(char)
|
|
513
|
+
char_width(char) == 0
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
# Check if a character is a wide (double-width) character
|
|
517
|
+
# @param char [String] Character to check
|
|
518
|
+
# @return [Boolean]
|
|
519
|
+
def wide?(char)
|
|
520
|
+
char_width(char) == 2
|
|
521
|
+
end
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
end
|