Skip to main content

bash_strings/
error.rs

1//! What a refusal says.
2
3use 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
34/// The text around an offset, widened to character boundaries — so a snippet
35/// is still a snippet when the input holds multi-byte characters.
36fn 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}