Apply the link templates.

This commit is contained in:
Tom Alexander
2023-10-06 22:08:26 -04:00
parent 2ba5156ee1
commit 4c8828b91b
8 changed files with 203 additions and 32 deletions

View File

@@ -1,7 +1,10 @@
use std::borrow::Cow;
use nom::branch::alt;
use nom::bytes::complete::escaped;
use nom::bytes::complete::tag;
use nom::bytes::complete::take_till1;
use nom::bytes::complete::take_until;
use nom::character::complete::anychar;
use nom::combinator::consumed;
use nom::combinator::eof;
@@ -14,6 +17,7 @@ use nom::combinator::rest;
use nom::combinator::verify;
use nom::multi::many_till;
use nom::sequence::tuple;
use nom::InputTake;
use super::object_parser::regular_link_description_set_object;
use super::org_source::OrgSource;
@@ -26,6 +30,8 @@ use crate::context::ContextElement;
use crate::context::ExitClass;
use crate::context::ExitMatcherNode;
use crate::context::RefContext;
use crate::error::CustomError;
use crate::error::MyError;
use crate::error::Res;
use crate::types::LinkType;
use crate::types::Object;
@@ -90,11 +96,12 @@ fn regular_link_with_description<'b, 'g, 'r, 's>(
))
}
#[derive(Debug)]
struct PathReg<'s> {
link_type: LinkType<'s>,
path: &'s str,
raw_link: &'s str,
search_option: Option<&'s str>,
path: Cow<'s, str>,
raw_link: Cow<'s, str>,
search_option: Option<Cow<'s, str>>,
}
#[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))]
@@ -120,14 +127,108 @@ fn parse_path_reg<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Res<OrgSource<'s>, PathReg<'s>> {
alt((
file_path_reg,
id_path_reg,
custom_id_path_reg,
code_ref_path_reg,
parser_with_context!(protocol_path_reg)(context),
fuzzy_path_reg,
if let Some(replaced_link) = apply_link_templates(context, input) {
let replaced_input = Into::<OrgSource<'_>>::into(replaced_link.as_str());
let (_remaining, link) = alt((
file_path_reg,
id_path_reg,
custom_id_path_reg,
code_ref_path_reg,
parser_with_context!(protocol_path_reg)(context),
fuzzy_path_reg,
))(replaced_input)
.map_err(|_| {
nom::Err::Error(CustomError::MyError(MyError(
"No pathreg match after replacement.",
)))
})?;
let remaining = input.take(input.len());
let link_type = match link.link_type {
LinkType::Protocol(protocol) => LinkType::Protocol(protocol.into_owned().into()),
LinkType::File => LinkType::File,
LinkType::Id => LinkType::Id,
LinkType::CustomId => LinkType::CustomId,
LinkType::CodeRef => LinkType::CodeRef,
LinkType::Fuzzy => LinkType::Fuzzy,
};
Ok((
remaining,
PathReg {
link_type,
path: link.path.into_owned().into(),
raw_link: link.raw_link.into_owned().into(),
search_option: link.search_option.map(|s| s.into_owned().into()),
},
))
} else {
alt((
file_path_reg,
id_path_reg,
custom_id_path_reg,
code_ref_path_reg,
parser_with_context!(protocol_path_reg)(context),
fuzzy_path_reg,
))(input)
}
}
enum ParserState {
Normal,
Percent,
}
fn apply_link_templates<'b, 'g, 'r, 's>(
context: RefContext<'b, 'g, 'r, 's>,
input: OrgSource<'s>,
) -> Option<String> {
let (remaining, key) = opt(map(
tuple((
recognize(take_until::<_, _, nom::error::Error<_>>("::")),
tag("::"),
)),
|(key, _)| key,
))(input)
.expect("opt ensures this cannot error.");
let key = match key {
Some(key) => key,
None => {
return None;
}
};
let replacement_template = match context.get_global_settings().link_templates.get(key.into()) {
Some(template) => template,
None => {
return None;
}
};
let inject_value = Into::<&str>::into(remaining);
let mut ret = String::with_capacity(replacement_template.len() + inject_value.len());
let mut state = ParserState::Normal;
for c in replacement_template.chars() {
state = match (&state, c) {
(ParserState::Normal, '%') => ParserState::Percent,
(ParserState::Normal, _) => {
ret.push(c);
ParserState::Normal
}
(ParserState::Percent, 's') => {
ret.push_str(inject_value);
ParserState::Normal
}
(ParserState::Percent, _) => {
panic!("Unhandled percent value: {}", c)
}
};
}
// Handle lingering state
match state {
ParserState::Percent => {
ret.push('%');
}
_ => {}
}
Some(ret)
}
fn file_path_reg<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PathReg<'s>> {
@@ -144,7 +245,9 @@ fn file_path_reg<'s>(input: OrgSource<'s>) -> Res<OrgSource<'s>, PathReg<'s>> {
link_type: LinkType::File,
path: path.into(),
raw_link: raw_link.into(),
search_option: search_option.map(Into::<&str>::into),
search_option: search_option
.map(Into::<&str>::into)
.map(Into::<Cow<str>>::into),
},
))
}