ratatui_ruby 0.1.0 → 0.3.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 +4 -4
- data/.builds/ruby-3.2.yml +52 -0
- data/.builds/ruby-3.3.yml +52 -0
- data/.builds/ruby-3.4.yml +52 -0
- data/.builds/ruby-4.0.0.yml +53 -0
- data/.pre-commit-config.yaml +9 -2
- data/AGENTS.md +53 -5
- data/CHANGELOG.md +51 -1
- data/README.md +38 -18
- data/REUSE.toml +5 -0
- data/Rakefile +3 -100
- data/{docs → doc}/contributors/index.md +2 -1
- data/doc/custom.css +8 -0
- data/doc/images/examples-calendar_demo.rb.png +0 -0
- data/doc/images/examples-chart_demo.rb.png +0 -0
- data/doc/images/examples-custom_widget.rb.png +0 -0
- data/doc/images/examples-list_styles.rb.png +0 -0
- data/doc/images/examples-popup_demo.rb.gif +0 -0
- data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
- data/doc/images/examples-scroll_text.rb.png +0 -0
- data/doc/images/examples-stock_ticker.rb.png +0 -0
- data/doc/images/examples-table_select.rb.png +0 -0
- data/{docs → doc}/index.md +1 -1
- data/{docs → doc}/quickstart.md +81 -11
- data/examples/analytics.rb +2 -1
- data/examples/calendar_demo.rb +55 -0
- data/examples/chart_demo.rb +84 -0
- data/examples/custom_widget.rb +43 -0
- data/examples/list_styles.rb +66 -0
- data/examples/login_form.rb +2 -1
- data/examples/popup_demo.rb +105 -0
- data/examples/quickstart_dsl.rb +30 -0
- data/examples/quickstart_lifecycle.rb +40 -0
- data/examples/readme_usage.rb +21 -0
- data/examples/scroll_text.rb +74 -0
- data/examples/stock_ticker.rb +13 -5
- data/examples/system_monitor.rb +2 -1
- data/examples/table_select.rb +70 -0
- data/examples/test_calendar_demo.rb +66 -0
- data/examples/test_list_styles.rb +61 -0
- data/examples/test_popup_demo.rb +62 -0
- data/examples/test_scroll_text.rb +130 -0
- data/examples/test_table_select.rb +37 -0
- data/ext/ratatui_ruby/.cargo/config.toml +5 -0
- data/ext/ratatui_ruby/Cargo.lock +260 -50
- data/ext/ratatui_ruby/Cargo.toml +5 -4
- data/ext/ratatui_ruby/extconf.rb +1 -1
- data/ext/ratatui_ruby/src/buffer.rs +54 -0
- data/ext/ratatui_ruby/src/events.rs +115 -107
- data/ext/ratatui_ruby/src/lib.rs +15 -6
- data/ext/ratatui_ruby/src/rendering.rs +18 -1
- data/ext/ratatui_ruby/src/style.rs +2 -1
- data/ext/ratatui_ruby/src/terminal.rs +27 -24
- data/ext/ratatui_ruby/src/widgets/calendar.rs +82 -0
- data/ext/ratatui_ruby/src/widgets/canvas.rs +1 -2
- data/ext/ratatui_ruby/src/widgets/center.rs +0 -2
- data/ext/ratatui_ruby/src/widgets/chart.rs +260 -0
- data/ext/ratatui_ruby/src/widgets/clear.rs +37 -0
- data/ext/ratatui_ruby/src/widgets/cursor.rs +1 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/list.rs +44 -5
- data/ext/ratatui_ruby/src/widgets/mod.rs +3 -1
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +10 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +25 -6
- data/ext/ratatui_ruby/src/widgets/tabs.rs +2 -1
- data/lib/ratatui_ruby/dsl.rb +64 -0
- data/lib/ratatui_ruby/schema/calendar.rb +26 -0
- data/lib/ratatui_ruby/schema/chart.rb +81 -0
- data/lib/ratatui_ruby/schema/clear.rb +83 -0
- data/lib/ratatui_ruby/schema/list.rb +8 -2
- data/lib/ratatui_ruby/schema/paragraph.rb +7 -4
- data/lib/ratatui_ruby/schema/rect.rb +24 -0
- data/lib/ratatui_ruby/schema/table.rb +8 -2
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby.rb +24 -2
- data/mise.toml +8 -0
- data/sig/ratatui_ruby/buffer.rbs +11 -0
- data/sig/ratatui_ruby/schema/calendar.rbs +13 -0
- data/sig/ratatui_ruby/schema/{line_chart.rbs → chart.rbs} +20 -1
- data/sig/ratatui_ruby/schema/list.rbs +4 -1
- data/sig/ratatui_ruby/schema/rect.rbs +14 -0
- data/tasks/bump/cargo_lockfile.rb +19 -0
- data/tasks/bump/changelog.rb +37 -0
- data/tasks/bump/comparison_links.rb +41 -0
- data/tasks/bump/header.rb +30 -0
- data/tasks/bump/history.rb +30 -0
- data/tasks/bump/manifest.rb +31 -0
- data/tasks/bump/ruby_gem.rb +35 -0
- data/tasks/bump/sem_ver.rb +34 -0
- data/tasks/bump/unreleased_section.rb +38 -0
- data/tasks/bump.rake +49 -0
- data/tasks/doc.rake +25 -0
- data/tasks/extension.rake +12 -0
- data/tasks/lint.rake +49 -0
- data/tasks/rdoc_config.rb +15 -0
- data/tasks/resources/build.yml.erb +65 -0
- data/tasks/resources/index.html.erb +38 -0
- data/tasks/resources/rubies.yml +7 -0
- data/tasks/sourcehut.rake +38 -0
- data/tasks/test.rake +31 -0
- data/tasks/website/index_page.rb +28 -0
- data/tasks/website/version.rb +117 -0
- data/tasks/website/version_menu.rb +68 -0
- data/tasks/website/versioned_documentation.rb +49 -0
- data/tasks/website/website.rb +53 -0
- data/tasks/website.rake +26 -0
- metadata +119 -28
- data/.build.yml +0 -34
- data/.ruby-version +0 -1
- data/CODE_OF_CONDUCT.md +0 -30
- data/CONTRIBUTING.md +0 -40
- data/docs/images/examples-stock_ticker.rb.png +0 -0
- data/ext/ratatui_ruby/src/widgets/linechart.rs +0 -154
- data/lib/ratatui_ruby/schema/line_chart.rb +0 -41
- /data/{docs → doc}/application_testing.md +0 -0
- /data/{docs → doc}/contributors/design/ruby_frontend.md +0 -0
- /data/{docs → doc}/contributors/design/rust_backend.md +0 -0
- /data/{docs → doc}/contributors/design.md +0 -0
- /data/{docs → doc}/images/examples-analytics.rb.png +0 -0
- /data/{docs → doc}/images/examples-box_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-dashboard.rb.png +0 -0
- /data/{docs → doc}/images/examples-login_form.rb.png +0 -0
- /data/{docs → doc}/images/examples-map_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-mouse_events.rb.png +0 -0
- /data/{docs → doc}/images/examples-scrollbar_demo.rb.png +0 -0
- /data/{docs → doc}/images/examples-system_monitor.rb.png +0 -0
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
// SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
-
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
-
|
|
4
|
-
use crate::style::{parse_block, parse_color};
|
|
5
|
-
use magnus::{prelude::*, Error, Value};
|
|
6
|
-
use ratatui::{
|
|
7
|
-
layout::Rect,
|
|
8
|
-
style::{Color, Style},
|
|
9
|
-
symbols,
|
|
10
|
-
widgets::{Chart, Dataset},
|
|
11
|
-
Frame,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
|
|
15
|
-
let datasets_val: magnus::RArray = node.funcall("datasets", ())?;
|
|
16
|
-
let x_labels_val: magnus::RArray = node.funcall("x_labels", ())?;
|
|
17
|
-
let y_labels_val: magnus::RArray = node.funcall("y_labels", ())?;
|
|
18
|
-
let y_bounds_val: magnus::RArray = node.funcall("y_bounds", ())?;
|
|
19
|
-
let block_val: Value = node.funcall("block", ())?;
|
|
20
|
-
|
|
21
|
-
let mut datasets = Vec::new();
|
|
22
|
-
// We need to keep the data alive until the chart is rendered
|
|
23
|
-
let mut data_storage: Vec<Vec<(f64, f64)>> = Vec::new();
|
|
24
|
-
let mut name_storage: Vec<String> = Vec::new();
|
|
25
|
-
|
|
26
|
-
for i in 0..datasets_val.len() {
|
|
27
|
-
let ds_val: Value = datasets_val.entry(i as isize)?;
|
|
28
|
-
let name: String = ds_val.funcall("name", ())?;
|
|
29
|
-
let data_array: magnus::RArray = ds_val.funcall("data", ())?;
|
|
30
|
-
|
|
31
|
-
let mut points = Vec::new();
|
|
32
|
-
for j in 0..data_array.len() {
|
|
33
|
-
let point_array_val: Value = data_array.entry(j as isize)?;
|
|
34
|
-
let point_array = magnus::RArray::from_value(point_array_val).ok_or_else(|| {
|
|
35
|
-
Error::new(magnus::exception::type_error(), "expected array for point")
|
|
36
|
-
})?;
|
|
37
|
-
let x_val: Value = point_array.entry(0)?;
|
|
38
|
-
let y_val: Value = point_array.entry(1)?;
|
|
39
|
-
|
|
40
|
-
let x: f64 = x_val.funcall("to_f", ())?;
|
|
41
|
-
let y: f64 = y_val.funcall("to_f", ())?;
|
|
42
|
-
points.push((x, y));
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
data_storage.push(points);
|
|
46
|
-
name_storage.push(name);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
for i in 0..data_storage.len() {
|
|
50
|
-
let ds_val: Value = datasets_val.entry(i as isize)?;
|
|
51
|
-
let color_val: Value = ds_val.funcall("color", ())?;
|
|
52
|
-
let color_str: String = color_val.funcall("to_s", ())?;
|
|
53
|
-
let color = parse_color(&color_str).unwrap_or(Color::White);
|
|
54
|
-
|
|
55
|
-
let ds = Dataset::default()
|
|
56
|
-
.name(name_storage[i].clone())
|
|
57
|
-
.marker(symbols::Marker::Braille)
|
|
58
|
-
.style(Style::default().fg(color))
|
|
59
|
-
.data(&data_storage[i]);
|
|
60
|
-
datasets.push(ds);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
let mut x_labels = Vec::new();
|
|
64
|
-
for i in 0..x_labels_val.len() {
|
|
65
|
-
let label: String = x_labels_val.entry(i as isize)?;
|
|
66
|
-
x_labels.push(ratatui::text::Span::from(label));
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
let mut y_labels = Vec::new();
|
|
70
|
-
for i in 0..y_labels_val.len() {
|
|
71
|
-
let label: String = y_labels_val.entry(i as isize)?;
|
|
72
|
-
y_labels.push(ratatui::text::Span::from(label));
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
let y_bounds: [f64; 2] = [y_bounds_val.entry(0)?, y_bounds_val.entry(1)?];
|
|
76
|
-
|
|
77
|
-
// Calculate x_bounds based on datasets if possible
|
|
78
|
-
let mut min_x = 0.0;
|
|
79
|
-
let mut max_x = 0.0;
|
|
80
|
-
let mut first = true;
|
|
81
|
-
for ds_data in &data_storage {
|
|
82
|
-
for (x, _) in ds_data {
|
|
83
|
-
if first {
|
|
84
|
-
min_x = *x;
|
|
85
|
-
max_x = *x;
|
|
86
|
-
first = false;
|
|
87
|
-
} else {
|
|
88
|
-
if *x < min_x {
|
|
89
|
-
min_x = *x;
|
|
90
|
-
}
|
|
91
|
-
if *x > max_x {
|
|
92
|
-
max_x = *x;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Ensure there's some range
|
|
99
|
-
if min_x == max_x {
|
|
100
|
-
max_x = min_x + 1.0;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
let x_axis = ratatui::widgets::Axis::default()
|
|
104
|
-
.labels(x_labels)
|
|
105
|
-
.bounds([min_x, max_x]);
|
|
106
|
-
|
|
107
|
-
let y_axis = ratatui::widgets::Axis::default()
|
|
108
|
-
.labels(y_labels)
|
|
109
|
-
.bounds(y_bounds);
|
|
110
|
-
|
|
111
|
-
let mut chart = Chart::new(datasets).x_axis(x_axis).y_axis(y_axis);
|
|
112
|
-
|
|
113
|
-
if !block_val.is_nil() {
|
|
114
|
-
chart = chart.block(parse_block(block_val)?);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
frame.render_widget(chart, area);
|
|
118
|
-
Ok(())
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
#[cfg(test)]
|
|
122
|
-
mod tests {
|
|
123
|
-
use super::*;
|
|
124
|
-
use ratatui::buffer::Buffer;
|
|
125
|
-
use ratatui::widgets::{Axis, Chart, Dataset, Widget};
|
|
126
|
-
|
|
127
|
-
#[test]
|
|
128
|
-
fn test_linechart_rendering() {
|
|
129
|
-
let data = vec![(0.0, 0.0), (1.0, 1.0)];
|
|
130
|
-
let datasets = vec![Dataset::default().name("TestDS").data(&data)];
|
|
131
|
-
let chart = Chart::new(datasets)
|
|
132
|
-
.x_axis(
|
|
133
|
-
Axis::default()
|
|
134
|
-
.bounds([0.0, 1.0])
|
|
135
|
-
.labels(vec!["XMIN".into(), "XMAX".into()]),
|
|
136
|
-
)
|
|
137
|
-
.y_axis(
|
|
138
|
-
Axis::default()
|
|
139
|
-
.bounds([0.0, 1.0])
|
|
140
|
-
.labels(vec!["YMIN".into(), "YMAX".into()]),
|
|
141
|
-
);
|
|
142
|
-
let mut buf = Buffer::empty(Rect::new(0, 0, 40, 20)); // Larger buffer
|
|
143
|
-
chart.render(Rect::new(0, 0, 40, 20), &mut buf);
|
|
144
|
-
// Should have chart rendered (braille characters)
|
|
145
|
-
assert!(buf.content().iter().any(|c| c.symbol() != " "));
|
|
146
|
-
// Should have labels
|
|
147
|
-
let content = buf.content().iter().map(|c| c.symbol()).collect::<String>();
|
|
148
|
-
assert!(content.contains("XMIN"));
|
|
149
|
-
assert!(content.contains("XMAX"));
|
|
150
|
-
assert!(content.contains("YMIN"));
|
|
151
|
-
assert!(content.contains("YMAX"));
|
|
152
|
-
assert!(content.contains("TestDS"));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
# SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
4
|
-
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
-
|
|
6
|
-
module RatatuiRuby
|
|
7
|
-
# A single line on a chart.
|
|
8
|
-
#
|
|
9
|
-
# [name] The name of the dataset.
|
|
10
|
-
# [data] Array of arrays [[x, y], [x, y]] (Floats).
|
|
11
|
-
# [color] The color of the line.
|
|
12
|
-
class Dataset < Data.define(:name, :data, :color)
|
|
13
|
-
# Creates a new Dataset.
|
|
14
|
-
# [name] The name of the dataset.
|
|
15
|
-
# [data] Array of arrays [[x, y], [x, y]] (Floats).
|
|
16
|
-
# [color] The color of the line.
|
|
17
|
-
def initialize(name:, data:, color: "white")
|
|
18
|
-
super
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
# A complex chart widget.
|
|
23
|
-
#
|
|
24
|
-
# [datasets] Array of Dataset objects.
|
|
25
|
-
# [x_labels] Array of Strings for the X-axis labels.
|
|
26
|
-
# [y_labels] Array of Strings for the Y-axis labels.
|
|
27
|
-
# [y_bounds] Array of two Floats [min, max] for the Y-axis.
|
|
28
|
-
# [block] Optional block widget to wrap the chart.
|
|
29
|
-
class LineChart < Data.define(:datasets, :x_labels, :y_labels, :y_bounds, :block)
|
|
30
|
-
# Creates a new LineChart widget.
|
|
31
|
-
#
|
|
32
|
-
# [datasets] Array of Dataset objects.
|
|
33
|
-
# [x_labels] Array of Strings for the X-axis labels.
|
|
34
|
-
# [y_labels] Array of Strings for the Y-axis labels.
|
|
35
|
-
# [y_bounds] Array of two Floats [min, max] for the Y-axis.
|
|
36
|
-
# [block] Optional block widget to wrap the chart.
|
|
37
|
-
def initialize(datasets:, x_labels: [], y_labels: [], y_bounds: [0.0, 100.0], block: nil)
|
|
38
|
-
super
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|