From 6989b936fa99420ee0c24a57ee686a73041d0cc1 Mon Sep 17 00:00:00 2001 From: Artem Pyanykh Date: Wed, 20 Nov 2024 21:35:48 +0000 Subject: [PATCH] refactor: Model Title explicitly at the symbol level Previously, a level 1 header was implicitly taken as title. This doesn't have to be this way. By having an explicit Title symbol we can make the 'level 1 header = title' interpretation configurable. stack-info: PR: https://github.com/artempyanykh/marksman/pull/364, branch: artempyanykh/stack/9 --- Marksman/Ast.fs | 10 ++- Marksman/Conn.fs | 2 +- Marksman/Folder.fs | 2 +- Marksman/Refs.fs | 14 ++-- Marksman/Syms.fs | 27 ++++--- Tests/RefsTests.fs | 4 +- Tests/_snapshots/ConnGraphTests.json | 102 +++++++++++++-------------- 7 files changed, 86 insertions(+), 75 deletions(-) diff --git a/Marksman/Ast.fs b/Marksman/Ast.fs index 963e5ea..75536bb 100644 --- a/Marksman/Ast.fs +++ b/Marksman/Ast.fs @@ -115,7 +115,13 @@ module Element = if Slug.isEmpty id then None else - Syms.Sym.Def(Def.Header(level, Slug.toString id)) |> Some + let id = Slug.toString id + + // TODO: make this configurable + if level <= 1 then + Syms.Sym.Def(Title(id)) |> Some + else + Syms.Sym.Def(Header(level, id)) |> Some // Wiki-links mapping | Element.WL { doc = None; heading = None } -> None | Element.WL { doc = Some doc; heading = None } -> @@ -160,7 +166,7 @@ module Element = Some(Syms.Sym.Ref(CrossRef(CrossSection(url, Slug.ofString anchor)))) // The rest | Element.MR mdRef -> Some(Syms.Sym.Ref(IntraRef(IntraLinkDef mdRef.DestLabel))) - | Element.MLD mdLinkDef -> Some(Syms.Sym.Def(Def.LinkDef(mdLinkDef.Label))) + | Element.MLD mdLinkDef -> Some(Syms.Sym.Def(LinkDef(mdLinkDef.Label))) | Element.T(Tag tag) -> Some(Syms.Sym.Tag(Syms.Tag tag)) type Ast = { elements: Element[] } diff --git a/Marksman/Conn.fs b/Marksman/Conn.fs index 348a51b..4fc312f 100644 --- a/Marksman/Conn.fs +++ b/Marksman/Conn.fs @@ -374,7 +374,7 @@ module Conn = match def with | Doc - | Header(1, _) -> + | Title _ -> // Whenever a new title is added, links that were previously pointing at the Doc // or the other titles need to be invalidated let affectedDefs = diff --git a/Marksman/Folder.fs b/Marksman/Folder.fs index 81ab2eb..392f903 100644 --- a/Marksman/Folder.fs +++ b/Marksman/Folder.fs @@ -221,7 +221,7 @@ module Oracle = | Ref.IntraRef(IntraSection section) -> Structure.symbols destStruct |> Seq.choose Sym.asDef - |> Seq.filter (Def.isHeaderWithId (Slug.toString section)) + |> Seq.filter (Def.isHeaderOrTitleWithId (Slug.toString section)) |> Seq.toArray | Ref.IntraRef(IntraLinkDef label) -> Structure.symbols destStruct diff --git a/Marksman/Refs.fs b/Marksman/Refs.fs index f078adb..5f6e953 100644 --- a/Marksman/Refs.fs +++ b/Marksman/Refs.fs @@ -179,6 +179,7 @@ module Dest = match destSym with | Sym.Def Doc -> Dest.Doc(detectFileLink destDoc) + | Sym.Def(Title _) | Sym.Def(Header _) -> let docLink = detectDocLink destDoc @@ -238,24 +239,23 @@ module Dest = Seq.empty // This logic is a bit involved but the idea is that whenever we invoke 'find references' - // on a level 1 header (aka a title) we should also look for references to the document - // itself + // on a title we should also look for references to the document itself let defs, filter = match def with - | LinkDef _ -> Seq.singleton def, konst true - | Header(level, _) when level > 1 -> Seq.singleton def, konst true + | LinkDef _ + | Header _ -> Seq.singleton def, konst true | Doc -> let headers = inDoc.Structure.Symbols |> Seq.choose Sym.asDef - |> Seq.filter Def.isHeader + |> Seq.filter Def.isHeaderOrTitle Seq.append [ Def.Doc ] headers, Sym.isRefWithExplicitDoc - | Header(_, id) -> + | Title id -> let headers = inDoc.Structure.Symbols |> Seq.choose Sym.asDef - |> Seq.filter Def.isHeader + |> Seq.filter Def.isHeaderOrTitle let filter sym = Sym.isRefWithExplicitDoc sym diff --git a/Marksman/Syms.fs b/Marksman/Syms.fs index b8eb93e..6758130 100644 --- a/Marksman/Syms.fs +++ b/Marksman/Syms.fs @@ -80,12 +80,14 @@ type Tag = [] type Def = | Doc + | Title of string | Header of level: int * id: string | LinkDef of LinkLabel override this.ToString() = match this with | Doc -> "Doc" + | Title t -> $"T {{{t}}}" | Header(l, h) -> $"H{l} {{{h}}}" | LinkDef ld -> $"[{ld}]:" @@ -94,31 +96,34 @@ type Def = module Def = let isDoc = function - | Def.Doc -> true + | Doc -> true | _ -> false let isTitle = function - | Def.Header(level, _) when level <= 1 -> true + | Title _ -> true | _ -> false - let isHeader = + let isHeaderOrTitle = function - | Def.Header _ -> true + | Title _ + | Header _ -> true | _ -> false - let isHeaderWithId id = + let isHeaderOrTitleWithId id = function - | Def.Header(_, id') when id = id' -> true + | Title id' + | Header(_, id') -> id = id' | _ -> false let isLinkDefWithLabel label = function - | Def.LinkDef label' when label = label' -> true + | LinkDef label' when label = label' -> true | _ -> false let asHeader = function + | Title id -> Some(1, id) | Header(level, id) -> Some(level, id) | _ -> None @@ -172,10 +177,10 @@ module ScopeSlug = let private ofScopedDefAux (docId: DocId) (def: Def) = match def with - | Def.LinkDef _ -> None - | Def.Doc -> Some(ofDocId docId) - | Def.Header(1, id) -> Some(ScopeSlug(Slug.ofString id)) - | Def.Header _ -> Some(ofDocId docId) + | LinkDef _ -> None + | Doc + | Header _ -> Some(ofDocId docId) + | Title id -> Some(ScopeSlug(Slug.ofString id)) let ofScopedDef (scope: Scope, def: Def) = match Scope.asDoc scope with diff --git a/Tests/RefsTests.fs b/Tests/RefsTests.fs index 4878705..4274df4 100644 --- a/Tests/RefsTests.fs +++ b/Tests/RefsTests.fs @@ -396,7 +396,7 @@ module BasicRefsTests = let refs = Dest.findElementRefs false folder doc1 wl |> formatRefs - checkInlineSnapshot (fun x -> x.ToString()) refs [ + checkInlineSnapshot (_.ToString()) refs [ "(doc1.md, (4,0)-(4,16))" "(doc2.md, (6,0)-(6,11))" ] @@ -409,7 +409,7 @@ module BasicRefsTests = let refs = Dest.findElementRefs true folder doc1 wl |> formatRefs - checkInlineSnapshot (fun x -> x.ToString()) refs [ + checkInlineSnapshot (_.ToString()) refs [ "(doc1.md, (4,0)-(4,16))" "(doc2.md, (6,0)-(6,11))" "(doc2.md, (10,0)-(10,9))" diff --git a/Tests/_snapshots/ConnGraphTests.json b/Tests/_snapshots/ConnGraphTests.json index 654f5bb..1e739cd 100644 --- a/Tests/_snapshots/ConnGraphTests.json +++ b/Tests/_snapshots/ConnGraphTests.json @@ -26,31 +26,31 @@ "Defs:", " d1.md:", " Doc", - " H1 {doc-1}", + " T {doc-1}", " H2 {d1s1}", " d1_dup.md:", " Doc", - " H1 {doc-1}", + " T {doc-1}", " d2.md:", " Doc", - " H1 {doc-2}", + " T {doc-2}", " d3.md:", " Doc", - " H1 {doc-3}", + " T {doc-3}", " [link1]:", "Resolved:", " d1.md:", - " H1 {doc-1} -> [[doc-1]] @ d2.md", + " T {doc-1} -> [[doc-1]] @ d2.md", " H2 {d1s1} -> [[doc-1#d1s1]] @ d2.md", - " [[doc-2]] -> H1 {doc-2} @ d2.md", + " [[doc-2]] -> T {doc-2} @ d2.md", " d1_dup.md:", - " H1 {doc-1} -> [[doc-1]] @ d2.md", - " [[doc-2]] -> H1 {doc-2} @ d2.md", + " T {doc-1} -> [[doc-1]] @ d2.md", + " [[doc-2]] -> T {doc-2} @ d2.md", " d2.md:", - " H1 {doc-2} -> [[doc-2]] @ d1.md", - " H1 {doc-2} -> [[doc-2]] @ d1_dup.md", - " [[doc-1]] -> H1 {doc-1} @ d1.md", - " [[doc-1]] -> H1 {doc-1} @ d1_dup.md", + " T {doc-2} -> [[doc-2]] @ d1.md", + " T {doc-2} -> [[doc-2]] @ d1_dup.md", + " [[doc-1]] -> T {doc-1} @ d1.md", + " [[doc-1]] -> T {doc-1} @ d1_dup.md", " [[doc-1#d1s1]] -> H2 {d1s1} @ d1.md", " d3.md:", " [link1]: -> [link1] @ d3.md", @@ -69,20 +69,20 @@ " (d2.md, [[doc-1#d1s1]]) -> (d2.md, [[doc-1]])", "Last touched:", " Doc @ d1.md", - " H1 {doc-1} @ d1.md", + " T {doc-1} @ d1.md", " H2 {d1s1} @ d1.md", " [[doc-2]] @ d1.md", " [[doc-NA]] @ d1.md", " Doc @ d1_dup.md", - " H1 {doc-1} @ d1_dup.md", + " T {doc-1} @ d1_dup.md", " [[doc-2]] @ d1_dup.md", " Doc @ d2.md", - " H1 {doc-2} @ d2.md", + " T {doc-2} @ d2.md", " [[doc-1]] @ d2.md", " [[doc-NA2]] @ d2.md", " [[doc-1#d1s1]] @ d2.md", " Doc @ d3.md", - " H1 {doc-3} @ d3.md", + " T {doc-3} @ d3.md", " [link1]: @ d3.md", " [link1] @ d3.md", " [linkx] @ d3.md" @@ -104,23 +104,23 @@ "Defs:", " d1.md:", " Doc", - " H1 {doc-1}", + " T {doc-1}", " H2 {d1s1}", " d2.md:", " Doc", - " H1 {doc-2}", + " T {doc-2}", " d3.md:", " Doc", - " H1 {doc-3}", + " T {doc-3}", " [link1]:", "Resolved:", " d1.md:", - " H1 {doc-1} -> [[doc-1]] @ d2.md", + " T {doc-1} -> [[doc-1]] @ d2.md", " H2 {d1s1} -> [[doc-1#d1s1]] @ d2.md", - " [[doc-2]] -> H1 {doc-2} @ d2.md", + " [[doc-2]] -> T {doc-2} @ d2.md", " d2.md:", - " H1 {doc-2} -> [[doc-2]] @ d1.md", - " [[doc-1]] -> H1 {doc-1} @ d1.md", + " T {doc-2} -> [[doc-2]] @ d1.md", + " [[doc-1]] -> T {doc-1} @ d1.md", " [[doc-1#d1s1]] -> H2 {d1s1} @ d1.md", " d3.md:", " [link1]: -> [link1] @ d3.md", @@ -136,10 +136,10 @@ " (d2.md, [[doc-1]]) -> (d2.md, [[doc-1#d1s1]])", " (d2.md, [[doc-1#d1s1]]) -> (d2.md, [[doc-1]])", "Last touched:", - " H1 {doc-1} @ d1.md", + " T {doc-1} @ d1.md", " H2 {d1s1} @ d1.md", " Doc @ d1_dup.md", - " H1 {doc-1} @ d1_dup.md", + " T {doc-1} @ d1_dup.md", " [[doc-2]] @ d1_dup.md", " [[doc-1]] @ d2.md", " [[doc-1#d1s1]] @ d2.md" @@ -161,33 +161,33 @@ "Defs:", " d1.md:", " Doc", - " H1 {doc-1}", + " T {doc-1}", " H2 {d1s1}", " d2.md:", " Doc", - " H1 {doc-2}", + " T {doc-2}", " d3.md:", " Doc", - " H1 {doc-3}", + " T {doc-3}", " [link1]:", " docNA.md:", " Doc", - " H1 {doc-na}", + " T {doc-na}", "Resolved:", " d1.md:", - " H1 {doc-1} -> [[doc-1]] @ d2.md", + " T {doc-1} -> [[doc-1]] @ d2.md", " H2 {d1s1} -> [[doc-1#d1s1]] @ d2.md", - " [[doc-2]] -> H1 {doc-2} @ d2.md", - " [[doc-NA]] -> H1 {doc-na} @ docNA.md", + " [[doc-2]] -> T {doc-2} @ d2.md", + " [[doc-NA]] -> T {doc-na} @ docNA.md", " d2.md:", - " H1 {doc-2} -> [[doc-2]] @ d1.md", - " [[doc-1]] -> H1 {doc-1} @ d1.md", + " T {doc-2} -> [[doc-2]] @ d1.md", + " [[doc-1]] -> T {doc-1} @ d1.md", " [[doc-1#d1s1]] -> H2 {d1s1} @ d1.md", " d3.md:", " [link1]: -> [link1] @ d3.md", " [link1] -> [link1]: @ d3.md", " docNA.md:", - " H1 {doc-na} -> [[doc-NA]] @ d1.md", + " T {doc-na} -> [[doc-NA]] @ d1.md", "Unresolved:", " [[doc-NA2]] @ d2.md -> FullyUnknown", " [linkx] @ d3.md -> d3.md", @@ -200,7 +200,7 @@ " [[doc-NA]] @ d1.md", " [[doc-NA2]] @ d2.md", " Doc @ docNA.md", - " H1 {doc-na} @ docNA.md" + " T {doc-na} @ docNA.md" ] }, "addLinkDef": { @@ -219,24 +219,24 @@ "Defs:", " d1.md:", " Doc", - " H1 {doc-1}", + " T {doc-1}", " H2 {d1s1}", " d2.md:", " Doc", - " H1 {doc-2}", + " T {doc-2}", " d3.md:", " Doc", - " H1 {doc-3}", + " T {doc-3}", " [link1]:", " [linkx]:", "Resolved:", " d1.md:", - " H1 {doc-1} -> [[doc-1]] @ d2.md", + " T {doc-1} -> [[doc-1]] @ d2.md", " H2 {d1s1} -> [[doc-1#d1s1]] @ d2.md", - " [[doc-2]] -> H1 {doc-2} @ d2.md", + " [[doc-2]] -> T {doc-2} @ d2.md", " d2.md:", - " H1 {doc-2} -> [[doc-2]] @ d1.md", - " [[doc-1]] -> H1 {doc-1} @ d1.md", + " T {doc-2} -> [[doc-2]] @ d1.md", + " [[doc-1]] -> T {doc-1} @ d1.md", " [[doc-1#d1s1]] -> H2 {d1s1} @ d1.md", " d3.md:", " [link1]: -> [link1] @ d3.md", @@ -274,21 +274,21 @@ "Defs:", " d1.md:", " Doc", - " H1 {doc-1}", + " T {doc-1}", " d2.md:", " Doc", - " H1 {doc-2}", + " T {doc-2}", " d3.md:", " Doc", - " H1 {doc-3}", + " T {doc-3}", " [link1]:", "Resolved:", " d1.md:", - " H1 {doc-1} -> [[doc-1]] @ d2.md", - " [[doc-2]] -> H1 {doc-2} @ d2.md", + " T {doc-1} -> [[doc-1]] @ d2.md", + " [[doc-2]] -> T {doc-2} @ d2.md", " d2.md:", - " H1 {doc-2} -> [[doc-2]] @ d1.md", - " [[doc-1]] -> H1 {doc-1} @ d1.md", + " T {doc-2} -> [[doc-2]] @ d1.md", + " [[doc-1]] -> T {doc-1} @ d1.md", " d3.md:", " [link1]: -> [link1] @ d3.md", " [link1] -> [link1]: @ d3.md", @@ -305,7 +305,7 @@ " (d2.md, [[doc-1]]) -> (d2.md, [[doc-1#d1s1]])", " (d2.md, [[doc-1#d1s1]]) -> (d2.md, [[doc-1]])", "Last touched:", - " H1 {doc-1} @ d1.md", + " T {doc-1} @ d1.md", " H2 {d1s1} @ d1.md", " [[doc-1]] @ d2.md", " [[doc-1#d1s1]] @ d2.md"