use source_span::{
fmt::{Color, Formatter, Style},
Position, Span,
};
use std::fs::File;
use std::io::Read;
use utf8_decode::UnsafeDecoder;
#[derive(Clone, Default)]
pub struct Token {
string: String,
span: Span,
}
#[derive(PartialEq)]
pub enum Kind {
Space,
Separator,
Alphabetic,
Numeric,
}
fn main() -> std::io::Result<()> {
let file = File::open("examples/fib.txt")?;
let chars = UnsafeDecoder::new(file.bytes());
let metrics = source_span::DEFAULT_METRICS;
let buffer = source_span::SourceBuffer::new(chars, Position::default(), metrics);
let mut fmt = Formatter::with_margin_color(Color::Blue);
let mut tokens = Vec::new();
let mut current = Token::default();
let mut kind = Kind::Space;
let mut opened = Vec::new();
let mut groups = Vec::new();
let string_style = Style::new('^', '"', Color::Green);
for c in buffer.iter() {
let c = c?;
let new_kind;
if c.is_whitespace() {
new_kind = Kind::Space;
} else if c.is_alphabetic() {
new_kind = Kind::Alphabetic;
} else if c.is_numeric() {
new_kind = Kind::Numeric;
} else {
new_kind = Kind::Separator;
}
if kind != new_kind || kind == Kind::Separator {
if kind != Kind::Space {
tokens.push(current.clone());
}
current.string.clear();
current.span.clear(); }
if new_kind != Kind::Space {
current.string.push(c);
}
current.span.push(c, &metrics);
kind = new_kind;
match c {
'(' => opened.push((current.span.start(), ')')),
'[' => opened.push((current.span.start(), ']')),
'{' => opened.push((current.span.start(), '}')),
'"' if opened.is_empty() || opened.last().unwrap().1 != '"' => {
opened.push((current.span.start(), '"'))
}
')' | ']' | '}' | '"' => {
if let Some((start, expected)) = opened.pop() {
if c == expected {
let span = Span::new(start, current.span.last(), current.span.end());
groups.push(span);
let (label, style) = match c {
')' => ("this is a pair of parenthesis", Style::Note),
']' => ("this is a pair of brackets", Style::Warning),
'}' => ("this is a pair of braces", Style::Warning),
_ => ("this is a string", string_style),
};
fmt.add(span, Some(label.to_string()), style);
} else {
}
} else {
}
}
_ => (),
}
}
if !current.string.is_empty() {
tokens.push(current);
}
fmt.add(
buffer.span(),
Some("this is the whole program\nwhat a nice program!".to_string()),
Style::Error,
);
let formatted = fmt.render(buffer.iter(), buffer.span(), &metrics)?;
println!("{}", formatted);
Ok(())
}