rubyterm 0.2.2 → 0.2.5
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/bin/record +3 -0
- data/lib/bitmapwindow.rb +9 -5
- data/lib/charwidth.rb +55 -9
- data/lib/rubyterm/version.rb +1 -1
- data/lib/term.rb +26 -6
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: dad934f37ee68f63661c2d7bbd2e8c7af64a8811fb8fd27b9d5bd63787a8f021
|
|
4
|
+
data.tar.gz: 124c7b36ea94bef960b7bbc78f9143149cce43cf443b4e7d9ed99207e40d1f01
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ea7bf3f07aa5088ca07bc79058aa836d20af2c95d5d6887d7fe5e7fd8f44283170c4fa2df7078d5f10a271582b5d339143473e8fc3d1af51d74c42f562e3e0a5
|
|
7
|
+
data.tar.gz: 491468d6aab9c96754001425718102aaa1c677c994ca1f82c47a3fa07196327bb3ed132ef72c547d77904216f6ed9f700373fdd3c6b08cae3769904f36f562a9
|
data/bin/record
ADDED
data/lib/bitmapwindow.rb
CHANGED
|
@@ -83,10 +83,14 @@ class BitmapWindow
|
|
|
83
83
|
# for now - it does not affect correctness of the text, only its scale.
|
|
84
84
|
def draw(x, y, str, fg, bg, _lineattrs = nil)
|
|
85
85
|
fillrect(x, y, str.length * @char_w, @char_h, bg)
|
|
86
|
-
str.each_char.
|
|
87
|
-
|
|
86
|
+
cps = str.each_char.map(&:ord)
|
|
87
|
+
cps.each_with_index do |cp, i|
|
|
88
88
|
next if cp == 32 || cp == CharWidth::WIDE_SPACER # space / wide-glyph tail
|
|
89
|
-
|
|
89
|
+
# A WIDE_SPACER in the next cell means this is a double-width glyph; render
|
|
90
|
+
# it two cells wide so it overflows into the (skipped) spacer cell instead
|
|
91
|
+
# of being shrunk into one.
|
|
92
|
+
cells = cps[i + 1] == CharWidth::WIDE_SPACER ? 2 : 1
|
|
93
|
+
blit_glyph(cp, x + i * @char_w, y, fg, cells)
|
|
90
94
|
end
|
|
91
95
|
end
|
|
92
96
|
|
|
@@ -146,8 +150,8 @@ class BitmapWindow
|
|
|
146
150
|
end
|
|
147
151
|
end
|
|
148
152
|
|
|
149
|
-
def blit_glyph(codepoint, cx, cy, fg)
|
|
150
|
-
g = @cache.glyph(codepoint)
|
|
153
|
+
def blit_glyph(codepoint, cx, cy, fg, cells = 1)
|
|
154
|
+
g = @cache.glyph(codepoint, cells)
|
|
151
155
|
return unless g
|
|
152
156
|
if g.color?
|
|
153
157
|
blit_rgba(g, codepoint, cx, cy)
|
data/lib/charwidth.rb
CHANGED
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
# * width(cp) -> 1 or 2 cells (wide = CJK/Hangul/Kana/fullwidth + emoji)
|
|
12
12
|
# * emoji?(cp) -> whether to render in colour (the non-CJK wide blocks)
|
|
13
13
|
#
|
|
14
|
-
# Combining marks (width 0) are deliberately not handled yet (treated as 1).
|
|
15
14
|
module CharWidth
|
|
16
15
|
# Codepoint stored in the second cell of a double-width glyph: a blank,
|
|
17
16
|
# advancing placeholder. The terminal writes it after a wide char so the
|
|
@@ -19,19 +18,62 @@ module CharWidth
|
|
|
19
18
|
# advancing glyph and the bitmap/virtual backends skip it.
|
|
20
19
|
WIDE_SPACER = 0
|
|
21
20
|
|
|
21
|
+
# Zero-width (combining) codepoints. These modify the preceding base glyph
|
|
22
|
+
# rather than advancing the cursor, so they occupy no column — matching tmux
|
|
23
|
+
# (a lone U+FE0F reports cursor_x=0; a base+U+FE0F sequence stays the base's
|
|
24
|
+
# width). Notably this includes the variation selectors: U+FE0F (VS16, emoji
|
|
25
|
+
# presentation) and U+FE0E (VS15, text presentation) request a presentation
|
|
26
|
+
# for the preceding char but are themselves invisible and zero-width. Treating
|
|
27
|
+
# them as width 1 gave each its own cell, drawing a stray glyph over the next
|
|
28
|
+
# column. Per-script combining marks beyond these blocks are a deferred
|
|
29
|
+
# non-goal (still treated as width 1).
|
|
30
|
+
ZERO = [
|
|
31
|
+
0x0300..0x036F, # combining diacritical marks
|
|
32
|
+
0x1AB0..0x1AFF, # combining diacritical marks extended
|
|
33
|
+
0x1DC0..0x1DFF, # combining diacritical marks supplement
|
|
34
|
+
0x200B..0x200F, # ZWSP, ZWNJ, ZWJ, LRM, RLM (zero-width format)
|
|
35
|
+
0x20D0..0x20FF, # combining diacritical marks for symbols
|
|
36
|
+
0xFE00..0xFE0F, # variation selectors (incl. VS15/VS16)
|
|
37
|
+
0xFE20..0xFE2F, # combining half marks
|
|
38
|
+
0xE0100..0xE01EF # variation selectors supplement
|
|
39
|
+
].freeze
|
|
40
|
+
|
|
22
41
|
# Wide (two-cell) blocks: CJK, Hangul, Kana, fullwidth forms, and emoji.
|
|
42
|
+
#
|
|
43
|
+
# In the BMP symbol zone (Misc Symbols, Dingbats, Misc Symbols & Arrows)
|
|
44
|
+
# only the East Asian Wide + emoji-presentation codepoints are double-width;
|
|
45
|
+
# the surrounding text dingbats are single-width. A broad 0x25FD..0x27BF (and
|
|
46
|
+
# peers) wrongly widened text characters like U+273B (the spinner ✻ used by
|
|
47
|
+
# TUIs), shifting the cursor one column on every line that contained one and
|
|
48
|
+
# corrupting incremental redraws. These ranges now match tmux exactly.
|
|
23
49
|
WIDE = [
|
|
24
|
-
0x1100..0x115F,
|
|
25
|
-
|
|
50
|
+
0x1100..0x115F,
|
|
51
|
+
0x231A..0x231B, 0x2329..0x232A, 0x23E9..0x23EC, 0x23F0..0x23F0,
|
|
52
|
+
0x23F3..0x23F3, 0x25FD..0x25FE, 0x2614..0x2615, 0x2648..0x2653,
|
|
53
|
+
0x267F..0x267F, 0x2693..0x2693, 0x26A1..0x26A1, 0x26AA..0x26AB,
|
|
54
|
+
0x26BD..0x26BE, 0x26C4..0x26C5, 0x26CE..0x26CE, 0x26D4..0x26D4,
|
|
55
|
+
0x26EA..0x26EA, 0x26F2..0x26F3, 0x26F5..0x26F5, 0x26FA..0x26FA,
|
|
56
|
+
0x26FD..0x26FD, 0x2705..0x2705, 0x270A..0x270B, 0x2728..0x2728,
|
|
57
|
+
0x274C..0x274C, 0x274E..0x274E, 0x2753..0x2755, 0x2757..0x2757,
|
|
58
|
+
0x2795..0x2797, 0x27B0..0x27B0, 0x27BF..0x27BF, 0x2B1B..0x2B1C,
|
|
59
|
+
0x2B50..0x2B50, 0x2B55..0x2B55,
|
|
60
|
+
0x2E80..0xA4C6, 0xA960..0xA97C, 0xAC00..0xD7A3,
|
|
26
61
|
0xF900..0xFAD9, 0xFE10..0xFE6B, 0xFF01..0xFF60, 0xFFE0..0xFFE6,
|
|
27
62
|
0x16FE0..0x18D08, 0x1B000..0x1B2FB, 0x1F18E..0x1F19A, 0x1F200..0x1F265,
|
|
28
63
|
0x1F300..0x1F5A4, 0x1F5FB..0x1F6FC, 0x1F7E0..0x1F7EB, 0x1F90C..0x1F9FF,
|
|
29
64
|
0x1FA70..0x1FAD6, 0x20000..0x2EBE0, 0x2F800..0x2FA1D, 0x30000..0x3134A
|
|
30
65
|
].freeze
|
|
31
66
|
|
|
32
|
-
#
|
|
33
|
-
# in colour
|
|
34
|
-
#
|
|
67
|
+
# Emoji code blocks (excludes CJK/Hangul/Kana/fullwidth): a codepoint renders
|
|
68
|
+
# in colour only if it is BOTH in one of these blocks AND wide (width 2) —
|
|
69
|
+
# see emoji?. The width-2 gate is what distinguishes emoji-presentation
|
|
70
|
+
# codepoints (⚡ U+26A1, ✨ U+2728 — colour, width 2) from text-presentation
|
|
71
|
+
# dingbats that merely share a block (❤ U+2764, ✔ U+2714, ⚠ U+26A0 — width 1).
|
|
72
|
+
# Both properties derive from the same Unicode Emoji_Presentation flag, so
|
|
73
|
+
# this is not "width deciding colour": rather, colour is the subset of these
|
|
74
|
+
# blocks that is wide enough to render a square colour glyph without spilling
|
|
75
|
+
# into the next cell. Digits, '#', '*' are absent, so they stay ordinary text
|
|
76
|
+
# even though Noto maps colour keycaps.
|
|
35
77
|
EMOJI = [
|
|
36
78
|
0x231A..0x232A, 0x23E9..0x23F3, 0x25FD..0x27BF, 0x2B1B..0x2B55,
|
|
37
79
|
0x1F18E..0x1F19A, 0x1F200..0x1F265, 0x1F300..0x1F5A4, 0x1F5FB..0x1F6FC,
|
|
@@ -40,18 +82,22 @@ module CharWidth
|
|
|
40
82
|
|
|
41
83
|
module_function
|
|
42
84
|
|
|
43
|
-
# Number of terminal cells a codepoint occupies (1 or 2).
|
|
85
|
+
# Number of terminal cells a codepoint occupies (0, 1 or 2).
|
|
44
86
|
def width(cp)
|
|
45
|
-
return 1 if cp <
|
|
87
|
+
return 1 if cp < 0x0300 # fast path: ASCII/Latin-1 (no combining below)
|
|
88
|
+
return 0 if in_ranges?(ZERO, cp)
|
|
89
|
+
return 1 if cp < 0x1100 # fast path: most other text
|
|
46
90
|
in_ranges?(WIDE, cp) ? 2 : 1
|
|
47
91
|
end
|
|
48
92
|
|
|
49
93
|
def wide?(cp) = width(cp) == 2
|
|
50
94
|
|
|
51
95
|
# Whether a codepoint should render as a colour emoji (when the font has it).
|
|
96
|
+
# Gated to width-2 emoji: a colour glyph is rasterised square (~2 cells wide),
|
|
97
|
+
# so colouring a width-1 cell would overflow and corrupt the next column.
|
|
52
98
|
def emoji?(cp)
|
|
53
99
|
return false if cp < 0x231A
|
|
54
|
-
in_ranges?(EMOJI, cp)
|
|
100
|
+
in_ranges?(EMOJI, cp) && width(cp) == 2
|
|
55
101
|
end
|
|
56
102
|
|
|
57
103
|
# Binary search over a sorted array of non-overlapping ranges.
|
data/lib/rubyterm/version.rb
CHANGED
data/lib/term.rb
CHANGED
|
@@ -115,6 +115,15 @@ class Term
|
|
|
115
115
|
@buffer.clear # the buffer (TrackChanges) also clears the backend
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
# Cursor + charset save/restore, shared by DECSC/DECRC (ESC 7 / ESC 8) and
|
|
119
|
+
# DEC private modes 1048/1049. DECRC with no prior save defaults to the home
|
|
120
|
+
# position and default charsets rather than leaving @x/@y nil (which would
|
|
121
|
+
# crash draw_cursor).
|
|
122
|
+
def save_cursor = @saved = [@x, @y, @gl, @gr, @g.dup]
|
|
123
|
+
def restore_cursor
|
|
124
|
+
@x, @y, @gl, @gr, @g = @saved || [0, 0, 0, nil, [DefaultCharset, nil, nil, nil]]
|
|
125
|
+
end
|
|
126
|
+
|
|
118
127
|
# RIS - Reset to Initial State (ESC c). Full reset: restore margins,
|
|
119
128
|
# modes, charsets, tab stops and attributes to their defaults, home the
|
|
120
129
|
# cursor and clear the screen.
|
|
@@ -408,6 +417,16 @@ class Term
|
|
|
408
417
|
# FIXME: Save/restore
|
|
409
418
|
# FIXME: Scrollback should be disabled/enabled.
|
|
410
419
|
clear_screen
|
|
420
|
+
when 1048
|
|
421
|
+
# Save (h) / restore (l) cursor, as DECSC / DECRC.
|
|
422
|
+
set ? save_cursor : restore_cursor
|
|
423
|
+
when 1049
|
|
424
|
+
# Alternate screen + cursor save/restore. Like mode 47 this
|
|
425
|
+
# terminal has no separate alt buffer yet, so it just clears; the
|
|
426
|
+
# cursor save (on enter) / restore (on leave) is what apps rely on
|
|
427
|
+
# to land the cursor back where it was before the alt screen.
|
|
428
|
+
set ? save_cursor : restore_cursor
|
|
429
|
+
clear_screen
|
|
411
430
|
|
|
412
431
|
# Extended mouse modes
|
|
413
432
|
# See https://terminalguide.namepad.de/mouse/
|
|
@@ -546,6 +565,11 @@ class Term
|
|
|
546
565
|
return if ch == 127 # DEL is ignored in the data stream
|
|
547
566
|
|
|
548
567
|
cw = CharWidth.width(ch)
|
|
568
|
+
# Zero-width codepoints (variation selectors like U+FE0F, combining marks,
|
|
569
|
+
# zero-width joiners) modify the preceding glyph. This buffer stores one
|
|
570
|
+
# codepoint per cell and can't compose, so drop them rather than letting
|
|
571
|
+
# them claim a cell of their own — which would paint over the next column.
|
|
572
|
+
return if cw == 0
|
|
549
573
|
# A double-width glyph can't straddle the right margin: if only one
|
|
550
574
|
# column is left, blank it and wrap so the glyph starts the next line.
|
|
551
575
|
if cw == 2 && @wraparound && @x == line_width - 1
|
|
@@ -596,12 +620,8 @@ class Term
|
|
|
596
620
|
when ")B"; @g[1] = DefaultCharset
|
|
597
621
|
when "(0"; @g[0] = GraphicsCharset
|
|
598
622
|
when ")0"; @g[1] = GraphicsCharset
|
|
599
|
-
when "7";
|
|
600
|
-
when "8"
|
|
601
|
-
# DECRC with no prior DECSC: default to home position and default
|
|
602
|
-
# charsets rather than leaving @x/@y nil (which crashes draw_cursor).
|
|
603
|
-
sx, sy, sgl, sgr, sg = @saved || [0, 0, 0, nil, [DefaultCharset, nil, nil, nil]]
|
|
604
|
-
@x, @y, @gl, @gr, @g = sx, sy, sgl, sgr, sg
|
|
623
|
+
when "7"; save_cursor # DECSC
|
|
624
|
+
when "8"; restore_cursor # DECRC
|
|
605
625
|
else
|
|
606
626
|
unhandled(:escape, s)
|
|
607
627
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubyterm
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vidar Hokstad
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-06-
|
|
11
|
+
date: 2026-06-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: pure-x11
|
|
@@ -95,6 +95,7 @@ extensions: []
|
|
|
95
95
|
extra_rdoc_files: []
|
|
96
96
|
files:
|
|
97
97
|
- README.md
|
|
98
|
+
- bin/record
|
|
98
99
|
- bin/rubyterm
|
|
99
100
|
- example-config.toml
|
|
100
101
|
- lib/ansibackend.rb
|