pub struct Buffer {
pub area: Rect,
pub content: Vec<Cell>,
}
Expand description
A buffer that maps to the desired content of the terminal after the draw call
No widget in the library interacts directly with the terminal. Instead each of them is required to draw their state to an intermediate buffer. It is basically a grid where each cell contains a grapheme, a foreground color and a background color. This grid will then be used to output the appropriate escape sequences and characters to draw the UI as the user has defined it.
Examples:
use ratatui::{prelude::*, buffer::Cell};
let mut buf = Buffer::empty(Rect{x: 0, y: 0, width: 10, height: 5});
buf.get_mut(0, 2).set_symbol("x");
assert_eq!(buf.get(0, 2).symbol, "x");
buf.set_string(3, 0, "string", Style::default().fg(Color::Red).bg(Color::White));
assert_eq!(buf.get(5, 0), &Cell{
symbol: String::from("r"),
fg: Color::Red,
bg: Color::White,
#[cfg(feature = "crossterm")]
underline_color: Color::Reset,
modifier: Modifier::empty(),
skip: false
});
buf.get_mut(5, 0).set_char('x');
assert_eq!(buf.get(5, 0).symbol, "x");
Fields§
§area: Rect
The area represented by this buffer
content: Vec<Cell>
The content of the buffer. The length of this Vec should always be equal to area.width * area.height
Implementations§
source§impl Buffer
impl Buffer
sourcepub fn filled(area: Rect, cell: &Cell) -> Buffer
pub fn filled(area: Rect, cell: &Cell) -> Buffer
Returns a Buffer with all cells initialized with the attributes of the given Cell
sourcepub fn with_lines<'a, S>(lines: Vec<S>) -> Buffer
pub fn with_lines<'a, S>(lines: Vec<S>) -> Buffer
Returns a Buffer containing the given lines
sourcepub fn get(&self, x: u16, y: u16) -> &Cell
pub fn get(&self, x: u16, y: u16) -> &Cell
Returns a reference to Cell at the given coordinates
sourcepub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell
pub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell
Returns a mutable reference to Cell at the given coordinates
Examples found in repository?
12 13 14 15 16 17 18 19 20 21 22 23 24
fn render(self, area: Rect, buf: &mut Buffer) {
for (yi, y) in (area.top()..area.bottom()).enumerate() {
let value = area.height as f32 - yi as f32;
let value_fg = value / (area.height as f32);
let value_bg = (value - 0.5) / (area.height as f32);
for (xi, x) in (area.left()..area.right()).enumerate() {
let hue = xi as f32 * 360.0 / area.width as f32;
let fg = color_from_oklab(hue, Okhsv::max_saturation(), value_fg);
let bg = color_from_oklab(hue, Okhsv::max_saturation(), value_bg);
buf.get_mut(x, y).set_char('▀').set_fg(fg).set_bg(bg);
}
}
}
More examples
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
fn render_colors(area: Rect, buf: &mut Buffer) {
for (xi, x) in (area.left()..area.right()).enumerate() {
for (yi, y) in (area.top()..area.bottom()).enumerate() {
let hue = xi as f32 * 360.0 / area.width as f32;
let value_fg = (yi as f32) / (area.height as f32 - 0.5);
let fg = Okhsv::<f32>::new(hue, Okhsv::max_saturation(), value_fg);
let fg: Srgb = fg.into_color_unclamped();
let fg: Srgb<u8> = fg.into_format();
let fg = Color::Rgb(fg.red, fg.green, fg.blue);
let value_bg = (yi as f32 + 0.5) / (area.height as f32 - 0.5);
let bg = Okhsv::new(hue, Okhsv::max_saturation(), value_bg);
let bg = Srgb::<f32>::from_color_unclamped(bg);
let bg: Srgb<u8> = bg.into_format();
let bg = Color::Rgb(bg.red, bg.green, bg.blue);
buf.get_mut(x, y).set_char('▀').set_fg(fg).set_bg(bg);
}
}
}
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
pub fn render_logo(selected_row: usize, area: Rect, buf: &mut Buffer) {
let eye_color = if selected_row % 2 == 0 {
THEME.logo.rat_eye
} else {
THEME.logo.rat_eye_alt
};
let area = area.inner(&Margin {
vertical: 0,
horizontal: 2,
});
for (y, (line1, line2)) in RATATUI_LOGO.iter().tuples().enumerate() {
for (x, (ch1, ch2)) in line1.chars().zip(line2.chars()).enumerate() {
let x = area.left() + x as u16;
let y = area.top() + y as u16;
let cell = buf.get_mut(x, y);
let rat_color = THEME.logo.rat;
let term_color = THEME.logo.term;
match (ch1, ch2) {
('█', '█') => {
cell.set_char('█');
cell.fg = rat_color;
}
('█', ' ') => {
cell.set_char('▀');
cell.fg = rat_color;
}
(' ', '█') => {
cell.set_char('▄');
cell.fg = rat_color;
}
('█', 'x') => {
cell.set_char('▀');
cell.fg = rat_color;
cell.bg = term_color;
}
('x', '█') => {
cell.set_char('▄');
cell.fg = rat_color;
cell.bg = term_color;
}
('x', 'x') => {
cell.set_char(' ');
cell.fg = term_color;
cell.bg = term_color;
}
('█', 'e') => {
cell.set_char('▀');
cell.fg = rat_color;
cell.bg = eye_color;
}
('e', '█') => {
cell.set_char('▄');
cell.fg = rat_color;
cell.bg = eye_color;
}
(_, _) => {}
};
}
}
}
sourcepub fn index_of(&self, x: u16, y: u16) -> usize
pub fn index_of(&self, x: u16, y: u16) -> usize
Returns the index in the Vec<Cell>
for the given global (x, y) coordinates.
Global coordinates are offset by the Buffer’s area offset (x
/y
).
Examples
let rect = Rect::new(200, 100, 10, 10);
let buffer = Buffer::empty(rect);
// Global coordinates to the top corner of this buffer's area
assert_eq!(buffer.index_of(200, 100), 0);
Panics
Panics when given an coordinate that is outside of this Buffer’s area.
let rect = Rect::new(200, 100, 10, 10);
let buffer = Buffer::empty(rect);
// Top coordinate is outside of the buffer in global coordinate space, as the Buffer's area
// starts at (200, 100).
buffer.index_of(0, 0); // Panics
sourcepub fn pos_of(&self, i: usize) -> (u16, u16)
pub fn pos_of(&self, i: usize) -> (u16, u16)
Returns the (global) coordinates of a cell given its index
Global coordinates are offset by the Buffer’s area offset (x
/y
).
Examples
let rect = Rect::new(200, 100, 10, 10);
let buffer = Buffer::empty(rect);
assert_eq!(buffer.pos_of(0), (200, 100));
assert_eq!(buffer.pos_of(14), (204, 101));
Panics
Panics when given an index that is outside the Buffer’s content.
let rect = Rect::new(0, 0, 10, 10); // 100 cells in total
let buffer = Buffer::empty(rect);
// Index 100 is the 101th cell, which lies outside of the area of this Buffer.
buffer.pos_of(100); // Panics
sourcepub fn set_string<S>(&mut self, x: u16, y: u16, string: S, style: Style)
pub fn set_string<S>(&mut self, x: u16, y: u16, string: S, style: Style)
Print a string, starting at the position (x, y)
Examples found in repository?
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
fn render(self, area: Rect, buf: &mut Buffer) {
let (background, text, shadow, highlight) = self.colors();
buf.set_style(area, Style::new().bg(background).fg(text));
// render top line if there's enough space
if area.height > 2 {
buf.set_string(
area.x,
area.y,
"▔".repeat(area.width as usize),
Style::new().fg(highlight).bg(background),
);
}
// render bottom line if there's enough space
if area.height > 1 {
buf.set_string(
area.x,
area.y + area.height - 1,
"▁".repeat(area.width as usize),
Style::new().fg(shadow).bg(background),
);
}
// render label centered
buf.set_line(
area.x + (area.width.saturating_sub(self.label.width() as u16)) / 2,
area.y + (area.height.saturating_sub(1)) / 2,
&self.label,
area.width,
);
}
sourcepub fn set_stringn<S>(
&mut self,
x: u16,
y: u16,
string: S,
width: usize,
style: Style
) -> (u16, u16)
pub fn set_stringn<S>( &mut self, x: u16, y: u16, string: S, width: usize, style: Style ) -> (u16, u16)
Print at most the first n characters of a string if enough space is available until the end of the line
sourcepub fn set_line(
&mut self,
x: u16,
y: u16,
line: &Line<'_>,
width: u16
) -> (u16, u16)
pub fn set_line( &mut self, x: u16, y: u16, line: &Line<'_>, width: u16 ) -> (u16, u16)
Examples found in repository?
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
fn render(self, area: Rect, buf: &mut Buffer) {
let (background, text, shadow, highlight) = self.colors();
buf.set_style(area, Style::new().bg(background).fg(text));
// render top line if there's enough space
if area.height > 2 {
buf.set_string(
area.x,
area.y,
"▔".repeat(area.width as usize),
Style::new().fg(highlight).bg(background),
);
}
// render bottom line if there's enough space
if area.height > 1 {
buf.set_string(
area.x,
area.y + area.height - 1,
"▁".repeat(area.width as usize),
Style::new().fg(shadow).bg(background),
);
}
// render label centered
buf.set_line(
area.x + (area.width.saturating_sub(self.label.width() as u16)) / 2,
area.y + (area.height.saturating_sub(1)) / 2,
&self.label,
area.width,
);
}
pub fn set_span( &mut self, x: u16, y: u16, span: &Span<'_>, width: u16 ) -> (u16, u16)
pub fn set_background(&mut self, area: Rect, color: Color)
Buffer::set_style
sourcepub fn set_style(&mut self, area: Rect, style: Style)
pub fn set_style(&mut self, area: Rect, style: Style)
Examples found in repository?
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
fn render(self, area: Rect, buf: &mut Buffer) {
let (background, text, shadow, highlight) = self.colors();
buf.set_style(area, Style::new().bg(background).fg(text));
// render top line if there's enough space
if area.height > 2 {
buf.set_string(
area.x,
area.y,
"▔".repeat(area.width as usize),
Style::new().fg(highlight).bg(background),
);
}
// render bottom line if there's enough space
if area.height > 1 {
buf.set_string(
area.x,
area.y + area.height - 1,
"▁".repeat(area.width as usize),
Style::new().fg(shadow).bg(background),
);
}
// render label centered
buf.set_line(
area.x + (area.width.saturating_sub(self.label.width() as u16)) / 2,
area.y + (area.height.saturating_sub(1)) / 2,
&self.label,
area.width,
);
}
sourcepub fn resize(&mut self, area: Rect)
pub fn resize(&mut self, area: Rect)
Resize the buffer so that the mapped area matches the given area and that the buffer length is equal to area.width * area.height
sourcepub fn diff<'a>(&self, other: &'a Buffer) -> Vec<(u16, u16, &'a Cell)>
pub fn diff<'a>(&self, other: &'a Buffer) -> Vec<(u16, u16, &'a Cell)>
Builds a minimal sequence of coordinates and Cells necessary to update the UI from self to other.
We’re assuming that buffers are well-formed, that is no double-width cell is followed by a non-blank cell.
Multi-width characters handling:
(Index:) `01`
Prev: `コ`
Next: `aa`
Updates: `0: a, 1: a'
(Index:) `01`
Prev: `a `
Next: `コ`
Updates: `0: コ` (double width symbol at index 0 - skip index 1)
(Index:) `012`
Prev: `aaa`
Next: `aコ`
Updates: `0: a, 1: コ` (double width symbol at index 1 - skip index 2)
Trait Implementations§
source§impl Debug for Buffer
impl Debug for Buffer
source§fn fmt(&self, f: &mut Formatter<'_>) -> Result
fn fmt(&self, f: &mut Formatter<'_>) -> Result
Writes a debug representation of the buffer to the given formatter.
The format is like a pretty printed struct, with the following fields:
area
: displayed asRect { x: 1, y: 2, width: 3, height: 4 }
content
: displayed as a list of strings representing the content of the bufferstyles
: displayed as a list of:{ x: 1, y: 2, fg: Color::Red, bg: Color::Blue, modifier: Modifier::BOLD }
only showing a value when there is a change in style.