1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq)]
6pub struct ParseError {
7 pub message: String,
8 pub at: usize,
9 pub snippet: String,
10}
11
12impl ParseError {
13 pub fn new(input: &str, at: usize, message: impl Into<String>) -> Self {
14 Self {
15 message: message.into(),
16 at,
17 snippet: around(input, at),
18 }
19 }
20}
21
22impl fmt::Display for ParseError {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 write!(
25 f,
26 "bash value parse error at byte {}: {} — near {:?}",
27 self.at, self.message, self.snippet
28 )
29 }
30}
31
32impl std::error::Error for ParseError {}
33
34fn around(input: &str, at: usize) -> String {
37 let mut lo = at.saturating_sub(20).min(input.len());
38 let mut hi = (at + 20).min(input.len());
39
40 while !input.is_char_boundary(lo) {
41 lo -= 1;
42 }
43 while !input.is_char_boundary(hi) {
44 hi += 1;
45 }
46 input[lo..hi].to_string()
47}