mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-22 04:33:13 +00:00
refactor: Avoid unneeded allocations (#1345)
This commit is contained in:
parent
e02947be61
commit
20c88aaa5b
10 changed files with 62 additions and 108 deletions
|
@ -14,7 +14,6 @@
|
|||
//! [examples readme]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
||||
|
||||
use color_eyre::Result;
|
||||
use itertools::Itertools;
|
||||
use ratatui::{
|
||||
crossterm::event::{self, Event, KeyCode, KeyEventKind},
|
||||
layout::{Alignment, Constraint, Layout, Rect},
|
||||
|
@ -90,7 +89,7 @@ fn calculate_layout(area: Rect) -> (Rect, Vec<Vec<Rect>>) {
|
|||
.split(area)
|
||||
.to_vec()
|
||||
})
|
||||
.collect_vec();
|
||||
.collect();
|
||||
(title_area, main_areas)
|
||||
}
|
||||
|
||||
|
|
|
@ -99,19 +99,16 @@ fn render_fg_named_colors(frame: &mut Frame, bg: Color, area: Rect) {
|
|||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let layout = Layout::vertical([Constraint::Length(1); 2])
|
||||
.split(inner)
|
||||
.iter()
|
||||
.flat_map(|area| {
|
||||
Layout::horizontal([Constraint::Ratio(1, 8); 8])
|
||||
.split(*area)
|
||||
.to_vec()
|
||||
})
|
||||
.collect_vec();
|
||||
for (i, &fg) in NAMED_COLORS.iter().enumerate() {
|
||||
let vertical = Layout::vertical([Constraint::Length(1); 2]).split(inner);
|
||||
let areas = vertical.iter().flat_map(|area| {
|
||||
Layout::horizontal([Constraint::Ratio(1, 8); 8])
|
||||
.split(*area)
|
||||
.to_vec()
|
||||
});
|
||||
for (fg, area) in NAMED_COLORS.into_iter().zip(areas) {
|
||||
let color_name = fg.to_string();
|
||||
let paragraph = Paragraph::new(color_name).fg(fg).bg(bg);
|
||||
frame.render_widget(paragraph, layout[i]);
|
||||
frame.render_widget(paragraph, area);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -120,19 +117,16 @@ fn render_bg_named_colors(frame: &mut Frame, fg: Color, area: Rect) {
|
|||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
|
||||
let layout = Layout::vertical([Constraint::Length(1); 2])
|
||||
.split(inner)
|
||||
.iter()
|
||||
.flat_map(|area| {
|
||||
Layout::horizontal([Constraint::Ratio(1, 8); 8])
|
||||
.split(*area)
|
||||
.to_vec()
|
||||
})
|
||||
.collect_vec();
|
||||
for (i, &bg) in NAMED_COLORS.iter().enumerate() {
|
||||
let vertical = Layout::vertical([Constraint::Length(1); 2]).split(inner);
|
||||
let areas = vertical.iter().flat_map(|area| {
|
||||
Layout::horizontal([Constraint::Ratio(1, 8); 8])
|
||||
.split(*area)
|
||||
.to_vec()
|
||||
});
|
||||
for (bg, area) in NAMED_COLORS.into_iter().zip(areas) {
|
||||
let color_name = bg.to_string();
|
||||
let paragraph = Paragraph::new(color_name).fg(fg).bg(bg);
|
||||
frame.render_widget(paragraph, layout[i]);
|
||||
frame.render_widget(paragraph, area);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -346,13 +346,8 @@ impl App {
|
|||
}
|
||||
|
||||
fn render_user_constraints_legend(&self, area: Rect, buf: &mut Buffer) {
|
||||
let blocks = Layout::horizontal(
|
||||
self.constraints
|
||||
.iter()
|
||||
.map(|_| Constraint::Fill(1))
|
||||
.collect_vec(),
|
||||
)
|
||||
.split(area);
|
||||
let constraints = self.constraints.iter().map(|_| Constraint::Fill(1));
|
||||
let blocks = Layout::horizontal(constraints).split(area);
|
||||
|
||||
for (i, (area, constraint)) in blocks.iter().zip(self.constraints.iter()).enumerate() {
|
||||
let selected = self.selected_index == i;
|
||||
|
|
|
@ -96,13 +96,10 @@ fn render_inbox(selected_index: usize, area: Rect, buf: &mut Buffer) {
|
|||
.map(|e| e.from.width())
|
||||
.max()
|
||||
.unwrap_or_default();
|
||||
let items = EMAILS
|
||||
.iter()
|
||||
.map(|e| {
|
||||
let from = format!("{:width$}", e.from, width = from_width).into();
|
||||
ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
|
||||
})
|
||||
.collect_vec();
|
||||
let items = EMAILS.iter().map(|e| {
|
||||
let from = format!("{:width$}", e.from, width = from_width).into();
|
||||
ListItem::new(Line::from(vec![from, " ".into(), e.subject.into()]))
|
||||
});
|
||||
let mut state = ListState::default().with_selected(Some(selected_index));
|
||||
StatefulWidget::render(
|
||||
List::new(items)
|
||||
|
|
|
@ -52,10 +52,7 @@ impl Widget for TracerouteTab {
|
|||
|
||||
fn render_hops(selected_row: usize, area: Rect, buf: &mut Buffer) {
|
||||
let mut state = TableState::default().with_selected(Some(selected_row));
|
||||
let rows = HOPS
|
||||
.iter()
|
||||
.map(|hop| Row::new(vec![hop.host, hop.address]))
|
||||
.collect_vec();
|
||||
let rows = HOPS.iter().map(|hop| Row::new(vec![hop.host, hop.address]));
|
||||
let block = Block::new()
|
||||
.padding(Padding::new(1, 1, 1, 1))
|
||||
.title_alignment(Alignment::Center)
|
||||
|
|
|
@ -74,31 +74,28 @@ fn draw(frame: &mut Frame) {
|
|||
Min(0), // fills remaining space
|
||||
])
|
||||
.split(examples_area);
|
||||
let example_areas = example_rows
|
||||
let example_areas = example_rows.iter().flat_map(|area| {
|
||||
Layout::horizontal([
|
||||
Length(14),
|
||||
Length(14),
|
||||
Length(14),
|
||||
Length(14),
|
||||
Length(14),
|
||||
Min(0), // fills remaining space
|
||||
])
|
||||
.split(*area)
|
||||
.iter()
|
||||
.flat_map(|area| {
|
||||
Layout::horizontal([
|
||||
Length(14),
|
||||
Length(14),
|
||||
Length(14),
|
||||
Length(14),
|
||||
Length(14),
|
||||
Min(0), // fills remaining space
|
||||
])
|
||||
.split(*area)
|
||||
.iter()
|
||||
.copied()
|
||||
.take(5) // ignore Min(0)
|
||||
.collect_vec()
|
||||
})
|
||||
.collect_vec();
|
||||
.copied()
|
||||
.take(5) // ignore Min(0)
|
||||
.collect_vec()
|
||||
});
|
||||
|
||||
// the examples are a cartesian product of the following constraints
|
||||
// e.g. Len/Len, Len/Min, Len/Max, Len/Perc, Len/Ratio, Min/Len, Min/Min, ...
|
||||
let examples = [
|
||||
(
|
||||
"Len",
|
||||
vec![
|
||||
[
|
||||
Length(0),
|
||||
Length(2),
|
||||
Length(3),
|
||||
|
@ -107,17 +104,11 @@ fn draw(frame: &mut Frame) {
|
|||
Length(15),
|
||||
],
|
||||
),
|
||||
(
|
||||
"Min",
|
||||
vec![Min(0), Min(2), Min(3), Min(6), Min(10), Min(15)],
|
||||
),
|
||||
(
|
||||
"Max",
|
||||
vec![Max(0), Max(2), Max(3), Max(6), Max(10), Max(15)],
|
||||
),
|
||||
("Min", [Min(0), Min(2), Min(3), Min(6), Min(10), Min(15)]),
|
||||
("Max", [Max(0), Max(2), Max(3), Max(6), Max(10), Max(15)]),
|
||||
(
|
||||
"Perc",
|
||||
vec![
|
||||
[
|
||||
Percentage(0),
|
||||
Percentage(25),
|
||||
Percentage(50),
|
||||
|
@ -128,7 +119,7 @@ fn draw(frame: &mut Frame) {
|
|||
),
|
||||
(
|
||||
"Ratio",
|
||||
vec![
|
||||
[
|
||||
Ratio(0, 4),
|
||||
Ratio(1, 4),
|
||||
Ratio(2, 4),
|
||||
|
@ -139,24 +130,15 @@ fn draw(frame: &mut Frame) {
|
|||
),
|
||||
];
|
||||
|
||||
for (i, (a, b)) in examples
|
||||
for ((a, b), area) in examples
|
||||
.iter()
|
||||
.cartesian_product(examples.iter())
|
||||
.enumerate()
|
||||
.zip(example_areas)
|
||||
{
|
||||
let (name_a, examples_a) = a;
|
||||
let (name_b, examples_b) = b;
|
||||
let constraints = examples_a
|
||||
.iter()
|
||||
.copied()
|
||||
.zip(examples_b.iter().copied())
|
||||
.collect_vec();
|
||||
render_example_combination(
|
||||
frame,
|
||||
example_areas[i],
|
||||
&format!("{name_a}/{name_b}"),
|
||||
constraints,
|
||||
);
|
||||
let constraints = examples_a.iter().copied().zip(examples_b.iter().copied());
|
||||
render_example_combination(frame, area, &format!("{name_a}/{name_b}"), constraints);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +147,7 @@ fn render_example_combination(
|
|||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
title: &str,
|
||||
constraints: Vec<(Constraint, Constraint)>,
|
||||
constraints: impl ExactSizeIterator<Item = (Constraint, Constraint)>,
|
||||
) {
|
||||
let block = Block::bordered()
|
||||
.title(title.gray())
|
||||
|
@ -174,8 +156,8 @@ fn render_example_combination(
|
|||
let inner = block.inner(area);
|
||||
frame.render_widget(block, area);
|
||||
let layout = Layout::vertical(vec![Length(1); constraints.len() + 1]).split(inner);
|
||||
for (i, (a, b)) in constraints.into_iter().enumerate() {
|
||||
render_single_example(frame, layout[i], vec![a, b, Min(0)]);
|
||||
for ((a, b), &area) in constraints.into_iter().zip(layout.iter()) {
|
||||
render_single_example(frame, area, vec![a, b, Min(0)]);
|
||||
}
|
||||
// This is to make it easy to visually see the alignment of the examples
|
||||
// with the constraints.
|
||||
|
|
|
@ -294,7 +294,7 @@ fn generate_fake_names() -> Vec<Data> {
|
|||
}
|
||||
})
|
||||
.sorted_by(|a, b| a.name.cmp(&b.name))
|
||||
.collect_vec()
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn constraint_len_calculator(items: &[Data]) -> (u16, u16, u16) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use std::fmt;
|
||||
|
||||
use itertools::Itertools;
|
||||
use strum::EnumIs;
|
||||
|
||||
/// A constraint that defines the size of a layout element.
|
||||
|
@ -229,7 +228,7 @@ impl Constraint {
|
|||
where
|
||||
T: IntoIterator<Item = u16>,
|
||||
{
|
||||
lengths.into_iter().map(Self::Length).collect_vec()
|
||||
lengths.into_iter().map(Self::Length).collect()
|
||||
}
|
||||
|
||||
/// Convert an iterator of ratios into a vector of constraints
|
||||
|
@ -246,10 +245,7 @@ impl Constraint {
|
|||
where
|
||||
T: IntoIterator<Item = (u32, u32)>,
|
||||
{
|
||||
ratios
|
||||
.into_iter()
|
||||
.map(|(n, d)| Self::Ratio(n, d))
|
||||
.collect_vec()
|
||||
ratios.into_iter().map(|(n, d)| Self::Ratio(n, d)).collect()
|
||||
}
|
||||
|
||||
/// Convert an iterator of percentages into a vector of constraints
|
||||
|
@ -266,7 +262,7 @@ impl Constraint {
|
|||
where
|
||||
T: IntoIterator<Item = u16>,
|
||||
{
|
||||
percentages.into_iter().map(Self::Percentage).collect_vec()
|
||||
percentages.into_iter().map(Self::Percentage).collect()
|
||||
}
|
||||
|
||||
/// Convert an iterator of maxes into a vector of constraints
|
||||
|
@ -283,7 +279,7 @@ impl Constraint {
|
|||
where
|
||||
T: IntoIterator<Item = u16>,
|
||||
{
|
||||
maxes.into_iter().map(Self::Max).collect_vec()
|
||||
maxes.into_iter().map(Self::Max).collect()
|
||||
}
|
||||
|
||||
/// Convert an iterator of mins into a vector of constraints
|
||||
|
@ -300,7 +296,7 @@ impl Constraint {
|
|||
where
|
||||
T: IntoIterator<Item = u16>,
|
||||
{
|
||||
mins.into_iter().map(Self::Min).collect_vec()
|
||||
mins.into_iter().map(Self::Min).collect()
|
||||
}
|
||||
|
||||
/// Convert an iterator of proportional factors into a vector of constraints
|
||||
|
@ -317,10 +313,7 @@ impl Constraint {
|
|||
where
|
||||
T: IntoIterator<Item = u16>,
|
||||
{
|
||||
proportional_factors
|
||||
.into_iter()
|
||||
.map(Self::Fill)
|
||||
.collect_vec()
|
||||
proportional_factors.into_iter().map(Self::Fill).collect()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1315,9 +1315,9 @@ mod tests {
|
|||
.flex(flex)
|
||||
.split(area);
|
||||
let mut buffer = Buffer::empty(area);
|
||||
for (i, c) in ('a'..='z').take(constraints.len()).enumerate() {
|
||||
for (c, &area) in ('a'..='z').take(constraints.len()).zip(layout.iter()) {
|
||||
let s = c.to_string().repeat(area.width as usize);
|
||||
Paragraph::new(s).render(layout[i], &mut buffer);
|
||||
Paragraph::new(s).render(area, &mut buffer);
|
||||
}
|
||||
assert_eq!(buffer, Buffer::with_lines([expected]));
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
#![warn(missing_docs)]
|
||||
use std::{borrow::Cow, fmt};
|
||||
|
||||
use itertools::{Itertools, Position};
|
||||
|
||||
use crate::{prelude::*, style::Styled};
|
||||
|
||||
/// A string split over one or more lines.
|
||||
|
@ -632,12 +630,11 @@ impl<T: fmt::Display> ToText for T {
|
|||
|
||||
impl fmt::Display for Text<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
for (position, line) in self.iter().with_position() {
|
||||
if position == Position::Last || position == Position::Only {
|
||||
write!(f, "{line}")?;
|
||||
} else {
|
||||
if let Some((last, rest)) = self.lines.split_last() {
|
||||
for line in rest {
|
||||
writeln!(f, "{line}")?;
|
||||
}
|
||||
write!(f, "{last}")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue