ratatui_ruby 0.9.1 → 0.10.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 +1 -1
- data/.builds/ruby-3.3.yml +1 -1
- data/.builds/ruby-3.4.yml +1 -1
- data/.builds/ruby-4.0.0.yml +1 -1
- data/AGENTS.md +2 -1
- data/CHANGELOG.md +98 -0
- data/REUSE.toml +5 -0
- data/Rakefile +1 -1
- data/Steepfile +49 -0
- data/doc/concepts/debugging.md +401 -0
- data/doc/getting_started/quickstart.md +8 -3
- data/doc/images/app_all_events.png +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/troubleshooting/async.md +4 -0
- data/examples/app_debugging_showcase/README.md +119 -0
- data/examples/app_debugging_showcase/app.rb +318 -0
- data/examples/widget_canvas/app.rb +19 -14
- data/examples/widget_gauge/app.rb +18 -3
- data/examples/widget_layout_split/app.rb +10 -4
- data/examples/widget_list/app.rb +22 -6
- data/examples/widget_rect/app.rb +7 -6
- data/examples/widget_rich_text/app.rb +62 -37
- data/examples/widget_style_colors/app.rb +26 -47
- data/examples/widget_table/app.rb +28 -5
- data/examples/widget_text_width/app.rb +6 -4
- data/ext/ratatui_ruby/Cargo.lock +48 -1
- data/ext/ratatui_ruby/Cargo.toml +6 -2
- 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 +15 -14
- data/ext/ratatui_ruby/src/lib.rs +56 -0
- data/ext/ratatui_ruby/src/rendering.rs +3 -1
- data/ext/ratatui_ruby/src/style.rs +48 -21
- data/ext/ratatui_ruby/src/terminal.rs +40 -9
- data/ext/ratatui_ruby/src/text.rs +21 -9
- data/ext/ratatui_ruby/src/widgets/chart.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/layout.rs +90 -2
- data/ext/ratatui_ruby/src/widgets/list.rs +6 -5
- data/ext/ratatui_ruby/src/widgets/overlay.rs +2 -1
- data/ext/ratatui_ruby/src/widgets/table.rs +7 -6
- data/ext/ratatui_ruby/src/widgets/table_state.rs +55 -0
- data/ext/ratatui_ruby/src/widgets/tabs.rs +3 -2
- data/lib/ratatui_ruby/buffer/cell.rb +25 -15
- data/lib/ratatui_ruby/buffer.rb +134 -2
- data/lib/ratatui_ruby/cell.rb +13 -5
- data/lib/ratatui_ruby/debug.rb +215 -0
- data/lib/ratatui_ruby/event/key.rb +3 -2
- data/lib/ratatui_ruby/event.rb +1 -1
- data/lib/ratatui_ruby/layout/constraint.rb +49 -0
- data/lib/ratatui_ruby/layout/layout.rb +119 -13
- data/lib/ratatui_ruby/layout/position.rb +55 -0
- data/lib/ratatui_ruby/layout/rect.rb +188 -0
- data/lib/ratatui_ruby/layout/size.rb +55 -0
- data/lib/ratatui_ruby/layout.rb +4 -0
- data/lib/ratatui_ruby/style/color.rb +149 -0
- data/lib/ratatui_ruby/style/style.rb +51 -4
- data/lib/ratatui_ruby/style.rb +2 -0
- data/lib/ratatui_ruby/symbols.rb +435 -0
- data/lib/ratatui_ruby/synthetic_events.rb +1 -1
- data/lib/ratatui_ruby/table_state.rb +51 -0
- data/lib/ratatui_ruby/terminal_lifecycle.rb +2 -1
- data/lib/ratatui_ruby/test_helper/event_injection.rb +6 -1
- data/lib/ratatui_ruby/test_helper.rb +9 -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/canvas_factories.rb +103 -0
- data/lib/ratatui_ruby/tui/core.rb +13 -2
- data/lib/ratatui_ruby/tui/layout_factories.rb +50 -3
- data/lib/ratatui_ruby/tui/state_factories.rb +42 -0
- data/lib/ratatui_ruby/tui/text_factories.rb +40 -0
- data/lib/ratatui_ruby/tui/widget_factories.rb +135 -60
- data/lib/ratatui_ruby/tui.rb +22 -1
- data/lib/ratatui_ruby/version.rb +1 -1
- data/lib/ratatui_ruby/widgets/bar_chart/bar.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart/bar_group.rb +2 -0
- data/lib/ratatui_ruby/widgets/bar_chart.rb +30 -20
- data/lib/ratatui_ruby/widgets/block.rb +14 -6
- data/lib/ratatui_ruby/widgets/calendar.rb +2 -0
- data/lib/ratatui_ruby/widgets/canvas.rb +56 -0
- data/lib/ratatui_ruby/widgets/cell.rb +2 -0
- data/lib/ratatui_ruby/widgets/center.rb +2 -0
- data/lib/ratatui_ruby/widgets/chart.rb +6 -0
- data/lib/ratatui_ruby/widgets/clear.rb +2 -0
- data/lib/ratatui_ruby/widgets/coerceable_widget.rb +77 -0
- data/lib/ratatui_ruby/widgets/cursor.rb +2 -0
- data/lib/ratatui_ruby/widgets/gauge.rb +61 -3
- data/lib/ratatui_ruby/widgets/line_gauge.rb +66 -4
- data/lib/ratatui_ruby/widgets/list.rb +87 -3
- data/lib/ratatui_ruby/widgets/list_item.rb +2 -0
- data/lib/ratatui_ruby/widgets/overlay.rb +2 -0
- data/lib/ratatui_ruby/widgets/paragraph.rb +4 -0
- data/lib/ratatui_ruby/widgets/ratatui_logo.rb +2 -0
- data/lib/ratatui_ruby/widgets/ratatui_mascot.rb +2 -0
- data/lib/ratatui_ruby/widgets/row.rb +45 -0
- data/lib/ratatui_ruby/widgets/scrollbar.rb +2 -0
- data/lib/ratatui_ruby/widgets/shape/label.rb +2 -0
- data/lib/ratatui_ruby/widgets/sparkline.rb +21 -13
- data/lib/ratatui_ruby/widgets/table.rb +13 -3
- data/lib/ratatui_ruby/widgets/tabs.rb +6 -4
- data/lib/ratatui_ruby/widgets.rb +1 -0
- data/lib/ratatui_ruby.rb +40 -9
- data/sig/examples/app_all_events/model/app_model.rbs +23 -0
- data/sig/examples/app_all_events/model/event_entry.rbs +15 -8
- data/sig/examples/app_all_events/model/timestamp.rbs +1 -1
- data/sig/examples/app_all_events/view.rbs +1 -1
- data/sig/examples/app_stateful_interaction/app.rbs +5 -5
- data/sig/examples/widget_block_demo/app.rbs +6 -6
- data/sig/manifest.yaml +5 -0
- data/sig/patches/data.rbs +26 -0
- data/sig/patches/debugger__.rbs +8 -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 +68 -8
- data/sig/ratatui_ruby/frame.rbs +4 -4
- data/sig/ratatui_ruby/interfaces.rbs +25 -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/output_guard.rbs +23 -0
- data/sig/ratatui_ruby/ratatui_ruby.rbs +83 -4
- data/sig/ratatui_ruby/rect.rbs +17 -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 +21 -0
- data/sig/ratatui_ruby/table_state.rbs +6 -0
- data/sig/ratatui_ruby/terminal_lifecycle.rbs +31 -0
- data/sig/ratatui_ruby/test_helper/event_injection.rbs +2 -2
- data/sig/ratatui_ruby/test_helper/snapshot.rbs +22 -3
- data/sig/ratatui_ruby/test_helper/style_assertions.rbs +8 -1
- data/sig/ratatui_ruby/test_helper/test_doubles.rbs +7 -3
- 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 +1 -1
- data/sig/ratatui_ruby/tui/canvas_factories.rbs +23 -5
- data/sig/ratatui_ruby/tui/core.rbs +2 -2
- data/sig/ratatui_ruby/tui/layout_factories.rbs +16 -2
- data/sig/ratatui_ruby/tui/state_factories.rbs +8 -3
- data/sig/ratatui_ruby/tui/style_factories.rbs +3 -1
- data/sig/ratatui_ruby/tui/text_factories.rbs +7 -4
- data/sig/ratatui_ruby/tui/widget_factories.rbs +123 -30
- 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/{schema/list_item.rbs → widgets.rbs} +4 -4
- data/tasks/steep.rake +11 -0
- metadata +80 -63
- data/doc/contributors/v1.0.0_blockers.md +0 -870
- data/doc/troubleshooting/debugging.md +0 -101
- data/lib/ratatui_ruby/schema/bar_chart/bar.rb +0 -47
- data/lib/ratatui_ruby/schema/bar_chart/bar_group.rb +0 -25
- data/lib/ratatui_ruby/schema/bar_chart.rb +0 -287
- data/lib/ratatui_ruby/schema/block.rb +0 -198
- data/lib/ratatui_ruby/schema/calendar.rb +0 -84
- data/lib/ratatui_ruby/schema/canvas.rb +0 -239
- data/lib/ratatui_ruby/schema/center.rb +0 -67
- data/lib/ratatui_ruby/schema/chart.rb +0 -159
- data/lib/ratatui_ruby/schema/clear.rb +0 -62
- data/lib/ratatui_ruby/schema/constraint.rb +0 -151
- data/lib/ratatui_ruby/schema/cursor.rb +0 -50
- data/lib/ratatui_ruby/schema/gauge.rb +0 -72
- data/lib/ratatui_ruby/schema/layout.rb +0 -122
- data/lib/ratatui_ruby/schema/line_gauge.rb +0 -80
- data/lib/ratatui_ruby/schema/list.rb +0 -135
- data/lib/ratatui_ruby/schema/list_item.rb +0 -51
- data/lib/ratatui_ruby/schema/overlay.rb +0 -51
- data/lib/ratatui_ruby/schema/paragraph.rb +0 -107
- data/lib/ratatui_ruby/schema/ratatui_logo.rb +0 -31
- data/lib/ratatui_ruby/schema/ratatui_mascot.rb +0 -36
- data/lib/ratatui_ruby/schema/rect.rb +0 -174
- data/lib/ratatui_ruby/schema/row.rb +0 -76
- data/lib/ratatui_ruby/schema/scrollbar.rb +0 -143
- data/lib/ratatui_ruby/schema/shape/label.rb +0 -76
- data/lib/ratatui_ruby/schema/sparkline.rb +0 -142
- data/lib/ratatui_ruby/schema/style.rb +0 -97
- data/lib/ratatui_ruby/schema/table.rb +0 -141
- data/lib/ratatui_ruby/schema/tabs.rb +0 -85
- data/lib/ratatui_ruby/schema/text.rb +0 -217
- data/sig/examples/app_all_events/model/events.rbs +0 -15
- data/sig/examples/app_all_events/view_state.rbs +0 -21
- data/sig/ratatui_ruby/schema/bar_chart/bar.rbs +0 -22
- data/sig/ratatui_ruby/schema/bar_chart/bar_group.rbs +0 -19
- data/sig/ratatui_ruby/schema/bar_chart.rbs +0 -38
- data/sig/ratatui_ruby/schema/block.rbs +0 -18
- data/sig/ratatui_ruby/schema/calendar.rbs +0 -23
- data/sig/ratatui_ruby/schema/canvas.rbs +0 -81
- data/sig/ratatui_ruby/schema/center.rbs +0 -17
- data/sig/ratatui_ruby/schema/chart.rbs +0 -39
- data/sig/ratatui_ruby/schema/constraint.rbs +0 -30
- data/sig/ratatui_ruby/schema/cursor.rbs +0 -16
- data/sig/ratatui_ruby/schema/draw.rbs +0 -33
- data/sig/ratatui_ruby/schema/gauge.rbs +0 -23
- data/sig/ratatui_ruby/schema/layout.rbs +0 -27
- data/sig/ratatui_ruby/schema/line_gauge.rbs +0 -24
- data/sig/ratatui_ruby/schema/list.rbs +0 -28
- data/sig/ratatui_ruby/schema/overlay.rbs +0 -15
- data/sig/ratatui_ruby/schema/paragraph.rbs +0 -20
- data/sig/ratatui_ruby/schema/ratatui_logo.rbs +0 -14
- data/sig/ratatui_ruby/schema/ratatui_mascot.rbs +0 -17
- data/sig/ratatui_ruby/schema/rect.rbs +0 -48
- data/sig/ratatui_ruby/schema/row.rbs +0 -28
- data/sig/ratatui_ruby/schema/scrollbar.rbs +0 -42
- data/sig/ratatui_ruby/schema/sparkline.rbs +0 -22
- data/sig/ratatui_ruby/schema/style.rbs +0 -19
- data/sig/ratatui_ruby/schema/table.rbs +0 -32
- data/sig/ratatui_ruby/schema/tabs.rbs +0 -21
- data/sig/ratatui_ruby/schema/text.rbs +0 -31
- /data/lib/ratatui_ruby/{schema/draw.rb → draw.rb} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
2
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
3
|
|
|
4
|
+
use crate::errors::type_error_with_context;
|
|
4
5
|
use crate::style::{parse_block, parse_style};
|
|
5
6
|
use crate::text::{parse_line, parse_span};
|
|
6
7
|
use crate::widgets::list_state::RubyListState;
|
|
@@ -18,7 +19,7 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
|
|
|
18
19
|
let ruby = magnus::Ruby::get().unwrap();
|
|
19
20
|
let items_val: Value = node.funcall("items", ())?;
|
|
20
21
|
let items_array = magnus::RArray::from_value(items_val)
|
|
21
|
-
.ok_or_else(||
|
|
22
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for items", items_val))?;
|
|
22
23
|
let selected_index_val: Value = node.funcall("selected_index", ())?;
|
|
23
24
|
let style_val: Value = node.funcall("style", ())?;
|
|
24
25
|
let highlight_style_val: Value = node.funcall("highlight_style", ())?;
|
|
@@ -129,7 +130,7 @@ pub fn render_stateful(
|
|
|
129
130
|
// Build items
|
|
130
131
|
let items_val: Value = node.funcall("items", ())?;
|
|
131
132
|
let items_array = magnus::RArray::from_value(items_val)
|
|
132
|
-
.ok_or_else(||
|
|
133
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for items", items_val))?;
|
|
133
134
|
|
|
134
135
|
let mut items: Vec<ListItem> = Vec::new();
|
|
135
136
|
for i in 0..items_array.len() {
|
|
@@ -270,10 +271,10 @@ fn parse_list_item(value: Value) -> Result<ListItem<'static>, Error> {
|
|
|
270
271
|
return Ok(ListItem::new(Line::from(vec![span])));
|
|
271
272
|
}
|
|
272
273
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
ruby.exception_type_error(),
|
|
274
|
+
Err(type_error_with_context(
|
|
275
|
+
&ruby,
|
|
276
276
|
"expected String, Text::Span, Text::Line, or ListItem",
|
|
277
|
+
value,
|
|
277
278
|
))
|
|
278
279
|
}
|
|
279
280
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
2
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
3
|
|
|
4
|
+
use crate::errors::type_error_with_context;
|
|
4
5
|
use crate::rendering::render_node;
|
|
5
6
|
use magnus::{prelude::*, Error, Value};
|
|
6
7
|
use ratatui::{layout::Rect, Frame};
|
|
@@ -9,7 +10,7 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
|
|
|
9
10
|
let ruby = magnus::Ruby::get().unwrap();
|
|
10
11
|
let layers_val: Value = node.funcall("layers", ())?;
|
|
11
12
|
let layers_array = magnus::RArray::from_value(layers_val)
|
|
12
|
-
.ok_or_else(||
|
|
13
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for layers", layers_val))?;
|
|
13
14
|
|
|
14
15
|
for i in 0..layers_array.len() {
|
|
15
16
|
let index = isize::try_from(i)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
2
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
3
|
|
|
4
|
+
use crate::errors::type_error_with_context;
|
|
4
5
|
use crate::style::{parse_block, parse_style};
|
|
5
6
|
use crate::text::{parse_line, parse_span, parse_text};
|
|
6
7
|
use crate::widgets::table_state::RubyTableState;
|
|
@@ -19,10 +20,10 @@ pub fn render(frame: &mut Frame, area: Rect, node: Value) -> Result<(), Error> {
|
|
|
19
20
|
let footer_val: Value = node.funcall("footer", ())?;
|
|
20
21
|
let rows_value: Value = node.funcall("rows", ())?;
|
|
21
22
|
let rows_array = magnus::RArray::from_value(rows_value)
|
|
22
|
-
.ok_or_else(||
|
|
23
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for rows", rows_value))?;
|
|
23
24
|
let widths_val: Value = node.funcall("widths", ())?;
|
|
24
25
|
let widths_array = magnus::RArray::from_value(widths_val)
|
|
25
|
-
.ok_or_else(||
|
|
26
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for widths", widths_val))?;
|
|
26
27
|
let row_highlight_style_val: Value = node.funcall("row_highlight_style", ())?;
|
|
27
28
|
let column_highlight_style_val: Value = node.funcall("column_highlight_style", ())?;
|
|
28
29
|
let cell_highlight_style_val: Value = node.funcall("cell_highlight_style", ())?;
|
|
@@ -145,10 +146,10 @@ pub fn render_stateful(
|
|
|
145
146
|
// Parse rows
|
|
146
147
|
let rows_value: Value = node.funcall("rows", ())?;
|
|
147
148
|
let rows_array = magnus::RArray::from_value(rows_value)
|
|
148
|
-
.ok_or_else(||
|
|
149
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for rows", rows_value))?;
|
|
149
150
|
let widths_val: Value = node.funcall("widths", ())?;
|
|
150
151
|
let widths_array = magnus::RArray::from_value(widths_val)
|
|
151
|
-
.ok_or_else(||
|
|
152
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for widths", widths_val))?;
|
|
152
153
|
|
|
153
154
|
let mut rows = Vec::new();
|
|
154
155
|
for i in 0..rows_array.len() {
|
|
@@ -251,7 +252,7 @@ fn parse_row(row_val: Value) -> Result<Row<'static>, Error> {
|
|
|
251
252
|
let bottom_margin_val: Value = row_val.funcall("bottom_margin", ())?;
|
|
252
253
|
|
|
253
254
|
let cells_array = magnus::RArray::from_value(cells_val).ok_or_else(|| {
|
|
254
|
-
|
|
255
|
+
type_error_with_context(&ruby, "expected array for Row.cells", cells_val)
|
|
255
256
|
})?;
|
|
256
257
|
|
|
257
258
|
let mut cells = Vec::new();
|
|
@@ -285,7 +286,7 @@ fn parse_row(row_val: Value) -> Result<Row<'static>, Error> {
|
|
|
285
286
|
|
|
286
287
|
// Fallback: plain array of cells
|
|
287
288
|
let row_array = magnus::RArray::from_value(row_val)
|
|
288
|
-
.ok_or_else(||
|
|
289
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for row", row_val))?;
|
|
289
290
|
|
|
290
291
|
let mut cells = Vec::new();
|
|
291
292
|
for i in 0..row_array.len() {
|
|
@@ -69,6 +69,40 @@ impl RubyTableState {
|
|
|
69
69
|
self.inner.borrow_mut().scroll_up_by(amount);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/// Returns the currently selected cell as (row, column) tuple.
|
|
73
|
+
/// Returns None if either row or column is not selected.
|
|
74
|
+
pub fn selected_cell(&self) -> Option<(usize, usize)> {
|
|
75
|
+
self.inner.borrow().selected_cell()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Selects the next column or the first one if no column is selected.
|
|
79
|
+
pub fn select_next_column(&self) {
|
|
80
|
+
self.inner.borrow_mut().select_next_column();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// Selects the previous column or the last one if no column is selected.
|
|
84
|
+
pub fn select_previous_column(&self) {
|
|
85
|
+
self.inner.borrow_mut().select_previous_column();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/// Selects the first column.
|
|
89
|
+
pub fn select_first_column(&self) {
|
|
90
|
+
self.inner.borrow_mut().select_first_column();
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Selects the last column.
|
|
94
|
+
pub fn select_last_column(&self) {
|
|
95
|
+
self.inner.borrow_mut().select_last_column();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/// Creates a new `RubyTableState` with a selected cell (row, column).
|
|
99
|
+
pub fn with_selected_cell(cell: Option<(usize, usize)>) -> Self {
|
|
100
|
+
let state = TableState::default().with_selected_cell(cell);
|
|
101
|
+
Self {
|
|
102
|
+
inner: RefCell::new(state),
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
72
106
|
/// Borrows the inner `TableState` mutably for rendering.
|
|
73
107
|
pub fn borrow_mut(&self) -> std::cell::RefMut<'_, TableState> {
|
|
74
108
|
self.inner.borrow_mut()
|
|
@@ -79,6 +113,10 @@ impl RubyTableState {
|
|
|
79
113
|
pub fn register(ruby: &Ruby, module: magnus::RModule) -> Result<(), Error> {
|
|
80
114
|
let class = module.define_class("TableState", ruby.class_object())?;
|
|
81
115
|
class.define_singleton_method("new", function!(RubyTableState::new, 1))?;
|
|
116
|
+
class.define_singleton_method(
|
|
117
|
+
"with_selected_cell",
|
|
118
|
+
function!(RubyTableState::with_selected_cell, 1),
|
|
119
|
+
)?;
|
|
82
120
|
class.define_method("select", method!(RubyTableState::select, 1))?;
|
|
83
121
|
class.define_method("selected", method!(RubyTableState::selected, 0))?;
|
|
84
122
|
class.define_method("select_column", method!(RubyTableState::select_column, 1))?;
|
|
@@ -86,6 +124,23 @@ pub fn register(ruby: &Ruby, module: magnus::RModule) -> Result<(), Error> {
|
|
|
86
124
|
"selected_column",
|
|
87
125
|
method!(RubyTableState::selected_column, 0),
|
|
88
126
|
)?;
|
|
127
|
+
class.define_method("selected_cell", method!(RubyTableState::selected_cell, 0))?;
|
|
128
|
+
class.define_method(
|
|
129
|
+
"select_next_column",
|
|
130
|
+
method!(RubyTableState::select_next_column, 0),
|
|
131
|
+
)?;
|
|
132
|
+
class.define_method(
|
|
133
|
+
"select_previous_column",
|
|
134
|
+
method!(RubyTableState::select_previous_column, 0),
|
|
135
|
+
)?;
|
|
136
|
+
class.define_method(
|
|
137
|
+
"select_first_column",
|
|
138
|
+
method!(RubyTableState::select_first_column, 0),
|
|
139
|
+
)?;
|
|
140
|
+
class.define_method(
|
|
141
|
+
"select_last_column",
|
|
142
|
+
method!(RubyTableState::select_last_column, 0),
|
|
143
|
+
)?;
|
|
89
144
|
class.define_method("offset", method!(RubyTableState::offset, 0))?;
|
|
90
145
|
class.define_method("scroll_down_by", method!(RubyTableState::scroll_down_by, 1))?;
|
|
91
146
|
class.define_method("scroll_up_by", method!(RubyTableState::scroll_up_by, 1))?;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com>
|
|
2
2
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
|
3
3
|
|
|
4
|
+
use crate::errors::type_error_with_context;
|
|
4
5
|
use crate::style::parse_block;
|
|
5
6
|
use crate::text::{parse_line, parse_span};
|
|
6
7
|
use bumpalo::Bump;
|
|
@@ -59,7 +60,7 @@ fn create_tabs(node: Value, bump: &Bump) -> Result<Tabs<'_>, Error> {
|
|
|
59
60
|
let padding_right_val: Value = node.funcall("padding_right", ())?;
|
|
60
61
|
|
|
61
62
|
let titles_array = magnus::RArray::from_value(titles_val)
|
|
62
|
-
.ok_or_else(||
|
|
63
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for titles", titles_val))?;
|
|
63
64
|
|
|
64
65
|
let mut titles = Vec::new();
|
|
65
66
|
for i in 0..titles_array.len() {
|
|
@@ -117,7 +118,7 @@ pub fn width(node: Value) -> Result<usize, Error> {
|
|
|
117
118
|
let padding_right: usize = node.funcall("padding_right", ())?;
|
|
118
119
|
|
|
119
120
|
let titles_array = magnus::RArray::from_value(titles_val)
|
|
120
|
-
.ok_or_else(||
|
|
121
|
+
.ok_or_else(|| type_error_with_context(&ruby, "expected array for titles", titles_val))?;
|
|
121
122
|
|
|
122
123
|
let mut total_width = padding_left + padding_right;
|
|
123
124
|
|
|
@@ -46,6 +46,11 @@ module RatatuiRuby
|
|
|
46
46
|
# The background color of the cell (e.g., :black, nil).
|
|
47
47
|
attr_reader :bg
|
|
48
48
|
|
|
49
|
+
# The underline color of the cell.
|
|
50
|
+
#
|
|
51
|
+
# Distinct from foreground color. Some terminals support colored underlines.
|
|
52
|
+
attr_reader :underline_color
|
|
53
|
+
|
|
49
54
|
# The list of active modifiers (e.g., ["bold", "italic"]).
|
|
50
55
|
attr_reader :modifiers
|
|
51
56
|
|
|
@@ -64,7 +69,7 @@ module RatatuiRuby
|
|
|
64
69
|
# SPDX-SnippetEnd
|
|
65
70
|
#++
|
|
66
71
|
def self.empty
|
|
67
|
-
new(symbol: " ", fg: nil, bg: nil, modifiers: [])
|
|
72
|
+
new(symbol: " ", fg: nil, bg: nil, underline_color: nil, modifiers: [])
|
|
68
73
|
end
|
|
69
74
|
|
|
70
75
|
# Returns a default cell (alias for empty).
|
|
@@ -102,7 +107,7 @@ module RatatuiRuby
|
|
|
102
107
|
# SPDX-SnippetEnd
|
|
103
108
|
#++
|
|
104
109
|
def self.symbol(symbol)
|
|
105
|
-
new(symbol:, fg: nil, bg: nil, modifiers: [])
|
|
110
|
+
new(symbol:, fg: nil, bg: nil, underline_color: nil, modifiers: [])
|
|
106
111
|
end
|
|
107
112
|
|
|
108
113
|
# Alias for Rubyists who prefer a shorter name.
|
|
@@ -115,58 +120,61 @@ module RatatuiRuby
|
|
|
115
120
|
# [symbol] String (single character). Aliased as <tt>char:</tt>.
|
|
116
121
|
# [fg] Symbol or String (nullable).
|
|
117
122
|
# [bg] Symbol or String (nullable).
|
|
118
|
-
# [
|
|
119
|
-
|
|
123
|
+
# [underline_color] Symbol or String (nullable).
|
|
124
|
+
# [modifiers] Array of Strings, Symbols, or any object responding to to_sym or to_s.
|
|
125
|
+
# Normalized to Symbols for consistent output.
|
|
126
|
+
def initialize(symbol: nil, char: nil, fg: nil, bg: nil, underline_color: nil, modifiers: [])
|
|
120
127
|
@symbol = (symbol || char || " ").freeze
|
|
121
128
|
@fg = fg&.freeze
|
|
122
129
|
@bg = bg&.freeze
|
|
123
|
-
@
|
|
130
|
+
@underline_color = underline_color&.freeze
|
|
131
|
+
@modifiers = modifiers.map { |m| m.respond_to?(:to_sym) ? m.to_sym : m.to_s.to_sym }.freeze
|
|
124
132
|
freeze
|
|
125
133
|
end
|
|
126
134
|
|
|
127
135
|
# Returns true if the cell has the bold modifier.
|
|
128
136
|
def bold?
|
|
129
|
-
modifiers.include?(
|
|
137
|
+
modifiers.include?(:bold)
|
|
130
138
|
end
|
|
131
139
|
|
|
132
140
|
# Returns true if the cell has the dim modifier.
|
|
133
141
|
def dim?
|
|
134
|
-
modifiers.include?(
|
|
142
|
+
modifiers.include?(:dim)
|
|
135
143
|
end
|
|
136
144
|
|
|
137
145
|
# Returns true if the cell has the italic modifier.
|
|
138
146
|
def italic?
|
|
139
|
-
modifiers.include?(
|
|
147
|
+
modifiers.include?(:italic)
|
|
140
148
|
end
|
|
141
149
|
|
|
142
150
|
# Returns true if the cell has the underlined modifier.
|
|
143
151
|
def underlined?
|
|
144
|
-
modifiers.include?(
|
|
152
|
+
modifiers.include?(:underlined)
|
|
145
153
|
end
|
|
146
154
|
|
|
147
155
|
# Returns true if the cell has the slow_blink modifier.
|
|
148
156
|
def slow_blink?
|
|
149
|
-
modifiers.include?(
|
|
157
|
+
modifiers.include?(:slow_blink)
|
|
150
158
|
end
|
|
151
159
|
|
|
152
160
|
# Returns true if the cell has the rapid_blink modifier.
|
|
153
161
|
def rapid_blink?
|
|
154
|
-
modifiers.include?(
|
|
162
|
+
modifiers.include?(:rapid_blink)
|
|
155
163
|
end
|
|
156
164
|
|
|
157
165
|
# Returns true if the cell has the reversed modifier.
|
|
158
166
|
def reversed?
|
|
159
|
-
modifiers.include?(
|
|
167
|
+
modifiers.include?(:reversed)
|
|
160
168
|
end
|
|
161
169
|
|
|
162
170
|
# Returns true if the cell has the hidden modifier.
|
|
163
171
|
def hidden?
|
|
164
|
-
modifiers.include?(
|
|
172
|
+
modifiers.include?(:hidden)
|
|
165
173
|
end
|
|
166
174
|
|
|
167
175
|
# Returns true if the cell has the crossed_out modifier.
|
|
168
176
|
def crossed_out?
|
|
169
|
-
modifiers.include?(
|
|
177
|
+
modifiers.include?(:crossed_out)
|
|
170
178
|
end
|
|
171
179
|
|
|
172
180
|
# Checks equality with another Cell.
|
|
@@ -175,6 +183,7 @@ module RatatuiRuby
|
|
|
175
183
|
char == other.char &&
|
|
176
184
|
fg == other.fg &&
|
|
177
185
|
bg == other.bg &&
|
|
186
|
+
underline_color == other.underline_color &&
|
|
178
187
|
modifiers == other.modifiers
|
|
179
188
|
end
|
|
180
189
|
|
|
@@ -183,6 +192,7 @@ module RatatuiRuby
|
|
|
183
192
|
parts = ["symbol=#{symbol.inspect}"]
|
|
184
193
|
parts << "fg=#{fg.inspect}" if fg
|
|
185
194
|
parts << "bg=#{bg.inspect}" if bg
|
|
195
|
+
parts << "underline_color=#{underline_color.inspect}" if underline_color
|
|
186
196
|
parts << "modifiers=#{modifiers.inspect}" unless modifiers.empty?
|
|
187
197
|
"#<#{self.class} #{parts.join(' ')}>"
|
|
188
198
|
end
|
|
@@ -195,7 +205,7 @@ module RatatuiRuby
|
|
|
195
205
|
# Support for pattern matching.
|
|
196
206
|
# Supports both <tt>:symbol</tt> and <tt>:char</tt> keys.
|
|
197
207
|
def deconstruct_keys(keys)
|
|
198
|
-
{ symbol:, char: symbol, fg:, bg:, modifiers: }
|
|
208
|
+
{ symbol:, char: symbol, fg:, bg:, underline_color:, modifiers: }
|
|
199
209
|
end
|
|
200
210
|
end
|
|
201
211
|
end
|
data/lib/ratatui_ruby/buffer.rb
CHANGED
|
@@ -8,9 +8,141 @@
|
|
|
8
8
|
module RatatuiRuby
|
|
9
9
|
# Buffer primitives for terminal cell inspection.
|
|
10
10
|
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
11
|
+
# Widgets render to an intermediate buffer, not directly to the terminal.
|
|
12
|
+
# Testing and debugging require access to buffer state.
|
|
13
|
+
#
|
|
14
|
+
# This module mirrors +ratatui::buffer+ and provides query methods
|
|
15
|
+
# for inspecting buffer contents, converting between coordinates and indices,
|
|
16
|
+
# and retrieving individual cells.
|
|
17
|
+
#
|
|
18
|
+
# Use it in tests to verify rendered output or in debugging to inspect state.
|
|
13
19
|
module Buffer
|
|
20
|
+
class << self
|
|
21
|
+
# Converts a position to a linear buffer index.
|
|
22
|
+
#
|
|
23
|
+
# Buffers store cells in a flat array, row by row. Widget code
|
|
24
|
+
# works with (x, y) coordinates. Bridging these representations
|
|
25
|
+
# requires index translation.
|
|
26
|
+
#
|
|
27
|
+
# The index is calculated as <tt>y * width + x</tt>.
|
|
28
|
+
#
|
|
29
|
+
# === Example
|
|
30
|
+
#
|
|
31
|
+
#--
|
|
32
|
+
# SPDX-SnippetBegin
|
|
33
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
34
|
+
# SPDX-License-Identifier: MIT-0
|
|
35
|
+
#++
|
|
36
|
+
# # In a 10-wide buffer, position (3, 2) maps to index 23
|
|
37
|
+
# Buffer.index_of(3, 2) # => 23
|
|
38
|
+
#--
|
|
39
|
+
# SPDX-SnippetEnd
|
|
40
|
+
#++
|
|
41
|
+
#
|
|
42
|
+
# [x] Column (0-indexed from left).
|
|
43
|
+
# [y] Row (0-indexed from top).
|
|
44
|
+
#
|
|
45
|
+
# Returns the linear index (Integer).
|
|
46
|
+
def index_of(x, y)
|
|
47
|
+
area = RatatuiRuby._get_terminal_area
|
|
48
|
+
(y * area["width"]) + x
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Converts a linear buffer index to position coordinates.
|
|
52
|
+
#
|
|
53
|
+
# Inverse of +index_of+. When iterating over buffer content
|
|
54
|
+
# by index, use this to recover the original coordinates.
|
|
55
|
+
#
|
|
56
|
+
# === Example
|
|
57
|
+
#
|
|
58
|
+
#--
|
|
59
|
+
# SPDX-SnippetBegin
|
|
60
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
61
|
+
# SPDX-License-Identifier: MIT-0
|
|
62
|
+
#++
|
|
63
|
+
# # In a 10-wide buffer, index 23 maps to position (3, 2)
|
|
64
|
+
# Buffer.pos_of(23) # => [3, 2]
|
|
65
|
+
#--
|
|
66
|
+
# SPDX-SnippetEnd
|
|
67
|
+
#++
|
|
68
|
+
#
|
|
69
|
+
# [index] Linear buffer index (Integer).
|
|
70
|
+
#
|
|
71
|
+
# Returns <tt>[x, y]</tt> coordinates.
|
|
72
|
+
def pos_of(index)
|
|
73
|
+
area = RatatuiRuby._get_terminal_area
|
|
74
|
+
width = area["width"]
|
|
75
|
+
x = index % width
|
|
76
|
+
y = index / width
|
|
77
|
+
[x, y]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Returns the Cell at the specified position.
|
|
81
|
+
#
|
|
82
|
+
# Tests assert on cell contents. This method provides direct
|
|
83
|
+
# access without iterating the entire buffer.
|
|
84
|
+
#
|
|
85
|
+
# Delegates to +RatatuiRuby.get_cell_at+.
|
|
86
|
+
#
|
|
87
|
+
# === Example
|
|
88
|
+
#
|
|
89
|
+
#--
|
|
90
|
+
# SPDX-SnippetBegin
|
|
91
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
92
|
+
# SPDX-License-Identifier: MIT-0
|
|
93
|
+
#++
|
|
94
|
+
# cell = Buffer.get(0, 0)
|
|
95
|
+
# assert_equal "H", cell.char
|
|
96
|
+
#--
|
|
97
|
+
# SPDX-SnippetEnd
|
|
98
|
+
#++
|
|
99
|
+
#
|
|
100
|
+
# [x] Column (0-indexed from left).
|
|
101
|
+
# [y] Row (0-indexed from top).
|
|
102
|
+
#
|
|
103
|
+
# Returns a Buffer::Cell containing the character and style at that position.
|
|
104
|
+
def get(x, y)
|
|
105
|
+
RatatuiRuby.get_cell_at(x, y)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Returns all cells in the buffer as a flat array.
|
|
109
|
+
#
|
|
110
|
+
# Snapshot testing compares entire buffer states. Manually
|
|
111
|
+
# iterating coordinates is verbose and error-prone.
|
|
112
|
+
#
|
|
113
|
+
# This method returns every cell, ordered row by row
|
|
114
|
+
# (top to bottom, left to right).
|
|
115
|
+
#
|
|
116
|
+
# === Example
|
|
117
|
+
#
|
|
118
|
+
#--
|
|
119
|
+
# SPDX-SnippetBegin
|
|
120
|
+
# SPDX-FileCopyrightText: 2026 Kerrick Long
|
|
121
|
+
# SPDX-License-Identifier: MIT-0
|
|
122
|
+
#++
|
|
123
|
+
# cells = Buffer.content
|
|
124
|
+
# cells.each { |cell| puts cell.char }
|
|
125
|
+
#--
|
|
126
|
+
# SPDX-SnippetEnd
|
|
127
|
+
#++
|
|
128
|
+
#
|
|
129
|
+
# Returns an Array of Buffer::Cell objects.
|
|
130
|
+
def content
|
|
131
|
+
area = RatatuiRuby._get_terminal_area
|
|
132
|
+
width = area["width"]
|
|
133
|
+
height = area["height"]
|
|
134
|
+
cells = [] #: Array[Buffer::Cell]
|
|
135
|
+
(0...height).each do |y|
|
|
136
|
+
(0...width).each do |x|
|
|
137
|
+
cells << RatatuiRuby.get_cell_at(x, y)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
cells
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Ruby-idiomatic alias (TIMTOWTDI)
|
|
144
|
+
alias [] get
|
|
145
|
+
end
|
|
14
146
|
end
|
|
15
147
|
end
|
|
16
148
|
|
data/lib/ratatui_ruby/cell.rb
CHANGED
|
@@ -45,8 +45,12 @@ module RatatuiRuby
|
|
|
45
45
|
# The background color of the cell (e.g., :black, nil).
|
|
46
46
|
attr_reader :bg
|
|
47
47
|
|
|
48
|
+
# The underline color of the cell.
|
|
49
|
+
#
|
|
50
|
+
# Distinct from foreground color. Some terminals support colored underlines.
|
|
51
|
+
attr_reader :underline_color
|
|
52
|
+
|
|
48
53
|
# The list of active modifiers (e.g., ["bold", "italic"]).
|
|
49
|
-
attr_reader :modifiers
|
|
50
54
|
|
|
51
55
|
# Returns an empty cell (space character, no styles).
|
|
52
56
|
#
|
|
@@ -63,7 +67,7 @@ module RatatuiRuby
|
|
|
63
67
|
# SPDX-SnippetEnd
|
|
64
68
|
#++
|
|
65
69
|
def self.empty
|
|
66
|
-
new(symbol: " ", fg: nil, bg: nil, modifiers: [])
|
|
70
|
+
new(symbol: " ", fg: nil, bg: nil, underline_color: nil, modifiers: [])
|
|
67
71
|
end
|
|
68
72
|
|
|
69
73
|
# Returns a default cell (alias for empty).
|
|
@@ -101,7 +105,7 @@ module RatatuiRuby
|
|
|
101
105
|
# SPDX-SnippetEnd
|
|
102
106
|
#++
|
|
103
107
|
def self.symbol(symbol)
|
|
104
|
-
new(symbol:, fg: nil, bg: nil, modifiers: [])
|
|
108
|
+
new(symbol:, fg: nil, bg: nil, underline_color: nil, modifiers: [])
|
|
105
109
|
end
|
|
106
110
|
|
|
107
111
|
# Alias for Rubyists who prefer a shorter name.
|
|
@@ -114,11 +118,13 @@ module RatatuiRuby
|
|
|
114
118
|
# [symbol] String (single character). Aliased as <tt>char:</tt>.
|
|
115
119
|
# [fg] Symbol or String (nullable).
|
|
116
120
|
# [bg] Symbol or String (nullable).
|
|
121
|
+
# [underline_color] Symbol or String (nullable).
|
|
117
122
|
# [modifiers] Array of Strings.
|
|
118
|
-
def initialize(symbol: nil, char: nil, fg: nil, bg: nil, modifiers: [])
|
|
123
|
+
def initialize(symbol: nil, char: nil, fg: nil, bg: nil, underline_color: nil, modifiers: [])
|
|
119
124
|
@symbol = (symbol || char || " ").freeze
|
|
120
125
|
@fg = fg&.freeze
|
|
121
126
|
@bg = bg&.freeze
|
|
127
|
+
@underline_color = underline_color&.freeze
|
|
122
128
|
@modifiers = modifiers.map(&:freeze).freeze
|
|
123
129
|
freeze
|
|
124
130
|
end
|
|
@@ -174,6 +180,7 @@ module RatatuiRuby
|
|
|
174
180
|
char == other.char &&
|
|
175
181
|
fg == other.fg &&
|
|
176
182
|
bg == other.bg &&
|
|
183
|
+
underline_color == other.underline_color &&
|
|
177
184
|
modifiers == other.modifiers
|
|
178
185
|
end
|
|
179
186
|
|
|
@@ -182,6 +189,7 @@ module RatatuiRuby
|
|
|
182
189
|
parts = ["symbol=#{symbol.inspect}"]
|
|
183
190
|
parts << "fg=#{fg.inspect}" if fg
|
|
184
191
|
parts << "bg=#{bg.inspect}" if bg
|
|
192
|
+
parts << "underline_color=#{underline_color.inspect}" if underline_color
|
|
185
193
|
parts << "modifiers=#{modifiers.inspect}" unless modifiers.empty?
|
|
186
194
|
"#<#{self.class} #{parts.join(' ')}>"
|
|
187
195
|
end
|
|
@@ -194,7 +202,7 @@ module RatatuiRuby
|
|
|
194
202
|
# Support for pattern matching.
|
|
195
203
|
# Supports both <tt>:symbol</tt> and <tt>:char</tt> keys.
|
|
196
204
|
def deconstruct_keys(keys)
|
|
197
|
-
{ symbol:, char: symbol, fg:, bg:, modifiers: }
|
|
205
|
+
{ symbol:, char: symbol, fg:, bg:, underline_color:, modifiers: }
|
|
198
206
|
end
|
|
199
207
|
end
|
|
200
208
|
end
|