Skip to content
quarry Artifact [fb9a341d91]
Login

Artifact [fb9a341d91]

Artifact fb9a341d91e44a2827e04aba981491133bf79dae0fcb58f0533ddcc61f6e7f98:


package markup

import (
	gast "github.com/yuin/goldmark/ast"
	east "github.com/yuin/goldmark/extension/ast"
	"github.com/yuin/goldmark/parser"
	"github.com/yuin/goldmark/text"
)

// The rendering hooks the stylesheet keys on: task-list state, table
// column hints and GitHub-style alerts. All of them are computed here,
// at render time, and reach the page as classes the sanitizer admits by
// exact name.

// taskLists marks each task item with its state and a list made only of
// task items with md-tasks, so the stylesheet can drop the bullet that
// would otherwise sit beside the checkbox. The TaskList extension emits
// the checkbox but no class on either.
type taskLists struct{}

func (taskLists) Transform(doc *gast.Document, _ text.Reader, _ parser.Context) {
	gast.Walk(doc, func(n gast.Node, entering bool) (gast.WalkStatus, error) {
		list, ok := n.(*gast.List)
		if !ok || !entering {
			return gast.WalkContinue, nil
		}
		all := list.ChildCount() > 0
		for li := list.FirstChild(); li != nil; li = li.NextSibling() {
			box := taskBox(li)
			if box == nil {
				all = false
				continue
			}
			state := "unchecked"
			if box.IsChecked {
				state = "checked"
			}
			li.SetAttributeString("class", []byte(state))
		}
		if all {
			list.SetAttributeString("class", []byte("md-tasks"))
		}
		return gast.WalkContinue, nil
	})
}

// taskBox is the checkbox opening a list item, or nil.
func taskBox(li gast.Node) *east.TaskCheckBox {
	if fc := li.FirstChild(); fc != nil {
		if b, ok := fc.FirstChild().(*east.TaskCheckBox); ok {
			return b
		}
	}
	return nil
}