docs/content-model.md opens with "Engine specification". It is also where the rule lives that a leading underscore makes a file unaddressable — and the human who owns this site did not know that rule, because nothing in this repository is addressed to an author. Twelve documents named docs/ while being exclusively about building the parser is a signpost pointing at the wrong room. Naming the directory for its audience makes the gap visible instead of hiding it. docs/ is now reserved and deliberately absent: an empty docs/ is an honest statement that end-user documentation does not exist, where docs/ full of parser specs was a claim that it did. HARNESS.md stays at the root. Root holds the three entry points — README.md for a human, CLAUDE.md for an agent, HARNESS.md for whoever maintains the machine — and harness/README.md is the map of the directory, so moving the guide inside would have collided with it for nothing. Mechanical and wide: 100 path references across 24 files. Every verify.sh gate that names a doc by path, the directory lists the dangling-path and ADR-number gates scan, surface.sh's output target, the Makefile, CLAUDE.md's read order, the skill, four commands, and two Go package comments. A first pass with a shell loop silently edited only four files and the rest still said docs/; the fix was to write the file list out and check the remaining count was zero rather than trust the loop's exit status. No rule, threshold, gate or obligation moved — this is a rename, and the gates demonstrated it twice: they stayed green on the new paths, and the ADR-number gate caught ADR-0082 before the entry existed. Deferred, both on the human's call: the end-user documentation site itself, which wants its own decision about where it lives and whether its claims are gated; and moving examples/ under docs/, since demo-site is a live site root that verify.sh, the coverage test and make demo all point at, and moving it would couple a rename to a design nobody has made. 31 files, +146/-106. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
24 KiB
Surface
Generated by scripts/surface.sh — do not edit. Regenerate with make surface.
Every top-level declaration in the engine, with its line. Read this before opening a source
file: it answers "where does X live" and "what is in this package" without the bodies. What each
file is for lives in state.md; why it is that way lives in decisions.md.
cmd/khosra — 320 lines + 308 test
check.go 45 · main.go 177 · new.go 42 · wire.go 56
- check.go:16 func runCheck(args []string)
- main.go:23 func main()
- main.go:44 func runServe()
- main.go:100 func pollInterval(dev bool, chosen time.Duration) time.Duration
- main.go:116 func watching(fsys fs.FS, every time.Duration, rebuild func() int)
- main.go:128 func rebuilder(fsys fs.FS, settings content.Settings, cache string, reveal bool,
- main.go:160 func defaultCache() string
- main.go:170 func fatal(msg string, err error)
- new.go:12 func runNew(args []string)
- wire.go:20 func theme(siteFS fs.FS, settings content.Settings) (*render.Renderer, error)
- wire.go:33 func extenders(partial render.Partial) []goldmark.Extender
- wire.go:54 func routes(siteFS fs.FS, settings content.Settings) map[string]http.Handler
internal/content — 1074 lines + 598 test
clock.go 12 · content.go 481 · doc.go 5 · extras.go 92 · settings.go 59 · site.go 425
- clock.go:9 var now = time.Now
- clock.go:12 func Now() time.Time { return now() }
- content.go:20 const DefaultLang = "en"
- content.go:27 type Bundle struct
- content.go:77 func OpenSite(dir string) (fs.FS, error)
- content.go:89 type Problem struct
- content.go:101 func Scan(fsys fs.FS) ([]Bundle, error)
- content.go:110 func ScanReport(fsys fs.FS) ([]Bundle, []Problem, error)
- content.go:149 func Parse(name string, data []byte) (Bundle, error)
- content.go:196 func (b Bundle) Published(at time.Time) bool
- content.go:205 func (b Bundle) Assets() (string, bool)
- content.go:215 func stringList(v any) []string
- content.go:237 func asTime(v any) time.Time
- content.go:253 func asInt(v any) int
- content.go:271 func bundleFiles(v any, where string) []string
- content.go:283 func terms(v any) []string
- content.go:307 func TagSlug(tag string) string
- content.go:316 func Normalise(s string) string { return norm.NFC.String(s) }
- content.go:322 func splitName(name string) (key, lang string, ok bool)
- content.go:344 func isLangTag(s string) bool
- content.go:362 func isPartial(base string) bool
- content.go:374 func skipDir(base string) bool
- content.go:382 func splitFrontmatter(data []byte) (front, body []byte)
- content.go:397 func trimLeadingFence(data []byte, fence string) ([]byte, bool)
- content.go:414 func dropCollisions(all []Bundle) ([]Bundle, []Problem)
- content.go:436 const PerPage = 10
- content.go:442 func URL(key, lang string) string
- content.go:455 func TagURL(section, slug, lang string, page int) string
- content.go:465 const DerivedPrefix = "/derived/"
- content.go:468 func DerivedURL(name string) string { return DerivedPrefix + name }
- content.go:471 const TagsSegment = "tags"
- content.go:475 func PageURL(key, lang string, page int) string
- extras.go:14 const ExtrasDir = "extras"
- extras.go:17 type Entry struct
- extras.go:33 func Extras(fsys fs.FS, b Bundle) []Entry
- extras.go:67 func KindOf(name string) string
- extras.go:86 func ExtrasURL(route, lang, entry string) string
- settings.go:13 const SettingsFile = "site.yaml"
- settings.go:20 type Settings struct
- settings.go:33 func LoadSettings(fsys fs.FS) (Settings, error)
- settings.go:54 func Absolute(base, path string) string
- site.go:11 type Site struct
- site.go:28 func NewSite(bundles []Bundle) *Site
- site.go:45 func (s *Site) Reveal() { s.reveal = true }
- site.go:52 func (s *Site) visible(b Bundle) bool
- site.go:58 func (s *Site) Problems() []Problem { return s.problems }
- site.go:61 func (s *Site) note(path, detail string)
- site.go:72 func (s *Site) indexRoutes(bundles []Bundle)
- site.go:111 func (s *Site) KeyFor(route string) (string, bool)
- site.go:122 func (s *Site) RouteOf(key string) string
- site.go:130 func sorted(set map[string]bool) []string
- site.go:143 func (s *Site) indexAliases(bundles []Bundle)
- site.go:175 func (s *Site) Alias(alias string) (string, bool)
- site.go:184 func (s *Site) Lookup(key, lang string) (b Bundle, served string, ok bool)
- site.go:202 func (s *Site) Variants(key string) []string
- site.go:216 func (s *Site) HasLang(lang string) bool
- site.go:226 func (s *Site) Len() int { return len(s.byKeyLang) }
- site.go:232 type Query struct
- site.go:243 func (s *Site) Run(q Query) []Bundle
- site.go:268 func (s *Site) keys() []string
- site.go:284 type Sequence struct
- site.go:305 func (s *Site) Sequence(key, lang string) (Sequence, bool)
- site.go:326 func (s *Site) parent(key string) (string, bool)
- site.go:336 func (s *Site) has(key string) bool
- site.go:345 func (s *Site) members(series, lang string) []Bundle
- site.go:370 func (b Bundle) hasTag(slug string) bool
- site.go:383 func (b Bundle) Section() string
- site.go:395 func (s *Site) Everything() []Bundle
- site.go:408 func (s *Site) Sections() []string
internal/ext/check — 231 lines + 168 test
check.go 223 · doc.go 8
- check.go:16 type Finding struct
- check.go:30 func Run(fsys fs.FS, bundles []content.Bundle, site *content.Site, problems []content.Problem) []Finding
- check.go:53 func Fatal(found []Finding) bool
- check.go:63 func inspect(fsys fs.FS, b content.Bundle, site *content.Site) []Finding
- check.go:85 var figureCall = regexp.MustCompile(
(?m)^\s* figure\{([^}]*)\}\s*$) - check.go:89 var altArg = regexp.MustCompile(
alt=("[^"]+"|[^"\s}]+)) - check.go:95 func checkFigures(b content.Bundle) []Finding
- check.go:106 var internalLink = regexp.MustCompile(
\]\((/[^)\s"]*)) - check.go:112 func checkLinks(fsys fs.FS, b content.Bundle, site *content.Site) []Finding
- check.go:129 func engineOwned(target string) bool
- check.go:146 func resolves(fsys fs.FS, target string, from content.Bundle, site *content.Site) bool
- check.go:172 func asset(fsys fs.FS, trimmed string, site *content.Site) bool
- check.go:200 func mixedOrdering(bundles []content.Bundle, site *content.Site) []Finding
internal/ext/notation — 411 lines + 149 test
abbr.go 246 · doc.go 8 · notation.go 157
- abbr.go:17 var defined = parser.NewContextKey()
- abbr.go:21 var definitionKind = ast.NewNodeKind("AbbrDefinition")
- abbr.go:23 type definition struct{ ast.BaseBlock }
- abbr.go:25 func (n *definition) Kind() ast.NodeKind { return definitionKind }
- abbr.go:27 func (n *definition) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) }
- abbr.go:30 var abbrKind = ast.NewNodeKind("Abbr")
- abbr.go:32 type abbr struct
- abbr.go:37 func (n *abbr) Kind() ast.NodeKind { return abbrKind }
- abbr.go:39 func (n *abbr) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) }
- abbr.go:45 type definitionParser struct{}
- abbr.go:47 func (definitionParser) Trigger() []byte { return []byte{'*'} }
- abbr.go:49 func (definitionParser) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State)
- abbr.go:65 func (definitionParser) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State
- abbr.go:69 func (definitionParser) Close(node ast.Node, reader text.Reader, pc parser.Context) {}
- abbr.go:71 func (definitionParser) CanInterruptParagraph() bool { return true }
- abbr.go:73 func (definitionParser) CanAcceptIndentedLine() bool { return false }
- abbr.go:77 func parseDefinition(line string) (term, expansion string, ok bool)
- abbr.go:101 type expand struct{}
- abbr.go:103 func (expand) Transform(doc *ast.Document, reader text.Reader, pc parser.Context)
- abbr.go:136 func replace(node *ast.Text, source []byte, terms map[string]string, ordered []string)
- abbr.go:172 func slice(seg text.Segment, from, to int) text.Segment
- abbr.go:180 func firstMatch(body string, ordered []string) (string, int)
- abbr.go:193 func earliest(body, term string) int
- abbr.go:209 func whole(body string, index, length int) bool
- abbr.go:226 func renderDefinition(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
- abbr.go:232 func renderAbbr(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
- abbr.go:243 func (nodeRenderer) registerAbbr(reg renderer.NodeRendererFuncRegisterer)
- notation.go:17 var marks = []mark{
- notation.go:27 type mark struct
- notation.go:33 func New() goldmark.Extender { return extension{} }
- notation.go:35 type extension struct{}
- notation.go:41 func (extension) Extend(md goldmark.Markdown)
- notation.go:56 var kind = ast.NewNodeKind("Notation")
- notation.go:59 type node struct
- notation.go:64 func (n *node) Kind() ast.NodeKind { return kind }
- notation.go:66 func (n *node) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) }
- notation.go:70 type processor struct{ tag string }
- notation.go:72 func (p processor) IsDelimiter(b byte) bool { return b == '~' || b == '=' }
- notation.go:74 func (p processor) CanOpenCloser(opener, closer *parser.Delimiter) bool
- notation.go:78 func (p processor) OnMatch(consumes int) ast.Node { return &node{tag p.tag} }
- notation.go:81 type inlineParser struct{ m mark }
- notation.go:83 func (p inlineParser) Trigger() []byte { return []byte{p.m.char} }
- notation.go:85 func (p inlineParser) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node
- notation.go:94 func (p inlineParser) doubled(block text.Reader, line []byte, segment text.Segment, pc parser.Context) ast.Node
- notation.go:113 func (p inlineParser) single(block text.Reader, line []byte, segment text.Segment) ast.Node
- notation.go:142 type nodeRenderer struct{}
- notation.go:144 func (r nodeRenderer) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)
- notation.go:149 func render(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
internal/ext/passthrough — 178 lines + 136 test
doc.go 11 · passthrough.go 167
- passthrough.go:23 const Dir = "root"
- passthrough.go:28 const headersFile = "_headers.yaml"
- passthrough.go:35 const tmplSuffix = ".tmpl"
- passthrough.go:46 func Routes(siteFS fs.FS, settings content.Settings) map[string]http.Handler
- passthrough.go:92 func readHeaders(siteFS fs.FS) map[string]map[string]string
- passthrough.go:109 type file struct
- passthrough.go:117 func (f *file) ServeHTTP(w http.ResponseWriter, r *http.Request)
- passthrough.go:157 func (f *file) render(data []byte) ([]byte, error)
internal/ext/scaffold — 102 lines + 89 test
doc.go 8 · scaffold.go 94
- scaffold.go:23 func New(siteDir, key, lang, title string) (string, error)
- scaffold.go:69 func frontmatter(title string) string
- scaffold.go:76 func titleFrom(key string) string
- scaffold.go:85 func mkdirAll(root *os.Root, dir string) error
internal/ext/shortcodes — 1333 lines + 842 test
code.go 211 · containers.go 192 · doc.go 7 · icons.go 129 · images.go 241 · memo.go 73 · shortcodes.go 385 · toc.go 95
- code.go:27 const codeFragment = "code"
- code.go:30 var codeKind = ast.NewNodeKind("ShortcodeCode")
- code.go:32 type codeBlock struct
- code.go:46 func (n *codeBlock) Kind() ast.NodeKind { return codeKind }
- code.go:48 func (n *codeBlock) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) }
- code.go:54 type code struct{}
- code.go:56 func (code) Transform(doc *ast.Document, reader text.Reader, pc parser.Context)
- code.go:76 func readFence(f *ast.FencedCodeBlock, source []byte, origin render.Origin) *codeBlock
- code.go:119 func fromFile(origin render.Origin, name, span string) ([]byte, int, bool)
- code.go:144 func ranges(spec string) [][2]int
- code.go:172 func (f fragments) renderCode(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
- containers.go:22 var containerKind = ast.NewNodeKind("ShortcodeContainer")
- containers.go:24 type container struct
- containers.go:34 func (n *container) Kind() ast.NodeKind { return containerKind }
- containers.go:36 func (n *container) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) }
- containers.go:39 type containers struct{}
- containers.go:41 func (containers) Trigger() []byte { return []byte{' '} }
- containers.go:43 func (containers) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State)
- containers.go:61 func (containers) Continue(node ast.Node, reader text.Reader, pc parser.Context) parser.State
- containers.go:70 func (containers) Close(node ast.Node, reader text.Reader, pc parser.Context) {}
- containers.go:72 func (containers) CanInterruptParagraph() bool { return true }
- containers.go:74 func (containers) CanAcceptIndentedLine() bool { return false }
- containers.go:80 type bodies struct
- containers.go:84 func (b bodies) Transform(doc *ast.Document, reader text.Reader, pc parser.Context)
- containers.go:108 func (f fragments) renderContainer(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
- containers.go:136 func Merge(src []byte, origin render.Origin) []byte
- containers.go:165 func withoutIncludes(body []byte) []byte
- containers.go:184 func included(origin render.Origin, name string) ([]byte, error)
- icons.go:19 const iconFragment = "icon"
- icons.go:27 type icons struct{}
- icons.go:29 func (icons) Trigger() []byte { return []byte{' '} }
- icons.go:31 func (icons) Parse(parent ast.Node, block text.Reader, pc parser.Context) ast.Node
- icons.go:52 var iconKind = ast.NewNodeKind("ShortcodeIcon")
- icons.go:54 type iconNode struct
- icons.go:61 func (n *iconNode) Kind() ast.NodeKind { return iconKind }
- icons.go:63 func (n *iconNode) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) }
- icons.go:67 func (f fragments) renderIcon(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
- icons.go:87 func iconName(line []byte) (string, int, bool)
- icons.go:117 func isNameByte(c byte, first bool) bool
- icons.go:129 func isWordRune(r rune) bool { return unicode.IsLetter(r) || unicode.IsDigit(r) }
- images.go:30 var widths = []int{480, 960, 1440}
- images.go:37 func Derive(siteFS fs.FS, cacheDir string) (int, error)
- images.go:75 func derive(data []byte, name, cacheDir string) (int, error)
- images.go:102 func scale(src image.Image, width int) image.Image
- images.go:114 func write(file string, img image.Image, source string) error
- images.go:132 func encode(w *os.File, img image.Image, source string) error
- images.go:148 var inspected = newMemo(remembered)
- images.go:155 func picture(origin render.Origin, file string) (render.Picture, bool)
- images.go:205 func derivedName(data []byte, source string, width int) string
- images.go:215 func lossless(source string) bool
- images.go:225 func showable(name string) bool
- images.go:235 func derivable(name string) bool
- memo.go:13 const remembered = 1024
- memo.go:21 type memo struct
- memo.go:30 type entry struct
- memo.go:35 func newMemo(max int) *memo
- memo.go:40 func (m *memo) get(key string) (render.Picture, bool)
- memo.go:52 func (m *memo) put(key string, picture render.Picture)
- memo.go:69 func (m *memo) len() int
- shortcodes.go:28 const
- shortcodes.go:37 func New(partial render.Partial) goldmark.Extender
- shortcodes.go:41 type extension struct
- shortcodes.go:50 func (e extension) Extend(md goldmark.Markdown)
- shortcodes.go:70 var nested = parser.NewContextKey()
- shortcodes.go:75 var includedAs = parser.NewContextKey()
- shortcodes.go:77 const footnoteKey = "khosra footnote-prefix"
- shortcodes.go:85 func FootnotePrefix(n ast.Node) []byte
- shortcodes.go:103 type includes struct
- shortcodes.go:107 func (in includes) Transform(doc *ast.Document, reader text.Reader, pc parser.Context)
- shortcodes.go:131 func (in includes) convert(name string, pc parser.Context) ([]byte, error)
- shortcodes.go:165 func pending(doc *ast.Document) []*node
- shortcodes.go:183 var kind = ast.NewNodeKind("Shortcode")
- shortcodes.go:186 type node struct
- shortcodes.go:205 func (n *node) Kind() ast.NodeKind { return kind }
- shortcodes.go:207 func (n *node) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) }
- shortcodes.go:210 type blocks struct{}
- shortcodes.go:212 func (blocks) Trigger() []byte { return []byte{' '} }
- shortcodes.go:214 func (blocks) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State)
- shortcodes.go:251 func gallery(pc parser.Context) []render.Picture
- shortcodes.go:278 func (blocks) Continue(n ast.Node, reader text.Reader, pc parser.Context) parser.State
- shortcodes.go:282 func (blocks) Close(n ast.Node, reader text.Reader, pc parser.Context) {}
- shortcodes.go:284 func (blocks) CanInterruptParagraph() bool { return true }
- shortcodes.go:286 func (blocks) CanAcceptIndentedLine() bool { return false }
- shortcodes.go:289 type fragments struct
- shortcodes.go:293 func (f fragments) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)
- shortcodes.go:304 func (f fragments) render(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
- shortcodes.go:332 func parse(line, prefix string) (name string, args map[string]string, ok bool)
- shortcodes.go:367 func argument(s string) (key, value, rest string, ok bool)
- toc.go:16 const tocName = "toc"
- toc.go:23 type tables struct{}
- toc.go:25 func (tables) Transform(doc *ast.Document, reader text.Reader, pc parser.Context)
- toc.go:53 func deeper(all []render.Heading, depth string) []render.Heading
- toc.go:69 func headingText(heading *ast.Heading, source []byte) string
- toc.go:84 func headingID(heading *ast.Heading) string
- toc.go:95 var _ parser.ASTTransformer = tables{}
internal/ext/watch — 133 lines + 114 test
doc.go 8 · watch.go 125
- watch.go:16 type Changed func()
- watch.go:32 func Watch(fsys fs.FS, every, settle time.Duration, stop <-chan struct{}, onChange Changed)
- watch.go:76 func Fingerprint(fsys fs.FS) string
- watch.go:90 func record(sum hash.Hash, p string, d fs.DirEntry, err error) error
- watch.go:113 func dropping(name string) bool
internal/render — 806 lines + 441 test
chrome.go 115 · render.go 499 · view.go 192
- chrome.go:19 var chrome = map[string]map[string]string{
- chrome.go:38 var months = map[string][]string{
- chrome.go:46 var digits = map[string][]rune{
- chrome.go:52 var funcs = template.FuncMap{"t" text, "num" numerals, "day" day}
- chrome.go:58 func text(lang, key string, args ...string) string
- chrome.go:78 func numerals(lang string, n int) string
- chrome.go:87 func day(lang string, t time.Time) string
- chrome.go:103 func localiseDigits(lang, s string) string
- render.go:27 var themeFS embed.FS
- render.go:31 type Renderer struct
- render.go:50 type parsedTheme struct
- render.go:63 var originKey = parser.NewContextKey()
- render.go:66 func OriginFrom(pc parser.Context) (Origin, bool)
- render.go:73 func WithOrigin(pc parser.Context, origin Origin)
- render.go:79 var callsKey = parser.NewContextKey()
- render.go:90 func RecordCall(pc parser.Context, name string)
- render.go:102 func callsFrom(pc parser.Context) []string
- render.go:118 func New(siteFS fs.FS, settings content.Settings, extend func(Partial) []goldmark.Extender) (*Renderer, error)
- render.go:148 func parseTheme(siteFS fs.FS) (*parsedTheme, error)
- render.go:176 func (r *Renderer) head(title, lang, canonical string) head
- render.go:193 func (r *Renderer) absolute(path string) string
- render.go:201 func (r *Renderer) Navigation(sections func() []string) { r.sections = sections }
- render.go:207 func (r *Renderer) Compose(rewrite func(src []byte, origin Origin) []byte) { r.compose = rewrite }
- render.go:211 func (r *Renderer) Partial(name string, data Fragment) ([]byte, error)
- render.go:229 func (r *Renderer) assets(names []string) template.HTML
- render.go:253 func parseSet(siteFS fs.FS, names ...string) (*template.Template, error)
- render.go:282 func readStyle(siteFS fs.FS) (template.CSS, error)
- render.go:300 func (r *Renderer) Extras(b content.Bundle, served string, entries []content.Entry, selected *Selected) ([]byte, error)
- render.go:321 func (r *Renderer) RenderText(kind string, data []byte) (template.HTML, error)
- render.go:339 func (r *Renderer) Bundle(b content.Bundle, served string, variants []string, seq *content.Sequence) ([]byte, error)
- render.go:393 func (r *Renderer) Listing(section, lang string, all []content.Bundle, page int) ([]byte, error)
- render.go:412 func (r *Renderer) Tag(section, slug, lang string, all []content.Bundle, page int) ([]byte, error)
- render.go:439 func (r *Renderer) sequence(seq *content.Sequence, lang string) *Sequence
- render.go:466 func (r *Renderer) item(b content.Bundle, lang string) Item
- render.go:471 func (r *Renderer) paginate(title, lang, canonical string, all []content.Bundle, page int, url func(int) string) (List, []content.Bundle)
- render.go:493 func (r *Renderer) execute(set *template.Template, data any, what string) ([]byte, error)
- view.go:17 type head struct
- view.go:37 type Page struct
- view.go:63 type Sequence struct
- view.go:79 type Extras struct
- view.go:90 type Selected struct
- view.go:99 type List struct
- view.go:113 type Group struct
- view.go:119 type Item struct
- view.go:130 type Alternate struct
- view.go:142 type Partial func(name string, data Fragment) ([]byte, error)
- view.go:145 type Fragment struct
- view.go:161 type Heading struct
- view.go:167 type Picture struct
- view.go:184 type Origin struct
internal/web — 765 lines + 1423 test
asset.go 58 · discover.go 71 · extras.go 93 · feed.go 125 · resolve.go 170 · web.go 248
- asset.go:22 func serveAsset(w http.ResponseWriter, req *http.Request, site *content.Site, siteFS fs.FS, res resolution) bool
- discover.go:14 const
- discover.go:24 func serveRobots(w http.ResponseWriter, req *http.Request, siteFS fs.FS, base string)
- discover.go:45 func serveSitemap(w http.ResponseWriter, req *http.Request, site *content.Site, base string)
- discover.go:67 func xmlEscape(s string) string
- extras.go:18 func serveExtras(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer,
- extras.go:69 func renderExtras(w http.ResponseWriter, r *render.Renderer, b content.Bundle, served string,
- extras.go:85 func find(entries []content.Entry, want string) (content.Entry, bool)
- feed.go:13 const feedFile = "feed.xml"
- feed.go:17 const feedMax = 20
- feed.go:24 type atom struct
- feed.go:34 type atomLink struct
- feed.go:40 type atomEntry struct
- feed.go:52 func serveFeed(w http.ResponseWriter, req *http.Request, site *content.Site, res resolution, settings content.Settings) bool
- feed.go:102 func dated(all []content.Bundle) []content.Bundle
- feed.go:113 func feedTitle(settings content.Settings, res resolution) string
- resolve.go:12 type resolution struct
- resolve.go:40 func resolve(path string, site *content.Site) (resolution, bool)
- resolve.go:102 func cutLang(key string, site *content.Site) (lang, rest, redirect string)
- resolve.go:117 func cutExtras(key string) (bundle, entry string, ok bool)
- resolve.go:131 func cutFeed(key string) (rest string, ok bool)
- resolve.go:142 func cutTag(key string) (tag, section string, ok bool)
- resolve.go:154 func cutPage(key string) (rest string, page int, ok bool)
- web.go:19 type Snapshot struct
- web.go:28 type Current func() *Snapshot
- web.go:31 func Fixed(site *content.Site, theme *render.Renderer) Current
- web.go:43 func Handler(current Current, siteFS, derivedFS fs.FS, settings content.Settings, routes map[string]http.Handler) http.Handler
- web.go:91 func serveStatic(sub fs.FS) http.Handler
- web.go:107 func serveListing(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, res resolution) bool
- web.go:131 func serveTags(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, res resolution) bool
- web.go:156 func write(w http.ResponseWriter, out []byte, what string)
- web.go:165 func writeAs(w http.ResponseWriter, contentType string, out []byte, what string)
- web.go:173 func serve(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, siteFS fs.FS, settings content.Settings)
- web.go:204 func serveBundle(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer,