diff options
| author | Ellie Huxtable <ellie@elliehuxtable.com> | 2023-03-31 22:57:37 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-03-31 22:57:37 +0100 |
| commit | a515b06bcb556c1be2d0fc3095cd778d413fe40d (patch) | |
| tree | 4b544de9aa53d6976177c08b91aa3943ef4d9e92 /src/ratatui/widgets/sparkline.rs | |
| parent | feat: add github action to test the nix builds (#833) (diff) | |
| download | atuin-a515b06bcb556c1be2d0fc3095cd778d413fe40d.zip | |
Vendor ratatui temporarily (#835)
* Vendor ratatui temporarily
Once https://github.com/tui-rs-revival/ratatui/pull/114 has been merged,
we can undo this! But otherwise we can't publish to crates.io with a git
dependency.
* make tests pass
* Shush.
* these literally just fail in nix, nowhere else
idk how to work with nix properly, and they're also not our tests
Diffstat (limited to 'src/ratatui/widgets/sparkline.rs')
| -rw-r--r-- | src/ratatui/widgets/sparkline.rs | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/ratatui/widgets/sparkline.rs b/src/ratatui/widgets/sparkline.rs new file mode 100644 index 00000000..a05df112 --- /dev/null +++ b/src/ratatui/widgets/sparkline.rs @@ -0,0 +1,155 @@ +use crate::ratatui::{ + buffer::Buffer, + layout::Rect, + style::Style, + symbols, + widgets::{Block, Widget}, +}; +use std::cmp::min; + +/// Widget to render a sparkline over one or more lines. +/// +/// # Examples +/// +/// ``` +/// # use ratatui::widgets::{Block, Borders, Sparkline}; +/// # use ratatui::style::{Style, Color}; +/// Sparkline::default() +/// .block(Block::default().title("Sparkline").borders(Borders::ALL)) +/// .data(&[0, 2, 3, 4, 1, 4, 10]) +/// .max(5) +/// .style(Style::default().fg(Color::Red).bg(Color::White)); +/// ``` +#[derive(Debug, Clone)] +pub struct Sparkline<'a> { + /// A block to wrap the widget in + block: Option<Block<'a>>, + /// Widget style + style: Style, + /// A slice of the data to display + data: &'a [u64], + /// The maximum value to take to compute the maximum bar height (if nothing is specified, the + /// widget uses the max of the dataset) + max: Option<u64>, + /// A set of bar symbols used to represent the give data + bar_set: symbols::bar::Set, +} + +impl<'a> Default for Sparkline<'a> { + fn default() -> Sparkline<'a> { + Sparkline { + block: None, + style: Default::default(), + data: &[], + max: None, + bar_set: symbols::bar::NINE_LEVELS, + } + } +} + +impl<'a> Sparkline<'a> { + pub fn block(mut self, block: Block<'a>) -> Sparkline<'a> { + self.block = Some(block); + self + } + + pub fn style(mut self, style: Style) -> Sparkline<'a> { + self.style = style; + self + } + + pub fn data(mut self, data: &'a [u64]) -> Sparkline<'a> { + self.data = data; + self + } + + pub fn max(mut self, max: u64) -> Sparkline<'a> { + self.max = Some(max); + self + } + + pub fn bar_set(mut self, bar_set: symbols::bar::Set) -> Sparkline<'a> { + self.bar_set = bar_set; + self + } +} + +impl<'a> Widget for Sparkline<'a> { + fn render(mut self, area: Rect, buf: &mut Buffer) { + let spark_area = match self.block.take() { + Some(b) => { + let inner_area = b.inner(area); + b.render(area, buf); + inner_area + } + None => area, + }; + + if spark_area.height < 1 { + return; + } + + let max = match self.max { + Some(v) => v, + None => *self.data.iter().max().unwrap_or(&1u64), + }; + let max_index = min(spark_area.width as usize, self.data.len()); + let mut data = self + .data + .iter() + .take(max_index) + .map(|e| { + if max != 0 { + e * u64::from(spark_area.height) * 8 / max + } else { + 0 + } + }) + .collect::<Vec<u64>>(); + for j in (0..spark_area.height).rev() { + for (i, d) in data.iter_mut().enumerate() { + let symbol = match *d { + 0 => self.bar_set.empty, + 1 => self.bar_set.one_eighth, + 2 => self.bar_set.one_quarter, + 3 => self.bar_set.three_eighths, + 4 => self.bar_set.half, + 5 => self.bar_set.five_eighths, + 6 => self.bar_set.three_quarters, + 7 => self.bar_set.seven_eighths, + _ => self.bar_set.full, + }; + buf.get_mut(spark_area.left() + i as u16, spark_area.top() + j) + .set_symbol(symbol) + .set_style(self.style); + + if *d > 8 { + *d -= 8; + } else { + *d = 0; + } + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_does_not_panic_if_max_is_zero() { + let widget = Sparkline::default().data(&[0, 0, 0]); + let area = Rect::new(0, 0, 3, 1); + let mut buffer = Buffer::empty(area); + widget.render(area, &mut buffer); + } + + #[test] + fn it_does_not_panic_if_max_is_set_to_zero() { + let widget = Sparkline::default().data(&[0, 1, 2]).max(0); + let area = Rect::new(0, 0, 3, 1); + let mut buffer = Buffer::empty(area); + widget.render(area, &mut buffer); + } +} |
