tui_tui 0.1.0
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 +7 -0
- data/.github/workflows/ci.yml +20 -0
- data/LICENSE.txt +21 -0
- data/README.md +132 -0
- data/Rakefile +8 -0
- data/examples/clock.rb +112 -0
- data/examples/counter.rb +48 -0
- data/examples/csv_viewer.rb +233 -0
- data/examples/file_browser.rb +665 -0
- data/examples/form.rb +633 -0
- data/examples/life.rb +144 -0
- data/examples/paint.rb +246 -0
- data/examples/todo.rb +250 -0
- data/examples/widgets.rb +101 -0
- data/lib/tui_tui/ansi.rb +34 -0
- data/lib/tui_tui/canvas.rb +187 -0
- data/lib/tui_tui/canvas_compositor.rb +45 -0
- data/lib/tui_tui/cell.rb +11 -0
- data/lib/tui_tui/color_depth.rb +39 -0
- data/lib/tui_tui/confirm.rb +74 -0
- data/lib/tui_tui/display_text.rb +73 -0
- data/lib/tui_tui/event.rb +10 -0
- data/lib/tui_tui/event_stream.rb +39 -0
- data/lib/tui_tui/focus_ring.rb +25 -0
- data/lib/tui_tui/fuzzy.rb +56 -0
- data/lib/tui_tui/help.rb +44 -0
- data/lib/tui_tui/key_code.rb +9 -0
- data/lib/tui_tui/key_intent.rb +29 -0
- data/lib/tui_tui/key_reader.rb +175 -0
- data/lib/tui_tui/line.rb +59 -0
- data/lib/tui_tui/list.rb +45 -0
- data/lib/tui_tui/modal.rb +30 -0
- data/lib/tui_tui/pager.rb +94 -0
- data/lib/tui_tui/palette.rb +49 -0
- data/lib/tui_tui/prompt.rb +111 -0
- data/lib/tui_tui/rect.rb +48 -0
- data/lib/tui_tui/runtime.rb +53 -0
- data/lib/tui_tui/screen.rb +85 -0
- data/lib/tui_tui/scroll_list.rb +57 -0
- data/lib/tui_tui/scrollbar.rb +40 -0
- data/lib/tui_tui/select.rb +104 -0
- data/lib/tui_tui/size.rb +5 -0
- data/lib/tui_tui/span.rb +14 -0
- data/lib/tui_tui/status_bar.rb +23 -0
- data/lib/tui_tui/style.rb +101 -0
- data/lib/tui_tui/terminal_session.rb +65 -0
- data/lib/tui_tui/terminal_size.rb +24 -0
- data/lib/tui_tui/text_sanitizer.rb +13 -0
- data/lib/tui_tui/text_view.rb +52 -0
- data/lib/tui_tui/theme.rb +127 -0
- data/lib/tui_tui/toast.rb +82 -0
- data/lib/tui_tui/version.rb +5 -0
- data/lib/tui_tui/width.rb +101 -0
- data/lib/tui_tui.rb +51 -0
- metadata +98 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "style"
|
|
4
|
+
|
|
5
|
+
module TuiTui
|
|
6
|
+
# Semantic Style roles shared by the built-in widgets.
|
|
7
|
+
# Themes combine a background surface with an accent hue.
|
|
8
|
+
Theme = Data.define(
|
|
9
|
+
# box borders / dividers
|
|
10
|
+
:frame,
|
|
11
|
+
:title,
|
|
12
|
+
:text,
|
|
13
|
+
# de-emphasized text (descriptions, body)
|
|
14
|
+
:muted,
|
|
15
|
+
# highlighted detail (e.g. key names)
|
|
16
|
+
:accent,
|
|
17
|
+
# the focused/selected item or button
|
|
18
|
+
:selection,
|
|
19
|
+
# a selected item in an unfocused pane (de-emphasized)
|
|
20
|
+
:selection_dim,
|
|
21
|
+
# status / footer bar background
|
|
22
|
+
:bar,
|
|
23
|
+
:cursor,
|
|
24
|
+
:scroll_track,
|
|
25
|
+
:scroll_thumb
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
class Theme
|
|
29
|
+
# Background-dependent neutral roles.
|
|
30
|
+
SURFACES = {
|
|
31
|
+
dark: {
|
|
32
|
+
text: Style.new,
|
|
33
|
+
muted: Style.new(fg: 245),
|
|
34
|
+
bar: Style.new(fg: 252, bg: 238),
|
|
35
|
+
selection_dim: Style.new(fg: 247, bg: 238)
|
|
36
|
+
},
|
|
37
|
+
light: {
|
|
38
|
+
text: Style.new,
|
|
39
|
+
muted: Style.new(fg: 240),
|
|
40
|
+
bar: Style.new(fg: 16, bg: 252),
|
|
41
|
+
selection_dim: Style.new(fg: 240, bg: 252)
|
|
42
|
+
}
|
|
43
|
+
}.freeze
|
|
44
|
+
|
|
45
|
+
# Accent roles per hue and background.
|
|
46
|
+
ACCENTS = {
|
|
47
|
+
cool: {
|
|
48
|
+
dark: {line: 66, title: 109, accent: 73, sel: [231, 60]},
|
|
49
|
+
light: {line: 30, title: 25, accent: 30, sel: [16, 152]}
|
|
50
|
+
},
|
|
51
|
+
warm: {
|
|
52
|
+
dark: {line: 95, title: 137, accent: 173, sel: [231, 95]},
|
|
53
|
+
light: {line: 95, title: 94, accent: 130, sel: [16, 180]}
|
|
54
|
+
},
|
|
55
|
+
mono: {
|
|
56
|
+
dark: {line: 240, title: 252, accent: 252, sel: [16, 250]},
|
|
57
|
+
light: {line: 240, title: 236, accent: 236, sel: [16, 250]}
|
|
58
|
+
}
|
|
59
|
+
}.freeze
|
|
60
|
+
|
|
61
|
+
# COLORFGBG background values meaning "light".
|
|
62
|
+
LIGHT_FGBG = %w[7 15].freeze
|
|
63
|
+
|
|
64
|
+
def self.bold(fg) = Style.new(fg: fg, attrs: [:bold])
|
|
65
|
+
|
|
66
|
+
# Build the palette for a (background, hue) pair.
|
|
67
|
+
def self.compose(background, hue)
|
|
68
|
+
surface = SURFACES.fetch(background)
|
|
69
|
+
a = ACCENTS.fetch(hue).fetch(background)
|
|
70
|
+
selection = Style.new(fg: a[:sel][0], bg: a[:sel][1])
|
|
71
|
+
new(
|
|
72
|
+
frame: Style.new(fg: a[:line]),
|
|
73
|
+
title: bold(a[:title]),
|
|
74
|
+
text: surface[:text],
|
|
75
|
+
muted: surface[:muted],
|
|
76
|
+
accent: bold(a[:accent]),
|
|
77
|
+
selection: selection,
|
|
78
|
+
selection_dim: surface[:selection_dim],
|
|
79
|
+
bar: surface[:bar],
|
|
80
|
+
cursor: selection,
|
|
81
|
+
scroll_track: Style.new(fg: a[:line]),
|
|
82
|
+
scroll_thumb: Style.new(bg: a[:sel][1])
|
|
83
|
+
)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Shared palettes for every surface/hue pair.
|
|
87
|
+
TABLE = SURFACES.keys.product(ACCENTS.keys).to_h { |bg, hue| [[bg, hue], compose(bg, hue)] }.freeze
|
|
88
|
+
|
|
89
|
+
def self.build(background: :dark, hue: :cool) = TABLE.fetch([background, hue])
|
|
90
|
+
|
|
91
|
+
# Best-effort terminal background (:light/:dark).
|
|
92
|
+
def self.detect_background(env: ENV)
|
|
93
|
+
case env["TUITUI_BACKGROUND"]&.downcase
|
|
94
|
+
when "light"
|
|
95
|
+
:light
|
|
96
|
+
when "dark"
|
|
97
|
+
:dark
|
|
98
|
+
else
|
|
99
|
+
bg = env["COLORFGBG"]&.split(";")&.last
|
|
100
|
+
bg && LIGHT_FGBG.include?(bg) ? :light : :dark
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# The hue palette tuned for the detected background.
|
|
105
|
+
def self.auto(hue: :cool, env: ENV) = build(background: detect_background(env: env), hue: hue)
|
|
106
|
+
|
|
107
|
+
# Fetch a preset by name (Symbol/String); unknown names fall back to DEFAULT.
|
|
108
|
+
def self.named(name) = PRESETS.fetch(name&.to_sym, DEFAULT)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
Theme::DARK = Theme.build(background: :dark, hue: :cool)
|
|
112
|
+
Theme::LIGHT = Theme.build(background: :light, hue: :cool)
|
|
113
|
+
Theme::DEFAULT = Theme::DARK
|
|
114
|
+
Theme::WARM = Theme.build(background: :dark, hue: :warm)
|
|
115
|
+
Theme::MONO = Theme.build(background: :dark, hue: :mono)
|
|
116
|
+
|
|
117
|
+
class Theme
|
|
118
|
+
PRESETS = {
|
|
119
|
+
default: DEFAULT,
|
|
120
|
+
cool: DEFAULT,
|
|
121
|
+
dark: DARK,
|
|
122
|
+
light: LIGHT,
|
|
123
|
+
warm: WARM,
|
|
124
|
+
mono: MONO
|
|
125
|
+
}.freeze
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "display_text"
|
|
4
|
+
require_relative "style"
|
|
5
|
+
|
|
6
|
+
module TuiTui
|
|
7
|
+
# A transient notification overlay.
|
|
8
|
+
# The clock is injectable so expiry is testable without sleeping.
|
|
9
|
+
class Toast
|
|
10
|
+
DEFAULT_SECONDS = 2.0
|
|
11
|
+
DEFAULT_STYLE = Style.new(attrs: [:reverse])
|
|
12
|
+
DEFAULT_POSITION = :bottom_center
|
|
13
|
+
POSITIONS = {
|
|
14
|
+
top_left: [:top, :left],
|
|
15
|
+
top_center: [:top, :center],
|
|
16
|
+
top_right: [:top, :right],
|
|
17
|
+
middle_left: [:middle, :left],
|
|
18
|
+
middle_center: [:middle, :center],
|
|
19
|
+
middle_right: [:middle, :right],
|
|
20
|
+
bottom_left: [:bottom, :left],
|
|
21
|
+
bottom_center: [:bottom, :center],
|
|
22
|
+
bottom_right: [:bottom, :right],
|
|
23
|
+
center: [:middle, :center]
|
|
24
|
+
}.freeze
|
|
25
|
+
MONOTONIC = -> { Process.clock_gettime(Process::CLOCK_MONOTONIC) }
|
|
26
|
+
|
|
27
|
+
def initialize(message, seconds: DEFAULT_SECONDS, position: DEFAULT_POSITION, clock: MONOTONIC)
|
|
28
|
+
@message = DisplayText.new(message)
|
|
29
|
+
@position = position
|
|
30
|
+
@clock = clock
|
|
31
|
+
@expires_at = clock.call + seconds
|
|
32
|
+
validate_position!
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def expired? = @clock.call >= @expires_at
|
|
36
|
+
|
|
37
|
+
def draw(canvas, size, style: DEFAULT_STYLE, position: @position)
|
|
38
|
+
return canvas if expired?
|
|
39
|
+
|
|
40
|
+
label = DisplayText.new(" #{@message} ").truncate(size.cols)
|
|
41
|
+
vertical, horizontal = position_parts(position)
|
|
42
|
+
row = row_for(size, vertical)
|
|
43
|
+
col = col_for(size, label.width, horizontal)
|
|
44
|
+
canvas.text(row, col, label, style)
|
|
45
|
+
canvas
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
def validate_position!
|
|
51
|
+
position_parts(@position)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def position_parts(position)
|
|
55
|
+
POSITIONS.fetch(position) do
|
|
56
|
+
raise ArgumentError, "unknown toast position: #{position.inspect}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def row_for(size, vertical)
|
|
61
|
+
case vertical
|
|
62
|
+
when :top
|
|
63
|
+
1
|
|
64
|
+
when :middle
|
|
65
|
+
((size.rows + 1) / 2).clamp(1, size.rows)
|
|
66
|
+
when :bottom
|
|
67
|
+
[size.rows - 2, 1].max
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def col_for(size, width, horizontal)
|
|
72
|
+
case horizontal
|
|
73
|
+
when :left
|
|
74
|
+
1
|
|
75
|
+
when :center
|
|
76
|
+
[((size.cols - width) / 2) + 1, 1].max
|
|
77
|
+
when :right
|
|
78
|
+
[size.cols - width + 1, 1].max
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module TuiTui
|
|
4
|
+
# Terminal column width for the Unicode ranges this renderer needs.
|
|
5
|
+
# Wide/fullwidth clusters are 2, combining/control clusters are 0.
|
|
6
|
+
module Width
|
|
7
|
+
WIDE = [
|
|
8
|
+
# Hangul Jamo
|
|
9
|
+
[0x1100, 0x115F],
|
|
10
|
+
# CJK radicals, Kangxi, CJK symbols & punctuation
|
|
11
|
+
[0x2E80, 0x303E],
|
|
12
|
+
# Hiragana, Katakana, CJK symbols, enclosed CJK, ...
|
|
13
|
+
[0x3041, 0x33FF],
|
|
14
|
+
# CJK Unified Ext A
|
|
15
|
+
[0x3400, 0x4DBF],
|
|
16
|
+
# CJK Unified Ideographs
|
|
17
|
+
[0x4E00, 0x9FFF],
|
|
18
|
+
# Yi
|
|
19
|
+
[0xA000, 0xA4CF],
|
|
20
|
+
# Hangul Jamo Ext A
|
|
21
|
+
[0xA960, 0xA97F],
|
|
22
|
+
# Hangul Syllables
|
|
23
|
+
[0xAC00, 0xD7A3],
|
|
24
|
+
# CJK Compatibility Ideographs
|
|
25
|
+
[0xF900, 0xFAFF],
|
|
26
|
+
# Vertical forms
|
|
27
|
+
[0xFE10, 0xFE19],
|
|
28
|
+
# CJK Compatibility / small forms
|
|
29
|
+
[0xFE30, 0xFE6F],
|
|
30
|
+
# Fullwidth forms
|
|
31
|
+
[0xFF00, 0xFF60],
|
|
32
|
+
# Fullwidth signs
|
|
33
|
+
[0xFFE0, 0xFFE6],
|
|
34
|
+
# Kana supplement / extended
|
|
35
|
+
[0x1B000, 0x1B16F],
|
|
36
|
+
# Regional indicator symbols (flag letters)
|
|
37
|
+
[0x1F1E6, 0x1F1FF],
|
|
38
|
+
# Enclosed ideographic supplement
|
|
39
|
+
[0x1F200, 0x1F251],
|
|
40
|
+
# Misc symbols & pictographs + emoticons
|
|
41
|
+
[0x1F300, 0x1F64F],
|
|
42
|
+
# Transport & map symbols
|
|
43
|
+
[0x1F680, 0x1F6FF],
|
|
44
|
+
# Supplemental symbols & pictographs
|
|
45
|
+
[0x1F900, 0x1F9FF],
|
|
46
|
+
# Symbols & pictographs extended-A
|
|
47
|
+
[0x1FA70, 0x1FAFF],
|
|
48
|
+
# CJK Unified Ext B and beyond
|
|
49
|
+
[0x20000, 0x3FFFD]
|
|
50
|
+
].freeze
|
|
51
|
+
|
|
52
|
+
ZERO = [
|
|
53
|
+
# Combining diacritical marks
|
|
54
|
+
[0x0300, 0x036F],
|
|
55
|
+
[0x0483, 0x0489],
|
|
56
|
+
[0x0591, 0x05BD],
|
|
57
|
+
[0x0610, 0x061A],
|
|
58
|
+
[0x064B, 0x065F],
|
|
59
|
+
[0x06D6, 0x06DC],
|
|
60
|
+
# Zero-width space / joiners / marks
|
|
61
|
+
[0x200B, 0x200F],
|
|
62
|
+
# Variation selectors
|
|
63
|
+
[0xFE00, 0xFE0F],
|
|
64
|
+
# Zero-width no-break space (BOM)
|
|
65
|
+
[0xFEFF, 0xFEFF],
|
|
66
|
+
# Emoji skin-tone modifiers (combine onto the base)
|
|
67
|
+
[0x1F3FB, 0x1F3FF]
|
|
68
|
+
].freeze
|
|
69
|
+
|
|
70
|
+
class << self
|
|
71
|
+
|
|
72
|
+
def cluster(grapheme)
|
|
73
|
+
# A cluster's base codepoint determines its terminal width.
|
|
74
|
+
base = grapheme[0]
|
|
75
|
+
return 1 if control?(base.ord)
|
|
76
|
+
|
|
77
|
+
char(base)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def char(char)
|
|
81
|
+
cp = char.ord
|
|
82
|
+
return 0 if control?(cp)
|
|
83
|
+
return 0 if in?(cp, ZERO)
|
|
84
|
+
|
|
85
|
+
in?(cp, WIDE) ? 2 : 1
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def control?(cp)
|
|
89
|
+
cp < 0x20 || cp == 0x7F || cp.between?(0x80, 0x9F)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def in?(cp, ranges)
|
|
95
|
+
# Ranges are sorted and non-overlapping, so one binary search is enough.
|
|
96
|
+
index = ranges.bsearch_index { |_lo, hi| hi >= cp }
|
|
97
|
+
!index.nil? && ranges[index][0] <= cp
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
data/lib/tui_tui.rb
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "tui_tui/version"
|
|
4
|
+
|
|
5
|
+
require_relative "tui_tui/width"
|
|
6
|
+
require_relative "tui_tui/text_sanitizer"
|
|
7
|
+
require_relative "tui_tui/display_text"
|
|
8
|
+
require_relative "tui_tui/span"
|
|
9
|
+
require_relative "tui_tui/line"
|
|
10
|
+
require_relative "tui_tui/ansi"
|
|
11
|
+
require_relative "tui_tui/color_depth"
|
|
12
|
+
require_relative "tui_tui/palette"
|
|
13
|
+
require_relative "tui_tui/style"
|
|
14
|
+
require_relative "tui_tui/theme"
|
|
15
|
+
require_relative "tui_tui/size"
|
|
16
|
+
require_relative "tui_tui/rect"
|
|
17
|
+
require_relative "tui_tui/cell"
|
|
18
|
+
require_relative "tui_tui/canvas"
|
|
19
|
+
require_relative "tui_tui/canvas_compositor"
|
|
20
|
+
require_relative "tui_tui/event"
|
|
21
|
+
require_relative "tui_tui/key_code"
|
|
22
|
+
require_relative "tui_tui/key_reader"
|
|
23
|
+
require_relative "tui_tui/key_intent"
|
|
24
|
+
require_relative "tui_tui/event_stream"
|
|
25
|
+
require_relative "tui_tui/terminal_session"
|
|
26
|
+
require_relative "tui_tui/scroll_list"
|
|
27
|
+
require_relative "tui_tui/list"
|
|
28
|
+
require_relative "tui_tui/text_view"
|
|
29
|
+
require_relative "tui_tui/scrollbar"
|
|
30
|
+
require_relative "tui_tui/status_bar"
|
|
31
|
+
require_relative "tui_tui/toast"
|
|
32
|
+
require_relative "tui_tui/focus_ring"
|
|
33
|
+
require_relative "tui_tui/fuzzy"
|
|
34
|
+
require_relative "tui_tui/modal"
|
|
35
|
+
require_relative "tui_tui/confirm"
|
|
36
|
+
require_relative "tui_tui/select"
|
|
37
|
+
require_relative "tui_tui/help"
|
|
38
|
+
require_relative "tui_tui/prompt"
|
|
39
|
+
require_relative "tui_tui/pager"
|
|
40
|
+
require_relative "tui_tui/screen"
|
|
41
|
+
require_relative "tui_tui/runtime"
|
|
42
|
+
|
|
43
|
+
# A tiny, owned TUI runtime for rendering in modern graphical terminals. Its only
|
|
44
|
+
# dependency is `io/console` (a default gem, used by the Screen driver); the pure
|
|
45
|
+
# pieces — width, color, style, layout — need nothing.
|
|
46
|
+
#
|
|
47
|
+
# The framework is application-agnostic. Build an app object responding to
|
|
48
|
+
# `view(size) -> Canvas` and `update(event) -> app | :quit`, then drive it with
|
|
49
|
+
# `TuiTui::Runtime`.
|
|
50
|
+
module TuiTui
|
|
51
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tui_tui
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- takahashim
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: 'TuiTui is a small terminal-UI framework: a width-aware canvas, a diffing
|
|
13
|
+
renderer, an Elm-style runtime loop, and composable widgets (modals, lists, prompts).
|
|
14
|
+
Its only dependency is io/console.'
|
|
15
|
+
email:
|
|
16
|
+
- takahashimm@gmail.com
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- ".github/workflows/ci.yml"
|
|
22
|
+
- LICENSE.txt
|
|
23
|
+
- README.md
|
|
24
|
+
- Rakefile
|
|
25
|
+
- examples/clock.rb
|
|
26
|
+
- examples/counter.rb
|
|
27
|
+
- examples/csv_viewer.rb
|
|
28
|
+
- examples/file_browser.rb
|
|
29
|
+
- examples/form.rb
|
|
30
|
+
- examples/life.rb
|
|
31
|
+
- examples/paint.rb
|
|
32
|
+
- examples/todo.rb
|
|
33
|
+
- examples/widgets.rb
|
|
34
|
+
- lib/tui_tui.rb
|
|
35
|
+
- lib/tui_tui/ansi.rb
|
|
36
|
+
- lib/tui_tui/canvas.rb
|
|
37
|
+
- lib/tui_tui/canvas_compositor.rb
|
|
38
|
+
- lib/tui_tui/cell.rb
|
|
39
|
+
- lib/tui_tui/color_depth.rb
|
|
40
|
+
- lib/tui_tui/confirm.rb
|
|
41
|
+
- lib/tui_tui/display_text.rb
|
|
42
|
+
- lib/tui_tui/event.rb
|
|
43
|
+
- lib/tui_tui/event_stream.rb
|
|
44
|
+
- lib/tui_tui/focus_ring.rb
|
|
45
|
+
- lib/tui_tui/fuzzy.rb
|
|
46
|
+
- lib/tui_tui/help.rb
|
|
47
|
+
- lib/tui_tui/key_code.rb
|
|
48
|
+
- lib/tui_tui/key_intent.rb
|
|
49
|
+
- lib/tui_tui/key_reader.rb
|
|
50
|
+
- lib/tui_tui/line.rb
|
|
51
|
+
- lib/tui_tui/list.rb
|
|
52
|
+
- lib/tui_tui/modal.rb
|
|
53
|
+
- lib/tui_tui/pager.rb
|
|
54
|
+
- lib/tui_tui/palette.rb
|
|
55
|
+
- lib/tui_tui/prompt.rb
|
|
56
|
+
- lib/tui_tui/rect.rb
|
|
57
|
+
- lib/tui_tui/runtime.rb
|
|
58
|
+
- lib/tui_tui/screen.rb
|
|
59
|
+
- lib/tui_tui/scroll_list.rb
|
|
60
|
+
- lib/tui_tui/scrollbar.rb
|
|
61
|
+
- lib/tui_tui/select.rb
|
|
62
|
+
- lib/tui_tui/size.rb
|
|
63
|
+
- lib/tui_tui/span.rb
|
|
64
|
+
- lib/tui_tui/status_bar.rb
|
|
65
|
+
- lib/tui_tui/style.rb
|
|
66
|
+
- lib/tui_tui/terminal_session.rb
|
|
67
|
+
- lib/tui_tui/terminal_size.rb
|
|
68
|
+
- lib/tui_tui/text_sanitizer.rb
|
|
69
|
+
- lib/tui_tui/text_view.rb
|
|
70
|
+
- lib/tui_tui/theme.rb
|
|
71
|
+
- lib/tui_tui/toast.rb
|
|
72
|
+
- lib/tui_tui/version.rb
|
|
73
|
+
- lib/tui_tui/width.rb
|
|
74
|
+
homepage: https://github.com/takahashim/tui_tui
|
|
75
|
+
licenses:
|
|
76
|
+
- MIT
|
|
77
|
+
metadata:
|
|
78
|
+
allowed_push_host: https://rubygems.org
|
|
79
|
+
homepage_uri: https://github.com/takahashim/tui_tui
|
|
80
|
+
source_code_uri: https://github.com/takahashim/tui_tui
|
|
81
|
+
rdoc_options: []
|
|
82
|
+
require_paths:
|
|
83
|
+
- lib
|
|
84
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: 3.2.0
|
|
89
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
90
|
+
requirements:
|
|
91
|
+
- - ">="
|
|
92
|
+
- !ruby/object:Gem::Version
|
|
93
|
+
version: '0'
|
|
94
|
+
requirements: []
|
|
95
|
+
rubygems_version: 4.0.10
|
|
96
|
+
specification_version: 4
|
|
97
|
+
summary: A tiny, dependency-free TUI runtime for modern terminals.
|
|
98
|
+
test_files: []
|