rubytui 1.2.3 → 1.2.4
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/README.md +17 -15
- data/lib/rubytui/app.rb +8 -6
- data/lib/rubytui/backends/ansi_backend.rb +32 -27
- data/lib/rubytui/buffer.rb +1 -7
- data/lib/rubytui/errors.rb +2 -0
- data/lib/rubytui/event.rb +14 -4
- data/lib/rubytui/input/parser.rb +224 -14
- data/lib/rubytui/input/reader.rb +156 -65
- data/lib/rubytui/layout/flex.rb +1 -1
- data/lib/rubytui/layout/layout.rb +25 -10
- data/lib/rubytui/text/line.rb +8 -4
- data/lib/rubytui/text/span.rb +3 -2
- data/lib/rubytui/text/text.rb +10 -5
- data/lib/rubytui/unicode.rb +1 -1
- data/lib/rubytui/version.rb +1 -1
- data/lib/rubytui/widgets/async_image.rb +42 -30
- data/lib/rubytui/widgets/block.rb +5 -5
- data/lib/rubytui/widgets/canvas.rb +26 -14
- data/lib/rubytui/widgets/chart.rb +48 -35
- data/lib/rubytui/widgets/gauge.rb +2 -2
- data/lib/rubytui/widgets/image.rb +8 -4
- data/lib/rubytui/widgets/input_field.rb +59 -17
- data/lib/rubytui/widgets/list.rb +28 -19
- data/lib/rubytui/widgets/paragraph.rb +53 -24
- data/lib/rubytui/widgets/scrollbar.rb +8 -5
- data/lib/rubytui/widgets/table.rb +26 -17
- data/lib/rubytui/widgets/tabs.rb +7 -5
- data/lib/rubytui.rb +14 -9
- metadata +3 -3
|
@@ -10,24 +10,30 @@ module RubyTUI
|
|
|
10
10
|
class Paragraph
|
|
11
11
|
include Widget
|
|
12
12
|
|
|
13
|
-
# Wrap at whitespace; a single word wider than the area is not broken
|
|
13
|
+
# Wrap at whitespace; a single word wider than the area is not broken
|
|
14
|
+
# and is clipped at the area's right edge.
|
|
14
15
|
WRAP_WORD = :word
|
|
15
|
-
# Wrap
|
|
16
|
+
# Wrap between any two grapheme clusters (see {Unicode.cluster_width}), so a
|
|
17
|
+
# Devanagari conjunct or an emoji ZWJ sequence is never split and a
|
|
18
|
+
# two-column cluster moves to the next line rather than straddle the edge.
|
|
16
19
|
WRAP_CHAR = :char
|
|
17
20
|
# Do not wrap.
|
|
18
21
|
WRAP_NONE = :none
|
|
19
22
|
|
|
20
23
|
attr_reader :text, :style, :alignment, :wrap
|
|
21
24
|
|
|
22
|
-
# @param text [String, Line, Text, nil, #to_s] content; a String is split
|
|
23
|
-
# lines on newlines,
|
|
24
|
-
# +
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
# (
|
|
25
|
+
# @param text [String, Line, Text, Span, nil, #to_s] content; a String is split
|
|
26
|
+
# into lines on newlines, a Span is split the same way into one-span Lines
|
|
27
|
+
# that keep its {Span#style}, +nil+ means no text, other objects are
|
|
28
|
+
# converted with +to_s+ (default: nil)
|
|
29
|
+
# @param style [Style] base style of the text. Each span is drawn with this
|
|
30
|
+
# style patched ({Style#patch}) with {Text#style}, then {Line#style}, then
|
|
31
|
+
# {Span#style}, so later layers win. When it is not {Style::DEFAULT} it is
|
|
32
|
+
# also patched onto every cell of the area (default: {Style::DEFAULT})
|
|
28
33
|
# @param alignment [Symbol] +:left+ (default), +:center+ or +:right+
|
|
29
34
|
# @param wrap [Symbol] {WRAP_WORD} (default), {WRAP_CHAR} or {WRAP_NONE}. Wrapped
|
|
30
|
-
# lines take the style of the original line's first span
|
|
35
|
+
# lines take the style of the original line's first span and keep the
|
|
36
|
+
# original line's {Line#style}
|
|
31
37
|
# @param block [Widgets::Block, nil] optional wrapping block
|
|
32
38
|
def initialize(
|
|
33
39
|
text: nil,
|
|
@@ -46,8 +52,9 @@ module RubyTUI
|
|
|
46
52
|
# Render the wrapped lines from the top of the area; lines beyond its height
|
|
47
53
|
# are not drawn.
|
|
48
54
|
#
|
|
49
|
-
# Lines
|
|
50
|
-
#
|
|
55
|
+
# Lines wider than the area (with {WRAP_NONE}, or a long word with
|
|
56
|
+
# {WRAP_WORD}) are clipped at its right edge: nothing is drawn at or beyond
|
|
57
|
+
# it, and a two-column character that would straddle it is not drawn.
|
|
51
58
|
#
|
|
52
59
|
# @param area [Rect] the rectangular area to render into
|
|
53
60
|
# @param buf [Buffer] the buffer to write cells into
|
|
@@ -76,6 +83,22 @@ module RubyTUI
|
|
|
76
83
|
end
|
|
77
84
|
end
|
|
78
85
|
|
|
86
|
+
# Number of lines {#render} draws, before clipping to the area's height, when
|
|
87
|
+
# the text is wrapped with {#wrap} to +width+ columns.
|
|
88
|
+
#
|
|
89
|
+
# @param width [Integer] width of the area the text is drawn in: the area
|
|
90
|
+
# inside +block+ when the paragraph has one. A width of 0 or less does not
|
|
91
|
+
# wrap
|
|
92
|
+
# @return [Integer] wrapped line count (0 when there is no text); empty lines
|
|
93
|
+
# count as one line each
|
|
94
|
+
#
|
|
95
|
+
# @example Height needed to show all of the text
|
|
96
|
+
# para = RubyTUI::Widgets::Paragraph.new(text: "alpha beta gamma delta")
|
|
97
|
+
# para.line_count(10) # => 3
|
|
98
|
+
def line_count(width)
|
|
99
|
+
wrap_lines(width).length
|
|
100
|
+
end
|
|
101
|
+
|
|
79
102
|
private
|
|
80
103
|
|
|
81
104
|
def normalize_text(text)
|
|
@@ -83,6 +106,7 @@ module RubyTUI
|
|
|
83
106
|
when Text then text
|
|
84
107
|
when String then Text.from(text)
|
|
85
108
|
when Line then Text.new([text])
|
|
109
|
+
when Span then Text.new(text.content.split("\n").map { |l| Line.from(l, text.style) })
|
|
86
110
|
when nil then Text.new([])
|
|
87
111
|
else Text.from(text.to_s)
|
|
88
112
|
end
|
|
@@ -117,7 +141,7 @@ module RubyTUI
|
|
|
117
141
|
current_width = 0
|
|
118
142
|
|
|
119
143
|
words.each do |word|
|
|
120
|
-
word_width =
|
|
144
|
+
word_width = Unicode.string_width(word)
|
|
121
145
|
if current.empty?
|
|
122
146
|
current << word
|
|
123
147
|
current_width = word_width
|
|
@@ -125,13 +149,13 @@ module RubyTUI
|
|
|
125
149
|
current << word
|
|
126
150
|
current_width += word_width
|
|
127
151
|
else
|
|
128
|
-
wrapped << Line.
|
|
152
|
+
wrapped << Line.new([Span.new(current.rstrip, line_style)], line.style) unless current.strip.empty?
|
|
129
153
|
current = word.lstrip
|
|
130
|
-
current_width =
|
|
154
|
+
current_width = Unicode.string_width(current)
|
|
131
155
|
end
|
|
132
156
|
end
|
|
133
157
|
|
|
134
|
-
wrapped << Line.
|
|
158
|
+
wrapped << Line.new([Span.new(current.rstrip, line_style)], line.style) unless current.strip.empty?
|
|
135
159
|
wrapped << Line.new if wrapped.empty?
|
|
136
160
|
wrapped
|
|
137
161
|
end
|
|
@@ -144,17 +168,18 @@ module RubyTUI
|
|
|
144
168
|
current = String.new
|
|
145
169
|
current_width = 0
|
|
146
170
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
171
|
+
# Break only between grapheme clusters, so conjuncts and ZWJ sequences stay whole
|
|
172
|
+
plain.grapheme_clusters.each do |gc|
|
|
173
|
+
gc_width = Unicode.cluster_width(gc)
|
|
174
|
+
if current_width + gc_width > max_width
|
|
175
|
+
wrapped << Line.new([Span.new(current, line_style)], line.style) unless current.empty?
|
|
151
176
|
current = String.new
|
|
152
177
|
current_width = 0
|
|
153
178
|
end
|
|
154
|
-
current <<
|
|
155
|
-
current_width +=
|
|
179
|
+
current << gc
|
|
180
|
+
current_width += gc_width
|
|
156
181
|
end
|
|
157
|
-
wrapped << Line.
|
|
182
|
+
wrapped << Line.new([Span.new(current, line_style)], line.style) unless current.empty?
|
|
158
183
|
wrapped << Line.new if wrapped.empty?
|
|
159
184
|
wrapped
|
|
160
185
|
end
|
|
@@ -169,11 +194,15 @@ module RubyTUI
|
|
|
169
194
|
|
|
170
195
|
x = area.x + x_offset
|
|
171
196
|
y = area.y + row
|
|
197
|
+
line_style = @style.patch(@text.style).patch(line.style)
|
|
172
198
|
|
|
173
199
|
line.spans.each do |span|
|
|
174
|
-
|
|
175
|
-
|
|
200
|
+
# Clip at the area's right edge; a wide cluster that would straddle it is dropped
|
|
201
|
+
content = Unicode.truncate_to_width(span.content, area.right - x)
|
|
202
|
+
effective_style = line_style.patch(span.style)
|
|
203
|
+
count = buf.set_string(x, y, content, effective_style)
|
|
176
204
|
x += count
|
|
205
|
+
break if content.length < span.content.length
|
|
177
206
|
end
|
|
178
207
|
end
|
|
179
208
|
end
|
|
@@ -41,9 +41,12 @@ module RubyTUI
|
|
|
41
41
|
# (default: nil, the track length in cells, arrows included)
|
|
42
42
|
# @param orientation [Symbol] {VERTICAL} (default) or {HORIZONTAL}; any other
|
|
43
43
|
# value is drawn horizontally
|
|
44
|
-
# @param style [Style]
|
|
45
|
-
#
|
|
46
|
-
# @param
|
|
44
|
+
# @param style [Style] base style; +thumb_style+ and +track_style+ are patched
|
|
45
|
+
# onto it with {Style#patch} (default: {Style::DEFAULT})
|
|
46
|
+
# @param thumb_style [Style, nil] thumb style, patched onto +style+ (default: nil,
|
|
47
|
+
# white foreground unless +style+ sets one)
|
|
48
|
+
# @param track_style [Style, nil] track and arrow style, patched onto +style+
|
|
49
|
+
# (default: nil, bright black foreground unless +style+ sets one)
|
|
47
50
|
# @param show_arrows [Boolean] draw an arrow at each end (default: true)
|
|
48
51
|
def initialize(
|
|
49
52
|
content_length:,
|
|
@@ -60,8 +63,8 @@ module RubyTUI
|
|
|
60
63
|
@viewport_length = viewport_length
|
|
61
64
|
@orientation = orientation
|
|
62
65
|
@style = style
|
|
63
|
-
@thumb_style = thumb_style
|
|
64
|
-
@track_style = track_style
|
|
66
|
+
@thumb_style = thumb_style ? style.patch(thumb_style) : Style.new.fg(Color::WHITE).patch(style)
|
|
67
|
+
@track_style = track_style ? style.patch(track_style) : Style.new.fg(Color::BRIGHT_BLACK).patch(style)
|
|
65
68
|
@show_arrows = show_arrows
|
|
66
69
|
end
|
|
67
70
|
|
|
@@ -4,38 +4,42 @@ module RubyTUI
|
|
|
4
4
|
module Widgets
|
|
5
5
|
# TableState holds external state for the Table widget.
|
|
6
6
|
#
|
|
7
|
-
# +selected+ is the index of the selected row
|
|
8
|
-
# first visible row. {Table#render} clamps both in
|
|
7
|
+
# +selected+ is the index of the selected row, or +nil+ for no selection, and
|
|
8
|
+
# +offset+ the index of the first visible row. {Table#render} clamps both in
|
|
9
|
+
# place; a +nil+ +selected+ is left as +nil+.
|
|
9
10
|
#
|
|
10
11
|
# @see Table
|
|
11
12
|
class TableState
|
|
12
13
|
attr_accessor :selected, :offset
|
|
13
14
|
|
|
14
|
-
# @param selected [Integer] initial selected row index
|
|
15
|
+
# @param selected [Integer, nil] initial selected row index; +nil+ selects no
|
|
16
|
+
# row (default: 0)
|
|
15
17
|
# @param offset [Integer] initial scroll offset (default: 0)
|
|
16
18
|
def initialize(selected: 0, offset: 0)
|
|
17
19
|
@selected = selected
|
|
18
20
|
@offset = offset
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
# Select the next row, wrapping from the last row to the first.
|
|
23
|
+
# Select the next row, wrapping from the last row to the first. With no
|
|
24
|
+
# selection (+nil+), selects the first row.
|
|
22
25
|
#
|
|
23
26
|
# Does nothing when +total+ is 0 or negative.
|
|
24
27
|
#
|
|
25
28
|
# @param total [Integer] number of rows in the table
|
|
26
29
|
# @return [void]
|
|
27
30
|
def select_next(total)
|
|
28
|
-
@selected = (@selected + 1) % total if total > 0
|
|
31
|
+
@selected = ((@selected || -1) + 1) % total if total > 0
|
|
29
32
|
end
|
|
30
33
|
|
|
31
|
-
# Select the previous row, wrapping from the first row to the last.
|
|
34
|
+
# Select the previous row, wrapping from the first row to the last. With no
|
|
35
|
+
# selection (+nil+), selects the last row.
|
|
32
36
|
#
|
|
33
37
|
# Does nothing when +total+ is 0 or negative.
|
|
34
38
|
#
|
|
35
39
|
# @param total [Integer] number of rows in the table
|
|
36
40
|
# @return [void]
|
|
37
41
|
def select_previous(total)
|
|
38
|
-
@selected = (@selected - 1) % total if total > 0
|
|
42
|
+
@selected = ((@selected || 0) - 1) % total if total > 0
|
|
39
43
|
end
|
|
40
44
|
end
|
|
41
45
|
|
|
@@ -85,7 +89,7 @@ module RubyTUI
|
|
|
85
89
|
@header_style = header_style || Style.new.fg(Color::CYAN).bold
|
|
86
90
|
@highlight_style = highlight_style || Style.new.fg(Color::YELLOW).bold
|
|
87
91
|
@highlight_symbol = highlight_symbol
|
|
88
|
-
@highlight_symbol_width =
|
|
92
|
+
@highlight_symbol_width = Unicode.string_width(@highlight_symbol)
|
|
89
93
|
@normal_symbol = " " * @highlight_symbol_width
|
|
90
94
|
@column_spacing = column_spacing
|
|
91
95
|
@block = block
|
|
@@ -94,8 +98,11 @@ module RubyTUI
|
|
|
94
98
|
# Render the header, separator and visible rows.
|
|
95
99
|
#
|
|
96
100
|
# Clamps <tt>state.selected</tt> to the row range and adjusts
|
|
97
|
-
# <tt>state.offset</tt> in place so the selected row is visible.
|
|
98
|
-
#
|
|
101
|
+
# <tt>state.offset</tt> in place so the selected row is visible. When
|
|
102
|
+
# <tt>state.selected</tt> is +nil+, no row is highlighted or prefixed with
|
|
103
|
+
# +highlight_symbol+, +selected+ stays +nil+ and +offset+ is only clamped to the
|
|
104
|
+
# row range. Cell text is truncated to its column width; explicit +widths+ are
|
|
105
|
+
# not reduced to fit the area.
|
|
99
106
|
#
|
|
100
107
|
# @param area [Rect] the rectangular area to render into
|
|
101
108
|
# @param buf [Buffer] the buffer to write cells into
|
|
@@ -140,11 +147,13 @@ module RubyTUI
|
|
|
140
147
|
|
|
141
148
|
# Clamp state
|
|
142
149
|
total = @rows.length
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
state.
|
|
146
|
-
|
|
147
|
-
state.
|
|
150
|
+
if state.selected
|
|
151
|
+
state.selected = state.selected.clamp(0, [total - 1, 0].max)
|
|
152
|
+
if state.selected < state.offset
|
|
153
|
+
state.offset = state.selected
|
|
154
|
+
elsif state.selected >= state.offset + visible_height
|
|
155
|
+
state.offset = state.selected - visible_height + 1
|
|
156
|
+
end
|
|
148
157
|
end
|
|
149
158
|
state.offset = state.offset.clamp(0, [total - visible_height, 0].max)
|
|
150
159
|
|
|
@@ -209,8 +218,8 @@ module RubyTUI
|
|
|
209
218
|
break if i >= col_widths.length
|
|
210
219
|
|
|
211
220
|
w = col_widths[i]
|
|
212
|
-
text =
|
|
213
|
-
text_width =
|
|
221
|
+
text = Unicode.truncate_to_width(cell.content, w)
|
|
222
|
+
text_width = Unicode.string_width(text)
|
|
214
223
|
effective_style = row_style.patch(cell.style)
|
|
215
224
|
buf.set_string(x, y, text, effective_style)
|
|
216
225
|
|
data/lib/rubytui/widgets/tabs.rb
CHANGED
|
@@ -18,7 +18,8 @@ module RubyTUI
|
|
|
18
18
|
# @param inactive_style [Style, nil] style of inactive tabs and dividers
|
|
19
19
|
# (default: bright black foreground)
|
|
20
20
|
# @param divider [String] separator drawn between tabs (default: <tt>" │ "</tt>)
|
|
21
|
-
# @param highlight_style [Style, nil]
|
|
21
|
+
# @param highlight_style [Style, nil] patched onto the active tab's style after
|
|
22
|
+
# +active_style+ (default: nil, no extra styling)
|
|
22
23
|
# @param block [Widgets::Block, nil] optional wrapping block
|
|
23
24
|
def initialize(
|
|
24
25
|
titles: [],
|
|
@@ -65,12 +66,13 @@ module RubyTUI
|
|
|
65
66
|
|
|
66
67
|
is_active = i == @selected
|
|
67
68
|
tab_style = is_active ? @style.patch(@active_style) : @style.patch(@inactive_style)
|
|
69
|
+
tab_style = tab_style.patch(@highlight_style) if is_active && @highlight_style
|
|
68
70
|
|
|
69
71
|
# Render tab title
|
|
70
72
|
display = title.to_s
|
|
71
73
|
available = render_area.right - x
|
|
72
|
-
display =
|
|
73
|
-
display_width =
|
|
74
|
+
display = Unicode.truncate_to_width(display, available)
|
|
75
|
+
display_width = Unicode.string_width(display)
|
|
74
76
|
|
|
75
77
|
buf.set_string(x, y, display, tab_style)
|
|
76
78
|
x += display_width
|
|
@@ -78,8 +80,8 @@ module RubyTUI
|
|
|
78
80
|
# Render divider (except after last tab)
|
|
79
81
|
if i < @titles.length - 1
|
|
80
82
|
available = render_area.right - x
|
|
81
|
-
divider_text =
|
|
82
|
-
divider_width =
|
|
83
|
+
divider_text = Unicode.truncate_to_width(@divider, available)
|
|
84
|
+
divider_width = Unicode.string_width(divider_text)
|
|
83
85
|
buf.set_string(x, y, divider_text, @style.patch(@inactive_style))
|
|
84
86
|
x += divider_width
|
|
85
87
|
end
|
data/lib/rubytui.rb
CHANGED
|
@@ -61,7 +61,7 @@ require_relative "rubytui/input/reader"
|
|
|
61
61
|
# App framework
|
|
62
62
|
require_relative "rubytui/app"
|
|
63
63
|
|
|
64
|
-
# A
|
|
64
|
+
# A zero-dependency terminal user interface library.
|
|
65
65
|
#
|
|
66
66
|
# RubyTUI provides immediate-mode rendering with double buffering,
|
|
67
67
|
# constraint-based layouts, and a duck-typed widget protocol.
|
|
@@ -206,6 +206,7 @@ module RubyTUI
|
|
|
206
206
|
#
|
|
207
207
|
# Renders a {Widgets::Table} with optional header, borders, and title,
|
|
208
208
|
# then prints the ANSI output directly. Auto-calculates the required height.
|
|
209
|
+
# No row is selected, so no row is drawn in the highlight style.
|
|
209
210
|
#
|
|
210
211
|
# @param header [Array<String>, nil] column header labels
|
|
211
212
|
# @param rows [Array<Array<String>>] table data rows
|
|
@@ -216,7 +217,8 @@ module RubyTUI
|
|
|
216
217
|
# @param border_style [Style] style for the border characters (default: {Style::DEFAULT})
|
|
217
218
|
# @param header_style [Style, nil] style for header row (default: cyan bold)
|
|
218
219
|
# @param style [Style] base style for data rows (default: {Style::DEFAULT})
|
|
219
|
-
# @param highlight_symbol [String]
|
|
220
|
+
# @param highlight_symbol [String] only its display width is used: every row is
|
|
221
|
+
# prefixed with that many spaces, as no row is selected (default: " ")
|
|
220
222
|
# @param column_spacing [Integer] gap between columns (default: 1)
|
|
221
223
|
# @param width [Integer, nil] total width in columns (default: auto-detect)
|
|
222
224
|
# @param output [IO] output stream (default: $stdout)
|
|
@@ -245,7 +247,7 @@ module RubyTUI
|
|
|
245
247
|
header_style: header_style, highlight_symbol: highlight_symbol,
|
|
246
248
|
column_spacing: column_spacing, block: block_widget
|
|
247
249
|
)
|
|
248
|
-
state = Widgets::TableState.new(selected:
|
|
250
|
+
state = Widgets::TableState.new(selected: nil) # No selection for one-shot
|
|
249
251
|
|
|
250
252
|
# Calculate height: header(1) + separator(1) + rows + border(2)
|
|
251
253
|
h = rows.length + (header ? 2 : 0) + (title ? 2 : 0)
|
|
@@ -264,7 +266,13 @@ module RubyTUI
|
|
|
264
266
|
# then prints the ANSI output directly.
|
|
265
267
|
#
|
|
266
268
|
# @param title [String, nil] box title rendered on the top border
|
|
267
|
-
# @param content [String, Array<String
|
|
269
|
+
# @param content [String, Array<String>, Text, Line, Span, nil] text content: a
|
|
270
|
+
# String split on newlines, an Array of lines (an element may itself contain
|
|
271
|
+
# newlines), or a {Text}, {Line} or {Span}. Lines are word-wrapped to the box's
|
|
272
|
+
# inner width (+width+ - 2) and the box is tall enough for every wrapped line
|
|
273
|
+
# ({Widgets::Paragraph#line_count}). Trailing empty lines of a String or Array
|
|
274
|
+
# are dropped (see {Text#initialize}); empty content (+nil+, <tt>""</tt>,
|
|
275
|
+
# <tt>[]</tt>) gives one empty row
|
|
268
276
|
# @param border [Symbol, Symbols::BorderSet] border style — +:rounded+, +:double+,
|
|
269
277
|
# +:thick+, +:light+, +:plain+, or a {Symbols::BorderSet} (default: +:rounded+)
|
|
270
278
|
# @param border_style [Style] style for the border characters (default: {Style::DEFAULT})
|
|
@@ -303,11 +311,8 @@ module RubyTUI
|
|
|
303
311
|
)
|
|
304
312
|
|
|
305
313
|
w = width || terminal_width(output)
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
when Array then content.length
|
|
309
|
-
else 1
|
|
310
|
-
end
|
|
314
|
+
# Lines after wrapping to the inner width; at least one (empty) row
|
|
315
|
+
line_count = [para.line_count(w - 2), 1].max
|
|
311
316
|
h = line_count + 2 # +2 for borders
|
|
312
317
|
|
|
313
318
|
area = Rect.new(0, 0, w, h)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rubytui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.2.
|
|
4
|
+
version: 1.2.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- CoCL
|
|
@@ -10,7 +10,7 @@ cert_chain: []
|
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: |
|
|
13
|
-
A
|
|
13
|
+
A zero-dependency terminal user interface library featuring
|
|
14
14
|
immediate-mode rendering with double buffering, constraint-based layouts,
|
|
15
15
|
a duck-typed widget system, cross-platform input handling, and Kitty
|
|
16
16
|
graphics protocol support for inline images.
|
|
@@ -85,5 +85,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
85
85
|
requirements: []
|
|
86
86
|
rubygems_version: 4.0.19
|
|
87
87
|
specification_version: 4
|
|
88
|
-
summary:
|
|
88
|
+
summary: Zero-dependency terminal user interface library
|
|
89
89
|
test_files: []
|