From 56865c68fc8633df7425720389cac01367438001 Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Tue, 29 Aug 2023 15:44:04 -0400 Subject: [PATCH] Do not allow plain links without a path. --- .../object/plain_link/empty_links.org | 52 +++++++++++++ src/parser/entity.rs | 6 +- src/parser/plain_link.rs | 76 +++++++++++-------- 3 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 org_mode_samples/object/plain_link/empty_links.org diff --git a/org_mode_samples/object/plain_link/empty_links.org b/org_mode_samples/object/plain_link/empty_links.org new file mode 100644 index 00000000..73c94a8d --- /dev/null +++ b/org_mode_samples/object/plain_link/empty_links.org @@ -0,0 +1,52 @@ +non-link text +eww:// +rmail:// +mhe:// +irc:// +info:// +gnus:// +docview:// +bibtex:// +bbdb:// +w3m:// +doi:// +file+sys:// +file+emacs:// +shell:// +news:// +mailto:// +https:// +http:// +ftp:// +help:// +file:// +elisp:// +randomfakeprotocl:// +non-link text + + +non-link text +eww: +rmail: +mhe: +irc: +info: +gnus: +docview: +bibtex: +bbdb: +w3m: +doi: +file+sys: +file+emacs: +shell: +news: +mailto: +https: +http: +ftp: +help: +file: +elisp: +randomfakeprotocl: +non-link text diff --git a/src/parser/entity.rs b/src/parser/entity.rs index 8bd7186e..7621e59f 100644 --- a/src/parser/entity.rs +++ b/src/parser/entity.rs @@ -15,7 +15,8 @@ use crate::error::Res; use crate::parser::object::Entity; use crate::parser::util::get_consumed; -const ENTITIES: [&'static str; 413] = [ +// TODO: Make this a user-provided variable corresponding to elisp's org-entities +const ORG_ENTITIES: [&'static str; 413] = [ "Agrave", "agrave", "Aacute", @@ -457,8 +458,7 @@ fn name<'r, 's>( input: OrgSource<'s>, ) -> Res, OrgSource<'s>> { // TODO: This should be defined by org-entities and optionally org-entities-user - for entity in ENTITIES { - // foo + for entity in ORG_ENTITIES { let result = tag_no_case::<_, _, CustomError<_>>(entity)(input); match result { Ok((remaining, ent)) => { diff --git a/src/parser/plain_link.rs b/src/parser/plain_link.rs index 58617ea6..8518ae6c 100644 --- a/src/parser/plain_link.rs +++ b/src/parser/plain_link.rs @@ -7,6 +7,7 @@ use nom::character::complete::one_of; use nom::combinator::eof; use nom::combinator::peek; use nom::combinator::recognize; +use nom::combinator::verify; use nom::multi::many_till; use super::org_source::OrgSource; @@ -23,6 +24,33 @@ use crate::parser::util::exit_matcher_parser; use crate::parser::util::get_consumed; use crate::parser::util::WORD_CONSTITUENT_CHARACTERS; +// TODO: Make this a user-provided variable corresponding to elisp's org-link-parameters +const ORG_LINK_PARAMETERS: [&'static str; 23] = [ + "id", + "eww", + "rmail", + "mhe", + "irc", + "info", + "gnus", + "docview", + "bibtex", + "bbdb", + "w3m", + "doi", + "file+sys", + "file+emacs", + "shell", + "news", + "mailto", + "https", + "http", + "ftp", + "help", + "file", + "elisp", +]; + #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] pub fn plain_link<'r, 's>( context: Context<'r, 's>, @@ -73,36 +101,19 @@ pub fn protocol<'r, 's>( input: OrgSource<'s>, ) -> Res, OrgSource<'s>> { // 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)) + for link_parameter in ORG_LINK_PARAMETERS { + let result = tag_no_case::<_, _, CustomError<_>>(link_parameter)(input); + match result { + Ok((remaining, ent)) => { + return Ok((remaining, ent)); + } + Err(_) => {} + } + } + + Err(nom::Err::Error(CustomError::MyError(MyError( + "NoLinkProtocol".into(), + )))) } #[cfg_attr(feature = "tracing", tracing::instrument(ret, level = "debug"))] @@ -119,7 +130,10 @@ fn path_plain<'r, 's>( let exit_matcher = parser_with_context!(exit_matcher_parser)(&parser_context); - let (remaining, path) = recognize(many_till(anychar, peek(exit_matcher)))(input)?; + let (remaining, path) = recognize(verify( + many_till(anychar, peek(exit_matcher)), + |(children, _exit_contents)| !children.is_empty(), + ))(input)?; Ok((remaining, path)) }