# 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 — 305 lines + 63 test check.go 45 · main.go 191 · new.go 42 · wire.go 27 - check.go:16 func runCheck(args []string) - main.go:24 func main() - main.go:45 func runServe() - main.go:106 func pollInterval(dev bool, chosen time.Duration) time.Duration - main.go:119 func watching(fsys fs.FS, every time.Duration, renderer *render.Renderer, rebuild func() int) - main.go:136 func rebuilder(fsys fs.FS, cache string, reveal bool, live *atomic.Pointer[content.Site]) func() int - main.go:162 func given(name string) bool - main.go:174 func defaultCache() string - main.go:184 func fatal(msg string, err error) - new.go:12 func runNew(args []string) - wire.go:17 func extenders(partial render.Partial) []goldmark.Extender ## internal/content — 1042 lines + 537 test clock.go 12 · content.go 450 · doc.go 5 · extras.go 92 · settings.go 59 · site.go 424 - 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:70 func OpenSite(dir string) (fs.FS, error) - content.go:82 type Problem struct - content.go:94 func Scan(fsys fs.FS) ([]Bundle, error) - content.go:103 func ScanReport(fsys fs.FS) ([]Bundle, []Problem, error) - content.go:142 func Parse(name string, data []byte) (Bundle, error) - content.go:182 func (b Bundle) Published(at time.Time) bool - content.go:191 func (b Bundle) Assets() (string, bool) - content.go:201 func stringList(v any) []string - content.go:223 func asTime(v any) time.Time - content.go:239 func asInt(v any) int - content.go:252 func terms(v any) []string - content.go:276 func TagSlug(tag string) string - content.go:285 func Normalise(s string) string { return norm.NFC.String(s) } - content.go:291 func splitName(name string) (key, lang string, ok bool) - content.go:313 func isLangTag(s string) bool - content.go:331 func isPartial(base string) bool - content.go:343 func skipDir(base string) bool - content.go:351 func splitFrontmatter(data []byte) (front, body []byte) - content.go:366 func trimLeadingFence(data []byte, fence string) ([]byte, bool) - content.go:383 func dropCollisions(all []Bundle) ([]Bundle, []Problem) - content.go:405 const PerPage = 10 - content.go:411 func URL(key, lang string) string - content.go:424 func TagURL(section, slug, lang string, page int) string - content.go:434 const DerivedPrefix = "/derived/" - content.go:437 func DerivedURL(name string) string { return DerivedPrefix + name } - content.go:440 const TagsSegment = "tags" - content.go:444 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:304 func (s *Site) Sequence(key, lang string) (Sequence, bool) - site.go:325 func (s *Site) parent(key string) (string, bool) - site.go:335 func (s *Site) has(key string) bool - site.go:344 func (s *Site) members(series, lang string) []Bundle - site.go:369 func (b Bundle) hasTag(slug string) bool - site.go:382 func (b Bundle) Section() string - site.go:394 func (s *Site) Everything() []Bundle - site.go:407 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/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 — 611 lines + 435 test doc.go 7 · images.go 250 · shortcodes.go 354 - images.go:31 var widths = []int{480, 960, 1440} - images.go:38 func Derive(siteFS fs.FS, cacheDir string) (int, error) - images.go:76 func derive(data []byte, name, cacheDir string) (int, error) - images.go:103 func scale(src image.Image, width int) image.Image - images.go:115 func write(file string, img image.Image, source string) error - images.go:133 func encode(w *os.File, img image.Image, source string) error - images.go:149 var - images.go:159 func picture(origin render.Origin, file string) (render.Picture, bool) - images.go:214 func derivedName(data []byte, source string, width int) string - images.go:224 func lossless(source string) bool - images.go:234 func showable(name string) bool - images.go:244 func derivable(name string) bool - shortcodes.go:28 const opener = " " - shortcodes.go:34 func New(partial render.Partial) goldmark.Extender - shortcodes.go:38 type extension struct - shortcodes.go:47 func (e extension) Extend(md goldmark.Markdown) - shortcodes.go:57 var nested = parser.NewContextKey() - shortcodes.go:62 var includedAs = parser.NewContextKey() - shortcodes.go:64 const footnoteKey = "khosra footnote-prefix" - shortcodes.go:72 func FootnotePrefix(n ast.Node) []byte - shortcodes.go:90 type includes struct - shortcodes.go:94 func (in includes) Transform(doc *ast.Document, reader text.Reader, pc parser.Context) - shortcodes.go:118 func (in includes) convert(name string, pc parser.Context) ([]byte, error) - shortcodes.go:149 func pending(doc *ast.Document) []*node - shortcodes.go:167 var kind = ast.NewNodeKind("Shortcode") - shortcodes.go:170 type node struct - shortcodes.go:184 func (n *node) Kind() ast.NodeKind { return kind } - shortcodes.go:186 func (n *node) Dump(source []byte, level int) { ast.DumpHelper(n, source, level, nil, nil) } - shortcodes.go:189 type blocks struct{} - shortcodes.go:191 func (blocks) Trigger() []byte { return []byte{' '} } - shortcodes.go:193 func (blocks) Open(parent ast.Node, reader text.Reader, pc parser.Context) (ast.Node, parser.State) - shortcodes.go:224 func gallery(pc parser.Context) []render.Picture - shortcodes.go:251 func (blocks) Continue(n ast.Node, reader text.Reader, pc parser.Context) parser.State - shortcodes.go:255 func (blocks) Close(n ast.Node, reader text.Reader, pc parser.Context) {} - shortcodes.go:257 func (blocks) CanInterruptParagraph() bool { return true } - shortcodes.go:259 func (blocks) CanAcceptIndentedLine() bool { return false } - shortcodes.go:262 type fragments struct - shortcodes.go:266 func (f fragments) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer) - shortcodes.go:274 func (f fragments) render(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error) - shortcodes.go:301 func parse(line string) (name string, args map[string]string, ok bool) - shortcodes.go:336 func argument(s string) (key, value, rest string, ok bool) ## 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 — 713 lines + 489 test chrome.go 110 · render.go 473 · view.go 130 - chrome.go:19 var chrome = map[string]map[string]string{ - chrome.go:33 var months = map[string][]string{ - chrome.go:41 var digits = map[string][]rune{ - chrome.go:47 var funcs = template.FuncMap{"t" text, "num" numerals, "day" day} - chrome.go:53 func text(lang, key string, args ...string) string - chrome.go:73 func numerals(lang string, n int) string - chrome.go:82 func day(lang string, t time.Time) string - chrome.go:98 func localiseDigits(lang, s string) string - render.go:26 var themeFS embed.FS - render.go:30 type Renderer struct - render.go:49 type parsedTheme struct - render.go:63 type Partial func(name string, data Fragment) ([]byte, error) - render.go:66 type Fragment struct - render.go:76 type Picture struct - render.go:93 type Origin struct - render.go:102 var originKey = parser.NewContextKey() - render.go:105 func OriginFrom(pc parser.Context) (Origin, bool) - render.go:112 func WithOrigin(pc parser.Context, origin Origin) - render.go:125 func New(siteFS fs.FS, settings content.Settings, extend func(Partial) []goldmark.Extender) (*Renderer, error) - render.go:156 func parseTheme(siteFS fs.FS) (*parsedTheme, error) - render.go:184 func (r *Renderer) head(title, lang, canonical string) head - render.go:201 func (r *Renderer) absolute(path string) string - render.go:209 func (r *Renderer) Navigation(sections func() []string) { r.sections = sections } - render.go:221 func (r *Renderer) Refresh() error - render.go:232 func (r *Renderer) Partial(name string, data Fragment) ([]byte, error) - render.go:251 func parseSet(siteFS fs.FS, names ...string) (*template.Template, error) - render.go:273 func readStyle(siteFS fs.FS) (template.CSS, error) - render.go:291 func (r *Renderer) Extras(b content.Bundle, served string, entries []content.Entry, selected *Selected) ([]byte, error) - render.go:312 func (r *Renderer) RenderText(kind string, data []byte) (template.HTML, error) - render.go:330 func (r *Renderer) Bundle(b content.Bundle, served string, variants []string, seq *content.Sequence) ([]byte, error) - render.go:367 func (r *Renderer) Listing(section, lang string, all []content.Bundle, page int) ([]byte, error) - render.go:386 func (r *Renderer) Tag(section, slug, lang string, all []content.Bundle, page int) ([]byte, error) - render.go:413 func (r *Renderer) sequence(seq *content.Sequence, lang string) *Sequence - render.go:440 func (r *Renderer) item(b content.Bundle, lang string) Item - render.go:445 func (r *Renderer) paginate(title, lang, canonical string, all []content.Bundle, page int, url func(int) string) (List, []content.Bundle) - render.go:467 func (r *Renderer) execute(set *template.Template, data any, what string) ([]byte, error) - view.go:16 type head struct - view.go:36 type Page struct - view.go:55 type Sequence struct - view.go:71 type Extras struct - view.go:82 type Selected struct - view.go:91 type List struct - view.go:105 type Group struct - view.go:111 type Item struct - view.go:122 type Alternate struct ## internal/web — 734 lines + 1608 test asset.go 58 · discover.go 71 · extras.go 93 · feed.go 125 · resolve.go 170 · web.go 217 - 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 Current func() *content.Site - web.go:22 func Fixed(site *content.Site) Current { return func() *content.Site { return site } } - web.go:27 func Handler(current Current, r *render.Renderer, siteFS, derivedFS fs.FS, settings content.Settings) http.Handler - web.go:60 func serveStatic(sub fs.FS) http.Handler - web.go:76 func serveListing(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, res resolution) bool - web.go:100 func serveTags(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, res resolution) bool - web.go:125 func write(w http.ResponseWriter, out []byte, what string) - web.go:134 func writeAs(w http.ResponseWriter, contentType string, out []byte, what string) - web.go:142 func serve(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, siteFS fs.FS, settings content.Settings) - web.go:173 func serveBundle(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer,