Skip to content

Commit

Permalink
feat: enable optional toc heading
Browse files Browse the repository at this point in the history
  • Loading branch information
jar-b committed Dec 31, 2021
1 parent bf63587 commit c96b59c
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 15 deletions.
5 changes: 3 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Changelog


## Unreleased
## v0.4.0

### Added
- Version (`-version`) CLI flag
- Config struct to store insert settings
- Flags/configuration to enable optional TOC headings (`-with-toc-heading`, `-toc-heading`)

### Changed
- `Insert` function signature now accepts `*Config` type
Expand All @@ -24,7 +25,7 @@
## v0.2.1

### Fixed
- Ignore lines matching header regex when inside code blocks
- Ignore lines matching heading regex when inside code blocks


## v0.2.0
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ Flags:
force overwrite of existing contents (optional)
-out string
output file (optional, defaults to adding to source file)
-toc-heading string
contents heading (-with-toc-heading must be specified) (default "Table of Contents")
-version
display version
-with-toc-heading
include a heading with the generated contents (optional)
```

### Examples
Expand All @@ -56,6 +60,9 @@ mdtoc -force mydoc.md

# redirect output to new document
mdtoc -out other.md mydoc.md

# with custom heading
mdtoc -with-toc-heading -toc-heading "document stuff" mydoc.md
```

## Library
Expand Down
12 changes: 9 additions & 3 deletions cmd/mdtoc/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import (
)

var (
force, dryRun, version bool
out string
force, dryRun, withTocHeading, version bool

out string
tocHeading string = mdtoc.DefaultTocHeading
)

