Skip to content
Merged
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 61 additions & 31 deletions compiler/rustc_errors/src/styled_buffer.rs
Original file line number Diff line number Diff line change
@@ -1,39 +1,56 @@
// 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)]
struct StyledChar {
chr: char,
style: Style,
}

impl StyledChar {
fn new(chr: char, style: Style) -> Self {
StyledChar { chr, style }
}
}

impl Default for StyledChar {
fn default() -> Self {
StyledChar::new(' ', Style::NoStyle)
}
}

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 });
Expand All @@ -49,29 +66,31 @@ impl StyledBuffer {
}

fn ensure_lines(&mut self, line: usize) {
while line >= self.text.len() {
self.text.push(vec![]);
self.styles.push(vec![]);
while line >= self.lines.len() {
self.lines.push(vec![]);
}
}

/// Sets `chr` with `style` for given `line`, `col`.
/// If line not exist in `StyledBuffer`, adds lines up to given
/// and fills last line with spaces and `Style::NoStyle` style
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;
if col < self.lines[line].len() {
self.lines[line][col] = StyledChar::new(chr, style);
} else {
let mut i = self.text[line].len();
let mut i = self.lines[line].len();
while i < col {
self.text[line].push(' ');
self.styles[line].push(Style::NoStyle);
self.lines[line].push(StyledChar::default());
i += 1;
}
self.text[line].push(chr);
self.styles[line].push(style);
self.lines[line].push(StyledChar::new(chr, style));
}
}

/// Sets `string` with `style` for given `line`, starting from `col`.
/// If line not exist in `StyledBuffer`, adds lines up to given
/// and fills last line with spaces and `Style::NoStyle` style
pub fn puts(&mut self, line: usize, col: usize, string: &str, style: Style) {
let mut n = col;
for c in string.chars() {
Expand All @@ -80,32 +99,40 @@ impl StyledBuffer {
}
}

/// 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::default());
}
}

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,
Expand All @@ -119,10 +146,13 @@ impl StyledBuffer {
}
}

/// 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;
}
}
Expand Down