Range resolving
This commit is contained in:
parent
726dbdaf7c
commit
352b395929
15 changed files with 60 additions and 102 deletions
|
@ -33,7 +33,7 @@ use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use crate::parser::source::VirtualSource;
|
use crate::parser::source::VirtualSource;
|
||||||
use crate::parser::style::StyleHolder;
|
use crate::parser::style::StyleHolder;
|
||||||
use crate::parser::util::process_escaped;
|
use crate::parser::util::escape_text;
|
||||||
use crate::parser::util::Property;
|
use crate::parser::util::Property;
|
||||||
use crate::parser::util::PropertyParser;
|
use crate::parser::util::PropertyParser;
|
||||||
|
|
||||||
|
@ -209,7 +209,7 @@ impl BlockquoteRule {
|
||||||
&self,
|
&self,
|
||||||
m: Match,
|
m: Match,
|
||||||
) -> Result<(Option<String>, Option<String>, Option<String>), String> {
|
) -> Result<(Option<String>, Option<String>, Option<String>), String> {
|
||||||
let processed = process_escaped('\\', "]", m.as_str());
|
let processed = escape_text('\\', "]", m.as_str());
|
||||||
let pm = self.properties.parse(processed.as_str())?;
|
let pm = self.properties.parse(processed.as_str())?;
|
||||||
|
|
||||||
let author = pm
|
let author = pm
|
||||||
|
|
|
@ -357,7 +357,7 @@ impl RegexRule for CodeRule {
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let processed =
|
let processed =
|
||||||
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
reports.push(
|
reports.push(
|
||||||
|
@ -421,9 +421,9 @@ impl RegexRule for CodeRule {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut code_content = if index == 0 {
|
let mut code_content = if index == 0 {
|
||||||
util::process_escaped('\\', "```", matches.get(4).unwrap().as_str())
|
util::escape_text('\\', "```", matches.get(4).unwrap().as_str())
|
||||||
} else {
|
} else {
|
||||||
util::process_escaped('\\', "``", matches.get(3).unwrap().as_str())
|
util::escape_text('\\', "``", matches.get(3).unwrap().as_str())
|
||||||
};
|
};
|
||||||
if code_content.bytes().last() == Some(b'\n')
|
if code_content.bytes().last() == Some(b'\n')
|
||||||
// Remove newline
|
// Remove newline
|
||||||
|
|
|
@ -227,7 +227,7 @@ impl RegexRule for GraphRule {
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
Some(content) => {
|
Some(content) => {
|
||||||
let processed = util::process_escaped(
|
let processed = util::escape_text(
|
||||||
'\\',
|
'\\',
|
||||||
"[/graph]",
|
"[/graph]",
|
||||||
content.as_str().trim_start().trim_end(),
|
content.as_str().trim_start().trim_end(),
|
||||||
|
@ -270,7 +270,7 @@ impl RegexRule for GraphRule {
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let processed =
|
let processed =
|
||||||
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
reports.push(
|
reports.push(
|
||||||
|
|
|
@ -15,7 +15,7 @@ use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use crate::parser::state::RuleState;
|
use crate::parser::state::RuleState;
|
||||||
use crate::parser::state::Scope;
|
use crate::parser::state::Scope;
|
||||||
use crate::parser::util::process_escaped;
|
use crate::parser::util::escape_text;
|
||||||
use ariadne::Fmt;
|
use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
|
@ -361,7 +361,7 @@ impl LayoutRule {
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let trimmed = props.as_str().trim_start().trim_end();
|
let trimmed = props.as_str().trim_start().trim_end();
|
||||||
let content = process_escaped('\\', "]", trimmed);
|
let content = escape_text('\\', "]", trimmed);
|
||||||
match layout_type.parse_properties(content.as_str()) {
|
match layout_type.parse_properties(content.as_str()) {
|
||||||
Ok(props) => Ok(props),
|
Ok(props) => Ok(props),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
|
|
|
@ -371,26 +371,10 @@ nml.link.push("**BOLD link**", "another url")
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn semantics() {
|
fn semantics() {
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"".to_string(),
|
|
||||||
r#" - [la(*testi*nk](url)
|
|
||||||
"#
|
|
||||||
.to_string(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
let parser = LangParser::default();
|
|
||||||
let (_, state) = parser.parse(
|
|
||||||
ParserState::new_with_semantics(&parser, None),
|
|
||||||
source.clone(),
|
|
||||||
None,
|
|
||||||
ParseMode::default(),
|
|
||||||
);
|
|
||||||
println!("{:#?}", state.shared.semantics);
|
|
||||||
return;
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
let source = Rc::new(SourceFile::with_content(
|
||||||
"".to_string(),
|
"".to_string(),
|
||||||
r#"
|
r#"
|
||||||
[li**n**k](url)
|
- [la\](*testi*nk](url)
|
||||||
"#
|
"#
|
||||||
.to_string(),
|
.to_string(),
|
||||||
None,
|
None,
|
||||||
|
@ -404,9 +388,10 @@ nml.link.push("**BOLD link**", "another url")
|
||||||
);
|
);
|
||||||
|
|
||||||
validate_semantics!(state, source.clone(), 0,
|
validate_semantics!(state, source.clone(), 0,
|
||||||
link_display_sep { delta_line == 1, delta_start == 0, length == 1 };
|
list_bullet { delta_line == 1, delta_start == 1, length == 1 };
|
||||||
style_marker { delta_line == 0, delta_start == 3, length == 2 };
|
link_display_sep { delta_line == 0, delta_start == 2, length == 1 };
|
||||||
style_marker { delta_line == 0, delta_start == 3, length == 2 };
|
style_marker { delta_line == 0, delta_start == 6, length == 1 };
|
||||||
|
style_marker { delta_line == 0, delta_start == 6, length == 1 };
|
||||||
link_display_sep { delta_line == 0, delta_start == 3, length == 1 };
|
link_display_sep { delta_line == 0, delta_start == 3, length == 1 };
|
||||||
link_url_sep { delta_line == 0, delta_start == 1, length == 1 };
|
link_url_sep { delta_line == 0, delta_start == 1, length == 1 };
|
||||||
link_url { delta_line == 0, delta_start == 1, length == 3 };
|
link_url { delta_line == 0, delta_start == 1, length == 3 };
|
||||||
|
|
|
@ -20,7 +20,7 @@ use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use crate::parser::source::VirtualSource;
|
use crate::parser::source::VirtualSource;
|
||||||
use crate::parser::util;
|
use crate::parser::util;
|
||||||
use crate::parser::util::process_escaped;
|
use crate::parser::util::escape_text;
|
||||||
use crate::parser::util::Property;
|
use crate::parser::util::Property;
|
||||||
use crate::parser::util::PropertyMapError;
|
use crate::parser::util::PropertyMapError;
|
||||||
use crate::parser::util::PropertyParser;
|
use crate::parser::util::PropertyParser;
|
||||||
|
@ -196,7 +196,7 @@ impl ListRule {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_properties(&self, m: Match) -> Result<(Option<usize>, Option<String>), String> {
|
fn parse_properties(&self, m: Match) -> Result<(Option<usize>, Option<String>), String> {
|
||||||
let processed = process_escaped('\\', "]", m.as_str());
|
let processed = escape_text('\\', "]", m.as_str());
|
||||||
let pm = self.properties.parse(processed.as_str())?;
|
let pm = self.properties.parse(processed.as_str())?;
|
||||||
|
|
||||||
let offset = match pm.get("offset", |_, s| s.parse::<usize>()) {
|
let offset = match pm.get("offset", |_, s| s.parse::<usize>()) {
|
||||||
|
|
|
@ -306,7 +306,7 @@ impl MediaRule {
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let processed =
|
let processed =
|
||||||
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => Err(
|
Err(e) => Err(
|
||||||
Report::build(ReportKind::Error, token.source(), props.start())
|
Report::build(ReportKind::Error, token.source(), props.start())
|
||||||
|
@ -382,7 +382,7 @@ impl RegexRule for MediaRule {
|
||||||
matches.get(2).unwrap(),
|
matches.get(2).unwrap(),
|
||||||
MediaRule::validate_uri(matches.get(2).unwrap().as_str()),
|
MediaRule::validate_uri(matches.get(2).unwrap().as_str()),
|
||||||
) {
|
) {
|
||||||
(_, Ok(uri)) => util::process_escaped('\\', ")", uri),
|
(_, Ok(uri)) => util::escape_text('\\', ")", uri),
|
||||||
(m, Err(err)) => {
|
(m, Err(err)) => {
|
||||||
reports.push(
|
reports.push(
|
||||||
Report::build(ReportKind::Error, token.source(), m.start())
|
Report::build(ReportKind::Error, token.source(), m.start())
|
||||||
|
|
|
@ -118,7 +118,7 @@ impl RegexRule for RawRule {
|
||||||
}
|
}
|
||||||
Some(content) => {
|
Some(content) => {
|
||||||
let processed =
|
let processed =
|
||||||
util::process_escaped('\\', "?}", content.as_str().trim_start().trim_end());
|
util::escape_text('\\', "?}", content.as_str().trim_start().trim_end());
|
||||||
|
|
||||||
if processed.is_empty() {
|
if processed.is_empty() {
|
||||||
reports.push(
|
reports.push(
|
||||||
|
@ -155,7 +155,7 @@ impl RegexRule for RawRule {
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let processed =
|
let processed =
|
||||||
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
reports.push(
|
reports.push(
|
||||||
|
|
|
@ -206,7 +206,7 @@ impl ReferenceRule {
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let processed =
|
let processed =
|
||||||
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => Err(
|
Err(e) => Err(
|
||||||
Report::build(ReportKind::Error, token.source(), props.start())
|
Report::build(ReportKind::Error, token.source(), props.start())
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::parser::source::Source;
|
||||||
use crate::parser::source::Token;
|
use crate::parser::source::Token;
|
||||||
use crate::parser::source::VirtualSource;
|
use crate::parser::source::VirtualSource;
|
||||||
use crate::parser::util;
|
use crate::parser::util;
|
||||||
|
use crate::parser::util::escape_source;
|
||||||
use ariadne::Fmt;
|
use ariadne::Fmt;
|
||||||
use ariadne::Label;
|
use ariadne::Label;
|
||||||
use ariadne::Report;
|
use ariadne::Report;
|
||||||
|
@ -127,41 +128,27 @@ impl RegexRule for ScriptRule {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let kernel_data = matches
|
let script_range = matches.get(if index == 0 { 2 } else { 3 }).unwrap().range();
|
||||||
.get(if index == 0 { 2 } else { 3 })
|
let source = escape_source(token.source(), script_range.clone(), format!(
|
||||||
.and_then(|code| {
|
|
||||||
let trimmed = code.as_str().trim_start().trim_end();
|
|
||||||
(!trimmed.is_empty()).then_some((trimmed, code.range()))
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
reports.push(
|
|
||||||
Report::build(ReportKind::Warning, token.source(), token.start())
|
|
||||||
.with_message("Invalid kernel code")
|
|
||||||
.with_label(
|
|
||||||
Label::new((token.source(), token.start() + 1..token.end()))
|
|
||||||
.with_message("Kernel code is empty")
|
|
||||||
.with_color(state.parser.colors().warning),
|
|
||||||
)
|
|
||||||
.finish(),
|
|
||||||
);
|
|
||||||
|
|
||||||
None
|
|
||||||
});
|
|
||||||
|
|
||||||
if kernel_data.is_none() {
|
|
||||||
return reports;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (kernel_content, kernel_range) = kernel_data.unwrap();
|
|
||||||
let source = Rc::new(VirtualSource::new(
|
|
||||||
Token::new(kernel_range, token.source()),
|
|
||||||
format!(
|
|
||||||
":LUA:{kernel_name}#{}#{}",
|
":LUA:{kernel_name}#{}#{}",
|
||||||
token.source().name(),
|
token.source().name(),
|
||||||
matches.get(0).unwrap().start()
|
matches.get(0).unwrap().start()
|
||||||
),
|
), '\\', ">@");
|
||||||
util::process_escaped('\\', ">@", kernel_content),
|
if source.content().is_empty()
|
||||||
)) as Rc<dyn Source>;
|
{
|
||||||
|
reports.push(
|
||||||
|
Report::build(ReportKind::Warning, token.source(), token.start())
|
||||||
|
.with_message("Invalid kernel code")
|
||||||
|
.with_label(
|
||||||
|
Label::new((token.source(), script_range))
|
||||||
|
.with_message("Kernel code is empty")
|
||||||
|
.with_color(state.parser.colors().warning),
|
||||||
|
)
|
||||||
|
.finish(),
|
||||||
|
);
|
||||||
|
return reports;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let execute = |lua: &Lua| {
|
let execute = |lua: &Lua| {
|
||||||
let chunk = lua.load(source.content()).set_name(kernel_name);
|
let chunk = lua.load(source.content()).set_name(kernel_name);
|
||||||
|
|
|
@ -286,7 +286,7 @@ impl TexRule {
|
||||||
},
|
},
|
||||||
Some(props) => {
|
Some(props) => {
|
||||||
let processed =
|
let processed =
|
||||||
util::process_escaped('\\', "]", props.as_str().trim_start().trim_end());
|
util::escape_text('\\', "]", props.as_str().trim_start().trim_end());
|
||||||
match self.properties.parse(processed.as_str()) {
|
match self.properties.parse(processed.as_str()) {
|
||||||
Err(e) => Err(
|
Err(e) => Err(
|
||||||
Report::build(ReportKind::Error, token.source(), props.start())
|
Report::build(ReportKind::Error, token.source(), props.start())
|
||||||
|
@ -344,7 +344,7 @@ impl RegexRule for TexRule {
|
||||||
return reports;
|
return reports;
|
||||||
}
|
}
|
||||||
Some(content) => {
|
Some(content) => {
|
||||||
let processed = util::process_escaped(
|
let processed = util::escape_text(
|
||||||
'\\',
|
'\\',
|
||||||
["|$", "$"][index],
|
["|$", "$"][index],
|
||||||
content.as_str().trim_start().trim_end(),
|
content.as_str().trim_start().trim_end(),
|
||||||
|
|
|
@ -320,7 +320,6 @@ impl<'a> Semantics<'a> {
|
||||||
let mut tokens = self.sems.tokens.borrow_mut();
|
let mut tokens = self.sems.tokens.borrow_mut();
|
||||||
let mut cursor = self.sems.cursor.borrow_mut();
|
let mut cursor = self.sems.cursor.borrow_mut();
|
||||||
let mut current = cursor.clone();
|
let mut current = cursor.clone();
|
||||||
println!("range={range:#?}");
|
|
||||||
cursor.move_to(range.start);
|
cursor.move_to(range.start);
|
||||||
|
|
||||||
while cursor.pos != range.end {
|
while cursor.pos != range.end {
|
||||||
|
|
|
@ -41,7 +41,7 @@ fn main() -> ExitCode {
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
let program = args[0].clone();
|
let program = args[0].clone();
|
||||||
|
|
||||||
let mut opts = Options::new();
|
slet mut opts = Options::new();
|
||||||
opts.optopt("i", "input", "Input path", "PATH");
|
opts.optopt("i", "input", "Input path", "PATH");
|
||||||
opts.optopt("o", "output", "Output path", "PATH");
|
opts.optopt("o", "output", "Output path", "PATH");
|
||||||
opts.optopt("d", "database", "Cache database location", "PATH");
|
opts.optopt("d", "database", "Cache database location", "PATH");
|
||||||
|
|
|
@ -176,7 +176,6 @@ pub fn original_range(source: Rc<dyn Source>, mut range: Range<usize>) -> (Rc<dy
|
||||||
// Recurse to parent
|
// Recurse to parent
|
||||||
if let Some(parent) = source.location()
|
if let Some(parent) = source.location()
|
||||||
{
|
{
|
||||||
//println!("FOUND PARENT={}", parent.source().name());
|
|
||||||
return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end);
|
return original_range(parent.source.clone(), parent.range.start + range.start..parent.range.start + range.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +240,6 @@ impl LineCursor {
|
||||||
/// # Error
|
/// # Error
|
||||||
/// This function will panic if [`pos`] is not utf8 aligned
|
/// This function will panic if [`pos`] is not utf8 aligned
|
||||||
pub fn move_to(&mut self, pos: usize) {
|
pub fn move_to(&mut self, pos: usize) {
|
||||||
println!("pos={pos}");
|
|
||||||
if self.pos < pos {
|
if self.pos < pos {
|
||||||
let start = self.pos;
|
let start = self.pos;
|
||||||
let mut it = self.source.content().as_str()[start..].chars().peekable();
|
let mut it = self.source.content().as_str()[start..].chars().peekable();
|
||||||
|
|
|
@ -97,6 +97,9 @@ pub fn process_text(document: &dyn Document, content: &str) -> String {
|
||||||
/// Transforms source into a new [`VirtualSource`]. Transforms range from source by
|
/// Transforms source into a new [`VirtualSource`]. Transforms range from source by
|
||||||
/// detecting escaped tokens.
|
/// detecting escaped tokens.
|
||||||
///
|
///
|
||||||
|
/// # Notes
|
||||||
|
///
|
||||||
|
/// If you only need to escape content that won't be parsed, use [`process_escaped`] instead.
|
||||||
pub fn escape_source(source: Rc<dyn Source>, range: Range<usize>, name: String, escape: char, token: &'static str) -> Rc<dyn Source>
|
pub fn escape_source(source: Rc<dyn Source>, range: Range<usize>, name: String, escape: char, token: &'static str) -> Rc<dyn Source>
|
||||||
{
|
{
|
||||||
let content = &source.content()[range.clone()];
|
let content = &source.content()[range.clone()];
|
||||||
|
@ -144,23 +147,6 @@ pub fn escape_source(source: Rc<dyn Source>, range: Range<usize>, name: String,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn app()
|
|
||||||
{
|
|
||||||
let mut s = String::new();
|
|
||||||
|
|
||||||
let source = Rc::new(SourceFile::with_content(
|
|
||||||
"test".to_string(),
|
|
||||||
"a\\\\\\```b".into(),
|
|
||||||
None,
|
|
||||||
));
|
|
||||||
let src = escape_source(source.clone(), 0..source.content().len(), "sub".to_string(), '\\', "```");
|
|
||||||
println!("{}", src.content());
|
|
||||||
let range = 0..src.content().len();
|
|
||||||
println!("{:#?}", range);
|
|
||||||
let orange = original_range(src.clone(), range);
|
|
||||||
println!("{:#?}", orange);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Processed a string and escapes a single token out of it
|
/// Processed a string and escapes a single token out of it
|
||||||
/// Escaped characters other than the [`token`] will be not be treated as escaped
|
/// Escaped characters other than the [`token`] will be not be treated as escaped
|
||||||
///
|
///
|
||||||
|
@ -169,9 +155,12 @@ pub fn app()
|
||||||
/// assert_eq!(process_escaped('\\', "%", "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"),
|
/// assert_eq!(process_escaped('\\', "%", "escaped: \\%, also escaped: \\\\\\%, untouched: \\a"),
|
||||||
/// "escaped: %, also escaped: \\%, untouched: \\a");
|
/// "escaped: %, also escaped: \\%, untouched: \\a");
|
||||||
/// ```
|
/// ```
|
||||||
/// TODO: Make this function return a delta to pass to the semantics, maybe store it in the virtualsource, so this function should return a source...
|
///
|
||||||
#[deprecated]
|
/// # Notes
|
||||||
pub fn process_escaped<S: AsRef<str>>(escape: char, token: &'static str, content: S) -> String {
|
///
|
||||||
|
/// If you need to create a source, do not use this function, use [`escape_source`] instead
|
||||||
|
/// as it will populate an offsets to get accurate diagnostics and semantics.
|
||||||
|
pub fn escape_text<S: AsRef<str>>(escape: char, token: &'static str, content: S) -> String {
|
||||||
let mut processed = String::new();
|
let mut processed = String::new();
|
||||||
let mut escaped = 0;
|
let mut escaped = 0;
|
||||||
let mut token_it = token.chars().peekable();
|
let mut token_it = token.chars().peekable();
|
||||||
|
@ -522,7 +511,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn process_escaped_tests() {
|
fn process_escaped_tests() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_escaped(
|
escape_text(
|
||||||
'\\',
|
'\\',
|
||||||
"%",
|
"%",
|
||||||
"escaped: \\%, also escaped: \\\\\\%, untouched: \\a"
|
"escaped: \\%, also escaped: \\\\\\%, untouched: \\a"
|
||||||
|
@ -530,27 +519,27 @@ mod tests {
|
||||||
"escaped: %, also escaped: \\%, untouched: \\a"
|
"escaped: %, also escaped: \\%, untouched: \\a"
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_escaped('"', "><)))°>", "Escaped fish: \"><)))°>"),
|
escape_text('"', "><)))°>", "Escaped fish: \"><)))°>"),
|
||||||
"Escaped fish: ><)))°>".to_string()
|
"Escaped fish: ><)))°>".to_string()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_escaped('\\', "]", "Escaped \\]"),
|
escape_text('\\', "]", "Escaped \\]"),
|
||||||
"Escaped ]".to_string()
|
"Escaped ]".to_string()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_escaped('\\', "]", "Unescaped \\\\]"),
|
escape_text('\\', "]", "Unescaped \\\\]"),
|
||||||
"Unescaped \\\\]".to_string()
|
"Unescaped \\\\]".to_string()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_escaped('\\', "]", "Escaped \\\\\\]"),
|
escape_text('\\', "]", "Escaped \\\\\\]"),
|
||||||
"Escaped \\]".to_string()
|
"Escaped \\]".to_string()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
process_escaped('\\', "]", "Unescaped \\\\\\\\]"),
|
escape_text('\\', "]", "Unescaped \\\\\\\\]"),
|
||||||
"Unescaped \\\\\\\\]".to_string()
|
"Unescaped \\\\\\\\]".to_string()
|
||||||
);
|
);
|
||||||
assert_eq!(process_escaped('\\', ")", "A\\)B\\"), "A)B".to_string(),);
|
assert_eq!(escape_text('\\', ")", "A\\)B\\"), "A)B".to_string(),);
|
||||||
assert_eq!(process_escaped('\\', ")", "A\\)B\\\\"), "A)B\\".to_string(),);
|
assert_eq!(escape_text('\\', ")", "A\\)B\\\\"), "A)B\\".to_string(),);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue