diff --git a/src/syntax/link.rs b/src/syntax/link.rs index a2aa4d9..447b5a1 100644 --- a/src/syntax/link.rs +++ b/src/syntax/link.rs @@ -22,7 +22,7 @@ pub fn link_node(input: Input) -> IResult { let mut parser = map( tuple(( l_bracket2_token, - take_while(|c: char| c != '<' && c != '>' && c != '\n' && c != ']'), + take_while(|c: char| c != '<' && c != '>' && c != ']'), opt(tuple(( r_bracket_token, l_bracket_token, @@ -110,3 +110,66 @@ fn parse() { assert!(link_node(("[[#id][desc]", config).into()).is_err()); } + +/// Emacs org-mode accepts a single newline inside a bracket link — both inside +/// the path and inside the description. These tests document the discrepancy +/// against orgize and serve as the reproducer for the upstream issue/PR. +#[test] +fn parse_multiline_link() { + use crate::{ast::Link, tests::to_ast}; + + let to_link = to_ast::(link_node); + + // Path-only link with a newline inside the path. + let link = to_link("[[really really long link\nthat just keeps going]]"); + insta::assert_debug_snapshot!( + link.syntax, + @r###" + LINK@0..49 + L_BRACKET2@0..2 "[[" + LINK_PATH@2..47 "really really long li ..." + R_BRACKET2@47..49 "]]" + "### + ); + + // Link with separate description that contains a newline. + let link = to_link("[[https://example.com][some\ndescription]]"); + insta::assert_debug_snapshot!( + link.syntax, + @r###" + LINK@0..41 + L_BRACKET2@0..2 "[[" + LINK_PATH@2..21 "https://example.com" + R_BRACKET@21..22 "]" + L_BRACKET@22..23 "[" + TEXT@23..39 "some\ndescription" + R_BRACKET2@39..41 "]]" + "### + ); +} + +/// `Org::parse` should also pick up multi-line links inside paragraphs. This +/// is the end-to-end case relevant to downstream formatters (e.g. org-fmt). +#[test] +fn parse_multiline_link_in_paragraph() { + use crate::{ast::Link, Org}; + use rowan::ast::AstNode; + + let org = Org::parse( + "Here is a [[really really long link\nthat just keeps going]] in prose.\n", + ); + + let links: Vec<_> = org + .document() + .syntax() + .descendants() + .filter_map(Link::cast) + .collect(); + + assert_eq!( + links.len(), + 1, + "expected one link, found {}", + links.len(), + ); +}