Documentation
¶
Overview ¶
Package garden turns a folder of markdown notes into a static knowledge garden: a site where links open notes in stacked panes, side by side, and every note lists the notes that link to it.
The package can be used in two ways. Build does everything in one call, the same as the garden command:
cfg, err := garden.LoadConfig("garden.yaml")
if err != nil { ... }
_, stats, err := garden.Build(ctx, cfg)
Or the steps can be separated, so a larger system can work with the link graph before (or instead of) writing a site. Load reads and renders every note in parallel and computes backlinks, all in memory:
g, err := garden.Load(ctx, cfg)
for _, n := range g.Notes {
fmt.Println(n.ID, len(n.Links), len(g.Backlinks(n.ID)))
}
stats, err := g.Write(ctx, "dist")
Notes are read from Config.FS when it is set (an embed.FS, an fstest.MapFS, a zip archive), otherwise from the Config.Vault directory.
Math ¶
$inline$, $$display$$, \(inline\), \[display\] and \begin{env} blocks are set aside before markdown parsing, so the parser can't alter them, and rendered in the browser with a bundled copy of KaTeX. A dollar sign is only treated as math when it pairs up the way Pandoc requires, so prices, shell variables and code are left alone.
Output ¶
Garden.Write produces plain static files: an app shell (index.html, garden.css, garden.js), the note data split into shards that the browser loads on demand, optional per-note HTML pages, and the assets notes reference. Files whose content hasn't changed are not rewritten.
Index ¶
- func Build(ctx context.Context, cfg *Config) (*Garden, *Stats, error)
- func DefaultTheme() fs.FS
- func Styles() []string
- type Backlink
- type Config
- type Garden
- func (g *Garden) Assets() []string
- func (g *Garden) Backlinks(id string) []Backlink
- func (g *Garden) Note(id string) (*Note, bool)
- func (g *Garden) Report() string
- func (g *Garden) Resolve(from, dest string) (id, anchor string, ok bool)
- func (g *Garden) Write(ctx context.Context, out string) (*Stats, error)
- type Link
- type NavNode
- type Note
- type Phase
- type Stats
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Build ¶
Build loads the vault and writes the site to cfg.Out.
Example ¶
Build a site from a garden.yaml, as the garden command does.
package main
import (
"context"
"fmt"
"log"
"github.com/zoravur/garden"
)
func main() {
cfg, err := garden.LoadConfig("garden.yaml")
if err != nil {
log.Fatal(err)
}
_, stats, err := garden.Build(context.Background(), cfg)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d notes written to %s\n", stats.Notes, cfg.Out)
}
Output:
func DefaultTheme ¶
DefaultTheme returns the built-in theme files: index.html (the app shell), note.html (static note pages), garden.css and garden.js.
Types ¶
type Backlink ¶
type Backlink struct {
Source string // ID of the linking note
Refs []Link // the links, with Target set to the linked note
}
Backlink is a note that links to another, with each place it does so.
type Config ¶
type Config struct {
// Title and Description are used for the site's <title> and metadata.
Title string `yaml:"title"`
Description string `yaml:"description"`
// Vault is the folder of markdown notes. Ignored when FS is set.
Vault string `yaml:"vault"`
// FS, when set, is read instead of the Vault directory. Paths in it are
// vault-relative, e.g. "ideas/backlinks.md".
FS fs.FS `yaml:"-"`
// Out is the folder Write and Build write the site to. Default "dist".
Out string `yaml:"out"`
// Home is the ID of the note opened first (its path without ".md").
// When blank, a note at the vault root named index.md is used if there
// is one; otherwise an index page is generated: the most-linked notes
// and a contents tree. When set, the note must exist.
Home string `yaml:"home"`
// Exclude lists vault-relative patterns to skip. "dir/**" skips a whole
// folder; other patterns use path.Match against the full path and the
// file name.
Exclude []string `yaml:"exclude"`
// folders; "mkdocs:path/to/mkdocs.yml" reads an MkDocs nav.
Nav string `yaml:"nav"`
// PublicOnly publishes only notes whose frontmatter has `public: true`.
// Links to other notes render as plain text, without their names.
PublicOnly bool `yaml:"public_only"`
// SitePrefix is an absolute URL prefix (e.g. "/blue-book/") to strip
// from links and raw HTML, for vaults written for a site in a subpath.
SitePrefix string `yaml:"site_prefix"`
// HeadingShift is added to every heading level. 1 turns "# X" into <h2>,
// matching MkDocs' toc baselevel: 2.
HeadingShift int `yaml:"heading_shift"`
// SourceURL, if set, adds a "Source" link to each note: SourceURL + the
// note's vault path.
SourceURL string `yaml:"source_url"`
// StaticPages also writes notes/<id>.html, a plain page per note for
// search engines and readers without JavaScript. Default true.
StaticPages *bool `yaml:"static_pages"`
// ShardKB is the target size of each note data file. Default 512.
ShardKB int `yaml:"shard_kb"`
// MaxAssetMB skips copying assets larger than this (0 means no limit).
// References to skipped assets point at AssetFallbackURL instead.
MaxAssetMB float64 `yaml:"max_asset_mb"`
AssetFallbackURL string `yaml:"asset_fallback_url"`
// Style picks a built-in look layered over the default theme: "" (the
// default) or "wiki" (light, blue links, red links for missing or
// unpublished notes). See Styles.
Style string `yaml:"style"`
// CSS lists extra stylesheets, applied after the theme and Style, so
// they can override any rule or CSS variable.
CSS []string `yaml:"css"`
// Theme is a folder whose garden.css, garden.js, index.html or note.html
// replace the built-in ones. Default "theme" next to the config file,
// used only if it exists.
Theme string `yaml:"theme"`
// Workers is how many notes are processed at once. Default: CPU count.
Workers int `yaml:"workers"`
// contains filtered or unexported fields
}
Config describes a garden: where its notes live and how to publish them. It is usually read from a garden.yaml file with LoadConfig, but can be built in code. Relative paths in a config file resolve against the file's directory; relative paths set in code resolve against the working directory.
func LoadConfig ¶
LoadConfig reads a garden.yaml file.
type Garden ¶
type Garden struct {
Config *Config // normalized copy of the config it was loaded with
Notes []*Note // published notes, sorted by ID
// Broken maps link targets that match nothing to the IDs of notes that
// link to them.
Broken map[string][]string
// contains filtered or unexported fields
}
Garden is a vault loaded into memory: every published note rendered, plus the link graph. It is safe for concurrent reads.
func Load ¶
Load scans the vault, renders every published note in parallel and computes backlinks. Nothing is written to disk.
Example ¶
Load a vault into memory and walk its link graph without writing a site.
package main
import (
"context"
"fmt"
"log"
"testing/fstest"
"github.com/zoravur/garden"
)
func main() {
vault := fstest.MapFS{
"index.md": {Data: []byte("Start with [[Evergreen notes]].")},
"Evergreen notes.md": {Data: []byte("They grow through [[ideas/Backlinks|backlinks]].")},
"ideas/Backlinks.md": {Data: []byte("A link seen from the other end. Back to [[index]].")},
}
g, err := garden.Load(context.Background(), &garden.Config{FS: vault})
if err != nil {
log.Fatal(err)
}
for _, n := range g.Notes {
fmt.Printf("%-16s links out: %d, linked from: %d\n", n.Title, len(n.Links), len(g.Backlinks(n.ID)))
}
}
Output: Evergreen notes links out: 1, linked from: 1 Backlinks links out: 1, linked from: 1 Index links out: 1, linked from: 1
type Link ¶
type Link struct {
Target string // ID of the linked note
Anchor string // heading ID within the target, if any
Label string // the link's text
Section string // heading in the source note the link sits under
Context string // the sentence or list item around the link, trimmed
}
Link is an edge from one note to another, with the text around it.
type NavNode ¶
type NavNode struct {
}
NavNode is an entry in the contents tree. A section can also be a note (its index page), so ID and Children can both be set.
type Note ¶
type Note struct {
ID string // vault path without ".md", e.g. "ideas/backlinks"
Path string // vault path, e.g. "ideas/backlinks.md"
Title string // frontmatter title, else the leading # heading, else the file name
Date string // frontmatter date, as written
Frontmatter map[string]any // parsed YAML frontmatter; nil if there is none
HTML string // rendered body; links are relative to the site root
Excerpt string // plain text of the first paragraph, trimmed
Links []Link // outgoing links to other published notes, in document order
Assets []string // vault paths of images and files the note uses
Broken []string // link targets that match no note or file
HasCode bool // contains a code block
HasMath bool // contains math, rendered in the browser with KaTeX
Generated bool // made by garden (the index page), not read from the vault
}
Note is one rendered note and the links found in it.
type Stats ¶
type Stats struct {
Notes int // published notes
Links int // note-to-note links
Broken int // links that match nothing
Written int // output files created or changed
Unchanged int // output files left as they were
AssetsCopied int // assets in the output
AssetsSkipped int // assets over MaxAssetMB, served from AssetFallbackURL
Phases []Phase // time per step, load included
Took time.Duration
}
Stats summarizes a build.