pub use crate::input::{Input, Rewind, Show, ParserInfo};
#[cfg(feature = "color")]
use yansi::Paint;
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub struct Span<'a> {
pub start: (usize, usize, usize),
pub end: (usize, usize, usize),
pub cursor: Option<char>,
pub snippet: Option<&'a str>,
}
const SNIPPET_LEN: usize = 30;
impl<'a> Show for Span<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let (a, b, _) = self.start;
let (c, d, _) = self.end;
if self.start == self.end {
write!(f, "{}:{}", a, b)?;
} else {
write!(f, "{}:{} to {}:{}", a, b, c, d)?;
}
let write_snippet = |f: &mut std::fmt::Formatter<'_>, snippet: &str| {
for c in snippet.escape_debug() { write!(f, "{}", c)?; }
Ok(())
};
if let Some(snippet) = self.snippet {
write!(f, " \"")?;
if snippet.len() > SNIPPET_LEN + 6 {
write_snippet(f, &snippet[..SNIPPET_LEN / 2])?;
#[cfg(feature = "color")]
write!(f, " {} ", "...".blue())?;
#[cfg(not(feature = "color"))]
write!(f, " ... ")?;
let end_start = snippet.len() - SNIPPET_LEN / 2;
write_snippet(f, &snippet[end_start..])?;
} else {
write_snippet(f, snippet)?;
}
if let Some(cursor) = self.cursor {
#[cfg(feature = "color")]
write!(f, "{}", cursor.escape_debug().blue())?;
#[cfg(not(feature = "color"))]
write!(f, "{}", cursor.escape_debug())?;
}
write!(f, "\"")?;
} else {
#[cfg(feature = "color")]
write!(f, " {}", "[EOF]".blue())?;
#[cfg(not(feature = "color"))]
write!(f, " [EOF]")?;
}
Ok(())
}
}
#[derive(Debug)]
pub struct Text<'a> {
current: &'a str,
start: &'a str,
}
impl<'a> From<&'a str> for Text<'a> {
fn from(start: &'a str) -> Text<'a> {
Text { start, current: start }
}
}
impl Rewind for Text<'_> {
fn rewind_to(&mut self, marker: Self::Marker) {
self.current = &self.start[marker..];
}
}
impl<'a> Input for Text<'a> {
type Token = char;
type Slice = &'a str;
type Many = Self::Slice;
type Marker = usize;
type Context = Span<'a>;
fn token(&mut self) -> Option<Self::Token> {
self.current.token()
}
fn slice(&mut self, n: usize) -> Option<Self::Slice> {
self.current.slice(n)
}
fn peek<F>(&mut self, cond: F) -> bool
where F: FnMut(&Self::Token) -> bool
{
self.current.peek(cond)
}
fn peek_slice<F>(&mut self, n: usize, cond: F) -> bool
where F: FnMut(&Self::Slice) -> bool
{
self.current.peek_slice(n, cond)
}
fn eat<F>(&mut self, cond: F) -> Option<Self::Token>
where F: FnMut(&Self::Token) -> bool
{
self.current.eat(cond)
}
fn eat_slice<F>(&mut self, n: usize, cond: F) -> Option<Self::Slice>
where F: FnMut(&Self::Slice) -> bool
{
self.current.eat_slice(n, cond)
}
fn take<F>(&mut self, cond: F) -> Self::Many
where F: FnMut(&Self::Token) -> bool
{
self.current.take(cond)
}
fn skip<F>(&mut self, cond: F) -> usize
where F: FnMut(&Self::Token) -> bool
{
self.current.skip(cond)
}
fn has(&mut self, n: usize) -> bool {
self.current.has(n)
}
#[inline(always)]
fn mark(&mut self, _: &ParserInfo) -> Self::Marker {
self.start.len() - self.current.len()
}
fn context(&mut self, mark: Self::Marker) -> Self::Context {
let cursor = self.token();
let bytes_read = self.start.len() - self.current.len();
if bytes_read == 0 {
Span { start: (1, 1, 0), end: (1, 1, 0), snippet: None, cursor }
} else {
let start_offset = mark;
let end_offset = bytes_read;
let to_start_str = &self.start[..start_offset];
let (start_line, start_col) = line_col(to_start_str);
let start = (start_line, start_col, start_offset);
let to_current_str = &self.start[..bytes_read];
let (end_line, end_col) = line_col(to_current_str);
let end = (end_line, end_col, bytes_read);
let snippet = if end_offset <= self.start.len() {
Some(&self.start[start_offset..end_offset])
} else {
None
};
Span { start, end, cursor, snippet }
}
}
}
fn line_col(string: &str) -> (usize, usize) {
if string.is_empty() {
return (1, 1);
}
let (line_count, last_line) = string.lines().enumerate().last().unwrap();
if string.ends_with('\n') {
(line_count + 2, 1)
} else {
(line_count + 1, last_line.len() + 1)
}
}