diff options
author | Conrad Ludgate <conradludgate@gmail.com> | 2023-03-23 09:19:29 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-23 09:19:29 +0000 |
commit | ba1d615f5e5d904a3bd7a7f5f0ce336b89995aea (patch) | |
tree | db84efdef064426a9c2e32b897bb39c06fe4145e | |
parent | 378be6b790c3d504c8d7d873ce035daf926e98ed (diff) |
chore: remove tui vendoring (#804)
-rw-r--r-- | Cargo.lock | 21 | ||||
-rw-r--r-- | Cargo.toml | 6 | ||||
-rw-r--r-- | src/command/client/search/history_list.rs | 4 | ||||
-rw-r--r-- | src/command/client/search/interactive.rs | 18 | ||||
-rw-r--r-- | src/main.rs | 1 | ||||
-rw-r--r-- | src/tui/LICENSE | 21 | ||||
-rw-r--r-- | src/tui/README.md | 5 | ||||
-rw-r--r-- | src/tui/backend/crossterm.rs | 221 | ||||
-rw-r--r-- | src/tui/backend/mod.rs | 20 | ||||
-rw-r--r-- | src/tui/buffer.rs | 734 | ||||
-rw-r--r-- | src/tui/layout.rs | 537 | ||||
-rw-r--r-- | src/tui/mod.rs | 20 | ||||
-rw-r--r-- | src/tui/style.rs | 278 | ||||
-rw-r--r-- | src/tui/symbols.rs | 233 | ||||
-rw-r--r-- | src/tui/terminal.rs | 321 | ||||
-rw-r--r-- | src/tui/text.rs | 428 | ||||
-rw-r--r-- | src/tui/widgets/block.rs | 562 | ||||
-rw-r--r-- | src/tui/widgets/mod.rs | 159 | ||||
-rw-r--r-- | src/tui/widgets/paragraph.rs | 194 | ||||
-rw-r--r-- | src/tui/widgets/reflow.rs | 537 |
20 files changed, 27 insertions, 4293 deletions
@@ -83,8 +83,6 @@ dependencies = [ "atuin-common", "atuin-server", "base64 0.20.0", - "bitflags", - "cassowary", "chrono", "clap", "clap_complete", @@ -99,6 +97,7 @@ dependencies = [ "interim", "itertools", "log", + "ratatui", "rpassword", "runtime-format", "semver", @@ -108,7 +107,6 @@ dependencies = [ "tiny-bip39", "tokio", "tracing-subscriber", - "unicode-segmentation", "unicode-width", "whoami", ] @@ -1764,6 +1762,19 @@ dependencies = [ ] [[package]] +name = "ratatui" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcc0d032bccba900ee32151ec0265667535c230169f5a011154cdcd984e16829" +dependencies = [ + "bitflags", + "cassowary", + "crossterm", + "unicode-segmentation", + "unicode-width", +] + +[[package]] name = "rayon" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2790,9 +2801,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" @@ -74,11 +74,7 @@ runtime-format = "0.1.2" tiny-bip39 = "1" futures-util = "0.3" skim = { version = "0.10.2", default-features = false } - -# from tui -bitflags = "1.3" -cassowary = "0.3" -unicode-segmentation = "1.2" +ratatui = "0.20.1" [dependencies.tracing-subscriber] version = "0.3" diff --git a/src/command/client/search/history_list.rs b/src/command/client/search/history_list.rs index 27a8b294..60ec15a8 100644 --- a/src/command/client/search/history_list.rs +++ b/src/command/client/search/history_list.rs @@ -1,12 +1,12 @@ use std::{sync::Arc, time::Duration}; -use crate::tui::{ +use atuin_client::history::History; +use ratatui::{ buffer::Buffer, layout::Rect, style::{Color, Modifier, Style}, widgets::{Block, StatefulWidget, Widget}, }; -use atuin_client::history::History; use super::{format_duration, interactive::HistoryWrapper}; diff --git a/src/command/client/search/interactive.rs b/src/command/client/search/interactive.rs index 6b26def8..4b5e0d7e 100644 --- a/src/command/client/search/interactive.rs +++ b/src/command/client/search/interactive.rs @@ -26,16 +26,14 @@ use super::{ cursor::Cursor, history_list::{HistoryList, ListState, PREFIX_LENGTH}, }; -use crate::{ - tui::{ - backend::{Backend, CrosstermBackend}, - layout::{Alignment, Constraint, Direction, Layout}, - style::{Color, Modifier, Style}, - text::{Span, Spans, Text}, - widgets::{Block, BorderType, Borders, Paragraph}, - Frame, Terminal, - }, - VERSION, +use crate::VERSION; +use ratatui::{ + backend::{Backend, CrosstermBackend}, + layout::{Alignment, Constraint, Direction, Layout}, + style::{Color, Modifier, Style}, + text::{Span, Spans, Text}, + widgets::{Block, BorderType, Borders, Paragraph}, + Frame, Terminal, }; const RETURN_ORIGINAL: usize = usize::MAX; diff --git a/src/main.rs b/src/main.rs index 3004e0b1..2f81f4fc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ use eyre::Result; use command::AtuinCmd; mod command; -mod tui; const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/tui/LICENSE b/src/tui/LICENSE deleted file mode 100644 index 7a0657cb..00000000 --- a/src/tui/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 Florian Dehau - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/src/tui/README.md b/src/tui/README.md deleted file mode 100644 index 506bdf8f..00000000 --- a/src/tui/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# tui-rs - -A fork of https://crates.io/crates/tui/0.19.0 since it is now unmaintained. - -Some parts have been removed or modified for simplicity, but it is currently mostly equivalent. diff --git a/src/tui/backend/crossterm.rs b/src/tui/backend/crossterm.rs deleted file mode 100644 index 2cbfd6e0..00000000 --- a/src/tui/backend/crossterm.rs +++ /dev/null @@ -1,221 +0,0 @@ -use crate::tui::{ - backend::Backend, - buffer::Cell, - layout::Rect, - style::{Color, Modifier}, -}; -use crossterm::{ - cursor::{Hide, MoveTo, Show}, - execute, queue, - style::{ - Attribute as CAttribute, Color as CColor, Print, SetAttribute, SetBackgroundColor, - SetForegroundColor, - }, - terminal::{self, Clear, ClearType}, -}; -use std::io::{self, Write}; - -pub struct CrosstermBackend<W: Write> { - buffer: W, -} - -impl<W> CrosstermBackend<W> -where - W: Write, -{ - pub fn new(buffer: W) -> CrosstermBackend<W> { - CrosstermBackend { buffer } - } -} - -impl<W> Write for CrosstermBackend<W> -where - W: Write, -{ - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - self.buffer.write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.buffer.flush() - } -} - -impl<W> Backend for CrosstermBackend<W> -where - W: Write, -{ - fn draw<'a, I>(&mut self, content: I) -> io::Result<()> - where - I: Iterator<Item = (u16, u16, &'a Cell)>, - { - let mut fg = Color::Reset; - let mut bg = Color::Reset; - let mut modifier = Modifier::empty(); - let mut last_pos: Option<(u16, u16)> = None; - for (x, y, cell) in content { - // Move the cursor if the previous location was not (x - 1, y) - if !matches!(last_pos, Some(p) if x == p.0 + 1 && y == p.1) { - map_error(queue!(self.buffer, MoveTo(x, y)))?; - } - last_pos = Some((x, y)); - if cell.modifier != modifier { - let diff = ModifierDiff { - from: modifier, - to: cell.modifier, - }; - diff.queue(&mut self.buffer)?; - modifier = cell.modifier; - } - if cell.fg != fg { - let color = CColor::from(cell.fg); - map_error(queue!(self.buffer, SetForegroundColor(color)))?; - fg = cell.fg; - } - if cell.bg != bg { - let color = CColor::from(cell.bg); - map_error(queue!(self.buffer, SetBackgroundColor(color)))?; - bg = cell.bg; - } - - map_error(queue!(self.buffer, Print(&cell.symbol)))?; - } - - map_error(queue!( - self.buffer, - SetForegroundColor(CColor::Reset), - SetBackgroundColor(CColor::Reset), - SetAttribute(CAttribute::Reset) - )) - } - - fn hide_cursor(&mut self) -> io::Result<()> { - map_error(execute!(self.buffer, Hide)) - } - - fn show_cursor(&mut self) -> io::Result<()> { - map_error(execute!(self.buffer, Show)) - } - - fn get_cursor(&mut self) -> io::Result<(u16, u16)> { - crossterm::cursor::position() - .map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) - } - - fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> { - map_error(execute!(self.buffer, MoveTo(x, y))) - } - - fn clear(&mut self) -> io::Result<()> { - map_error(execute!(self.buffer, Clear(ClearType::All))) - } - - fn size(&self) -> io::Result<Rect> { - let (width, height) = - terminal::size().map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))?; - - Ok(Rect::new(0, 0, width, height)) - } - - fn flush(&mut self) -> io::Result<()> { - self.buffer.flush() - } -} - -fn map_error(error: crossterm::Result<()>) -> io::Result<()> { - error.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string())) -} - -impl From<Color> for CColor { - fn from(color: Color) -> Self { - match color { - Color::Reset => CColor::Reset, - Color::Black => CColor::Black, - Color::Red => CColor::DarkRed, - Color::Green => CColor::DarkGreen, - Color::Yellow => CColor::DarkYellow, - Color::Blue => CColor::DarkBlue, - Color::Magenta => CColor::DarkMagenta, - Color::Cyan => CColor::DarkCyan, - Color::Gray => CColor::Grey, - Color::DarkGray => CColor::DarkGrey, - Color::LightRed => CColor::Red, - Color::LightGreen => CColor::Green, - Color::LightBlue => CColor::Blue, - Color::LightYellow => CColor::Yellow, - Color::LightMagenta => CColor::Magenta, - Color::LightCyan => CColor::Cyan, - Color::White => CColor::White, - Color::Indexed(i) => CColor::AnsiValue(i), - Color::Rgb(r, g, b) => CColor::Rgb { r, g, b }, - } - } -} - -#[derive(Debug)] -struct ModifierDiff { - pub from: Modifier, - pub to: Modifier, -} - -impl ModifierDiff { - fn queue<W>(&self, mut w: W) -> io::Result<()> - where - W: io::Write, - { - //use crossterm::Attribute; - let removed = self.from - self.to; - if removed.contains(Modifier::REVERSED) { - map_error(queue!(w, SetAttribute(CAttribute::NoReverse)))?; - } - if removed.contains(Modifier::BOLD) { - map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?; - if self.to.contains(Modifier::DIM) { - map_error(queue!(w, SetAttribute(CAttribute::Dim)))?; - } - } - if removed.contains(Modifier::ITALIC) { - map_error(queue!(w, SetAttribute(CAttribute::NoItalic)))?; - } - if removed.contains(Modifier::UNDERLINED) { - map_error(queue!(w, SetAttribute(CAttribute::NoUnderline)))?; - } - if removed.contains(Modifier::DIM) { - map_error(queue!(w, SetAttribute(CAttribute::NormalIntensity)))?; - } - if removed.contains(Modifier::CROSSED_OUT) { - map_error(queue!(w, SetAttribute(CAttribute::NotCrossedOut)))?; - } - if removed.contains(Modifier::SLOW_BLINK) || removed.contains(Modifier::RAPID_BLINK) { - map_error(queue!(w, SetAttribute(CAttribute::NoBlink)))?; - } - - let added = self.to - self.from; - if added.contains(Modifier::REVERSED) { - map_error(queue!(w, SetAttribute(CAttribute::Reverse)))?; - } - if added.contains(Modifier::BOLD) { - map_error(queue!(w, SetAttribute(CAttribute::Bold)))?; - } - if added.contains(Modifier::ITALIC) { - map_error(queue!(w, SetAttribute(CAttribute::Italic)))?; - } - if added.contains(Modifier::UNDERLINED) { - map_error(queue!(w, SetAttribute(CAttribute::Underlined)))?; - } - if added.contains(Modifier::DIM) { - map_error(queue!(w, SetAttribute(CAttribute::Dim)))?; - } - if added.contains(Modifier::CROSSED_OUT) { - map_error(queue!(w, SetAttribute(CAttribute::CrossedOut)))?; - } - if added.contains(Modifier::SLOW_BLINK) { - map_error(queue!(w, SetAttribute(CAttribute::SlowBlink)))?; - } - if added.contains(Modifier::RAPID_BLINK) { - map_error(queue!(w, SetAttribute(CAttribute::RapidBlink)))?; - } - - Ok(()) - } -} diff --git a/src/tui/backend/mod.rs b/src/tui/backend/mod.rs deleted file mode 100644 index 1a197e79..00000000 --- a/src/tui/backend/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -use std::io; - -use crate::tui::buffer::Cell; -use crate::tui::layout::Rect; - -mod crossterm; -pub use self::crossterm::CrosstermBackend; - -pub trait Backend { - fn draw<'a, I>(&mut self, content: I) -> Result<(), io::Error> - where - I: Iterator<Item = (u16, u16, &'a Cell)>; - fn hide_cursor(&mut self) -> Result<(), io::Error>; - fn show_cursor(&mut self) -> Result<(), io::Error>; - fn get_cursor(&mut self) -> Result<(u16, u16), io::Error>; - fn set_cursor(&mut self, x: u16, y: u16) -> Result<(), io::Error>; - fn clear(&mut self) -> Result<(), io::Error>; - fn size(&self) -> Result<Rect, io::Error>; - fn flush(&mut self) -> Result<(), io::Error>; -} diff --git a/src/tui/buffer.rs b/src/tui/buffer.rs deleted file mode 100644 index 8bc49316..00000000 --- a/src/tui/buffer.rs +++ /dev/null @@ -1,734 +0,0 @@ -use crate::tui::{ - layout::Rect, - style::{Color, Modifier, Style}, - text::{Span, Spans}, -}; -use std::cmp::min; -use unicode_segmentation::UnicodeSegmentation; -use unicode_width::UnicodeWidthStr; - -/// A buffer cell -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Cell { - pub symbol: String, - pub fg: Color, - pub bg: Color, - pub modifier: Modifier, -} - -impl Cell { - pub fn set_symbol(&mut self, symbol: &str) -> &mut Cell { - self.symbol.clear(); - self.symbol.push_str(symbol); - self - } - - pub fn set_char(&mut self, ch: char) -> &mut Cell { - self.symbol.clear(); - self.symbol.push(ch); - self - } - - pub fn set_fg(&mut self, color: Color) -> &mut Cell { - self.fg = color; - self - } - - pub fn set_bg(&mut self, color: Color) -> &mut Cell { - self.bg = color; - self - } - - pub fn set_style(&mut self, style: Style) -> &mut Cell { - if let Some(c) = style.fg { - self.fg = c; - } - if let Some(c) = style.bg { - self.bg = c; - } - self.modifier.insert(style.add_modifier); - self.modifier.remove(style.sub_modifier); - self - } - - pub fn style(&self) -> Style { - Style::default() - .fg(self.fg) - .bg(self.bg) - .add_modifier(self.modifier) - } - - pub fn reset(&mut self) { - self.symbol.clear(); - self.symbol.push(' '); - self.fg = Color::Reset; - self.bg = Color::Reset; - self.modifier = Modifier::empty(); - } -} - -impl Default for Cell { - fn default() -> Cell { - Cell { - symbol: " ".into(), - fg: Color::Reset, - bg: Color::Reset, - modifier: Modifier::empty(), - } - } -} - -/// 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 tui::buffer::{Buffer, Cell}; -/// use tui::layout::Rect; -/// use tui::style::{Color, Style, Modifier}; -/// -/// 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, -/// modifier: Modifier::empty() -/// }); -/// buf.get_mut(5, 0).set_char('x'); -/// assert_eq!(buf.get(5, 0).symbol, "x"); -/// ``` -#[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct Buffer { - /// The area represented by this buffer - pub area: Rect, - /// The content of the buffer. The length of this Vec should always be equal to area.width * - /// area.height - pub content: Vec<Cell>, -} - -impl Buffer { - /// Returns a Buffer with all cells set to the default one - pub fn empty(area: Rect) -> Buffer { - let cell = Cell::default(); - Buffer::filled(area, &cell) - } - - /// Returns a Buffer with all cells initialized with the attributes of the given Cell - pub fn filled(area: Rect, cell: &Cell) -> Buffer { - let size = area.area() as usize; - let mut content = Vec::with_capacity(size); - for _ in 0..size { - content.push(cell.clone()); - } - Buffer { area, content } - } - - /// Returns a Buffer containing the given lines - pub fn with_lines<S>(lines: &[S]) -> Buffer - where - S: AsRef<str>, - { - let height = lines.len() as u16; - let width = lines - .iter() - .map(|i| i.as_ref().width() as u16) - .max() - .unwrap_or_default(); - let mut buffer = Buffer::empty(Rect { - x: 0, - y: 0, - width, - height, - }); - for (y, line) in lines.iter().enumerate() { - buffer.set_string(0, y as u16, line, Style::default()); - } - buffer - } - - /// Returns the content of the buffer as a slice - pub fn content(&self) -> &[Cell] { - &self.content - } - - /// Returns the area covered by this buffer - pub fn area(&self) -> &Rect { - &self.area - } - - /// Returns a reference to Cell at the given coordinates - pub fn get(&self, x: u16, y: u16) -> &Cell { - let i = self.index_of(x, y); - &self.content[i] - } - - /// Returns a mutable reference to Cell at the given coordinates - pub fn get_mut(&mut self, x: u16, y: u16) -> &mut Cell { - let i = self.index_of(x, y); - &mut self.content[i] - } - - /// 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 - /// - /// ``` - /// # use tui::buffer::Buffer; - /// # use tui::layout::Rect; - /// 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. - /// - /// ```should_panic - /// # use tui::buffer::Buffer; - /// # use tui::layout::Rect; - /// 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 - /// ``` - pub fn index_of(&self, x: u16, y: u16) -> usize { - debug_assert!( - x >= self.area.left() - && x < self.area.right() - && y >= self.area.top() - && y < self.area.bottom(), - "Trying to access position outside the buffer: x={}, y={}, area={:?}", - x, - y, - self.area - ); - ((y - self.area.y) * self.area.width + (x - self.area.x)) as usize - } - - /// Returns the (global) coordinates of a cell given its index - /// - /// Global coordinates are offset by the Buffer's area offset (`x`/`y`). - /// - /// # Examples - /// - /// ``` - /// # use tui::buffer::Buffer; - /// # use tui::layout::Rect; - /// 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. - /// - /// ```should_panic - /// # use tui::buffer::Buffer; - /// # use tui::layout::Rect; - /// 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 - /// ``` - pub fn pos_of(&self, i: usize) -> (u16, u16) { - debug_assert!( - i < self.content.len(), - "Trying to get the coords of a cell outside the buffer: i={} len={}", - i, - self.content.len() - ); - ( - self.area.x + i as u16 % self.area.width, - self.area.y + i as u16 / self.area.width, - ) - } - - /// Print a string, starting at the position (x, y) - pub fn set_string<S>(&mut self, x: u16, y: u16, string: S, style: Style) - where - S: AsRef<str>, - { - self.set_stringn(x, y, string, usize::MAX, style); - } - - /// Print at most the first n characters of a string if enough space is available - /// until the end of the line - pub fn set_stringn<S>( - &mut self, - x: u16, - y: u16, - string: S, - width: usize, - style: Style, - ) -> (u16, u16) - where - S: AsRef<str>, - { - let mut index = self.index_of(x, y); - let mut x_offset = x as usize; - let graphemes = UnicodeSegmentation::graphemes(string.as_ref(), true); - let max_offset = min(self.area.right() as usize, width.saturating_add(x as usize)); - for s in graphemes { - let width = s.width(); - if width == 0 { - continue; - } - // `x_offset + width > max_offset` could be integer overflow on 32-bit machines if we - // change dimenstions to usize or u32 and someone resizes the terminal to 1x2^32. - if width > max_offset.saturating_sub(x_offset) { - break; - } - - self.content[index].set_symbol(s); - self.content[index].set_style(style); - // Reset following cells if multi-width (they would be hidden by the grapheme), - for i in index + 1..index + width { - self.content[i].reset(); - } - index += width; - x_offset += width; - } - (x_offset as u16, y) - } - - pub fn set_spans(&mut self, x: u16, y: u16, spans: &Spans<'_>, width: u16) -> (u16, u16) { - let mut remaining_width = width; - let mut x = x; - for span in &spans.0 { - if remaining_width == 0 { - break; - } - let pos = self.set_stringn( - x, - y, - span.content.as_ref(), - remaining_width as usize, - span.style, - ); - let w = pos.0.saturating_sub(x); - x = pos.0; - remaining_width = remaining_width.saturating_sub(w); - } - (x, y) - } - - pub fn set_span(&mut self, x: u16, y: u16, span: &Span<'_>, width: u16) -> (u16, u16) { - self.set_stringn(x, y, span.content.as_ref(), width as usize, span.style) - } - - #[deprecated( - since = "0.10.0", - note = "You should use styling capabilities of `Buffer::set_style`" - )] - pub fn set_background(&mut self, area: Rect, color: Color) { - for y in area.top()..area.bottom() { - for x in area.left()..area.right() { - self.get_mut(x, y).set_bg(color); - } - } - } - - pub fn set_style(&mut self, area: Rect, style: Style) { - for y in area.top()..area.bottom() { - for x in area.left()..area.right() { - self.get_mut(x, y).set_style(style); - } - } - } - - /// Resize the buffer so that the mapped area matches the given area and that the buffer - /// length is equal to area.width * area.height - pub fn resize(&mut self, area: Rect) { - let length = area.area() as usize; - if self.content.len() > length { - self.content.truncate(length); - } else { - self.content.resize(length, Cell::default()); - } - self.area = area; - } - - /// Reset all cells in the buffer - pub fn reset(&mut self) { - for c in &mut self.content { - c.reset(); - } - } - - /// Merge an other buffer into this one - pub fn merge(&mut self, other: &Buffer) { - let area = self.area.union(other.area); - let cell = Cell::default(); - self.content.resize(area.area() as usize, cell.clone()); - - // Move original content to the appropriate space - let size = self.area.area() as usize; - for i in (0..size).rev() { - let (x, y) = self.pos_of(i); - // New index in content - let k = ((y - area.y) * area.width + x - area.x) as usize; - if i != k { - self.content[k] = self.content[i].clone(); - self.content[i] = cell.clone(); - } - } - - // Push content of the other buffer into this one (may erase previous - // data) - let size = other.area.area() as usize; - for i in 0..size { - let (x, y) = other.pos_of(i); - // New index in content - let k = ((y - area.y) * area.width + x - area.x) as usize; - self.content[k] = other.content[i].clone(); - } - self.area = area; - } - - /// 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: - /// - /// ```text - /// (Index:) `01` - /// Prev: `コ` - /// Next: `aa` - /// Updates: `0: a, 1: a' - /// ``` - /// - /// ```text - /// (Index:) `01` - /// Prev: `a ` - /// Next: `コ` - /// Updates |