Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions Benchmarks/Program.fs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ type ReferenceResolution() =
let link =
Doc.index doc |> Index.linkAtPos (Position.Mk(1, 3)) |> Option.get

let refs = Dest.tryResolveElement this.Folder doc link |> Seq.toArray
let refs =
Dest.tryResolveElement this.Folder Seq.empty doc link |> Seq.toArray

refs |> ignore

[<Benchmark>]
Expand All @@ -66,7 +68,10 @@ type ReferenceResolution() =
let header =
Cst.elementAtPos (Position.Mk(0, 3)) (Doc.cst doc) |> Option.get

let refs = Dest.findElementRefs true this.Folder doc header |> Seq.toArray
let refs =
Dest.findElementRefs true this.Folder Seq.empty doc header
|> Seq.toArray

refs |> ignore


Expand Down
3 changes: 2 additions & 1 deletion Marksman/CodeActions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ let createMissingFile
(_context: CodeActionContext)
(doc: Doc)
(folder: Folder)
(extraFolders: seq<Folder>)
: CreateFileAction option =
let configuredExts = (Folder.configuredMarkdownExts folder)

Expand All @@ -141,7 +142,7 @@ let createMissingFile
| _ -> None

let docRefAtPos = Sym.Ref(CrossRef(CrossDoc docAtPos))
let refs = Dest.tryResolveSym folder doc docRefAtPos
let refs = Dest.tryResolveSym folder extraFolders doc docRefAtPos

// Early return if the file exists
do! guard (Seq.isEmpty refs)
Expand Down
101 changes: 78 additions & 23 deletions Marksman/Compl.fs
Original file line number Diff line number Diff line change
Expand Up @@ -680,30 +680,53 @@ module Completions =
}

module Candidates =
let findDocCandidates (folder: Folder) (srcDoc: Doc) (destPart: option<InternName>) : seq<Doc> =
let candidates =
let findDocCandidates
(folder: Folder)
(extraFolders: seq<Folder>)
(srcDoc: Doc)
(destPart: option<InternName>)
: seq<Doc> =
let primaryCands =
match destPart with
| None -> Folder.docs folder
| Some name -> FileLink.filterFuzzyMatchingDocs folder name

candidates |> Seq.filter (fun d -> d <> srcDoc)
let primaryIds = primaryCands |> Seq.map Doc.id |> Set.ofSeq

let extraCands =
extraFolders
|> Seq.collect (fun ef ->
match destPart with
| None -> Folder.docs ef
| Some name -> FileLink.filterFuzzyMatchingDocs ef name)
|> Seq.filter (fun d -> not (Set.contains (Doc.id d) primaryIds))

Seq.append primaryCands extraCands
|> Seq.filter (fun d -> d <> srcDoc)

let findHeadingCandidates
(folder: Folder)
(extraFolders: seq<Folder>)
(srcDoc: Doc)
(destPart: option<InternName>)
(headingPart: string)
: seq<Doc * string> =
let targetDocs =
destPart
|> Option.map (FileLink.filterFuzzyMatchingDocs folder)
|> Option.defaultValue [ srcDoc ]
match destPart with
| None -> [ srcDoc ] :> seq<Doc>
| Some name ->
let primaryDocs =
FileLink.filterFuzzyMatchingDocs folder name
|> Seq.filter (fun d -> d <> srcDoc)

let targetDocs =
if destPart.IsSome then
targetDocs |> Seq.filter (fun d -> d <> srcDoc)
else
targetDocs
let primaryIds = primaryDocs |> Seq.map Doc.id |> Set.ofSeq

let extraDocs =
extraFolders
|> Seq.collect (fun ef -> FileLink.filterFuzzyMatchingDocs ef name)
|> Seq.filter (fun d -> d <> srcDoc && not (Set.contains (Doc.id d) primaryIds))

Seq.append primaryDocs extraDocs

let inputSlug = Slug.ofString headingPart

Expand All @@ -730,10 +753,25 @@ module Candidates =
(Doc.index srcDoc)
|> Seq.map Node.data

let findTagCandidates (folder: Folder) (_srcDoc: Doc) (input: string) : seq<string * int> =
let findTagCandidates
(folder: Folder)
(extraFolders: seq<Folder>)
(_srcDoc: Doc)
(input: string)
: seq<string * int> =
let primaryDocs = Folder.docs folder
let primaryIds = primaryDocs |> Seq.map Doc.id |> Set.ofSeq

let allDocs =
Seq.append
primaryDocs
(extraFolders
|> Seq.collect Folder.docs
|> Seq.filter (fun d -> not (Set.contains (Doc.id d) primaryIds)))

let matchingTags =
seq {
for doc in Folder.docs folder do
for doc in allDocs do
for tag in Index.tags (Doc.index doc) do
let tagName = tag.data.name.text

Expand Down Expand Up @@ -775,6 +813,7 @@ let findCompletableAtPos (doc: Doc) (pos: Position) : option<Completable> =

let findCandidatesForCompl
(folder: Folder)
(extraFolders: seq<Folder>)
(srcDoc: Doc)
(pos: Position)
(compl: Completable)
Expand All @@ -785,11 +824,14 @@ let findCandidatesForCompl
| None -> [||]
| Some(WikiDoc input) ->
let destPart = Some(InternName.mkUnchecked (Doc.id srcDoc) input)
let cand = Candidates.findDocCandidates folder srcDoc destPart

let cand =
Candidates.findDocCandidates folder extraFolders srcDoc destPart

cand |> Seq.choose (Completions.wikiDoc config pos compl)
| Some(WikiHeadingInSrcDoc input) ->
let cand = Candidates.findHeadingCandidates folder srcDoc None input
let cand =
Candidates.findHeadingCandidates folder extraFolders srcDoc None input

cand
|> Seq.map snd
Expand All @@ -798,7 +840,7 @@ let findCandidatesForCompl
let destPart = Some(InternName.mkUnchecked (Doc.id srcDoc) destPart)

let cand =
Candidates.findHeadingCandidates folder srcDoc destPart headingPart
Candidates.findHeadingCandidates folder extraFolders srcDoc destPart headingPart

cand
|> Seq.choose (Completions.wikiHeadingInOtherDoc config pos compl)
Expand All @@ -810,13 +852,16 @@ let findCandidatesForCompl
match
InternName.mkChecked (config.CoreMarkdownFileExtensions()) (Doc.id srcDoc) input
with
| None when input.IsEmpty() -> Candidates.findDocCandidates folder srcDoc None
| None when input.IsEmpty() ->
Candidates.findDocCandidates folder extraFolders srcDoc None
| None -> [||]
| Some destPart -> Candidates.findDocCandidates folder srcDoc (Some destPart)
| Some destPart ->
Candidates.findDocCandidates folder extraFolders srcDoc (Some destPart)

cand |> Seq.choose (Completions.inlineDoc pos compl)
| Some(InlineAnchorInSrcDoc input) ->
let cand = Candidates.findHeadingCandidates folder srcDoc None input
let cand =
Candidates.findHeadingCandidates folder extraFolders srcDoc None input

cand
|> Seq.map snd
Expand All @@ -828,18 +873,28 @@ let findCandidatesForCompl
with
| None -> Seq.empty
| Some destPart ->
Candidates.findHeadingCandidates folder srcDoc (Some destPart) anchorPart
Candidates.findHeadingCandidates
folder
extraFolders
srcDoc
(Some destPart)
anchorPart

cand |> Seq.choose (Completions.inlineAnchorInOtherDoc pos compl)
| Some(Tag input) ->
let cand = Candidates.findTagCandidates folder srcDoc input
let cand = Candidates.findTagCandidates folder extraFolders srcDoc input
cand |> Seq.choose (Completions.tag pos compl input)

let findCandidatesInDoc (folder: Folder) (doc: Doc) (pos: Position) : seq<CompletionItem> =
let findCandidatesInDoc
(folder: Folder)
(extraFolders: seq<Folder>)
(doc: Doc)
(pos: Position)
: seq<CompletionItem> =
match findCompletableAtPos doc pos with
| None ->
logger.trace (Log.setMessage "No completion point found")
[||]
| Some compl ->
logger.trace (Log.setMessage "Found completion point" >> Log.addContext "comp" compl)
findCandidatesForCompl folder doc pos compl
findCandidatesForCompl folder extraFolders doc pos compl
20 changes: 20 additions & 0 deletions Marksman/Config.fs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ type Config = {
coreTitleFromHeading: option<bool>
coreIncrementalReferences: option<bool>
coreParanoid: option<bool>
coreExtraFolders: option<array<string>>
complWikiStyle: option<ComplWikiStyle>
complCandidates: option<int>
} with
Expand All @@ -167,6 +168,7 @@ type Config = {
coreTitleFromHeading = Some true
coreIncrementalReferences = Some false
coreParanoid = Some false
coreExtraFolders = None
complWikiStyle = Some TitleSlug
complCandidates = Some 50
}
Expand All @@ -181,6 +183,7 @@ type Config = {
coreTitleFromHeading = None
coreIncrementalReferences = None
coreParanoid = None
coreExtraFolders = None
complWikiStyle = None
complCandidates = None
}
Expand Down Expand Up @@ -230,6 +233,8 @@ type Config = {
|> Option.orElse Config.Default.coreParanoid
|> Option.get

member this.CoreExtraFolders() = this.coreExtraFolders |> Option.defaultValue [||]

member this.ComplWikiStyle() =
match this.complWikiStyle with
| Some x -> x
Expand Down Expand Up @@ -272,6 +277,8 @@ let private configOfTable (table: TomlTable) : LookupResult<Config> =

let! coreParanoid = getFromTableOpt<bool> table [] [ "core"; "paranoid" ]

let! coreExtraFolders = getFromTableOpt<array<string>> table [] [ "core"; "extra_folders" ]

let! complWikiStyle = getFromTableOpt<string> table [] [ "completion"; "wiki"; "style" ]

let complWikiStyle =
Expand Down Expand Up @@ -302,6 +309,7 @@ let private configOfTable (table: TomlTable) : LookupResult<Config> =
coreTitleFromHeading = coreTitleFromHeading
coreIncrementalReferences = coreIncrementalReferences
coreParanoid = coreParanoid
coreExtraFolders = coreExtraFolders
complWikiStyle = complWikiStyle
complCandidates = complCandidates
}
Expand All @@ -328,6 +336,7 @@ module Config =
hi.coreIncrementalReferences
|> Option.orElse low.coreIncrementalReferences
coreParanoid = hi.coreParanoid |> Option.orElse low.coreParanoid
coreExtraFolders = hi.coreExtraFolders |> Option.orElse low.coreExtraFolders
complWikiStyle = hi.complWikiStyle |> Option.orElse low.complWikiStyle
complCandidates = hi.complCandidates |> Option.orElse low.complCandidates
}
Expand Down Expand Up @@ -379,6 +388,17 @@ module Config =

let orDefault configOpt = Option.defaultValue Config.Default configOpt

/// Resolve a raw extra-folder path relative to a config file's directory.
/// Returns None if the resolved path doesn't exist.
let resolveExtraFolderPath (configFileDir: string) (raw: string) : option<string> =
let resolved =
if Path.IsPathRooted(raw) then
raw
else
Path.GetFullPath(Path.Join(configFileDir, raw))

if Directory.Exists(resolved) then Some resolved else None

let defaultMarkdownExtensions =
Config.Default.CoreMarkdownFileExtensions() |> Seq.ofArray

Expand Down
28 changes: 18 additions & 10 deletions Marksman/Diag.fs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ let checkNonBreakingWhitespace (doc: Doc) =

[ NonBreakableWhitespace(whitespaceRange) ])

let checkLink (folder: Folder) (doc: Doc) (linkEl: Element) : seq<Entry> =
let checkLink
(folder: Folder)
(extraFolders: seq<Folder>)
(doc: Doc)
(linkEl: Element)
: seq<Entry> =
let exts = Folder.configuredMarkdownExts folder

let ref =
Expand All @@ -58,7 +63,8 @@ let checkLink (folder: Folder) (doc: Doc) (linkEl: Element) : seq<Entry> =
match ref with
| None -> []
| Some ref ->
let refs = Dest.tryResolveElement folder doc linkEl |> Array.ofSeq
let refs =
Dest.tryResolveElement folder extraFolders doc linkEl |> Array.ofSeq

if Folder.isSingleFile folder && Syms.Ref.isCross ref then
[]
Expand All @@ -83,16 +89,16 @@ let checkLink (folder: Folder) (doc: Doc) (linkEl: Element) : seq<Entry> =
else
[ AmbiguousLink(linkEl, ref, refs) ]

let checkLinks (folder: Folder) (doc: Doc) : seq<Entry> =
let checkLinks (folder: Folder) (extraFolders: seq<Folder>) (doc: Doc) : seq<Entry> =
let links = Doc.index >> Index.links <| doc
links |> Seq.collect (checkLink folder doc)
links |> Seq.collect (checkLink folder extraFolders doc)

let checkFolder (folder: Folder) : seq<DocId * list<Entry>> =
let checkFolder (folder: Folder) (extraFolders: seq<Folder>) : seq<DocId * list<Entry>> =
seq {
for doc in Folder.docs folder do
let docDiag =
seq {
yield! checkLinks folder doc
yield! checkLinks folder extraFolders doc
yield! checkNonBreakingWhitespace doc
}
|> List.ofSeq
Expand Down Expand Up @@ -188,8 +194,8 @@ let diagToLsp (diag: Entry) : Lsp.Diagnostic =
type FolderDiag = array<DocId * array<Lsp.Diagnostic>>

module FolderDiag =
let mk (folder: Folder) : FolderDiag =
checkFolder folder
let mk (folder: Folder) (extraFolders: seq<Folder>) : FolderDiag =
checkFolder folder extraFolders
|> Seq.map (fun (uri, diags) ->
let lspDiags = List.map diagToLsp diags |> Array.ofList

Expand All @@ -200,8 +206,10 @@ type WorkspaceDiag = Map<FolderId, FolderDiag>

module WorkspaceDiag =
let mk (ws: Workspace) : WorkspaceDiag =
Workspace.folders ws
|> Seq.map (fun folder -> (Folder.id folder), FolderDiag.mk folder)
Workspace.primaryFolders ws
|> Seq.map (fun folder ->
let extraFolders = Workspace.extraFoldersFor folder ws
(Folder.id folder), FolderDiag.mk folder extraFolders)
|> Map.ofSeq

let empty = Map.empty
Loading