105 lines
3.7 KiB
Rust
105 lines
3.7 KiB
Rust
use nom::branch::alt;
|
|
use nom::bytes::complete::tag;
|
|
use nom::bytes::complete::tag_no_case;
|
|
use nom::bytes::complete::take_while;
|
|
use nom::character::complete::none_of;
|
|
use nom::combinator::eof;
|
|
use nom::combinator::peek;
|
|
use nom::combinator::recognize;
|
|
|
|
use super::Context;
|
|
use crate::error::CustomError;
|
|
use crate::error::MyError;
|
|
use crate::error::Res;
|
|
use crate::parser::object::PlainLink;
|
|
use crate::parser::parser_with_context::parser_with_context;
|
|
use crate::parser::util::get_consumed;
|
|
use crate::parser::util::get_one_before;
|
|
use crate::parser::util::WORD_CONSTITUENT_CHARACTERS;
|
|
|
|
#[tracing::instrument(ret, level = "debug")]
|
|
pub fn plain_link<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, PlainLink<'s>> {
|
|
let (remaining, _) = pre(context, input)?;
|
|
let (remaining, proto) = protocol(context, remaining)?;
|
|
let (remaining, _separator) = tag(":")(remaining)?;
|
|
let (remaining, path) = path_plain(context, remaining)?;
|
|
peek(parser_with_context!(post)(context))(remaining)?;
|
|
let source = get_consumed(input, remaining);
|
|
Ok((
|
|
remaining,
|
|
PlainLink {
|
|
source,
|
|
link_type: proto,
|
|
path,
|
|
},
|
|
))
|
|
}
|
|
|
|
#[tracing::instrument(ret, level = "debug")]
|
|
pub fn pre<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, ()> {
|
|
let document_root = context.get_document_root().unwrap();
|
|
let preceding_character = get_one_before(document_root, input)
|
|
.map(|slice| slice.chars().next())
|
|
.flatten();
|
|
match preceding_character {
|
|
// If None, we are at the start of the file which is fine
|
|
None => {}
|
|
Some(x) if !WORD_CONSTITUENT_CHARACTERS.contains(x) => {}
|
|
Some(_) => {
|
|
// Not at start of line, cannot be a heading
|
|
return Err(nom::Err::Error(CustomError::MyError(MyError(
|
|
"Not a valid pre character for plain link.",
|
|
))));
|
|
}
|
|
};
|
|
Ok((input, ()))
|
|
}
|
|
|
|
#[tracing::instrument(ret, level = "debug")]
|
|
pub fn post<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, ()> {
|
|
let (remaining, _) = alt((eof, recognize(none_of(WORD_CONSTITUENT_CHARACTERS))))(input)?;
|
|
Ok((remaining, ()))
|
|
}
|
|
|
|
#[tracing::instrument(ret, level = "debug")]
|
|
pub fn protocol<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> {
|
|
// TODO: This should be defined by org-link-parameters
|
|
let (remaining, proto) = alt((
|
|
alt((
|
|
tag_no_case("id"),
|
|
tag_no_case("eww"),
|
|
tag_no_case("rmail"),
|
|
tag_no_case("mhe"),
|
|
tag_no_case("irc"),
|
|
tag_no_case("info"),
|
|
tag_no_case("gnus"),
|
|
tag_no_case("docview"),
|
|
tag_no_case("bibtex"),
|
|
tag_no_case("bbdb"),
|
|
tag_no_case("w3m"),
|
|
)),
|
|
alt((
|
|
tag_no_case("doi"),
|
|
tag_no_case("file+sys"),
|
|
tag_no_case("file+emacs"),
|
|
tag_no_case("shell"),
|
|
tag_no_case("news"),
|
|
tag_no_case("mailto"),
|
|
tag_no_case("https"),
|
|
tag_no_case("http"),
|
|
tag_no_case("ftp"),
|
|
tag_no_case("help"),
|
|
tag_no_case("file"),
|
|
tag_no_case("elisp"),
|
|
)),
|
|
))(input)?;
|
|
Ok((remaining, proto))
|
|
}
|
|
|
|
#[tracing::instrument(ret, level = "debug")]
|
|
pub fn path_plain<'r, 's>(context: Context<'r, 's>, input: &'s str) -> Res<&'s str, &'s str> {
|
|
// TODO: "optionally containing parenthesis-wrapped non-whitespace non-bracket substrings up to a depth of two. The string must end with either a non-punctation non-whitespace character, a forwards slash, or a parenthesis-wrapped substring"
|
|
take_while(|c| !" \t\r\n()[]<>".contains(c))(input)
|
|
// recognize(many1(none_of(" \t\r\n()[]<>")))(input)
|
|
}
|