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.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.builds/ruby-3.2.yml +52 -0
  3. data/.builds/ruby-3.3.yml +52 -0
  4. data/.builds/ruby-3.4.yml +52 -0
  5. data/.builds/ruby-4.0.0.yml +53 -0
  6. data/.pre-commit-config.yaml +9 -2
  7. data/AGENTS.md +53 -5
  8. data/CHANGELOG.md +51 -1
  9. data/README.md +38 -18
  10. data/REUSE.toml +5 -0
  11. data/Rakefile +3 -100
  12. data/{docs → doc}/contributors/index.md +2 -1
  13. data/doc/custom.css +8 -0
  14. data/doc/images/examples-calendar_demo.rb.png +0 -0
  15. data/doc/images/examples-chart_demo.rb.png +0 -0
  16. data/doc/images/examples-custom_widget.rb.png +0 -0
  17. data/doc/images/examples-list_styles.rb.png +0 -0
  18. data/doc/images/examples-popup_demo.rb.gif +0 -0
  19. data/doc/images/examples-quickstart_lifecycle.rb.png +0 -0
  20. data/doc/images/examples-scroll_text.rb.png +0 -0
  21. data/doc/images/examples-stock_ticker.rb.png +0 -0
  22. data/doc/images/examples-table_select.rb.png +0 -0
  23. data/{docs → doc}/index.md +1 -1
  24. data/{docs → doc}/quickstart.md +81 -11
  25. data/examples/analytics.rb +2 -1
  26. data/examples/calendar_demo.rb +55 -0
  27. data/examples/chart_demo.rb +84 -0
  28. data/examples/custom_widget.rb +43 -0
  29. data/examples/list_styles.rb +66 -0
  30. data/examples/login_form.rb +2 -1
  31. data/examples/popup_demo.rb +105 -0
  32. data/examples/quickstart_dsl.rb +30 -0
  33. data/examples/quickstart_lifecycle.rb +40 -0
  34. data/examples/readme_usage.rb +21 -0
  35. data/examples/scroll_text.rb +74 -0
  36. data/examples/stock_ticker.rb +13 -5
  37. data/examples/system_monitor.rb +2 -1
  38. data/examples/table_select.rb +70 -0
  39. data/examples/test_calendar_demo.rb +66 -0
  40. data/examples/test_list_styles.rb +61 -0
  41. data/examples/test_popup_demo.rb +62 -0
  42. data/examples/test_scroll_text.rb +130 -0
  43. data/examples/test_table_select.rb +37 -0
  44. data/ext/ratatui_ruby/.cargo/config.toml +5 -0
  45. data/ext/ratatui_ruby/Cargo.lock +260 -50
  46. data/ext/ratatui_ruby/Cargo.toml +5 -4
  47. data/ext/ratatui_ruby/extconf.rb +1 -1
  48. data/ext/ratatui_ruby/src/buffer.rs +54 -0
  49. data/ext/ratatui_ruby/src/events.rs +115 -107
  50. data/ext/ratatui_ruby/src/lib.rs +15 -6
  51. data/ext/ratatui_ruby/src/rendering.rs +18 -1
  52. data/ext/ratatui_ruby/src/style.rs +2 -1
  53. data/ext/ratatui_ruby/src/terminal.rs +27 -24
  54. data/ext/ratatui_ruby/src/widgets/calendar.rs +82 -0
  55. data/ext/ratatui_ruby/src/widgets/canvas.rs +1 -2
  56. data/ext/ratatui_ruby/src/widgets/center.rs +0 -2
  57. data/ext/ratatui_ruby/src/widgets/chart.rs +260 -0
  58. data/ext/ratatui_ruby/src/widgets/clear.rs +37 -0
  59. data/ext/ratatui_ruby/src/widgets/cursor.rs +1 -1
  60. data/ext/ratatui_ruby/src/widgets/layout.rs +2 -1
  61. data/ext/ratatui_ruby/src/widgets/list.rs +44 -5
  62. data/ext/ratatui_ruby/src/widgets/mod.rs +3 -1
  63. data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
  64. data/ext/ratatui_ruby/src/widgets/paragraph.rs +10 -0
  65. data/ext/ratatui_ruby/src/widgets/table.rs +25 -6
  66. data/ext/ratatui_ruby/src/widgets/tabs.rs +2 -1
  67. data/lib/ratatui_ruby/dsl.rb +64 -0
  68. data/lib/ratatui_ruby/schema/calendar.rb +26 -0
  69. data/lib/ratatui_ruby/schema/chart.rb +81 -0
  70. data/lib/ratatui_ruby/schema/clear.rb +83 -0
  71. data/lib/ratatui_ruby/schema/list.rb +8 -2
  72. data/lib/ratatui_ruby/schema/paragraph.rb +7 -4
  73. data/lib/ratatui_ruby/schema/rect.rb +24 -0
  74. data/lib/ratatui_ruby/schema/table.rb +8 -2
  75. data/lib/ratatui_ruby/version.rb +1 -1
  76. data/lib/ratatui_ruby.rb +24 -2
  77. data/mise.toml +8 -0
  78. data/sig/ratatui_ruby/buffer.rbs +11 -0
  79. data/sig/ratatui_ruby/schema/calendar.rbs +13 -0
  80. data/sig/ratatui_ruby/schema/{line_chart.rbs → chart.rbs} +20 -1
  81. data/sig/ratatui_ruby/schema/list.rbs +4 -1
  82. data/sig/ratatui_ruby/schema/rect.rbs +14 -0
  83. data/tasks/bump/cargo_lockfile.rb +19 -0
  84. data/tasks/bump/changelog.rb +37 -0
  85. data/tasks/bump/comparison_links.rb +41 -0
  86. data/tasks/bump/header.rb +30 -0
  87. data/tasks/bump/history.rb +30 -0
  88. data/tasks/bump/manifest.rb +31 -0
  89. data/tasks/bump/ruby_gem.rb +35 -0
  90. data/tasks/bump/sem_ver.rb +34 -0
  91. data/tasks/bump/unreleased_section.rb +38 -0
  92. data/tasks/bump.rake +49 -0
  93. data/tasks/doc.rake +25 -0
  94. data/tasks/extension.rake +12 -0
  95. data/tasks/lint.rake +49 -0
  96. data/tasks/rdoc_config.rb +15 -0
  97. data/tasks/resources/build.yml.erb +65 -0
  98. data/tasks/resources/index.html.erb +38 -0
  99. data/tasks/resources/rubies.yml +7 -0
  100. data/tasks/sourcehut.rake +38 -0
  101. data/tasks/test.rake +31 -0
  102. data/tasks/website/index_page.rb +28 -0
  103. data/tasks/website/version.rb +117 -0
  104. data/tasks/website/version_menu.rb +68 -0
  105. data/tasks/website/versioned_documentation.rb +49 -0
  106. data/tasks/website/website.rb +53 -0
  107. data/tasks/website.rake +26 -0
  108. metadata +119 -28
  109. data/.build.yml +0 -34
  110. data/.ruby-version +0 -1
  111. data/CODE_OF_CONDUCT.md +0 -30
  112. data/CONTRIBUTING.md +0 -40
  113. data/docs/images/examples-stock_ticker.rb.png +0 -0
  114. data/ext/ratatui_ruby/src/widgets/linechart.rs +0 -154
  115. data/lib/ratatui_ruby/schema/line_chart.rb +0 -41
  116. /data/{docs → doc}/application_testing.md +0 -0
  117. /data/{docs → doc}/contributors/design/ruby_frontend.md +0 -0
  118. /data/{docs → doc}/contributors/design/rust_backend.md +0 -0
  119. /data/{docs → doc}/contributors/design.md +0 -0
  120. /data/{docs → doc}/images/examples-analytics.rb.png +0 -0
  121. /data/{docs → doc}/images/examples-box_demo.rb.png +0 -0
  122. /data/{docs → doc}/images/examples-dashboard.rb.png +0 -0
  123. /data/{docs → doc}/images/examples-login_form.rb.png +0 -0
  124. /data/{docs → doc}/images/examples-map_demo.rb.png +0 -0
  125. /data/{docs → doc}/images/examples-mouse_events.rb.png +0 -0
  126. /data/{docs → doc}/images/examples-scrollbar_demo.rb.png +0 -0
  127. /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