ratatui_ruby 1.4.0-x86_64-linux
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/LICENSE +15 -0
- data/LICENSES/AGPL-3.0-or-later.txt +661 -0
- data/LICENSES/CC-BY-SA-4.0.txt +427 -0
- data/LICENSES/CC0-1.0.txt +121 -0
- data/LICENSES/LGPL-3.0-or-later.txt +304 -0
- data/LICENSES/MIT-0.txt +16 -0
- data/LICENSES/MIT.txt +21 -0
- data/REUSE.toml +42 -0
- data/exe/.gitkeep +0 -0
- data/ext/ratatui_ruby/.cargo/config.toml +13 -0
- data/ext/ratatui_ruby/.gitignore +4 -0
- data/ext/ratatui_ruby/Cargo.lock +1737 -0
- data/ext/ratatui_ruby/Cargo.toml +24 -0
- data/ext/ratatui_ruby/clippy.toml +7 -0
- data/ext/ratatui_ruby/extconf.rb +21 -0
- data/ext/ratatui_ruby/src/color.rs +82 -0
- data/ext/ratatui_ruby/src/errors.rs +28 -0
- data/ext/ratatui_ruby/src/events.rs +700 -0
- data/ext/ratatui_ruby/src/frame.rs +241 -0
- data/ext/ratatui_ruby/src/lib.rs +343 -0
- data/ext/ratatui_ruby/src/lib_header.rs +11 -0
- data/ext/ratatui_ruby/src/rendering.rs +158 -0
- data/ext/ratatui_ruby/src/string_width.rs +101 -0
- data/ext/ratatui_ruby/src/style.rs +469 -0
- data/ext/ratatui_ruby/src/terminal/capabilities.rs +46 -0
- data/ext/ratatui_ruby/src/terminal/init.rs +233 -0
- data/ext/ratatui_ruby/src/terminal/mod.rs +42 -0
- data/ext/ratatui_ruby/src/terminal/mutations.rs +158 -0
- data/ext/ratatui_ruby/src/terminal/queries.rs +231 -0
- data/ext/ratatui_ruby/src/terminal/query.rs +400 -0
- data/ext/ratatui_ruby/src/terminal/storage.rs +109 -0
- data/ext/ratatui_ruby/src/terminal/wrapper.rs +16 -0
- data/ext/ratatui_ruby/src/text.rs +225 -0
- data/ext/ratatui_ruby/src/widgets/barchart.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/block.rs +41 -0
- data/ext/ratatui_ruby/src/widgets/calendar.rs +84 -0
- data/ext/ratatui_ruby/src/widgets/canvas.rs +183 -0
- data/ext/ratatui_ruby/src/widgets/center.rs +79 -0
- data/ext/ratatui_ruby/src/widgets/chart.rs +222 -0
- data/ext/ratatui_ruby/src/widgets/clear.rs +39 -0
- data/ext/ratatui_ruby/src/widgets/cursor.rs +32 -0
- data/ext/ratatui_ruby/src/widgets/gauge.rs +65 -0
- data/ext/ratatui_ruby/src/widgets/layout.rs +379 -0
- data/ext/ratatui_ruby/src/widgets/line_gauge.rs +100 -0
- data/ext/ratatui_ruby/src/widgets/list.rs +378 -0
- data/ext/ratatui_ruby/src/widgets/list_state.rs +173 -0
- data/ext/ratatui_ruby/src/widgets/mod.rs +26 -0
- data/ext/ratatui_ruby/src/widgets/overlay.rs +24 -0
- data/ext/ratatui_ruby/src/widgets/paragraph.rs +87 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_logo.rs +40 -0
- data/ext/ratatui_ruby/src/widgets/ratatui_mascot.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar.rs +214 -0
- data/ext/ratatui_ruby/src/widgets/scrollbar_state.rs +169 -0
- data/ext/ratatui_ruby/src/widgets/sparkline.rs +127 -0
- data/ext/ratatui_ruby/src/widgets/table.rs +415 -0
- data/ext/ratatui_ruby/src/widgets/table_state.rs +203 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +194 -0
- data/lib/ratatui_ruby/backend/window_size.rb +50 -0
- data/lib/ratatui_ruby/backend.rb +59 -0
- data/lib/ratatui_ruby/buffer/cell.rb +212 -0
- data/lib/ratatui_ruby/buffer.rb +149 -0
- data/lib/ratatui_ruby/cell.rb +208 -0
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/draw.rb +63 -0
- data/lib/ratatui_ruby/event/focus_gained.rb +125 -0
- data/lib/ratatui_ruby/event/focus_lost.rb +127 -0
- data/lib/ratatui_ruby/event/key/character.rb +53 -0
- data/lib/ratatui_ruby/event/key/dwim.rb +301 -0
- data/lib/ratatui_ruby/event/key/media.rb +46 -0
- data/lib/ratatui_ruby/event/key/modifier.rb +107 -0
- data/lib/ratatui_ruby/event/key/navigation.rb +72 -0
- data/lib/ratatui_ruby/event/key/system.rb +47 -0
- data/lib/ratatui_ruby/event/key.rb +479 -0
- data/lib/ratatui_ruby/event/mouse.rb +291 -0
- data/lib/ratatui_ruby/event/none.rb +53 -0
- data/lib/ratatui_ruby/event/paste.rb +130 -0
- data/lib/ratatui_ruby/event/resize.rb +221 -0
- data/lib/ratatui_ruby/event/sync.rb +52 -0
- data/lib/ratatui_ruby/event.rb +163 -0
- data/lib/ratatui_ruby/frame.rb +257 -0
- data/lib/ratatui_ruby/labs/a11y.rb +182 -0
- data/lib/ratatui_ruby/labs/frame_a11y_capture.rb +50 -0
- data/lib/ratatui_ruby/labs.rb +47 -0
- data/lib/ratatui_ruby/layout/alignment.rb +91 -0
- data/lib/ratatui_ruby/layout/constraint.rb +337 -0
- data/lib/ratatui_ruby/layout/layout.rb +258 -0
- data/lib/ratatui_ruby/layout/position.rb +81 -0
- data/lib/ratatui_ruby/layout/rect.rb +733 -0
- data/lib/ratatui_ruby/layout/size.rb +62 -0
- data/lib/ratatui_ruby/layout.rb +29 -0
- data/lib/ratatui_ruby/list_state.rb +201 -0
- data/lib/ratatui_ruby/output_guard.rb +171 -0
- data/lib/ratatui_ruby/ratatui_ruby.so +0 -0
- data/lib/ratatui_ruby/scrollbar_state.rb +122 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +147 -0
- data/lib/ratatui_ruby/style.rb +19 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +106 -0
- data/lib/ratatui_ruby/table_state.rb +251 -0
- data/lib/ratatui_ruby/terminal/capabilities.rb +316 -0
- data/lib/ratatui_ruby/terminal/viewport.rb +80 -0
- data/lib/ratatui_ruby/terminal.rb +66 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +303 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb.bak +197 -0
- data/lib/ratatui_ruby/test_helper/event_injection.rb +241 -0
- data/lib/ratatui_ruby/test_helper/global_state.rb +111 -0
- data/lib/ratatui_ruby/test_helper/snapshot.rb +568 -0
- data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.ansi +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/axis_labels_alignment.txt +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.ansi +5 -0
- data/lib/ratatui_ruby/test_helper/snapshots/barchart_styled_label.txt +5 -0
- data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.ansi +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/chart_rendering.txt +24 -0
- data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/half_block_marker.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_bottom.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_left.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_right.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.ansi +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/legend_position_top.txt +12 -0
- data/lib/ratatui_ruby/test_helper/snapshots/my_snapshot.txt +1 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.ansi +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_axis_title.txt +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.ansi +10 -0
- data/lib/ratatui_ruby/test_helper/snapshots/styled_dataset_name.txt +10 -0
- data/lib/ratatui_ruby/test_helper/style_assertions.rb +449 -0
- data/lib/ratatui_ruby/test_helper/subprocess_timeout.rb +35 -0
- data/lib/ratatui_ruby/test_helper/terminal.rb +187 -0
- data/lib/ratatui_ruby/test_helper/test_doubles.rb +86 -0
- data/lib/ratatui_ruby/test_helper.rb +115 -0
- data/lib/ratatui_ruby/text/line.rb +245 -0
- data/lib/ratatui_ruby/text/span.rb +158 -0
- data/lib/ratatui_ruby/text.rb +99 -0
- data/lib/ratatui_ruby/tui/buffer_factories.rb +22 -0
- data/lib/ratatui_ruby/tui/canvas_factories.rb +149 -0
- data/lib/ratatui_ruby/tui/core.rb +67 -0
- data/lib/ratatui_ruby/tui/layout_factories.rb +153 -0
- data/lib/ratatui_ruby/tui/state_factories.rb +77 -0
- data/lib/ratatui_ruby/tui/style_factories.rb +22 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +86 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +272 -0
- data/lib/ratatui_ruby/tui.rb +106 -0
- data/lib/ratatui_ruby/version.rb +12 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +51 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +29 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +308 -0
- data/lib/ratatui_ruby/widgets/block.rb +266 -0
- data/lib/ratatui_ruby/widgets/calendar.rb +88 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +297 -0
- data/lib/ratatui_ruby/widgets/cell.rb +59 -0
- data/lib/ratatui_ruby/widgets/center.rb +71 -0
- data/lib/ratatui_ruby/widgets/chart.rb +172 -0
- data/lib/ratatui_ruby/widgets/clear.rb +66 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +54 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +146 -0
- data/lib/ratatui_ruby/widgets/line_gauge.rb +158 -0
- data/lib/ratatui_ruby/widgets/list.rb +252 -0
- data/lib/ratatui_ruby/widgets/list_item.rb +55 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +55 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +113 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +35 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +40 -0
- data/lib/ratatui_ruby/widgets/row.rb +123 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +147 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +80 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +153 -0
- data/lib/ratatui_ruby/widgets/table.rb +213 -0
- data/lib/ratatui_ruby/widgets/tabs.rb +91 -0
- data/lib/ratatui_ruby/widgets.rb +43 -0
- data/lib/ratatui_ruby.rb +555 -0
- data/sig/examples/app_all_events/app.rbs +11 -0
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +23 -0
- data/sig/examples/app_all_events/model/timestamp.rbs +11 -0
- data/sig/examples/app_all_events/view/app_view.rbs +8 -0
- data/sig/examples/app_all_events/view/controls_view.rbs +6 -0
- data/sig/examples/app_all_events/view/counts_view.rbs +6 -0
- data/sig/examples/app_all_events/view/live_view.rbs +6 -0
- data/sig/examples/app_all_events/view/log_view.rbs +6 -0
- data/sig/examples/app_all_events/view.rbs +14 -0
- data/sig/examples/app_cli_rich_moments/app.rbs +12 -0
- data/sig/examples/app_color_picker/app.rbs +17 -0
- data/sig/examples/app_external_editor/app.rbs +12 -0
- data/sig/examples/app_login_form/app.rbs +11 -0
- data/sig/examples/app_stateful_interaction/app.rbs +39 -0
- data/sig/examples/verify_quickstart_dsl/app.rbs +17 -0
- data/sig/examples/verify_quickstart_lifecycle/app.rbs +17 -0
- data/sig/examples/verify_readme_usage/app.rbs +17 -0
- data/sig/examples/widget_block_demo/app.rbs +38 -0
- data/sig/examples/widget_box_demo/app.rbs +17 -0
- data/sig/examples/widget_calendar_demo/app.rbs +17 -0
- data/sig/examples/widget_cell_demo/app.rbs +17 -0
- data/sig/examples/widget_chart_demo/app.rbs +17 -0
- data/sig/examples/widget_gauge_demo/app.rbs +17 -0
- data/sig/examples/widget_layout_split/app.rbs +16 -0
- data/sig/examples/widget_line_gauge_demo/app.rbs +17 -0
- data/sig/examples/widget_list_demo/app.rbs +17 -0
- data/sig/examples/widget_map_demo/app.rbs +17 -0
- data/sig/examples/widget_popup_demo/app.rbs +17 -0
- data/sig/examples/widget_ratatui_logo_demo/app.rbs +17 -0
- data/sig/examples/widget_ratatui_mascot_demo/app.rbs +17 -0
- data/sig/examples/widget_rect/app.rbs +18 -0
- data/sig/examples/widget_render/app.rbs +16 -0
- data/sig/examples/widget_rich_text/app.rbs +17 -0
- data/sig/examples/widget_scroll_text/app.rbs +17 -0
- data/sig/examples/widget_scrollbar_demo/app.rbs +17 -0
- data/sig/examples/widget_sparkline_demo/app.rbs +16 -0
- data/sig/examples/widget_style_colors/app.rbs +20 -0
- data/sig/examples/widget_table_demo/app.rbs +17 -0
- data/sig/examples/widget_text_width/app.rbs +16 -0
- data/sig/generated/event_key_predicates.rbs +1348 -0
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -0
- data/sig/ratatui_ruby/backend/window_size.rbs +17 -0
- data/sig/ratatui_ruby/backend.rbs +12 -0
- data/sig/ratatui_ruby/buffer/cell.rbs +46 -0
- data/sig/ratatui_ruby/buffer.rbs +18 -0
- data/sig/ratatui_ruby/cell.rbs +44 -0
- data/sig/ratatui_ruby/clear.rbs +18 -0
- data/sig/ratatui_ruby/constraint.rbs +26 -0
- data/sig/ratatui_ruby/debug.rbs +45 -0
- data/sig/ratatui_ruby/draw.rbs +30 -0
- data/sig/ratatui_ruby/event.rbs +249 -0
- data/sig/ratatui_ruby/frame.rbs +23 -0
- data/sig/ratatui_ruby/interfaces.rbs +25 -0
- data/sig/ratatui_ruby/labs.rbs +90 -0
- data/sig/ratatui_ruby/layout/alignment.rbs +26 -0
- data/sig/ratatui_ruby/layout/constraint.rbs +39 -0
- data/sig/ratatui_ruby/layout/layout.rbs +45 -0
- data/sig/ratatui_ruby/layout/position.rbs +18 -0
- data/sig/ratatui_ruby/layout/rect.rbs +64 -0
- data/sig/ratatui_ruby/layout/size.rbs +18 -0
- data/sig/ratatui_ruby/list_state.rbs +23 -0
- data/sig/ratatui_ruby/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +113 -0
- data/sig/ratatui_ruby/rect.rbs +17 -0
- data/sig/ratatui_ruby/scrollbar_state.rbs +24 -0
- data/sig/ratatui_ruby/session.rbs +93 -0
- data/sig/ratatui_ruby/style/color.rbs +22 -0
- data/sig/ratatui_ruby/style/style.rbs +29 -0
- data/sig/ratatui_ruby/symbols.rbs +141 -0
- data/sig/ratatui_ruby/synthetic_events.rbs +24 -0
- data/sig/ratatui_ruby/table_state.rbs +27 -0
- data/sig/ratatui_ruby/terminal/capabilities.rbs +38 -0
- data/sig/ratatui_ruby/terminal/viewport.rbs +33 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +39 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +22 -0
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +37 -0
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +77 -0
- data/sig/ratatui_ruby/test_helper/terminal.rbs +20 -0
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +32 -0
- data/sig/ratatui_ruby/test_helper.rbs +18 -0
- data/sig/ratatui_ruby/text/line.rbs +27 -0
- data/sig/ratatui_ruby/text/span.rbs +23 -0
- data/sig/ratatui_ruby/text.rbs +12 -0
- data/sig/ratatui_ruby/tui/buffer_factories.rbs +16 -0
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +38 -0
- data/sig/ratatui_ruby/tui/core.rbs +23 -0
- data/sig/ratatui_ruby/tui/layout_factories.rbs +39 -0
- data/sig/ratatui_ruby/tui/state_factories.rbs +23 -0
- data/sig/ratatui_ruby/tui/style_factories.rbs +18 -0
- data/sig/ratatui_ruby/tui/text_factories.rbs +23 -0
- data/sig/ratatui_ruby/tui/widget_factories.rbs +138 -0
- data/sig/ratatui_ruby/tui.rbs +25 -0
- data/sig/ratatui_ruby/version.rbs +12 -0
- data/sig/ratatui_ruby/widgets/bar_chart.rbs +95 -0
- data/sig/ratatui_ruby/widgets/block.rbs +51 -0
- data/sig/ratatui_ruby/widgets/calendar.rbs +45 -0
- data/sig/ratatui_ruby/widgets/canvas.rbs +95 -0
- data/sig/ratatui_ruby/widgets/chart.rbs +91 -0
- data/sig/ratatui_ruby/widgets/coerceable_widget.rbs +26 -0
- data/sig/ratatui_ruby/widgets/gauge.rbs +44 -0
- data/sig/ratatui_ruby/widgets/line_gauge.rbs +48 -0
- data/sig/ratatui_ruby/widgets/list.rbs +63 -0
- data/sig/ratatui_ruby/widgets/misc.rbs +158 -0
- data/sig/ratatui_ruby/widgets/paragraph.rbs +45 -0
- data/sig/ratatui_ruby/widgets/row.rbs +43 -0
- data/sig/ratatui_ruby/widgets/scrollbar.rbs +53 -0
- data/sig/ratatui_ruby/widgets/shape/label.rbs +37 -0
- data/sig/ratatui_ruby/widgets/sparkline.rbs +45 -0
- data/sig/ratatui_ruby/widgets/table.rbs +78 -0
- data/sig/ratatui_ruby/widgets/tabs.rbs +44 -0
- data/sig/ratatui_ruby/widgets.rbs +16 -0
- data/vendor/goodcop/base.yml +1047 -0
- metadata +729 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
use crate::style::{parse_color_value, parse_modifier_str, parse_style};
|
|
5
|
+
use crate::widgets;
|
|
6
|
+
use magnus::{prelude::*, Error, RArray, Value};
|
|
7
|
+
use ratatui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget};
|
|
8
|
+
|
|
9
|
+
pub fn render_node(buffer: &mut Buffer, area: Rect, node: Value) -> Result<(), Error> {
|
|
10
|
+
if node.respond_to("render", true)? {
|
|
11
|
+
let ruby = magnus::Ruby::get().unwrap();
|
|
12
|
+
let ruby_area = {
|
|
13
|
+
let module = ruby.define_module("RatatuiRuby")?;
|
|
14
|
+
let layout_mod = module.const_get::<_, magnus::RModule>("Layout")?;
|
|
15
|
+
let class = layout_mod.const_get::<_, magnus::RClass>("Rect")?;
|
|
16
|
+
class.funcall::<_, _, Value>("new", (area.x, area.y, area.width, area.height))?
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// Call render with just the area (no buffer!)
|
|
20
|
+
let commands: Value = node.funcall("render", (ruby_area,))?;
|
|
21
|
+
|
|
22
|
+
// Process returned draw commands
|
|
23
|
+
if let Some(arr) = RArray::from_value(commands) {
|
|
24
|
+
for i in 0..arr.len() {
|
|
25
|
+
let ruby = magnus::Ruby::get().unwrap();
|
|
26
|
+
let index = isize::try_from(i)
|
|
27
|
+
.map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
|
|
28
|
+
let cmd: Value = arr.entry(index)?;
|
|
29
|
+
process_draw_command(buffer, cmd)?;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return Ok(());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// SAFETY: Immediate conversion to owned string avoids GC-unsafe borrowed reference.
|
|
36
|
+
let class_name = unsafe { node.class().name() }.into_owned();
|
|
37
|
+
|
|
38
|
+
// Special case: Cursor widget requires Frame, not just Buffer
|
|
39
|
+
// For now, we skip it in buffer-only contexts (like insert_before)
|
|
40
|
+
// Frame-based callers should check for Cursor and handle it specially
|
|
41
|
+
if class_name.as_str() == "RatatuiRuby::Widgets::Cursor" {
|
|
42
|
+
// No-op for buffer-only rendering
|
|
43
|
+
// Frame-based rendering should use Frame.set_cursor_position directly
|
|
44
|
+
return Ok(());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
match class_name.as_str() {
|
|
48
|
+
"RatatuiRuby::Widgets::Paragraph" => widgets::paragraph::render(buffer, area, node)?,
|
|
49
|
+
"RatatuiRuby::Widgets::Clear" => widgets::clear::render(buffer, area, node)?,
|
|
50
|
+
"RatatuiRuby::Widgets::Overlay" => widgets::overlay::render(buffer, area, node)?,
|
|
51
|
+
"RatatuiRuby::Widgets::Center" => widgets::center::render(buffer, area, node)?,
|
|
52
|
+
"RatatuiRuby::Layout::Layout" => widgets::layout::render(buffer, area, node)?,
|
|
53
|
+
"RatatuiRuby::Widgets::List" => widgets::list::render(buffer, area, node)?,
|
|
54
|
+
"RatatuiRuby::Widgets::Gauge" => widgets::gauge::render(buffer, area, node)?,
|
|
55
|
+
"RatatuiRuby::Widgets::LineGauge" => widgets::line_gauge::render(buffer, area, node)?,
|
|
56
|
+
"RatatuiRuby::Widgets::Table" => widgets::table::render(buffer, area, node)?,
|
|
57
|
+
"RatatuiRuby::Widgets::Block" => widgets::block::render(buffer, area, node)?,
|
|
58
|
+
"RatatuiRuby::Widgets::Tabs" => widgets::tabs::render(buffer, area, node)?,
|
|
59
|
+
"RatatuiRuby::Widgets::Scrollbar" => widgets::scrollbar::render(buffer, area, node)?,
|
|
60
|
+
"RatatuiRuby::Widgets::BarChart" => widgets::barchart::render(buffer, area, node)?,
|
|
61
|
+
"RatatuiRuby::Widgets::Canvas" => widgets::canvas::render(buffer, area, node)?,
|
|
62
|
+
"RatatuiRuby::Widgets::Calendar" => widgets::calendar::render(buffer, area, node)?,
|
|
63
|
+
"RatatuiRuby::Widgets::Sparkline" => widgets::sparkline::render(buffer, area, node)?,
|
|
64
|
+
"RatatuiRuby::Widgets::Chart" => {
|
|
65
|
+
widgets::chart::render(buffer, area, node)?;
|
|
66
|
+
}
|
|
67
|
+
"RatatuiRuby::Widgets::RatatuiLogo" => widgets::ratatui_logo::render(buffer, area, node),
|
|
68
|
+
"RatatuiRuby::Widgets::RatatuiMascot" => {
|
|
69
|
+
widgets::ratatui_mascot::render_ratatui_mascot(buffer, area, node)?;
|
|
70
|
+
}
|
|
71
|
+
// Text primitives can also be rendered directly as widgets
|
|
72
|
+
"RatatuiRuby::Text::Line" => {
|
|
73
|
+
let line = crate::text::parse_line(node)?;
|
|
74
|
+
line.render(area, buffer);
|
|
75
|
+
}
|
|
76
|
+
"RatatuiRuby::Text::Span" => {
|
|
77
|
+
let span = crate::text::parse_span(node)?;
|
|
78
|
+
span.render(area, buffer);
|
|
79
|
+
}
|
|
80
|
+
_ => {}
|
|
81
|
+
}
|
|
82
|
+
Ok(())
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
pub fn render_widget_to_buffer(buffer: &mut Buffer, area: Rect, node: Value) -> Result<(), Error> {
|
|
86
|
+
// Just delegate to render_node since it now works with Buffer
|
|
87
|
+
render_node(buffer, area, node)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fn process_draw_command(buffer: &mut Buffer, cmd: Value) -> Result<(), Error> {
|
|
91
|
+
let ruby = magnus::Ruby::get().unwrap();
|
|
92
|
+
// SAFETY: Immediate conversion to owned string avoids GC-unsafe borrowed reference.
|
|
93
|
+
let class_name = unsafe { cmd.class().name() }.into_owned();
|
|
94
|
+
|
|
95
|
+
match class_name.as_str() {
|
|
96
|
+
"RatatuiRuby::Draw::StringCmd" => {
|
|
97
|
+
let x: u16 = cmd.funcall("x", ())?;
|
|
98
|
+
let y: u16 = cmd.funcall("y", ())?;
|
|
99
|
+
let string: String = cmd.funcall("string", ())?;
|
|
100
|
+
let style_val: Value = cmd.funcall("style", ())?;
|
|
101
|
+
let style = parse_style(style_val)?;
|
|
102
|
+
buffer.set_string(x, y, string, style);
|
|
103
|
+
}
|
|
104
|
+
"RatatuiRuby::Draw::CellCmd" => {
|
|
105
|
+
let x: u16 = cmd.funcall("x", ())?;
|
|
106
|
+
let y: u16 = cmd.funcall("y", ())?;
|
|
107
|
+
let cell_val: Value = cmd.funcall("cell", ())?;
|
|
108
|
+
|
|
109
|
+
let area = buffer.area;
|
|
110
|
+
if x >= area.x + area.width || y >= area.y + area.height {
|
|
111
|
+
return Ok(());
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let symbol: String = cell_val.funcall("char", ())?;
|
|
115
|
+
let fg_val: Value = cell_val.funcall("fg", ())?;
|
|
116
|
+
let bg_val: Value = cell_val.funcall("bg", ())?;
|
|
117
|
+
let modifiers_val: Value = cell_val.funcall("modifiers", ())?;
|
|
118
|
+
|
|
119
|
+
let mut style = Style::default();
|
|
120
|
+
|
|
121
|
+
if !fg_val.is_nil() {
|
|
122
|
+
if let Some(color) = parse_color_value(fg_val)? {
|
|
123
|
+
style = style.fg(color);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if !bg_val.is_nil() {
|
|
127
|
+
if let Some(color) = parse_color_value(bg_val)? {
|
|
128
|
+
style = style.bg(color);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if let Some(mods_array) = RArray::from_value(modifiers_val) {
|
|
133
|
+
for i in 0..mods_array.len() {
|
|
134
|
+
let index = isize::try_from(i)
|
|
135
|
+
.map_err(|e| Error::new(ruby.exception_range_error(), e.to_string()))?;
|
|
136
|
+
let mod_val: Value = mods_array.entry(index)?;
|
|
137
|
+
// Accept both symbols and strings (DWIM)
|
|
138
|
+
let mod_str: String = mod_val.funcall("to_s", ())?;
|
|
139
|
+
if let Some(modifier) = parse_modifier_str(&mod_str) {
|
|
140
|
+
style = style.add_modifier(modifier);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if let Some(cell) = buffer.cell_mut((x, y)) {
|
|
146
|
+
cell.set_symbol(&symbol).set_style(style);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
_ => {
|
|
150
|
+
return Err(Error::new(
|
|
151
|
+
ruby.exception_type_error(),
|
|
152
|
+
format!("Unknown draw command: {class_name}"),
|
|
153
|
+
));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
Ok(())
|
|
158
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
use magnus::{prelude::*, Error, Value};
|
|
5
|
+
|
|
6
|
+
/// Calculate the display width of a string in terminal cells.
|
|
7
|
+
///
|
|
8
|
+
/// Handles unicode correctly, including:
|
|
9
|
+
/// - Regular ASCII characters: 1 cell each
|
|
10
|
+
/// - CJK characters: 2 cells each (full-width)
|
|
11
|
+
/// - Emoji: typically 2 cells each (varies by terminal)
|
|
12
|
+
/// - Combining marks and zero-width characters: 0 cells
|
|
13
|
+
///
|
|
14
|
+
/// This uses the same `unicode-width` crate that Ratatui uses internally.
|
|
15
|
+
///
|
|
16
|
+
/// Returns the total display width in cells (not bytes or characters).
|
|
17
|
+
pub fn text_width(string: Value) -> Result<usize, Error> {
|
|
18
|
+
let ruby = magnus::Ruby::get().unwrap();
|
|
19
|
+
|
|
20
|
+
let s: String = String::try_convert(string).map_err(|_| {
|
|
21
|
+
Error::new(
|
|
22
|
+
ruby.exception_type_error(),
|
|
23
|
+
"expected a String or object that converts to String",
|
|
24
|
+
)
|
|
25
|
+
})?;
|
|
26
|
+
|
|
27
|
+
// Use unicode_width's width calculation.
|
|
28
|
+
// This is the same mechanism Ratatui uses internally for Paragraph.line_width().
|
|
29
|
+
let width = s
|
|
30
|
+
.chars()
|
|
31
|
+
.map(|c| unicode_width::UnicodeWidthChar::width(c).unwrap_or(0))
|
|
32
|
+
.sum();
|
|
33
|
+
|
|
34
|
+
Ok(width)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#[cfg(test)]
|
|
38
|
+
mod tests {
|
|
39
|
+
use unicode_width::UnicodeWidthChar;
|
|
40
|
+
|
|
41
|
+
fn measure_width(s: &str) -> usize {
|
|
42
|
+
s.chars()
|
|
43
|
+
.map(|c| UnicodeWidthChar::width(c).unwrap_or(0))
|
|
44
|
+
.sum()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
#[test]
|
|
48
|
+
fn test_ascii_width() {
|
|
49
|
+
// ASCII is 1 cell per character
|
|
50
|
+
assert_eq!(measure_width("hello"), 5);
|
|
51
|
+
assert_eq!(measure_width("Hello, World!"), 13);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#[test]
|
|
55
|
+
fn test_emoji_width() {
|
|
56
|
+
// Emoji typically take 2 cells
|
|
57
|
+
// 👍 is U+1F44D THUMBS UP SIGN, width 2
|
|
58
|
+
assert_eq!(measure_width("👍"), 2);
|
|
59
|
+
// 🌍 is U+1F30D EARTH GLOBE EUROPE-AFRICA, width 2
|
|
60
|
+
assert_eq!(measure_width("🌍"), 2);
|
|
61
|
+
// "Hello 👍" = 5 + 1 + 2 = 8
|
|
62
|
+
assert_eq!(measure_width("Hello 👍"), 8);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
#[test]
|
|
66
|
+
fn test_cjk_width() {
|
|
67
|
+
// CJK characters are full-width, 2 cells each
|
|
68
|
+
// 你 (U+4F60) is width 2
|
|
69
|
+
assert_eq!(measure_width("你"), 2);
|
|
70
|
+
// 好 (U+597D) is width 2
|
|
71
|
+
assert_eq!(measure_width("好"), 2);
|
|
72
|
+
// "你好" should be 4
|
|
73
|
+
assert_eq!(measure_width("你好"), 4);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#[test]
|
|
77
|
+
fn test_mixed_width() {
|
|
78
|
+
// "a你b好" = 1 + 2 + 1 + 2 = 6
|
|
79
|
+
assert_eq!(measure_width("a你b好"), 6);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#[test]
|
|
83
|
+
fn test_empty_string() {
|
|
84
|
+
assert_eq!(measure_width(""), 0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[test]
|
|
88
|
+
fn test_spaces_and_punctuation() {
|
|
89
|
+
// Regular ASCII space and punctuation are 1 cell each
|
|
90
|
+
assert_eq!(measure_width("a b c"), 5);
|
|
91
|
+
assert_eq!(measure_width("!!!"), 3);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#[test]
|
|
95
|
+
fn test_combining_marks() {
|
|
96
|
+
// Zero-width marks don't add to width
|
|
97
|
+
// "a" + combining acute accent (U+0301)
|
|
98
|
+
let combining = "a\u{0301}";
|
|
99
|
+
assert_eq!(measure_width(combining), 1);
|
|
100
|
+
}
|
|
101
|
+
}
|