Rollup merge of #84235 - klensy:styled-buffer, r=lcnr
refactor StyledBuffer Refactors StyledBuffer `text` and `styles` fields content into StyledChar and touches some other stuff.
This commit is contained in:
commit
e7e22b47ad
@ -1,39 +1,52 @@
|
||||
// Code for creating styled buffers
|
||||
|
||||
use crate::snippet::{Style, StyledString};
|
||||
use std::iter;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct StyledBuffer {
|
||||
text: Vec<Vec<char>>,
|
||||
styles: Vec<Vec<Style>>,
|
||||
lines: Vec<Vec<StyledChar>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct StyledChar {
|
||||
chr: char,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl StyledChar {
|
||||
const SPACE: Self = StyledChar::new(' ', Style::NoStyle);
|
||||
|
||||
const fn new(chr: char, style: Style) -> Self {
|
||||
StyledChar { chr, style }
|
||||
}
|
||||
}
|
||||
|
||||
impl StyledBuffer {
|
||||
pub fn new() -> StyledBuffer {
|
||||
StyledBuffer { text: vec![], styles: vec![] }
|
||||
StyledBuffer { lines: vec![] }
|
||||
}
|
||||
|
||||
/// Returns content of `StyledBuffer` splitted by lines and line styles
|
||||
pub fn render(&self) -> Vec<Vec<StyledString>> {
|
||||
// Tabs are assumed to have been replaced by spaces in calling code.
|
||||
debug_assert!(self.text.iter().all(|r| !r.contains(&'\t')));
|
||||
debug_assert!(self.lines.iter().all(|r| !r.iter().any(|sc| sc.chr == '\t')));
|
||||
|
||||
let mut output: Vec<Vec<StyledString>> = vec![];
|
||||
let mut styled_vec: Vec<StyledString> = vec![];
|
||||
|
||||
for (row, row_style) in iter::zip(&self.text, &self.styles) {
|
||||
for styled_line in &self.lines {
|
||||
let mut current_style = Style::NoStyle;
|
||||
let mut current_text = String::new();
|
||||
|
||||
for (&c, &s) in iter::zip(row, row_style) {
|
||||
if s != current_style {
|
||||
for sc in styled_line {
|
||||
if sc.style != current_style {
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
}
|
||||
current_style = s;
|
||||
current_style = sc.style;
|
||||
current_text = String::new();
|
||||
}
|
||||
current_text.push(c);
|
||||
current_text.push(sc.chr);
|
||||
}
|
||||
if !current_text.is_empty() {
|
||||
styled_vec.push(StyledString { text: current_text, style: current_style });
|
||||
@ -49,29 +62,25 @@ pub fn render(&self) -> Vec<Vec<StyledString>> {
|
||||
}
|
||||
|
||||
fn ensure_lines(&mut self, line: usize) {
|
||||
while line >= self.text.len() {
|
||||
self.text.push(vec![]);
|
||||
self.styles.push(vec![]);
|
||||
if line >= self.lines.len() {
|
||||
self.lines.resize(line + 1, Vec::new());
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets `chr` with `style` for given `line`, `col`.
|
||||
/// If `line` does not exist in our buffer, adds empty lines up to the given
|
||||
/// and fills the last line with unstyled whitespace.
|
||||
pub fn putc(&mut self, line: usize, col: usize, chr: char, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
if col < self.text[line].len() {
|
||||
self.text[line][col] = chr;
|
||||
self.styles[line][col] = style;
|
||||
} else {
|
||||
let mut i = self.text[line].len();
|
||||
while i < col {
|
||||
self.text[line].push(' ');
|
||||
self.styles[line].push(Style::NoStyle);
|
||||
i += 1;
|
||||
}
|
||||
self.text[line].push(chr);
|
||||
self.styles[line].push(style);
|
||||
if col >= self.lines[line].len() {
|
||||
self.lines[line].resize(col + 1, StyledChar::SPACE);
|
||||
}
|
||||
self.lines[line][col] = StyledChar::new(chr, style);
|
||||
}
|
||||
|
||||
/// Sets `string` with `style` for given `line`, starting from `col`.
|
||||
/// If `line` does not exist in our buffer, adds empty lines up to the given
|
||||
/// and fills the last line with unstyled whitespace.
|
||||
pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
|
||||
let mut n = col;
|
||||
for c in string.chars() {
|
||||
@ -80,32 +89,40 @@ pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
|
||||
}
|
||||
}
|
||||
|
||||
/// For given `line` inserts `string` with `style` before old content of that line,
|
||||
/// adding lines if needed
|
||||
pub fn prepend(&mut self, line: usize, string: &str, style: Style) {
|
||||
self.ensure_lines(line);
|
||||
let string_len = string.chars().count();
|
||||
|
||||
// Push the old content over to make room for new content
|
||||
for _ in 0..string_len {
|
||||
self.styles[line].insert(0, Style::NoStyle);
|
||||
self.text[line].insert(0, ' ');
|
||||
if !self.lines[line].is_empty() {
|
||||
// Push the old content over to make room for new content
|
||||
for _ in 0..string_len {
|
||||
self.lines[line].insert(0, StyledChar::SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
self.puts(line, 0, string, style);
|
||||
}
|
||||
|
||||
/// For given `line` inserts `string` with `style` after old content of that line,
|
||||
/// adding lines if needed
|
||||
pub fn append(&mut self, line: usize, string: &str, style: Style) {
|
||||
if line >= self.text.len() {
|
||||
if line >= self.lines.len() {
|
||||
self.puts(line, 0, string, style);
|
||||
} else {
|
||||
let col = self.text[line].len();
|
||||
let col = self.lines[line].len();
|
||||
self.puts(line, col, string, style);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn num_lines(&self) -> usize {
|
||||
self.text.len()
|
||||
self.lines.len()
|
||||
}
|
||||
|
||||
/// Set `style` for `line`, `col_start..col_end` range if:
|
||||
/// 1. That line and column range exist in `StyledBuffer`
|
||||
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
|
||||
pub fn set_style_range(
|
||||
&mut self,
|
||||
line: usize,
|
||||
@ -119,10 +136,13 @@ pub fn set_style_range(
|
||||
}
|
||||
}
|
||||
|
||||
/// Set `style` for `line`, `col` if:
|
||||
/// 1. That line and column exist in `StyledBuffer`
|
||||
/// 2. `overwrite` is `true` or existing style is `Style::NoStyle` or `Style::Quotation`
|
||||
pub fn set_style(&mut self, line: usize, col: usize, style: Style, overwrite: bool) {
|
||||
if let Some(ref mut line) = self.styles.get_mut(line) {
|
||||
if let Some(s) = line.get_mut(col) {
|
||||
if *s == Style::NoStyle || *s == Style::Quotation || overwrite {
|
||||
if let Some(ref mut line) = self.lines.get_mut(line) {
|
||||
if let Some(StyledChar { style: s, .. }) = line.get_mut(col) {
|
||||
if overwrite || *s == Style::NoStyle || *s == Style::Quotation {
|
||||
*s = style;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user