Handle escaping the characters in org macro arguments.

This commit is contained in:
Tom Alexander 2023-10-08 15:54:56 -04:00
parent a32cea8139
commit a6adeee40b
Signed by: talexander
GPG Key ID: D3A179C9A53C0EDE
3 changed files with 155 additions and 2 deletions

View File

@ -0,0 +1,7 @@
{{{foo}}}
{{{fo\o}}}
{{{foo(b\ar)}}}
{{{foo(b\,r)}}}

View File

@ -149,8 +149,8 @@ pub(crate) fn compare_property_list_of_quoted_string<
if e != r { if e != r {
let this_status = DiffStatus::Bad; let this_status = DiffStatus::Bad;
let message = Some(format!( let message = Some(format!(
"{} mismatch (emacs != rust) {:?} != {:?}", "{} mismatch (emacs != rust) {:?} != {:?}. Full list: {:?} != {:?}",
emacs_field, value, rust_value emacs_field, e, r, value, rust_value
)); ));
return Ok(Some((this_status, message))); return Ok(Some((this_status, message)));
} }

View File

@ -243,3 +243,149 @@ enum CoalesceWhitespace {
Normal, Normal,
HasWhitespace { in_whitespace: bool, ret: String }, HasWhitespace { in_whitespace: bool, ret: String },
} }
/// Removes all whitespace from a string and handle escaping characters.
///
/// Example: "foo bar" => "foobar" and "foo \n bar" => "foobar" but if the escape character is backslash and comma is an escapable character than "foo\,bar" becomes "foo,bar".
pub(crate) fn coalesce_whitespace_escaped<'c, C: Fn(char) -> bool>(
escape_character: char,
escapable_characters: C,
) -> impl for<'s> Fn(&'s str) -> Cow<'s, str> {
move |input| impl_coalesce_whitespace_escaped(input, escape_character, &escapable_characters)
}
fn impl_coalesce_whitespace_escaped<'s, C: Fn(char) -> bool>(
input: &'s str,
escape_character: char,
escapable_characters: C,
) -> Cow<'s, str> {
let mut state = CoalesceWhitespaceEscaped::Normal;
for (offset, c) in input.char_indices() {
state = match (state, c) {
(CoalesceWhitespaceEscaped::Normal, c) if c == escape_character => {
CoalesceWhitespaceEscaped::NormalEscaping {
escape_offset: offset,
}
}
(CoalesceWhitespaceEscaped::Normal, ' ' | '\t' | '\r' | '\n') => {
let mut ret = String::with_capacity(input.len());
ret.push_str(&input[..offset]);
ret.push(' ');
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: true,
ret,
}
}
(CoalesceWhitespaceEscaped::Normal, _) => CoalesceWhitespaceEscaped::Normal,
(CoalesceWhitespaceEscaped::NormalEscaping { escape_offset }, c)
if escapable_characters(c) =>
{
// We escaped a character so we need mutation
let mut ret = String::with_capacity(input.len());
ret.push_str(&input[..escape_offset]);
ret.push(c);
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: false,
ret,
}
}
(
CoalesceWhitespaceEscaped::NormalEscaping { escape_offset: _ },
' ' | '\t' | '\r' | '\n',
) => {
// We didn't escape the character but we hit whitespace anyway.
let mut ret = String::with_capacity(input.len());
ret.push_str(&input[..offset]);
ret.push(' ');
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: true,
ret,
}
}
(CoalesceWhitespaceEscaped::NormalEscaping { escape_offset: _ }, _) => {
// We didn't escape the character so continue as normal.
CoalesceWhitespaceEscaped::Normal
}
(
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: _,
ret,
},
c,
) if c == escape_character => {
CoalesceWhitespaceEscaped::RequiresMutationEscaping { ret }
}
(
CoalesceWhitespaceEscaped::RequiresMutation {
mut in_whitespace,
mut ret,
},
' ' | '\t' | '\r' | '\n',
) => {
if !in_whitespace {
in_whitespace = true;
ret.push(' ');
}
CoalesceWhitespaceEscaped::RequiresMutation { in_whitespace, ret }
}
(
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace,
mut ret,
},
_,
) => {
ret.push(c);
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: false,
ret,
}
}
(CoalesceWhitespaceEscaped::RequiresMutationEscaping { mut ret }, c)
if escapable_characters(c) =>
{
ret.push(c);
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: false,
ret,
}
}
(
CoalesceWhitespaceEscaped::RequiresMutationEscaping { mut ret },
' ' | '\t' | '\r' | '\n',
) => {
ret.push(' ');
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: true,
ret,
}
}
(CoalesceWhitespaceEscaped::RequiresMutationEscaping { mut ret }, c) => {
ret.push(escape_character);
ret.push(c);
// TODO
CoalesceWhitespaceEscaped::RequiresMutation {
in_whitespace: false,
ret,
}
}
}
}
// match state {
// CoalesceWhitespaceEscaped::Normal => Cow::Borrowed(input),
// CoalesceWhitespaceEscaped::RequiresMutation {
// in_whitespace: _,
// ret,
// } => Cow::Owned(ret),
// }
todo!()
}
enum CoalesceWhitespaceEscaped {
Normal,
NormalEscaping { escape_offset: usize },
RequiresMutation { in_whitespace: bool, ret: String },
RequiresMutationEscaping { ret: String },
}