func init() {
Expand All @@ -26,6 +28,8 @@ func main() {
flag.BoolVar(&force, "force", false, "force overwrite of existing contents (optional)")
flag.BoolVar(&dryRun, "dry-run", false, "print generated contents, but do not write to file (optional)")
flag.StringVar(&out, "out", "", "output file (optional, defaults to adding to source file)")
flag.BoolVar(&withTocHeading, "with-toc-heading", false, "include a heading with the generated contents (optional)")
flag.StringVar(&tocHeading, "toc-heading", tocHeading, "contents heading (-with-toc-heading must be specified)")
flag.BoolVar(&version, "version", false, "display version")
flag.Parse()

Expand Down Expand Up @@ -54,7 +58,9 @@ func main() {
}

cfg := mdtoc.Config{
Force: force,
Force: force,
WithTocHeading: withTocHeading,
TocHeading: tocHeading,
}
withToc, err := mdtoc.Insert(b, &cfg)
if err != nil {
Expand Down
13 changes: 13 additions & 0 deletions testdata/custom_heading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Title
An example document where a custom table of contents heading will be included.

## Heading 1

### A sub-bullet

### Another

## Heading 2

## Heading 3

22 changes: 22 additions & 0 deletions testdata/custom_heading_toc.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Title
An example document where a custom table of contents heading will be included.

<!--mdtoc: begin-->
## Contents <!--mdtoc: ignore-->

* [Heading 1](#heading-1)
* [A sub-bullet](#a-sub-bullet)
* [Another](#another)
* [Heading 2](#heading-2)
* [Heading 3](#heading-3)
<!--mdtoc: end-->
## Heading 1

### A sub-bullet

### Another

## Heading 2

## Heading 3

2 changes: 1 addition & 1 deletion testdata/special.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Example Document
An example document with headers including special/uncommon characters to test generating links.
An example document with headings including special/uncommon characters to test generating links.

## With/Slash

Expand Down
2 changes: 1 addition & 1 deletion testdata/special_toc.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Example Document
An example document with headers including special/uncommon characters to test generating links.
An example document with headings including special/uncommon characters to test generating links.

<!--mdtoc: begin-->
* [With/Slash](#withslash)
Expand Down
25 changes: 18 additions & 7 deletions toc.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@ var (
// DefaultConfig defines the default configuration settings
//
// These field values will align with the default flag values from the CLI
// - Force: false
DefaultConfig = &Config{
Force: false,
Force: false,
WithTocHeading: false,
TocHeading: DefaultTocHeading,
}

// DefaultTocHeading is the default heading applied when enabled
DefaultTocHeading = "Table of Contents"

// headingRegex is the expression which will match non-title heading lines
headingRegex = regexp.MustCompile("^([#]{2,})[ ]+(.+)")
)
Expand All @@ -47,12 +51,15 @@ type Item struct {

// Toc stores table of contents metadata
type Toc struct {
Items []Item
Items []Item
Config *Config
}

// Config stores settings to be used when inserting a new Toc
type Config struct {
Force bool
Force bool
WithTocHeading bool
TocHeading string
}

// Bytes returns a markdown formatted slice of bytes
Expand All @@ -61,6 +68,9 @@ func (t *Toc) Bytes() []byte {
w := bytes.NewBuffer(buf)

w.WriteString(fmt.Sprintf("%s\n", tocBegin))
if t.Config != nil && t.Config.WithTocHeading {
w.WriteString(fmt.Sprintf("## %s %s\n\n", t.Config.TocHeading, tocIgnore))
}
for _, item := range t.Items {
w.WriteString(fmt.Sprintf("%s* [%s](#%s)\n", strings.Repeat(" ", item.Indent*2), item.Text, item.Link))
}
Expand All @@ -80,6 +90,7 @@ func Insert(b []byte, cfg *Config) ([]byte, error) {
if err != nil {
return b, err
}
toc.Config = cfg

var new []byte
buf := bytes.NewBuffer(new)
Expand Down Expand Up @@ -129,7 +140,7 @@ func Insert(b []byte, cfg *Config) ([]byte, error) {

// New extacts table of contents attributes from an existing document
func New(b []byte) (*Toc, error) {
toc := Toc{}
toc := Toc{Config: DefaultConfig}

var inCodeBlock bool

Expand Down Expand Up @@ -181,9 +192,9 @@ func New(b []byte) (*Toc, error) {
return &toc, nil
}

// textToLink returns the header link formatted version of a string
// textToLink returns the heading link formatted version of a string
//
// ex. `Header One Two` = `header-one-two`
// ex. `Heading One Two` = `heading-one-two`
func textToLink(s string) string {
// TODO: find a more comprehensive/formally documented list of these
rep := strings.NewReplacer(" ", "-", "/", "", ",", "", ".", "", "+", "", ":", "", ";", "", "`", "", `"`, "", `'`, "", "{", "", "}", "")
Expand Down
7 changes: 6 additions & 1 deletion toc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func TestInsert(t *testing.T) {
codeblockToc, _ := os.ReadFile("testdata/codeblock_toc.md")
ignore, _ := os.ReadFile("testdata/ignore.md")
ignoreToc, _ := os.ReadFile("testdata/ignore_toc.md")
customHeading, _ := os.ReadFile("testdata/custom_heading.md")
customHeadingToc, _ := os.ReadFile("testdata/custom_heading_toc.md")

tt := []struct {
name string
Expand All @@ -33,6 +35,7 @@ func TestInsert(t *testing.T) {
{"ignore", ignore, DefaultConfig, ignoreToc, nil},
{"existing without force", basicToc, DefaultConfig, nil, ErrExistingToc},
{"existing with force", basicToc, &Config{Force: true}, basicToc, nil},
{"custom heading", customHeading, &Config{WithTocHeading: true, TocHeading: "Contents"}, customHeadingToc, nil},
}

for _, tc := range tt {
Expand Down Expand Up @@ -61,7 +64,9 @@ func TestNew(t *testing.T) {
Items: []Item{
{Indent: 0, Text: "Heading 1", Link: "heading-1"},
{Indent: 1, Text: "Heading 2", Link: "heading-2"},
}},
},
Config: DefaultConfig,
},
},
}

Expand Down

0 comments on commit c96b59c

Please sign in to comment.