From 5f4e240af00c4a6ed7b99fb6a7983ae9f4696a27 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Thu, 13 Jul 2023 19:09:44 -0400 Subject: [PATCH] Add an initial implementation of PlainLink. --- .../plain_link/all_default_links.org | 26 +++++++++ src/parser/object.rs | 3 +- src/parser/object_parser.rs | 1 + src/parser/plain_link.rs | 57 ++++++++++++++++++- 4 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 org_mode_samples/plain_link/all_default_links.org diff --git a/org_mode_samples/plain_link/all_default_links.org b/org_mode_samples/plain_link/all_default_links.org new file mode 100644 index 0000000..8ceca6f --- /dev/null +++ b/org_mode_samples/plain_link/all_default_links.org @@ -0,0 +1,26 @@ +non-link text +id://foo +eww://foo +rmail://foo +mhe://foo +irc://foo +info://foo +gnus://foo +docview://foo +bibtex://foo +bbdb://foo +w3m://foo +doi://foo +file+sys://foo +file+emacs://foo +shell://foo +news://foo +mailto://foo +https://foo +http://foo +ftp://foo +help://foo +file://foo +elisp://foo +randomfakeprotocl://foo +non-link text diff --git a/src/parser/object.rs b/src/parser/object.rs index 5ff013e..cef816c 100644 --- a/src/parser/object.rs +++ b/src/parser/object.rs @@ -76,7 +76,8 @@ pub struct RadioLink<'s> { #[derive(Debug, PartialEq)] pub struct PlainLink<'s> { pub source: &'s str, - pub children: Vec>, + pub link_type: &'s str, + pub path: &'s str, } impl<'s> Source<'s> for Object<'s> { diff --git a/src/parser/object_parser.rs b/src/parser/object_parser.rs index 086f648..3b29a6c 100644 --- a/src/parser/object_parser.rs +++ b/src/parser/object_parser.rs @@ -68,6 +68,7 @@ pub fn any_object_except_plain_text<'r, 's>( parser_with_context!(regular_link)(context), Object::RegularLink, ), + map(parser_with_context!(plain_link)(context), Object::PlainLink), ))(input) } diff --git a/src/parser/plain_link.rs b/src/parser/plain_link.rs index c95bb9c..c102ea6 100644 --- a/src/parser/plain_link.rs +++ b/src/parser/plain_link.rs @@ -1,6 +1,10 @@ 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; @@ -8,14 +12,20 @@ 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::not_yet_implemented; 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>> { - not_yet_implemented()?; - todo!(); + 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")] @@ -43,3 +53,44 @@ 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> { + 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) +}