ratatui_ruby 1.0.0 → 1.0.1
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/ext/ratatui_ruby/Cargo.lock +1 -1
- data/ext/ratatui_ruby/Cargo.toml +1 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- metadata +1 -232
- data/.builds/ruby-3.2.yml +0 -54
- data/.builds/ruby-3.3.yml +0 -54
- data/.builds/ruby-3.4.yml +0 -54
- data/.builds/ruby-4.0.0.yml +0 -54
- data/.pre-commit-config.yaml +0 -16
- data/.rubocop.yml +0 -10
- data/AGENTS.md +0 -146
- data/CHANGELOG.md +0 -710
- data/README.md +0 -187
- data/README.rdoc +0 -302
- data/Rakefile +0 -11
- data/Steepfile +0 -49
- data/doc/concepts/application_architecture.md +0 -321
- data/doc/concepts/application_testing.md +0 -193
- data/doc/concepts/async.md +0 -190
- data/doc/concepts/custom_widgets.md +0 -247
- data/doc/concepts/debugging.md +0 -401
- data/doc/concepts/event_handling.md +0 -162
- data/doc/concepts/interactive_design.md +0 -146
- data/doc/contributors/auditing/parity.md +0 -239
- data/doc/contributors/design/ruby_frontend.md +0 -420
- data/doc/contributors/design/rust_backend.md +0 -422
- data/doc/contributors/design.md +0 -11
- data/doc/contributors/developing_examples.md +0 -400
- data/doc/contributors/documentation_style.md +0 -121
- data/doc/contributors/index.md +0 -21
- data/doc/contributors/todo/align/api_completeness_audit-finished.md +0 -375
- data/doc/contributors/todo/align/api_completeness_audit-unfinished.md +0 -206
- data/doc/contributors/todo/align/terminal.md +0 -647
- data/doc/contributors/todo/future_work.md +0 -169
- data/doc/contributors/upstream_requests/tab_rects.md +0 -173
- data/doc/contributors/upstream_requests/title_rects.md +0 -132
- data/doc/custom.css +0 -22
- data/doc/getting_started/quickstart.md +0 -291
- data/doc/getting_started/why.md +0 -93
- data/doc/images/app_all_events.png +0 -0
- data/doc/images/app_cli_rich_moments.gif +0 -0
- data/doc/images/app_color_picker.png +0 -0
- data/doc/images/app_debugging_showcase.gif +0 -0
- data/doc/images/app_debugging_showcase.png +0 -0
- data/doc/images/app_login_form.png +0 -0
- data/doc/images/app_stateful_interaction.png +0 -0
- data/doc/images/verify_quickstart_dsl.png +0 -0
- data/doc/images/verify_quickstart_layout.png +0 -0
- data/doc/images/verify_quickstart_lifecycle.png +0 -0
- data/doc/images/verify_readme_usage.png +0 -0
- data/doc/images/widget_barchart.png +0 -0
- data/doc/images/widget_block.png +0 -0
- data/doc/images/widget_box.png +0 -0
- data/doc/images/widget_calendar.png +0 -0
- data/doc/images/widget_canvas.png +0 -0
- data/doc/images/widget_cell.png +0 -0
- data/doc/images/widget_center.png +0 -0
- data/doc/images/widget_chart.png +0 -0
- data/doc/images/widget_gauge.png +0 -0
- data/doc/images/widget_layout_split.png +0 -0
- data/doc/images/widget_line_gauge.png +0 -0
- data/doc/images/widget_list.png +0 -0
- data/doc/images/widget_map.png +0 -0
- data/doc/images/widget_overlay.png +0 -0
- data/doc/images/widget_popup.png +0 -0
- data/doc/images/widget_ratatui_logo.png +0 -0
- data/doc/images/widget_ratatui_mascot.png +0 -0
- data/doc/images/widget_rect.png +0 -0
- data/doc/images/widget_render.png +0 -0
- data/doc/images/widget_rich_text.png +0 -0
- data/doc/images/widget_scroll_text.png +0 -0
- data/doc/images/widget_scrollbar.png +0 -0
- data/doc/images/widget_sparkline.png +0 -0
- data/doc/images/widget_style_colors.png +0 -0
- data/doc/images/widget_table.png +0 -0
- data/doc/images/widget_tabs.png +0 -0
- data/doc/images/widget_text_width.png +0 -0
- data/doc/index.md +0 -39
- data/doc/troubleshooting/async.md +0 -4
- data/doc/troubleshooting/terminal_limitations.md +0 -131
- data/doc/troubleshooting/tui_output.md +0 -197
- data/examples/app_all_events/README.md +0 -114
- data/examples/app_all_events/app.rb +0 -98
- data/examples/app_all_events/model/app_model.rb +0 -159
- data/examples/app_all_events/model/event_color_cycle.rb +0 -43
- data/examples/app_all_events/model/event_entry.rb +0 -94
- data/examples/app_all_events/model/msg.rb +0 -39
- data/examples/app_all_events/model/timestamp.rb +0 -56
- data/examples/app_all_events/update.rb +0 -75
- data/examples/app_all_events/view/app_view.rb +0 -80
- data/examples/app_all_events/view/controls_view.rb +0 -54
- data/examples/app_all_events/view/counts_view.rb +0 -61
- data/examples/app_all_events/view/live_view.rb +0 -72
- data/examples/app_all_events/view/log_view.rb +0 -57
- data/examples/app_all_events/view.rb +0 -9
- data/examples/app_cli_rich_moments/README.md +0 -81
- data/examples/app_cli_rich_moments/app.rb +0 -189
- data/examples/app_color_picker/README.md +0 -156
- data/examples/app_color_picker/app.rb +0 -76
- data/examples/app_color_picker/clipboard.rb +0 -86
- data/examples/app_color_picker/color.rb +0 -193
- data/examples/app_color_picker/controls.rb +0 -92
- data/examples/app_color_picker/copy_dialog.rb +0 -168
- data/examples/app_color_picker/export_pane.rb +0 -128
- data/examples/app_color_picker/harmony.rb +0 -58
- data/examples/app_color_picker/input.rb +0 -176
- data/examples/app_color_picker/main_container.rb +0 -180
- data/examples/app_color_picker/palette.rb +0 -111
- data/examples/app_debugging_showcase/README.md +0 -119
- data/examples/app_debugging_showcase/app.rb +0 -318
- data/examples/app_login_form/README.md +0 -58
- data/examples/app_login_form/app.rb +0 -109
- data/examples/app_stateful_interaction/README.md +0 -35
- data/examples/app_stateful_interaction/app.rb +0 -328
- data/examples/timeout_demo.rb +0 -45
- data/examples/verify_quickstart_dsl/README.md +0 -55
- data/examples/verify_quickstart_dsl/app.rb +0 -49
- data/examples/verify_quickstart_layout/README.md +0 -77
- data/examples/verify_quickstart_layout/app.rb +0 -73
- data/examples/verify_quickstart_lifecycle/README.md +0 -68
- data/examples/verify_quickstart_lifecycle/app.rb +0 -62
- data/examples/verify_readme_usage/README.md +0 -49
- data/examples/verify_readme_usage/app.rb +0 -42
- data/examples/verify_website_managed/README.md +0 -48
- data/examples/verify_website_managed/app.rb +0 -36
- data/examples/verify_website_menu/README.md +0 -60
- data/examples/verify_website_menu/app.rb +0 -84
- data/examples/verify_website_spinner/README.md +0 -44
- data/examples/verify_website_spinner/app.rb +0 -34
- data/examples/widget_barchart/README.md +0 -58
- data/examples/widget_barchart/app.rb +0 -240
- data/examples/widget_block/README.md +0 -44
- data/examples/widget_block/app.rb +0 -258
- data/examples/widget_box/README.md +0 -54
- data/examples/widget_box/app.rb +0 -255
- data/examples/widget_calendar/README.md +0 -48
- data/examples/widget_calendar/app.rb +0 -115
- data/examples/widget_canvas/README.md +0 -31
- data/examples/widget_canvas/app.rb +0 -130
- data/examples/widget_cell/README.md +0 -45
- data/examples/widget_cell/app.rb +0 -112
- data/examples/widget_center/README.md +0 -33
- data/examples/widget_center/app.rb +0 -118
- data/examples/widget_chart/README.md +0 -50
- data/examples/widget_chart/app.rb +0 -220
- data/examples/widget_gauge/README.md +0 -50
- data/examples/widget_gauge/app.rb +0 -229
- data/examples/widget_layout_split/README.md +0 -53
- data/examples/widget_layout_split/app.rb +0 -260
- data/examples/widget_line_gauge/README.md +0 -50
- data/examples/widget_line_gauge/app.rb +0 -219
- data/examples/widget_list/README.md +0 -58
- data/examples/widget_list/app.rb +0 -384
- data/examples/widget_map/README.md +0 -48
- data/examples/widget_map/app.rb +0 -95
- data/examples/widget_overlay/README.md +0 -45
- data/examples/widget_overlay/app.rb +0 -250
- data/examples/widget_popup/README.md +0 -45
- data/examples/widget_popup/app.rb +0 -106
- data/examples/widget_ratatui_logo/README.md +0 -43
- data/examples/widget_ratatui_logo/app.rb +0 -104
- data/examples/widget_ratatui_mascot/README.md +0 -43
- data/examples/widget_ratatui_mascot/app.rb +0 -95
- data/examples/widget_rect/README.md +0 -53
- data/examples/widget_rect/app.rb +0 -222
- data/examples/widget_render/README.md +0 -46
- data/examples/widget_render/app.rb +0 -186
- data/examples/widget_render/app.rbs +0 -41
- data/examples/widget_rich_text/README.md +0 -44
- data/examples/widget_rich_text/app.rb +0 -193
- data/examples/widget_scroll_text/README.md +0 -46
- data/examples/widget_scroll_text/app.rb +0 -109
- data/examples/widget_scrollbar/README.md +0 -46
- data/examples/widget_scrollbar/app.rb +0 -155
- data/examples/widget_sparkline/README.md +0 -51
- data/examples/widget_sparkline/app.rb +0 -277
- data/examples/widget_style_colors/README.md +0 -43
- data/examples/widget_style_colors/app.rb +0 -83
- data/examples/widget_table/README.md +0 -57
- data/examples/widget_table/app.rb +0 -279
- data/examples/widget_tabs/README.md +0 -50
- data/examples/widget_tabs/app.rb +0 -183
- data/examples/widget_text_width/README.md +0 -44
- data/examples/widget_text_width/app.rb +0 -117
- data/migrate_to_buffer.rb +0 -145
- data/mise.toml +0 -8
- data/tasks/autodoc/examples.rb +0 -87
- data/tasks/autodoc/member.rb +0 -58
- data/tasks/autodoc/name.rb +0 -21
- data/tasks/autodoc.rake +0 -21
- data/tasks/bump/cargo_lockfile.rb +0 -21
- data/tasks/bump/changelog.rb +0 -47
- data/tasks/bump/header.rb +0 -32
- data/tasks/bump/history.rb +0 -32
- data/tasks/bump/links.rb +0 -69
- data/tasks/bump/manifest.rb +0 -33
- data/tasks/bump/ruby_gem.rb +0 -49
- data/tasks/bump/sem_ver.rb +0 -40
- data/tasks/bump/unreleased_section.rb +0 -56
- data/tasks/bump.rake +0 -51
- data/tasks/doc.rake +0 -887
- data/tasks/example_viewer.html.erb +0 -172
- data/tasks/extension.rake +0 -14
- data/tasks/license/headers_md.rb +0 -223
- data/tasks/license/headers_rb.rb +0 -210
- data/tasks/license/license_utils.rb +0 -130
- data/tasks/license/snippets_md.rb +0 -315
- data/tasks/license/snippets_rdoc.rb +0 -150
- data/tasks/license.rake +0 -91
- data/tasks/lint.rake +0 -170
- data/tasks/rdoc_config.rb +0 -29
- data/tasks/resources/build.yml.erb +0 -60
- data/tasks/resources/index.html.erb +0 -141
- data/tasks/resources/rubies.yml +0 -7
- data/tasks/sourcehut.rake +0 -110
- data/tasks/steep.rake +0 -11
- data/tasks/terminal_preview/app_screenshot.rb +0 -45
- data/tasks/terminal_preview/crash_report.rb +0 -54
- data/tasks/terminal_preview/example_app.rb +0 -27
- data/tasks/terminal_preview/launcher_script.rb +0 -48
- data/tasks/terminal_preview/preview_collection.rb +0 -60
- data/tasks/terminal_preview/preview_timing.rb +0 -24
- data/tasks/terminal_preview/safety_confirmation.rb +0 -58
- data/tasks/terminal_preview/saved_screenshot.rb +0 -56
- data/tasks/terminal_preview/system_appearance.rb +0 -13
- data/tasks/terminal_preview/terminal_window.rb +0 -138
- data/tasks/terminal_preview/window_id.rb +0 -16
- data/tasks/terminal_preview.rake +0 -30
- data/tasks/test.rake +0 -33
- data/tasks/website/index_page.rb +0 -30
- data/tasks/website/version.rb +0 -127
- data/tasks/website/version_menu.rb +0 -68
- data/tasks/website/versioned_documentation.rb +0 -83
- data/tasks/website/website.rb +0 -53
- data/tasks/website.rake +0 -28
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: MIT-0
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
9
|
-
require "ratatui_ruby"
|
|
10
|
-
|
|
11
|
-
# Demonstrates viewport navigation with interactive theme and orientation cycling.
|
|
12
|
-
#
|
|
13
|
-
# Content overflows. Users get lost in long lists without landmarks. They need to know where they are and how much is left.
|
|
14
|
-
#
|
|
15
|
-
# This demo showcases the <tt>Scrollbar</tt> widget. It provides an interactive playground where you can toggle orientations and cycle through different themes (Standard, Rounded, ASCII, Minimal) in real-time.
|
|
16
|
-
#
|
|
17
|
-
# Use it to understand how to provide spatial awareness and navigation cues for overflowing content.
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# Run the demo from the terminal:
|
|
22
|
-
#
|
|
23
|
-
# ruby examples/widget_scrollbar/app.rb
|
|
24
|
-
#
|
|
25
|
-
# rdoc-image:/doc/images/widget_scrollbar.png
|
|
26
|
-
class WidgetScrollbar
|
|
27
|
-
def initialize
|
|
28
|
-
@scroll_position = 0
|
|
29
|
-
@content_length = 50
|
|
30
|
-
@lines = (1..@content_length).map { |i| "Line #{i}" }
|
|
31
|
-
@orientation_index = 0
|
|
32
|
-
@orientations = [
|
|
33
|
-
:vertical,
|
|
34
|
-
:vertical_right,
|
|
35
|
-
:vertical_left,
|
|
36
|
-
:horizontal,
|
|
37
|
-
:horizontal_bottom,
|
|
38
|
-
:horizontal_top,
|
|
39
|
-
]
|
|
40
|
-
@theme_index = 0
|
|
41
|
-
@themes = [
|
|
42
|
-
{
|
|
43
|
-
name: "Standard",
|
|
44
|
-
track_symbol: nil,
|
|
45
|
-
thumb_symbol: "█",
|
|
46
|
-
track_style: nil,
|
|
47
|
-
thumb_style: nil,
|
|
48
|
-
begin_symbol: nil,
|
|
49
|
-
end_symbol: nil,
|
|
50
|
-
},
|
|
51
|
-
{
|
|
52
|
-
name: "Rounded",
|
|
53
|
-
track_symbol: "│",
|
|
54
|
-
thumb_symbol: "┃",
|
|
55
|
-
track_style: { fg: "dark_gray" },
|
|
56
|
-
thumb_style: { fg: "cyan" },
|
|
57
|
-
begin_symbol: "▲",
|
|
58
|
-
end_symbol: "▼",
|
|
59
|
-
},
|
|
60
|
-
{
|
|
61
|
-
name: "ASCII",
|
|
62
|
-
track_symbol: "|",
|
|
63
|
-
thumb_symbol: "#",
|
|
64
|
-
track_style: { fg: "white" },
|
|
65
|
-
thumb_style: { fg: "red" },
|
|
66
|
-
begin_symbol: "^",
|
|
67
|
-
end_symbol: "v",
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
name: "Minimal",
|
|
71
|
-
track_symbol: " ",
|
|
72
|
-
thumb_symbol: "▐",
|
|
73
|
-
track_style: nil,
|
|
74
|
-
thumb_style: { fg: "yellow" },
|
|
75
|
-
begin_symbol: nil,
|
|
76
|
-
end_symbol: nil,
|
|
77
|
-
},
|
|
78
|
-
]
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def run
|
|
82
|
-
RatatuiRuby.run do |tui|
|
|
83
|
-
@tui = tui
|
|
84
|
-
loop do
|
|
85
|
-
draw
|
|
86
|
-
event = @tui.poll_event
|
|
87
|
-
break if event == "q" || event == :ctrl_c
|
|
88
|
-
|
|
89
|
-
handle_event(event)
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
private def handle_event(event)
|
|
95
|
-
if event.mouse?
|
|
96
|
-
case event.kind
|
|
97
|
-
when "scroll_up"
|
|
98
|
-
@scroll_position = [@scroll_position - 1, 0].max
|
|
99
|
-
when "scroll_down"
|
|
100
|
-
@scroll_position = [@scroll_position + 1, @content_length].min
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
if event.key? && event.to_s == "s"
|
|
105
|
-
@theme_index = (@theme_index + 1) % @themes.length
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
if event.key? && event.to_s == "o"
|
|
109
|
-
@orientation_index = (@orientation_index + 1) % @orientations.length
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
private def draw
|
|
114
|
-
@tui.draw do |frame|
|
|
115
|
-
# Calculate visible lines based on scroll position
|
|
116
|
-
# In a real app, you'd want to know the height of the available area.
|
|
117
|
-
# For this demo, we'll just show all lines but offset the text.
|
|
118
|
-
visible_lines = @lines[@scroll_position..-1] || []
|
|
119
|
-
|
|
120
|
-
# Paragraph with content
|
|
121
|
-
theme = @themes[@theme_index]
|
|
122
|
-
orientation = @orientations[@orientation_index]
|
|
123
|
-
|
|
124
|
-
p = @tui.paragraph(
|
|
125
|
-
text: visible_lines.join("\n"),
|
|
126
|
-
block: @tui.block(
|
|
127
|
-
titles: [
|
|
128
|
-
{ content: "Scroll with Mouse Wheel | Theme: #{theme[:name]} | Orientation: #{orientation}" },
|
|
129
|
-
{ content: "Press 's' to cycle theme, 'o' to cycle orientation", position: :bottom, alignment: :center },
|
|
130
|
-
],
|
|
131
|
-
borders: [:all]
|
|
132
|
-
)
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
# Scrollbar
|
|
136
|
-
s = @tui.scrollbar(
|
|
137
|
-
content_length: @content_length,
|
|
138
|
-
position: @scroll_position,
|
|
139
|
-
orientation:,
|
|
140
|
-
track_symbol: theme[:track_symbol],
|
|
141
|
-
thumb_symbol: theme[:thumb_symbol],
|
|
142
|
-
track_style: theme[:track_style],
|
|
143
|
-
thumb_style: theme[:thumb_style],
|
|
144
|
-
begin_symbol: theme[:begin_symbol],
|
|
145
|
-
end_symbol: theme[:end_symbol]
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
# Render paragraph first, then scrollbar on top
|
|
149
|
-
frame.render_widget(p, frame.area)
|
|
150
|
-
frame.render_widget(s, frame.area)
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
WidgetScrollbar.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Sparkline Widget Example
|
|
7
|
-
|
|
8
|
-
[](app.rb)
|
|
9
|
-
|
|
10
|
-
Demonstrates high-density data visualization in a condensed footprint.
|
|
11
|
-
|
|
12
|
-
Users need context. A single number ("90% CPU") tells you status, but not the trend. Full charts take up too much space. Sparklines condense history into a single line, perfect for headers and dashboards.
|
|
13
|
-
|
|
14
|
-
## Features Demonstrated
|
|
15
|
-
|
|
16
|
-
- **High Density**: Showing dozens of data points in a small area.
|
|
17
|
-
- **Direction**: Rendering Left-to-Right (standard) or Right-to-Left (like a scrolling ticker).
|
|
18
|
-
- **Gaps**: Handling `nil` values with "absent symbols" to indicate missing data.
|
|
19
|
-
- **Styling**: Using colors and custom characters to indicate severity or type.
|
|
20
|
-
|
|
21
|
-
## Hotkeys
|
|
22
|
-
|
|
23
|
-
- **Up/Down (↑/↓)**: Cycle Data Set (`data`)
|
|
24
|
-
- **d**: Cycle Direction (`direction`)
|
|
25
|
-
- **c**: Cycle Color (`style`)
|
|
26
|
-
- **m**: Cycle Absent Value Marker Symbol (`absent_value_symbol`)
|
|
27
|
-
- **s**: Cycle Absent Value Marker Style (`absent_value_style`)
|
|
28
|
-
- **b**: Cycle Bar Character Set (`bar_set`)
|
|
29
|
-
- **q**: Quit
|
|
30
|
-
|
|
31
|
-
## Usage
|
|
32
|
-
|
|
33
|
-
<!-- SPDX-SnippetBegin -->
|
|
34
|
-
<!--
|
|
35
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
36
|
-
SPDX-License-Identifier: MIT-0
|
|
37
|
-
-->
|
|
38
|
-
```bash
|
|
39
|
-
ruby examples/widget_sparkline/app.rb
|
|
40
|
-
```
|
|
41
|
-
<!-- SPDX-SnippetEnd -->
|
|
42
|
-
|
|
43
|
-
## Learning Outcomes
|
|
44
|
-
|
|
45
|
-
Use this example if you need to...
|
|
46
|
-
|
|
47
|
-
- Add a "CPU Load" graph to your header.
|
|
48
|
-
- Visualize stock price trends in a list row.
|
|
49
|
-
- Monitor memory usage over the last 60 seconds.
|
|
50
|
-
|
|
51
|
-
[Read the source code →](app.rb)
|
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: MIT-0
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
9
|
-
require "ratatui_ruby"
|
|
10
|
-
|
|
11
|
-
# Demonstrates high-density data visualization with interactive attribute cycling.
|
|
12
|
-
#
|
|
13
|
-
# Users need context. A single value ("90% CPU") tells you current status, but not the trend. Full charts take up too much room.
|
|
14
|
-
#
|
|
15
|
-
# This demo showcases the <tt>Sparkline</tt> widget. It provides an interactive playground where you can cycle through data sets, directions, colors, and custom bar sets.
|
|
16
|
-
#
|
|
17
|
-
# Use it to understand how to condense history into a single line for dashboards or headers.
|
|
18
|
-
#
|
|
19
|
-
# === Example
|
|
20
|
-
#
|
|
21
|
-
# Run the demo from the terminal:
|
|
22
|
-
#
|
|
23
|
-
# ruby examples/widget_sparkline/app.rb
|
|
24
|
-
#
|
|
25
|
-
# rdoc-image:/doc/images/widget_sparkline.png
|
|
26
|
-
class WidgetSparkline
|
|
27
|
-
def run
|
|
28
|
-
RatatuiRuby.run do |tui|
|
|
29
|
-
@tui = tui
|
|
30
|
-
setup
|
|
31
|
-
loop do
|
|
32
|
-
render
|
|
33
|
-
break if handle_input == :quit
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private def setup
|
|
39
|
-
# Data sets with different characteristics
|
|
40
|
-
@data_sets = [
|
|
41
|
-
{
|
|
42
|
-
name: "Steady Growth",
|
|
43
|
-
data: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: "With Gaps",
|
|
47
|
-
data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil],
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
name: "Random",
|
|
51
|
-
data: [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8],
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: "Sawtooth",
|
|
55
|
-
data: [1, 2, 3, 4, 5, 4, 3, 2, 1, 2, 3, 4],
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
name: "Peaks",
|
|
59
|
-
data: [1, 5, 1, 8, 1, 6, 1, 9, 1, 7, 1, 10],
|
|
60
|
-
},
|
|
61
|
-
]
|
|
62
|
-
@data_index = 2
|
|
63
|
-
srand(12345) # Ensure reproducible "Random" data for snapshots
|
|
64
|
-
|
|
65
|
-
@directions = [
|
|
66
|
-
{ name: "Left to Right", direction: :left_to_right },
|
|
67
|
-
{ name: "Right to Left", direction: :right_to_left },
|
|
68
|
-
]
|
|
69
|
-
@direction_index = 0
|
|
70
|
-
|
|
71
|
-
@styles = [
|
|
72
|
-
{ name: "Green", style: @tui.style(fg: :green) },
|
|
73
|
-
{ name: "Yellow", style: @tui.style(fg: :yellow) },
|
|
74
|
-
{ name: "Red", style: @tui.style(fg: :red) },
|
|
75
|
-
{ name: "Cyan", style: @tui.style(fg: :cyan) },
|
|
76
|
-
{ name: "Magenta", style: @tui.style(fg: :magenta) },
|
|
77
|
-
]
|
|
78
|
-
@style_index = 3
|
|
79
|
-
|
|
80
|
-
@absent_symbols = [
|
|
81
|
-
{ name: "None", symbol: nil },
|
|
82
|
-
{ name: "Dot (·)", symbol: "·" },
|
|
83
|
-
{ name: "Square (▫)", symbol: "▫" },
|
|
84
|
-
{ name: "Dash (-)", symbol: "-" },
|
|
85
|
-
{ name: "Underscore (_)", symbol: "_" },
|
|
86
|
-
]
|
|
87
|
-
@absent_symbol_index = 1
|
|
88
|
-
|
|
89
|
-
@absent_styles = [
|
|
90
|
-
{ name: "Default", style: nil },
|
|
91
|
-
{ name: "Dark Gray", style: @tui.style(fg: :dark_gray) },
|
|
92
|
-
{ name: "Dim Red", style: @tui.style(fg: :red, modifiers: [:dim]) },
|
|
93
|
-
{ name: "Dim Yellow", style: @tui.style(fg: :yellow, modifiers: [:dim]) },
|
|
94
|
-
]
|
|
95
|
-
@absent_style_index = 2
|
|
96
|
-
|
|
97
|
-
@bar_sets = [
|
|
98
|
-
{ name: "Default (Block)", set: nil },
|
|
99
|
-
{
|
|
100
|
-
name: "Numbers (0-8)",
|
|
101
|
-
set: {
|
|
102
|
-
0 => "0", 1 => "1", 2 => "2", 3 => "3", 4 => "4", 5 => "5", 6 => "6", 7 => "7", 8 => "8"
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
{ name: "ASCII (Heights)", set: [" ", "_", ".", "-", "=", "+", "*", "#", "@"] },
|
|
106
|
-
]
|
|
107
|
-
@bar_set_index = 0
|
|
108
|
-
|
|
109
|
-
@hotkey_style = @tui.style(modifiers: [:bold, :underlined])
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
private def render
|
|
113
|
-
@tui.draw do |frame|
|
|
114
|
-
data_set = @data_sets[@data_index]
|
|
115
|
-
direction = @directions[@direction_index][:direction]
|
|
116
|
-
style = @styles[@style_index][:style]
|
|
117
|
-
absent_symbol = @absent_symbols[@absent_symbol_index][:symbol]
|
|
118
|
-
absent_value_style = @absent_styles[@absent_style_index][:style]
|
|
119
|
-
bar_set = @bar_sets[@bar_set_index][:set]
|
|
120
|
-
|
|
121
|
-
# Use static data for clarity when cycling options
|
|
122
|
-
current_data = data_set[:data]
|
|
123
|
-
|
|
124
|
-
layout = @tui.layout_split(
|
|
125
|
-
frame.area,
|
|
126
|
-
direction: :vertical,
|
|
127
|
-
constraints: [
|
|
128
|
-
@tui.constraint_fill(1),
|
|
129
|
-
@tui.constraint_length(6),
|
|
130
|
-
]
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
# Main content area with multiple sparkline examples
|
|
134
|
-
main_content_area = layout[0]
|
|
135
|
-
main_layout = @tui.layout_split(
|
|
136
|
-
main_content_area,
|
|
137
|
-
direction: :vertical,
|
|
138
|
-
constraints: [
|
|
139
|
-
@tui.constraint_length(1),
|
|
140
|
-
@tui.constraint_length(3),
|
|
141
|
-
@tui.constraint_length(3),
|
|
142
|
-
@tui.constraint_length(3),
|
|
143
|
-
@tui.constraint_length(3),
|
|
144
|
-
@tui.constraint_fill(1),
|
|
145
|
-
]
|
|
146
|
-
)
|
|
147
|
-
|
|
148
|
-
frame.render_widget(
|
|
149
|
-
@tui.paragraph(text: "Sparkline Widget - Cycle attributes with hotkeys"),
|
|
150
|
-
main_layout[0]
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
# Sparkline 1: Main interactive sparkline
|
|
154
|
-
frame.render_widget(
|
|
155
|
-
@tui.sparkline(
|
|
156
|
-
data: current_data,
|
|
157
|
-
direction:,
|
|
158
|
-
style:,
|
|
159
|
-
absent_value_symbol: absent_symbol,
|
|
160
|
-
absent_value_style:,
|
|
161
|
-
bar_set:,
|
|
162
|
-
block: @tui.block(title: "Interactive Sparkline")
|
|
163
|
-
),
|
|
164
|
-
main_layout[1]
|
|
165
|
-
)
|
|
166
|
-
|
|
167
|
-
# Sparkline 2: Same data, opposite direction
|
|
168
|
-
frame.render_widget(
|
|
169
|
-
@tui.sparkline(
|
|
170
|
-
data: current_data.reverse,
|
|
171
|
-
direction:,
|
|
172
|
-
style:,
|
|
173
|
-
absent_value_symbol: absent_symbol,
|
|
174
|
-
absent_value_style:,
|
|
175
|
-
bar_set:,
|
|
176
|
-
block: @tui.block(title: "Reversed Data")
|
|
177
|
-
),
|
|
178
|
-
main_layout[2]
|
|
179
|
-
)
|
|
180
|
-
|
|
181
|
-
# Sparkline 3: Without absent value symbol (for comparison)
|
|
182
|
-
frame.render_widget(
|
|
183
|
-
@tui.sparkline(
|
|
184
|
-
data: current_data,
|
|
185
|
-
direction:,
|
|
186
|
-
style:,
|
|
187
|
-
bar_set:,
|
|
188
|
-
block: @tui.block(title: "Without Absent Marker")
|
|
189
|
-
),
|
|
190
|
-
main_layout[3]
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
# Sparkline 4: Gap pattern responsive to absent marker controls
|
|
194
|
-
frame.render_widget(
|
|
195
|
-
@tui.sparkline(
|
|
196
|
-
data: [5, nil, 8, nil, 6, nil, 9, nil, 7, nil, 10, nil],
|
|
197
|
-
direction:,
|
|
198
|
-
style: @tui.style(fg: :blue),
|
|
199
|
-
absent_value_symbol: absent_symbol,
|
|
200
|
-
absent_value_style:,
|
|
201
|
-
bar_set:,
|
|
202
|
-
block: @tui.block(title: "Gap Pattern (Responsive)")
|
|
203
|
-
),
|
|
204
|
-
main_layout[4]
|
|
205
|
-
)
|
|
206
|
-
|
|
207
|
-
# Bottom control panel
|
|
208
|
-
control_area = layout[1]
|
|
209
|
-
frame.render_widget(
|
|
210
|
-
@tui.block(
|
|
211
|
-
title: "Controls",
|
|
212
|
-
borders: [:all],
|
|
213
|
-
children: [
|
|
214
|
-
@tui.paragraph(
|
|
215
|
-
text: [
|
|
216
|
-
# Line 1: Data
|
|
217
|
-
@tui.text_line(spans: [
|
|
218
|
-
@tui.text_span(content: "↑/↓", style: @hotkey_style),
|
|
219
|
-
@tui.text_span(content: ": Data (#{@data_sets[@data_index][:name]})"),
|
|
220
|
-
]),
|
|
221
|
-
# Line 2: View
|
|
222
|
-
@tui.text_line(spans: [
|
|
223
|
-
@tui.text_span(content: "d", style: @hotkey_style),
|
|
224
|
-
@tui.text_span(content: ": Direction (#{@directions[@direction_index][:name]}) "),
|
|
225
|
-
@tui.text_span(content: "c", style: @hotkey_style),
|
|
226
|
-
@tui.text_span(content: ": Color (#{@styles[@style_index][:name]})"),
|
|
227
|
-
]),
|
|
228
|
-
# Line 3: Markers
|
|
229
|
-
@tui.text_line(spans: [
|
|
230
|
-
@tui.text_span(content: "m", style: @hotkey_style),
|
|
231
|
-
@tui.text_span(content: ": Absent Value Symbol (#{@absent_symbols[@absent_symbol_index][:name]}) "),
|
|
232
|
-
@tui.text_span(content: "s", style: @hotkey_style),
|
|
233
|
-
@tui.text_span(content: ": Absent Value Style (#{@absent_styles[@absent_style_index][:name]})"),
|
|
234
|
-
]),
|
|
235
|
-
# Line 4: General
|
|
236
|
-
@tui.text_line(spans: [
|
|
237
|
-
@tui.text_span(content: "b", style: @hotkey_style),
|
|
238
|
-
@tui.text_span(content: ": Bar Set (#{@bar_sets[@bar_set_index][:name]}) "),
|
|
239
|
-
@tui.text_span(content: "q", style: @hotkey_style),
|
|
240
|
-
@tui.text_span(content: ": Quit"),
|
|
241
|
-
]),
|
|
242
|
-
]
|
|
243
|
-
),
|
|
244
|
-
]
|
|
245
|
-
),
|
|
246
|
-
control_area
|
|
247
|
-
)
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
private def handle_input
|
|
252
|
-
event = @tui.poll_event
|
|
253
|
-
|
|
254
|
-
case event
|
|
255
|
-
in { type: :key, code: "q" } | { type: :key, code: "c", modifiers: ["ctrl"] }
|
|
256
|
-
:quit
|
|
257
|
-
in type: :key, code: "up"
|
|
258
|
-
@data_index = (@data_index - 1) % @data_sets.length
|
|
259
|
-
in type: :key, code: "down"
|
|
260
|
-
@data_index = (@data_index + 1) % @data_sets.length
|
|
261
|
-
in type: :key, code: "d"
|
|
262
|
-
@direction_index = (@direction_index + 1) % @directions.length
|
|
263
|
-
in type: :key, code: "c"
|
|
264
|
-
@style_index = (@style_index + 1) % @styles.length
|
|
265
|
-
in type: :key, code: "m"
|
|
266
|
-
@absent_symbol_index = (@absent_symbol_index + 1) % @absent_symbols.length
|
|
267
|
-
in type: :key, code: "s"
|
|
268
|
-
@absent_style_index = (@absent_style_index + 1) % @absent_styles.length
|
|
269
|
-
in type: :key, code: "b"
|
|
270
|
-
@bar_set_index = (@bar_set_index + 1) % @bar_sets.length
|
|
271
|
-
else
|
|
272
|
-
nil
|
|
273
|
-
end
|
|
274
|
-
end
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
WidgetSparkline.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Style Colors Example
|
|
7
|
-
|
|
8
|
-
[](app.rb)
|
|
9
|
-
|
|
10
|
-
Demonstrates high-fidelity color support.
|
|
11
|
-
|
|
12
|
-
Terminals support millions of colors. This example generates a mathematically precise HSL gradient to prove the rendering engine's color fidelity.
|
|
13
|
-
|
|
14
|
-
## Features Demonstrated
|
|
15
|
-
|
|
16
|
-
- **HSL to RGB Conversion**: generating smooth color gradients programmatically.
|
|
17
|
-
- **TrueColor Support**: Rendering arbitrary HEX colors.
|
|
18
|
-
|
|
19
|
-
## Hotkeys
|
|
20
|
-
|
|
21
|
-
- **q** / **Ctrl+c**: Quit
|
|
22
|
-
|
|
23
|
-
## Usage
|
|
24
|
-
|
|
25
|
-
<!-- SPDX-SnippetBegin -->
|
|
26
|
-
<!--
|
|
27
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
28
|
-
SPDX-License-Identifier: MIT-0
|
|
29
|
-
-->
|
|
30
|
-
```bash
|
|
31
|
-
ruby examples/widget_style_colors/app.rb
|
|
32
|
-
```
|
|
33
|
-
<!-- SPDX-SnippetEnd -->
|
|
34
|
-
|
|
35
|
-
## Learning Outcomes
|
|
36
|
-
|
|
37
|
-
Use this example if you need to...
|
|
38
|
-
|
|
39
|
-
- Create meaningful heatmaps.
|
|
40
|
-
- Generate color palettes dynamically.
|
|
41
|
-
- Test your terminal's color support capabilities.
|
|
42
|
-
|
|
43
|
-
[Read the source code →](app.rb)
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
#--
|
|
4
|
-
# SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
5
|
-
# SPDX-License-Identifier: MIT-0
|
|
6
|
-
#++
|
|
7
|
-
|
|
8
|
-
$LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
|
|
9
|
-
require "ratatui_ruby"
|
|
10
|
-
|
|
11
|
-
# Demonstrates terminal color rendering and the Color module.
|
|
12
|
-
#
|
|
13
|
-
# Terminal apps need vibrant colors. Specifying colors as symbols or
|
|
14
|
-
# calculated hex strings works but limits expressiveness.
|
|
15
|
-
#
|
|
16
|
-
# This demo shows the Color module's constructors for creating colors
|
|
17
|
-
# from HSL values or hex integers, producing a full-spectrum gradient.
|
|
18
|
-
#
|
|
19
|
-
# Use it to understand color representation and the Color.hsl/Color.hex APIs.
|
|
20
|
-
class WidgetStyleColors
|
|
21
|
-
def initialize
|
|
22
|
-
@width = 80
|
|
23
|
-
@height = 24
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def run
|
|
27
|
-
RatatuiRuby.run do |tui|
|
|
28
|
-
loop do
|
|
29
|
-
tui.draw do |frame|
|
|
30
|
-
frame.render_widget(render(tui), frame.area)
|
|
31
|
-
end
|
|
32
|
-
event = tui.poll_event
|
|
33
|
-
break if event.key? && (event.ctrl_c? || event == :q)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private def render(tui)
|
|
39
|
-
lines = []
|
|
40
|
-
|
|
41
|
-
(0...@height).each do |row|
|
|
42
|
-
spans = []
|
|
43
|
-
(0...@width).each do |col|
|
|
44
|
-
hue = (col.to_f / @width) * 360.0
|
|
45
|
-
lightness = 50.0 - ((row.to_f / @height) * 50.0)
|
|
46
|
-
|
|
47
|
-
# Use Color.hsl for top half, Color.hsluv for bottom half
|
|
48
|
-
# HSLuv provides perceptually uniform colors (same visual brightness)
|
|
49
|
-
hex = if row < @height / 2
|
|
50
|
-
RatatuiRuby::Style::Color.hsl(hue, 100.0, lightness)
|
|
51
|
-
else
|
|
52
|
-
# HSLuv: perceptually uniform - all colors appear equal brightness
|
|
53
|
-
RatatuiRuby::Style::Color.hsluv(hue, 100.0, lightness)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
# Demonstrate Style.with for concise inline styling
|
|
57
|
-
span = tui.text_span(
|
|
58
|
-
content: " ",
|
|
59
|
-
style: RatatuiRuby::Style::Style.with(bg: hex)
|
|
60
|
-
)
|
|
61
|
-
spans << span
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
lines << tui.text_line(spans:)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
# Also demonstrate Color.hex for the border
|
|
68
|
-
border_color = RatatuiRuby::Style::Color.hex(0xFFD700) # Gold
|
|
69
|
-
|
|
70
|
-
tui.paragraph(
|
|
71
|
-
text: lines,
|
|
72
|
-
block: tui.block(
|
|
73
|
-
title: "HSL (top) vs HSLuv (bottom) - Style.with demo (Press 'q' to exit)",
|
|
74
|
-
borders: [:all],
|
|
75
|
-
border_type: :rounded,
|
|
76
|
-
# Using Style.with for concise border styling
|
|
77
|
-
border_style: RatatuiRuby::Style::Style.with(fg: border_color)
|
|
78
|
-
)
|
|
79
|
-
)
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
WidgetStyleColors.new.run if __FILE__ == $PROGRAM_NAME
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
|
|
3
|
-
SPDX-License-Identifier: CC-BY-SA-4.0
|
|
4
|
-
-->
|
|
5
|
-
|
|
6
|
-
# Table (Row, Cell) Example
|
|
7
|
-
|
|
8
|
-
[](app.rb)
|
|
9
|
-
|
|
10
|
-
Demonstrates advanced options for the `Table` widget, including selection, row-level highlighting, and column-level highlighting.
|
|
11
|
-
|
|
12
|
-
Data grids are complex. Users expect to navigate them with keys, select rows, and clearly see which cell is active. The `Table` widget provides these features out of the box efficiently.
|
|
13
|
-
|
|
14
|
-
## Features Demonstrated
|
|
15
|
-
|
|
16
|
-
- **Selection State**: Managing `selected_row` and `selected_column` to track user focus.
|
|
17
|
-
- **Complex Highlighting**:
|
|
18
|
-
- **Row**: Highlight the entire active row.
|
|
19
|
-
- **Highlight Symbol:** Adding a visual indicator (like `> `) to the selected row.
|
|
20
|
-
- **Spacing:** Adjusting `column_spacing` and `highlight_spacing` to control layout density.
|
|
21
|
-
- **Flex Layout:** Switching between different column distribution modes (`legacy`, `start`, `space_between`, etc.).
|
|
22
|
-
- **Offset Control:** Manually controlling the scroll position using `offset`.
|
|
23
|
-
|
|
24
|
-
## Hotkeys
|
|
25
|
-
|
|
26
|
-
- **Arrows (↑/↓)**: Navigate Rows (`selected_row`)
|
|
27
|
-
- **Arrows (←/→)**: Navigate Columns (`selected_column`)
|
|
28
|
-
- **x**: Toggle Row Selection (`selected_row` = nil)
|
|
29
|
-
- **s**: Cycle Table Style (`style`)
|
|
30
|
-
- **p**: Cycle Spacing (`highlight_spacing`)
|
|
31
|
-
- **c**: Toggle Column Highlight (`column_highlight_style`)
|
|
32
|
-
- **z**: Toggle Cell Highlight (`cell_highlight_style`)
|
|
33
|
-
- **o**: Cycle Offset Mode (`offset`)
|
|
34
|
-
- **f**: Cycle Flex Mode (`flex`)
|
|
35
|
-
- **q**: Quit
|
|
36
|
-
|
|
37
|
-
## Usage
|
|
38
|
-
|
|
39
|
-
<!-- SPDX-SnippetBegin -->
|
|
40
|
-
<!--
|
|
41
|
-
SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
42
|
-
SPDX-License-Identifier: MIT-0
|
|
43
|
-
-->
|
|
44
|
-
```bash
|
|
45
|
-
ruby examples/widget_table/app.rb
|
|
46
|
-
```
|
|
47
|
-
<!-- SPDX-SnippetEnd -->
|
|
48
|
-
|
|
49
|
-
## Learning Outcomes
|
|
50
|
-
|
|
51
|
-
Use this example if you need to...
|
|
52
|
-
|
|
53
|
-
- Build a file explorer or process list.
|
|
54
|
-
- Create a data-heavy dashboard.
|
|
55
|
-
- Handle conflicting style requirements (e.g., "Highlight this row, but make this error cell red").
|
|
56
|
-
|
|
57
|
-
[Read the source code →](app.rb)
|