anchor

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 24, 2023 License: MIT Imports: 8 Imported by: 13

README

goldmark-anchor

Go Reference CI codecov

goldmark-anchor is an extension for the goldmark Markdown parser that adds support for anchors next to all headers.

Installation

go get go.abhg.dev/goldmark/anchor@latest

Usage

To use goldmark-anchor, import the anchor package.

import "go.abhg.dev/goldmark/anchor"

Then include the anchor.Extender in the list of extensions when constructing your goldmark.Markdown.

goldmark.New(
  goldmark.WithParserOptions(
    parser.WithAutoHeadingID(), // read note
  ),
  goldmark.WithExtensions(
    // ...
    &anchor.Extender{},
  ),
).Convert(src, out)

This will begin adding '¶' anchors next to all headers in your Markdown files.

NOTE: The example above adds the parser.WithAutoHeadingID option. Without this, or a custom implementation of parser.IDs, Goldmark will not add id attributes to headers. If a header does not have an id, then goldmark-anchor will not generate an anchor for it.

Changing anchor text

Change the anchor text by setting the Texter field of the Extender to an anchor.Text value.

&anchor.Extender{
  Texter: anchor.Text("#"),
}
Dynamic anchor text

You can dynamically calculate anchor text by supplying a custom implementation of Texter to the Extender.

For example, the following Texter repeats '#' matching the header level, providing anchors similar to Markdown #-style headers.

type customTexter struct{}

func (*customTexter) AnchorText(h *anchor.HeaderInfo) []byte {
  return bytes.Repeat([]byte{'#'}, h.Level)
}

// Elsewhere:

&anchor.Extender{
  Texter: &customTexter{},
}
Skipping headers

To skip headers, supply a custom Texter that returns an empty output for the AnchorText method.

The following Texter will not render anchors for level 1 headers.

type customTexter struct{}

func (*customTexter) AnchorText(h *anchor.HeaderInfo) []byte {
  if h.Level == 1 {
    return nil
  }
  return []byte("#")
}
Changing anchor attributes

Change the anchor attributes by setting the Attributer field of the Extender.

&anchor.Extender{
  Attributer: anchor.Attributes{
    "class": "permalink",
  },
}

By default, goldmark-anchor will add class="anchor" to all anchors. Set Attributer to anchor.Attributes{} to disable this.

&anchor.Extender{
  Attributer: anchor.Attributes{},
}
Changing anchor positioning

Anchors can appear either at the start of the header before the header text, or at the end after the header text.

<!-- Before -->
<h1><a href="#">#</a> Foo</h1>

<!-- After -->
<h1>Foo <a href="#">¶</a></h1>

You can choose the placement by setting the Position field of Extender.

&anchor.Extender{
  Position: anchor.Before, // or anchor.After
}

By default, goldmark-anchor will place anchors after the header text.

FAQ

Why are no anchors being generated?

By default, Goldmark does not generate IDs for headings. Since goldmark-anchor generates anchors only for headings with IDs, this can result in no anchors being generated

You must enable heading ID generation using one of the following methods:

Alternatively, if your document specifies heading attributes manually, enable the parser.WithHeadingAttribute option and manually specify heading IDs next to each heading.

License

This software is made available under the MIT license.

Documentation

Overview

Package anchor is an extension for the Goldmark Markdown parser adding support for anchors for all headers.

Example
package main

import (
	"log"
	"os"

	"github.com/yuin/goldmark"
	"github.com/yuin/goldmark/parser"
	"go.abhg.dev/goldmark/anchor"
)

func main() {
	md := goldmark.New(
		// We need to enable automatic generation of heading IDs.
		// Otherwise, none of the headings will have IDs
		// which will leave goldmark-anchor
		// nothing to generate anchors for.
		goldmark.WithParserOptions(
			parser.WithAutoHeadingID(),
		),
		goldmark.WithExtensions(
			&anchor.Extender{},
		),
	)

	src := []byte("# Foo")
	if err := md.Convert(src, os.Stdout); err != nil {
		log.Fatal(err)
	}

}
Output:

<h1 id="foo">Foo <a class="anchor" href="#foo">¶</a></h1>

Index

Examples

Constants

This section is empty.

Variables

View Source
var Kind = ast.NewNodeKind("Anchor")

Kind is the NodeKind used by anchor nodes.

Functions

This section is empty.

Types

type Attributer

type Attributer interface {
	// AnchorAttributes returns the attributes
	// that should be attached to the anchor node
	// for the given header.
	//
	// If AnchorAttributes returns an empty map or nil,
	// no attributes will be added.
	AnchorAttributes(*HeaderInfo) map[string]string
}

Attributer determines attributes that will be attached to an anchor node.

By default, we will add 'class="anchor"' to all nodes.

type Attributes

type Attributes map[string]string

Attributes is an Attributer that uses a constant set of attributes for all anchor nodes.

Pass this into Extender or Transformer to specify custom attributes.

anchor.Extender{
	Attributer: Attributes{"class": "permalink"},
}

func (Attributes) AnchorAttributes

func (as Attributes) AnchorAttributes(*HeaderInfo) map[string]string

AnchorAttributes reports the attributes associated with this object for all headers.

type Extender

type Extender struct {
	// Texter determines the anchor text.
	//
	// Defaults to '¶' if unspecified.
	Texter Texter

	// Position specifies where the anchor will be placed in a header.
	//
	// Defaults to After.
	Position Position

	// Attributer determines the attributes
	// that will be associated with the anchor link.
	//
	// Defaults to adding a 'class="anchor"' attribute.
	Attributer Attributer
}

Extender adds support for anchors to a Goldmark Markdown parser.

Use it by installing it into the goldmark.Markdown object upon creation. For example:

goldmark.New(
	// ...
	goldmark.WithExtensions(
		// ...
		&anchor.Extender{},
	),
)

func (*Extender) Extend

func (e *Extender) Extend(md goldmark.Markdown)

Extend extends the provided Goldmark Markdown.

type HeaderInfo

type HeaderInfo struct {
	// Level of the header.
	Level int

	// Identifier for the header on the page.
	// This will typically become part of the URL fragment.
	ID []byte
}

HeaderInfo holds information about a header for which an anchor is being considered.

type Node

type Node struct {
	ast.BaseInline

	// ID of the header this anchor is for.
	ID []byte

	// Level of the header that this anchor is for.
	Level int

	// Value is the text inside the anchor.
	// Typically this is a fixed string
	// like '¶' or '#'.
	Value []byte
}

Node is an anchor node in the Markdown AST.

func (*Node) Dump

func (n *Node) Dump(src []byte, level int)

Dump dumps this node to stdout for debugging.

func (*Node) Kind

func (*Node) Kind() ast.NodeKind

Kind reports that this is a Anchor node.

type Position

type Position int

Position specifies where inside a heading we should place an anchor Node.

const (
	// After places the anchor node after the heading text.
	//
	// This is the default.
	After Position = iota

	// Before places the anchor node before the heading text.
	Before
)

func (Position) String

func (i Position) String() string

type Renderer

type Renderer struct {
	// Position specifies where in the header text
	// the anchor is being added.
	Position Position
}

Renderer renders anchor [Node]s.

func (*Renderer) RegisterFuncs

func (r *Renderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)

RegisterFuncs registers functions against the provided goldmark Registerer.

func (*Renderer) RenderNode

func (r *Renderer) RenderNode(w util.BufWriter, src []byte, node ast.Node, entering bool) (ast.WalkStatus, error)

RenderNode renders an anchor node. Goldmark will invoke this method when it encounters a Node.

type Texter

type Texter interface {
	// AnchorText returns the anchor text
	// that should be used for the provided header info.
	//
	// If AnchorText returns an empty slice or nil,
	// an anchor will not be generated for this header.
	AnchorText(*HeaderInfo) []byte
}

Texter determines the anchor text.

This is the clickable text displayed next to the header which tells readers that they can use it as an anchor to the header.

By default, we will use the string '¶'.

func Text

func Text(s string) Texter

Text builds a Texter that uses a constant string as the anchor text.

Pass this into Extender or Transformer to specify a custom anchor text.

anchor.Extender{
	Texter: Text("#"),
}

type Transformer

type Transformer struct {
	// Texter determines the anchor text.
	//
	// Defaults to '¶' for all headers if unset.
	Texter Texter

	// Position specifies where the anchor will be placed in a header.
	//
	// Defaults to After.
	Position Position

	// Attributer determines the attributes
	// that will be associated with the anchor link.
	//
	// Defaults to adding a 'class="anchor"' attribute
	// for all headers if unset.
	Attributer Attributer
}

Transformer transforms a Goldmark Markdown AST, adding anchor Node objects for headers across the document.

func (*Transformer) Transform

func (t *Transformer) Transform(doc *ast.Document, reader text.Reader, pctx parser.Context)

Transform traverses and transforms the provided Markdown document.

This method is typically called by Goldmark and should not need to be invoked directly.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL