From 65fd48f0a2ce3997eaf05bfb2e9ff4e534346267 Mon Sep 17 00:00:00 2001 From: hardfau1t Date: Wed, 4 Jun 2025 17:26:54 +0530 Subject: [PATCH 1/4] fix(stage3): support for line number in links --- src/stage_3.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/stage_3.rs b/src/stage_3.rs index 6e56490..26d76d1 100644 --- a/src/stage_3.rs +++ b/src/stage_3.rs @@ -220,7 +220,13 @@ fn paragraph_parser_opener_candidates_and_links() -> impl Parser< }, } } else { - LinkTarget::Url(content.into_iter().map_into::().collect()) + let content_str: String = + content.into_iter().map_into::().collect(); + if let Ok(line_number) = content_str.trim().parse::() { + LinkTarget::LineNumber(line_number) + } else { + LinkTarget::Url(content_str) + } }] } else { vec![] @@ -438,6 +444,7 @@ pub enum LinkTarget { Generic(Vec), Wiki(Vec), Extendable(Vec), + LineNumber(usize), Path(String), Url(String), Timestamp(String), @@ -580,10 +587,7 @@ fn detached_modifier_extensions() -> impl Parser< .or_not() .map(|tokens| { if let Some(tokens) = tokens { - tokens - .into_iter() - .map_into::() - .collect() + tokens.into_iter().map_into::().collect() } else { String::from("") } From 919a61ead1091d911de8c1c11e5a72f9745d7444 Mon Sep 17 00:00:00 2001 From: hardfau1t Date: Wed, 4 Jun 2025 17:44:56 +0530 Subject: [PATCH 2/4] fix(stage_3): support for generic links --- src/stage_3.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/stage_3.rs b/src/stage_3.rs index 26d76d1..109dde2 100644 --- a/src/stage_3.rs +++ b/src/stage_3.rs @@ -177,6 +177,7 @@ fn paragraph_parser_opener_candidates_and_links() -> impl Parser< just(ParagraphSegmentToken::Special('=')).to("=".to_string()), just(ParagraphSegmentToken::Special('?')).to("?".to_string()), just(ParagraphSegmentToken::Special('@')).to("@".to_string()), + just(ParagraphSegmentToken::Special('#')).to("#".to_string()), )) .then_ignore( just(ParagraphSegmentToken::Whitespace) @@ -206,6 +207,7 @@ fn paragraph_parser_opener_candidates_and_links() -> impl Parser< "^" => LinkTarget::Footnote(parse_paragraph(content).unwrap()), "?" => LinkTarget::Wiki(parse_paragraph(content).unwrap()), "=" => LinkTarget::Extendable(parse_paragraph(content).unwrap()), + "#" => LinkTarget::Generic(parse_paragraph(content).unwrap()), "/" => { LinkTarget::Path(content.into_iter().map_into::().collect()) } From 2fa40d9bacfd89e1b99246ba459149bacceed605 Mon Sep 17 00:00:00 2001 From: hardfau1t Date: Wed, 4 Jun 2025 18:57:08 +0530 Subject: [PATCH 3/4] test(links): add extra tests for links NOTE: scope and wiki links are not yet working --- src/lib.rs | 53 ++++- src/snapshots/rust_norg__tests__links.snap | 230 +++++++++++++++++++++ 2 files changed, 281 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 603c261..d7ec9c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -210,8 +210,9 @@ mod tests { "- (+) recurring", "~ (+ Friday) recurring with date", "** ( |# Low|< Feb 1) undone, low, & before Feb", - "** (# Two Words|x| |!|+|_|+ 5th|=|-|< Feb 1|> 2025|@ Jan 1 2025) All of them" - ].into_iter() + "** (# Two Words|x| |!|+|_|+ 5th|=|-|< Feb 1|> 2025|@ Jan 1 2025) All of them", + ] + .into_iter() .map(|example| example.to_string() + "\n") .map(|str| parse(&str)) .try_collect() @@ -709,6 +710,26 @@ mod tests { #[test] fn links() { let examples: Vec<_> = [ + // expected to fail + // r#"{:path:/ file}"#, + // r#"{:path:@ timestamp}"#, + // r#"{:path:https://my-url}"#, + // r#"{$$ Text}"#, + // r#"{\n * linkable}"#, + // r#"[linkable\n ]"#, + // r#"<\n this certainly isn't a linkable\n >"#, + // r#"{*text}"#, + // r#"{:file:https://github.com}"#, + // r#"{:file:/ file.txt}"#, + // r#"{:file:@ Wednesday 30th Jan}"#, + // r#"{\n * text}"#, + // r#"{\n * text\n }"#, + // r#"{* text\n }"#, + // r#"{ * text}"#, + // r#"{* text}[\n text\n ]"#, + // r#"{* text}[text\n ]"#, + // r#"{* text}[\n text]"#, + // these are the correct links "{https://github.com/nvim-neorg/neorg}", "{$ hello!}", "{/ a-path.txt}", @@ -721,6 +742,34 @@ mod tests { "This is a !", "<*linkable with markup*> here!", "{:another_file:}", + r#"{:path/to/other-file:}"#, + r#"{:path/to/file:123}"#, + r#"{:path/to/file:# Generic Location within that file}"#, + r#"{:path/to/file:** Level 2 heading}"#, + r#"{file://my/file.norg}"#, + // * Path Modifiers: + // - /my/file - Root of the file system. + // - ~/Documents/my-file - User's home directory. + // - $/my/file - Root of the Neorg workspace. + // - $notes/my/file - Links to a file from another workspace. + // - Line Number: + r#"{2}"#, + r#"{:file:4}"#, + // - Detached Modifier: + r#"{* I am a level 1 heading}"#, + // - Custom Detached Modifiers: + r#"{# My Location}"#, + r#"{/ /path/to/my/file.txt}"#, + r#"{/ my-file.txt:123}"#, + r#"{@ 5th May}"#, + r#"{? mammals}"#, + r#"{= Neorg2022}(my_bibliography)"#, + // - Inline Linkables: + r#"{# Carryover Tags}"#, + r#"{# Inline Link Targets}"#, + // - Scoping: + r#"{* Heading Name : *** Level 3 heading}"#, + r#"{* heading1 : ** heading2 : ^ Footnote}"#, ] .into_iter() .map(|example| example.to_string() + "\n") diff --git a/src/snapshots/rust_norg__tests__links.snap b/src/snapshots/rust_norg__tests__links.snap index 4c08abb..370ae5e 100644 --- a/src/snapshots/rust_norg__tests__links.snap +++ b/src/snapshots/rust_norg__tests__links.snap @@ -135,3 +135,233 @@ expression: examples filepath: another_file targets: [] description: ~ +- - Paragraph: + - Link: + filepath: path/to/other-file + targets: [] + description: ~ +- - Paragraph: + - Link: + filepath: path/to/file + targets: + - LineNumber: 123 + description: ~ +- - Paragraph: + - Link: + filepath: path/to/file + targets: + - Generic: + - Token: + Text: Generic + - Token: Whitespace + - Token: + Text: Location + - Token: Whitespace + - Token: + Text: within + - Token: Whitespace + - Token: + Text: that + - Token: Whitespace + - Token: + Text: file + description: ~ +- - Paragraph: + - Link: + filepath: path/to/file + targets: + - Heading: + level: 2 + title: + - Token: + Text: Level + - Token: Whitespace + - Token: + Text: "2" + - Token: Whitespace + - Token: + Text: heading + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Url: "file://my/file.norg" + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - LineNumber: 2 + description: ~ +- - Paragraph: + - Link: + filepath: file + targets: + - LineNumber: 4 + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Heading: + level: 1 + title: + - Token: + Text: I + - Token: Whitespace + - Token: + Text: am + - Token: Whitespace + - Token: + Text: a + - Token: Whitespace + - Token: + Text: level + - Token: Whitespace + - Token: + Text: "1" + - Token: Whitespace + - Token: + Text: heading + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Generic: + - Token: + Text: My + - Token: Whitespace + - Token: + Text: Location + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Path: /path/to/my/file.txt + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Path: "my-file.txt:123" + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Timestamp: 5th May + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Url: "? mammals" + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Extendable: + - Token: + Text: Neorg2022 + description: ~ + - Token: + Special: ( + - Token: + Text: my + - Token: + Special: _ + - Token: + Text: bibliography + - Token: + Special: ) +- - Paragraph: + - Link: + filepath: ~ + targets: + - Generic: + - Token: + Text: Carryover + - Token: Whitespace + - Token: + Text: Tags + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Generic: + - Token: + Text: Inline + - Token: Whitespace + - Token: + Text: Link + - Token: Whitespace + - Token: + Text: Targets + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Heading: + level: 1 + title: + - Token: + Text: Heading + - Token: Whitespace + - Token: + Text: Name + - Token: Whitespace + - Token: + Special: ":" + - Token: Whitespace + - Token: + Special: "*" + - Token: + Special: "*" + - Token: + Special: "*" + - Token: Whitespace + - Token: + Text: Level + - Token: Whitespace + - Token: + Text: "3" + - Token: Whitespace + - Token: + Text: heading + description: ~ +- - Paragraph: + - Link: + filepath: ~ + targets: + - Heading: + level: 1 + title: + - Token: + Text: heading1 + - Token: Whitespace + - Token: + Special: ":" + - Token: Whitespace + - Token: + Special: "*" + - Token: + Special: "*" + - Token: Whitespace + - Token: + Text: heading2 + - Token: Whitespace + - Token: + Special: ":" + - Token: Whitespace + - Token: + Special: ^ + - Token: Whitespace + - Token: + Text: Footnote + description: ~ From 279aa4497b97a881a88626375d512488e46f630e Mon Sep 17 00:00:00 2001 From: hardfau1t Date: Thu, 17 Jul 2025 17:06:03 +0530 Subject: [PATCH 4/4] test(links): add few more tests for links --- src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index d7ec9c4..c2236b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -744,6 +744,8 @@ mod tests { "{:another_file:}", r#"{:path/to/other-file:}"#, r#"{:path/to/file:123}"#, + r#"{:$/path/from/root/file:123}"#, + r#"{: $workspace/path/from/root/file:123}"#, r#"{:path/to/file:# Generic Location within that file}"#, r#"{:path/to/file:** Level 2 heading}"#, r#"{file://my/file.norg}"#,