New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Easier viewing of styles in widgets in a print debugging workflow #1045
Comments
We should probably update this function to handle styles as well: Lines 46 to 73 in 326a461
And make the |
Creating a new TestBuffer type for this would probably work ok. Imagine: let w = MyWidget::new(...);
let mut buf = TestBuffer::new(10, 3);
assert_eq!(
buf.render_string(w)),
"..."
); Add props for ansi / plain. Maybe even Even just a method would be fine perhaps but it would be nice to be able to configure this a little. Internally it would allocate the right size buffer, render and pull out the string value. |
Hey, I have a hacked together function that receives a ratatui |
Yes absolutely! I'm happy to make it a PR in the future too (crediting you of course)! |
There you go (no need to credit me, most of this is copied from various places in the ratatui codebase, the rest is just some ANSI serialization). Note that this does not consolidate styles (basically it'll serialize styling for each cell regardless of what came before it). IMO this is not an issue in this context, seeing as we basically want a debug print and the performance cost is not Humanly noticeable in modern terminals - but ofc up to you if you'd like to add some sort of style consolidations. I copy/pasted this from my project without testing, so let me know if I forgot anything! fn render_widget(widget: impl Widget, rows: usize, cols: usize) {
let rect = Rect {
x: 0,
y: 0,
width: cols as u16,
height: rows.saturating_sub(1) as u16,
};
let mut buf = Buffer::empty(rect.clone());
widget.render(rect, &mut buf);
let mut x = 0;
let mut y = 0;
fn stringify_cell_mofidier(modifier: Modifier) -> String {
let mut stringified = String::new();
match modifier {
Modifier::BOLD => {
stringified.push_str("\u{1b}[1m");
},
Modifier::ITALIC => {
stringified.push_str("\u{1b}[3m");
},
Modifier::UNDERLINED => {
stringified.push_str("\u{1b}[4m");
},
_ => {}
}
stringified
}
for (i, cell) in buf.content().iter().enumerate() {
let modifier = stringify_cell_mofidier(cell.modifier);
print!("{}{}{}{}", modifier, Fg(cell.fg), Bg(cell.bg), cell.symbol());
x += 1;
if x >= rect.width {
x = 0;
y += 1;
print!("\n");
}
}
}
struct Fg(Color);
struct Bg(Color);
impl fmt::Display for Bg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
Color::Reset => write!(f, "\u{1b}[49m"),
Color::Black => write!(f, "\u{1b}[40m"),
Color::Red => write!(f, "\u{1b}[41m"),
Color::Green => write!(f, "\u{1b}[42m"),
Color::Yellow => write!(f, "\u{1b}[43m"),
Color::Blue => write!(f, "\u{1b}[44m"),
Color::Magenta => write!(f, "\u{1b}[45m"),
Color::Cyan => write!(f, "\u{1b}[46m"),
Color::Gray => write!(f, "\u{1b}[47m"),
Color::DarkGray => write!(f, "\u{1b}[100m"),
Color::LightRed => write!(f, "\u{1b}[101m"),
Color::LightGreen => write!(f, "\u{1b}[102m"),
Color::LightYellow => write!(f, "\u{1b}[103m"),
Color::LightBlue => write!(f, "\u{1b}[104m"),
Color::LightMagenta => write!(f, "\u{1b}[105m"),
Color::LightCyan => write!(f, "\u{1b}[106m"),
Color::White => write!(f, "\u{1b}[107m"),
Color::Indexed(i) => write!(f, "\u{1b}[{}m", i),
Color::Rgb(r, g, b) => write!(f, "\u{1b}[48;2;{};{};{}m", r, g, b),
}
}
}
impl fmt::Display for Fg {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {
Color::Reset => write!(f, "\u{1b}[39m"),
Color::Black => write!(f, "\u{1b}[30m"),
Color::Red => write!(f, "\u{1b}[31m"),
Color::Green => write!(f, "\u{1b}[32m"),
Color::Yellow => write!(f, "\u{1b}[33m"),
Color::Blue => write!(f, "\u{1b}[34m"),
Color::Magenta => write!(f, "\u{1b}[35m"),
Color::Cyan => write!(f, "\u{1b}[36m"),
Color::Gray => write!(f, "\u{1b}[37m"),
Color::DarkGray => write!(f, "\u{1b}[90m"),
Color::LightRed => write!(f, "\u{1b}[91m"),
Color::LightGreen => write!(f, "\u{1b}[92m"),
Color::LightYellow => write!(f, "\u{1b}[93m"),
Color::LightBlue => write!(f, "\u{1b}[94m"),
Color::LightMagenta => write!(f, "\u{1b}[95m"),
Color::LightCyan => write!(f, "\u{1b}[96m"),
Color::White => write!(f, "\u{1b}[97m"),
Color::Indexed(i) => write!(f, "\u{1b}[{}m", i),
Color::Rgb(r, g, b) => write!(f, "\u{1b}[38;2;{};{};{}m", r, g, b),
}
}
} |
Importing the `WidgetExt` trait allows users to easily get a string representation of a widget with ANSI escape sequences for the terminal. This is useful for debugging and testing widgets. ```rust use ratatui::{prelude::*, widgets::widget_ext::WidgetExt}; fn main() { let greeting = Text::from(vec![ Line::styled("Hello", Color::Blue), Line::styled("World ", Color::Green), ]); println!("{}", greeting.to_ansi_string(5, 2)); } ``` Fixes: #1045
@imsnif I expanded on your approach in #1065 The cool thing about this is that it enables the following rather elegant code... use ratatui::{prelude::*, widgets::widget_ext::WidgetExt};
fn main() {
let greeting = Text::from(vec![
Line::styled("Hello", Color::Blue),
Line::styled("World ", Color::Green),
]);
println!("{}", greeting.to_ansi_string(5, 2));
} |
Importing the `WidgetExt` trait allows users to easily get a string representation of a widget with ANSI escape sequences for the terminal. This is useful for debugging and testing widgets. ```rust use ratatui::{prelude::*, widgets::widget_ext::WidgetExt}; fn main() { let greeting = Text::from(vec![ Line::styled("Hello", Color::Blue), Line::styled("World ", Color::Green), ]); println!("{}", greeting.to_ansi_string(5, 2)); } ``` Fixes: #1045
Amazing! I see another dependency+feature was added... I hope it will still compile to the I'll try to give it a spin to make sure later. |
Just a feature flag due to the various uncertainties over naming / approach, no extra deps added. |
Problem
Sometimes I want to print a widget that I'm developing to the terminal to see whether it is being displayed the way I expect it to. Currently, I have to set up a TUI with key handlers etc, run the TUI, exit the TUI.
I would like to instead just print the widget to the terminal.
TestBackend
has a debug print which almost does what I want but it doesn't display any colors.Solution
This works for me but I'm wondering if there's a better way to do this?
Ideally
TestBackend
would have a way to print with styles.The text was updated successfully, but these errors were encountered: