Skip to content
Merged
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: 6 additions & 3 deletions Marksman/CodeActions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ open Marksman.Refs
open Marksman.Toc
open Marksman.Structure
open Marksman.Syms
open Marksman.Config

let private logger = LogProvider.getLoggerByName "CodeActions"

Expand All @@ -35,8 +36,8 @@ let createFile newFileUri : WorkspaceEdit =

{ Changes = None; DocumentChanges = Some documentChanges }

let tableOfContentsInner (doc: Doc) : DocumentAction option =
match TableOfContents.mk (Doc.index doc) with
let tableOfContentsInner (includeLevels: array<int>) (doc: Doc) : DocumentAction option =
match TableOfContents.mk includeLevels (Doc.index doc) with
| Some toc ->
let rendered = TableOfContents.render toc
let existingRange = TableOfContents.detect (Doc.text doc)
Expand Down Expand Up @@ -111,9 +112,11 @@ let tableOfContentsInner (doc: Doc) : DocumentAction option =
let tableOfContents
(_range: Range)
(_context: CodeActionContext)
(config: Config)
(doc: Doc)
: DocumentAction option =
tableOfContentsInner doc
let includeLevels = config.CaTocInclude()
tableOfContentsInner includeLevels doc

let createMissingFile
(range: Range)
Expand Down
34 changes: 34 additions & 0 deletions Marksman/Config.fs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,26 @@ let private lookupAsOpt =
let private getFromTableOpt<'R> table revSeenPath remPath : Result<option<'R>, LookupError> =
getFromTable table revSeenPath remPath |> lookupAsOpt

let private nonNegativeIntArrayFromTableOpt
(table: TomlTable)
(revSeenPath: list<string>)
(path: list<string>)
: LookupResult<option<array<int>>> =
monad {
let! raw = getFromTableOpt<array<int64>> table revSeenPath path

match raw with
| None -> return None
| Some arr ->
let values = arr |> Array.map int

if values |> Array.exists (fun v -> v < 0) then
return! Error(WrongValue(path, arr, "expected non-negative integers"))
else
return Some values
}


type ComplWikiStyle =
/// Document title's slug, e.g. "A B C" -> "a-b-c"
| TitleSlug
Expand Down Expand Up @@ -125,6 +145,7 @@ module TextSync =
/// without lenses manageable.
type Config = {
caTocEnable: option<bool>
caTocInclude: option<array<int>>
caCreateMissingFileEnable: option<bool>
coreMarkdownFileExtensions: option<array<string>>
coreMarkdownGlfmHeadingIdsEnable: option<bool>
Expand All @@ -138,6 +159,7 @@ type Config = {

static member Default = {
caTocEnable = Some true
caTocInclude = Some [| 1; 2; 3; 4; 5; 6 |]
caCreateMissingFileEnable = Some true
coreMarkdownFileExtensions = Some [| "md"; "markdown" |]
coreMarkdownGlfmHeadingIdsEnable = Some true
Expand All @@ -151,6 +173,7 @@ type Config = {

static member Empty = {
caTocEnable = None
caTocInclude = None
caCreateMissingFileEnable = None
coreMarkdownFileExtensions = None
coreMarkdownGlfmHeadingIdsEnable = None
Expand All @@ -167,6 +190,11 @@ type Config = {
|> Option.orElse Config.Default.caTocEnable
|> Option.get

member this.CaTocInclude() =
this.caTocInclude
|> Option.orElse Config.Default.caTocInclude
|> Option.get

member this.CaCreateMissingFileEnable() =
this.caCreateMissingFileEnable
|> Option.orElse Config.Default.caCreateMissingFileEnable
Expand Down Expand Up @@ -220,6 +248,10 @@ let private configOfTable (table: TomlTable) : LookupResult<Config> =
monad {
let! caTocEnable = getFromTableOpt<bool> table [] [ "code_action"; "toc"; "enable" ]

let! caTocInclude =
nonNegativeIntArrayFromTableOpt table [] [ "code_action"; "toc"; "include" ]


let! caCreateMissingFileEnable =
getFromTableOpt<bool> table [] [ "code_action"; "create_missing_file"; "enable" ]

Expand Down Expand Up @@ -262,6 +294,7 @@ let private configOfTable (table: TomlTable) : LookupResult<Config> =

{
caTocEnable = caTocEnable
caTocInclude = caTocInclude
caCreateMissingFileEnable = caCreateMissingFileEnable
coreMarkdownFileExtensions = coreMarkdownFileExtensions
coreMarkdownGlfmHeadingIdsEnable = coreMarkdownGlfmHeadingIdsEnable
Expand All @@ -279,6 +312,7 @@ module Config =

let merge hi low = {
caTocEnable = hi.caTocEnable |> Option.orElse low.caTocEnable
caTocInclude = hi.caTocInclude |> Option.orElse low.caTocInclude
caCreateMissingFileEnable =
hi.caCreateMissingFileEnable
|> Option.orElse low.caCreateMissingFileEnable
Expand Down
2 changes: 1 addition & 1 deletion Marksman/Server.fs
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ type MarksmanServer(client: MarksmanClient) =

let tocAction =
if config.CaTocEnable() then
CodeActions.tableOfContents opts.Range opts.Context doc
CodeActions.tableOfContents opts.Range opts.Context config doc
|> Option.toArray
|> Array.map (fun ca ->
let wsEdit =
Expand Down
9 changes: 7 additions & 2 deletions Marksman/Toc.fs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,13 @@ module TableOfContents =

let logger = LogProvider.getLoggerByName "TocAgent"

let mk (index: Marksman.Index.Index) : TableOfContents option =
let headings = index.headings |> Array.map (fun x -> x.data)
let mk (includeLevels: int array) (index: Marksman.Index.Index) : TableOfContents option =
let allowedLevels = includeLevels |> Set.ofArray

let headings =
index.headings
|> Array.map (fun x -> x.data)
|> Array.filter (fun h -> Array.contains h.level includeLevels)

if Array.isEmpty index.headings then
None
Expand Down
25 changes: 25 additions & 0 deletions Tests/ConfigTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,20 @@ toc.enable = false

Assert.Equal(Some expected, actual)

[<Fact>]
let testParse_tocInclude () =
let content =
"""
[code_action]
toc.include = [2, 3, 4]
"""

let actual = Config.tryParse content

let expected = { Config.Empty with caTocInclude = Some [| 2; 3; 4 |] }

Assert.Equal(Some expected, actual)


[<Fact>]
let testParse_3 () =
Expand Down Expand Up @@ -205,6 +219,17 @@ markdown.glfm_heading_ids.enable = -1
let actual = Config.tryParse content
Assert.Equal(None, actual)

[<Fact>]
let testParse_broken_tocInclude () =
let content =
"""
[code_action]
toc.include = [1, -1]
"""

let actual = Config.tryParse content
Assert.Equal(None, actual)

[<Fact>]
let testDefault () =
let content =
Expand Down
44 changes: 35 additions & 9 deletions Tests/TocTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ open Xunit
open Marksman.Helpers
open Marksman.Toc
open Marksman.Doc
open Marksman.Config

open type System.Environment

// the option is guaranteed to be Some by construction, so we can use Option.get safely
let includeAllLevels = Config.Default.caTocInclude |> Option.get

module DetectToc =
[<Fact>]
let detectToc_1 () =
Expand Down Expand Up @@ -56,7 +60,8 @@ module CreateToc =
let createToc () =
let doc = FakeDoc.Mk [| "# T1"; "## T2" |]

let titles = TableOfContents.mk (Doc.index doc) |> Option.get
let titles =
TableOfContents.mk includeAllLevels (Doc.index doc) |> Option.get

let expected = { entries = [| Entry.Mk(1, "T1"); Entry.Mk(2, "T2") |] }

Expand All @@ -75,7 +80,8 @@ module CreateToc =
"## T2"
|]

let titles = TableOfContents.mk (Doc.index doc) |> Option.get
let titles =
TableOfContents.mk includeAllLevels (Doc.index doc) |> Option.get

let expected = { entries = [| Entry.Mk(1, "T1"); Entry.Mk(2, "T2") |] }

Expand Down Expand Up @@ -148,7 +154,7 @@ module RenderToc =
let doc = FakeDoc.Mk [| "# T1"; "## T2"; "### T3"; "## T4"; "### T5" |]

let titles =
TableOfContents.mk (Doc.index doc)
TableOfContents.mk includeAllLevels (Doc.index doc)
|> Option.get
|> TableOfContents.render

Expand All @@ -166,6 +172,21 @@ module RenderToc =

Assert.Equal(expected, titles)

[<Fact>]
let createToc_filteredLevels () =
let doc = FakeDoc.Mk [| "# T1"; "## T2"; "### T3"; "#### T4" |]

let titles =
TableOfContents.mk [| 2; 3 |] (Doc.index doc)
|> Option.get
|> TableOfContents.render

let expectedLines = [| StartMarker; "- [T2](#t2)"; " - [T3](#t3)"; EndMarker |]

let expected = String.concat NewLine expectedLines

Assert.Equal(expected, titles)

module DocumentEdit =
[<Fact>]
let insert_afterYaml () =
Expand All @@ -185,7 +206,8 @@ module DocumentEdit =

let doc = FakeDoc.Mk text

let action = CodeActions.tableOfContentsInner doc |> Option.get
let action =
CodeActions.tableOfContentsInner includeAllLevels doc |> Option.get

let modifiedText = applyDocumentAction doc action

Expand Down Expand Up @@ -226,7 +248,8 @@ module DocumentEdit =

let doc = FakeDoc.Mk text

let action = CodeActions.tableOfContentsInner doc |> Option.get
let action =
CodeActions.tableOfContentsInner includeAllLevels doc |> Option.get

let modifiedText = applyDocumentAction doc action

Expand Down Expand Up @@ -266,7 +289,8 @@ module DocumentEdit =

let doc = FakeDoc.Mk text

let action = CodeActions.tableOfContentsInner doc |> Option.get
let action =
CodeActions.tableOfContentsInner includeAllLevels doc |> Option.get

let modifiedText = applyDocumentAction doc action

Expand Down Expand Up @@ -304,7 +328,9 @@ module DocumentEdit =
|# T2"
)

let action = CodeActions.tableOfContentsInner doc |> Option.get
let action =
CodeActions.tableOfContentsInner includeAllLevels doc |> Option.get

let modifiedText = applyDocumentAction doc action

let expected =
Expand Down Expand Up @@ -332,7 +358,7 @@ module DocumentEdit =

let doc = FakeDoc.Mk text

let action = CodeActions.tableOfContentsInner doc
let action = CodeActions.tableOfContentsInner includeAllLevels doc

Assert.Equal(None, action)

Expand All @@ -350,6 +376,6 @@ module DocumentEdit =

let doc = FakeDoc.Mk text

let action = CodeActions.tableOfContentsInner doc
let action = CodeActions.tableOfContentsInner includeAllLevels doc

Assert.Equal(None, action)
2 changes: 2 additions & 0 deletions Tests/default.marksman.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ paranoid = false
[code_action]
# Enable/disable "Table of Contents" code action
toc.enable = true
# Heading levels to include when generating a Table of Contents
toc.include = [1, 2, 3, 4, 5, 6]

# Enable/disable "Create missing linked file" code action
create_missing_file.enable = true
Expand Down