diff --git a/src/compare/diff.rs b/src/compare/diff.rs index 2343942e..f57eefc1 100644 --- a/src/compare/diff.rs +++ b/src/compare/diff.rs @@ -889,11 +889,12 @@ fn compare_plain_text<'s>( let mut this_status = DiffStatus::Good; let mut message = None; let text = emacs.as_text()?; - if text.text != rust.source { + let unquoted_text = text.unquote()?; + if unquoted_text != rust.source { this_status = DiffStatus::Bad; message = Some(format!( "(emacs != rust) {:?} != {:?}", - text.text, rust.source + unquoted_text, rust.source )); } diff --git a/src/parser/sexp.rs b/src/parser/sexp.rs index 85435482..da5f2b78 100644 --- a/src/parser/sexp.rs +++ b/src/parser/sexp.rs @@ -32,6 +32,45 @@ pub struct TextWithProperties<'s> { pub properties: Vec>, } +impl<'s> TextWithProperties<'s> { + pub fn unquote(&self) -> Result> { + let mut out = String::with_capacity(self.text.len()); + if !self.text.starts_with(r#"""#) { + return Err("Quoted text does not start with quote.".into()); + } + if !self.text.ends_with(r#"""#) { + return Err("Quoted text does not end with quote.".into()); + } + let interior_text = &self.text[1..(self.text.len() - 1)]; + let mut state = ParseState::Normal; + for current_char in interior_text.chars().into_iter() { + state = match (state, current_char) { + (ParseState::Normal, '\\') => ParseState::Escape, + (ParseState::Normal, _) => { + out.push(current_char); + ParseState::Normal + } + (ParseState::Escape, 'n') => { + out.push('\n'); + ParseState::Normal + } + (ParseState::Escape, '\\') => { + out.push('\\'); + ParseState::Normal + } + _ => todo!(), + }; + } + + Ok(out) + } +} + +enum ParseState { + Normal, + Escape, +} + impl<'s> Token<'s> { pub fn as_list<'p>(&'p self) -> Result<&'p Vec>, Box> { Ok(match self {