Two stores meant a request landing between them saw a new theme with the previous index: each half coherent, the pair a state that never existed on disk. Microseconds, which is why it waited — it closes now because the fix removes machinery instead of adding it. web.Snapshot holds both behind one atomic.Pointer that a rebuild stores once. A Renderer never changes after New, so Refresh and the atomic inside the renderer are gone; an immutable renderer is the simpler object, and the one place a change is applied is now the one place it is observed. web.Handler lost its renderer argument and twenty test construction sites moved with it. Live reload verified on the real binary through the new path: a template edit appeared and reverted, two rebuilds for two edits. Also answers the session's open question: no subagents for fan-out reads. A verdict arriving without the reading behind it cannot be audited, which is the thing this harness exists to make possible. Latent list: 6.
23 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 — 305 lines + 292 test
check.go 45 · main.go 177 · new.go 42 · wire.go 41
- 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:18 func theme(siteFS fs.FS, settings content.Settings) (*render.Renderer, error)
- wire.go:31 func extenders(partial render.Partial) []goldmark.Extender
internal/content — 1043 lines + 558 test
clock.go 12 · content.go 451 · 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:183 func (b Bundle) Published(at time.Time) bool
- content.go:192 func (b Bundle) Assets() (string, bool)
- content.go:202 func stringList(v any) []string
- content.go:224 func asTime(v any) time.Time
- content.go:240 func asInt(v any) int
- content.go:253 func terms(v any) []string
- content.go:277 func TagSlug(tag string) string
- content.go:286 func Normalise(s string) string { return norm.NFC.String(s) }
- content.go:292 func splitName(name string) (key, lang string, ok bool)
- content.go:314 func isLangTag(s string) bool
- content.go:332 func isPartial(base string) bool
- content.go:344 func skipDir(base string) bool
- content.go:352 func splitFrontmatter(data []byte) (front, body []byte)
- content.go:367 func trimLeadingFence(data []byte, fence string) ([]byte, bool)
- content.go:384 func dropCollisions(all []Bundle) ([]Bundle, []Problem)
- content.go:406 const PerPage = 10
- content.go:412 func URL(key, lang string) string
- content.go:425 func TagURL(section, slug, lang string, page int) string
- content.go:435 const DerivedPrefix = "/derived/"
- content.go:438 func DerivedURL(name string) string { return DerivedPrefix + name }
- content.go:441 const TagsSegment = "tags"
- content.go:445 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 — 1330 lines + 842 test
code.go 211 · containers.go 192 · doc.go 7 · icons.go 129 · images.go 241 · memo.go 73 · shortcodes.go 382 · 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:248 func gallery(pc parser.Context) []render.Picture
- shortcodes.go:275 func (blocks) Continue(n ast.Node, reader text.Reader, pc parser.Context) parser.State
- shortcodes.go:279 func (blocks) Close(n ast.Node, reader text.Reader, pc parser.Context) {}
- shortcodes.go:281 func (blocks) CanInterruptParagraph() bool { return true }
- shortcodes.go:283 func (blocks) CanAcceptIndentedLine() bool { return false }
- shortcodes.go:286 type fragments struct
- shortcodes.go:290 func (f fragments) RegisterFuncs(reg renderer.NodeRendererFuncRegisterer)
- shortcodes.go:301 func (f fragments) render(w util.BufWriter, source []byte, n ast.Node, entering bool) (ast.WalkStatus, error)
- shortcodes.go:329 func parse(line, prefix string) (name string, args map[string]string, ok bool)
- shortcodes.go:364 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 — 733 lines + 441 test
chrome.go 115 · render.go 433 · view.go 185
- 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:25 var themeFS embed.FS
- render.go:29 type Renderer struct
- render.go:48 type parsedTheme struct
- render.go:61 var originKey = parser.NewContextKey()
- render.go:64 func OriginFrom(pc parser.Context) (Origin, bool)
- render.go:71 func WithOrigin(pc parser.Context, origin Origin)
- render.go:84 func New(siteFS fs.FS, settings content.Settings, extend func(Partial) []goldmark.Extender) (*Renderer, error)
- render.go:114 func parseTheme(siteFS fs.FS) (*parsedTheme, error)
- render.go:142 func (r *Renderer) head(title, lang, canonical string) head
- render.go:159 func (r *Renderer) absolute(path string) string
- render.go:167 func (r *Renderer) Navigation(sections func() []string) { r.sections = sections }
- render.go:173 func (r *Renderer) Compose(rewrite func(src []byte, origin Origin) []byte) { r.compose = rewrite }
- render.go:177 func (r *Renderer) Partial(name string, data Fragment) ([]byte, error)
- render.go:196 func parseSet(siteFS fs.FS, names ...string) (*template.Template, error)
- render.go:225 func readStyle(siteFS fs.FS) (template.CSS, error)
- render.go:243 func (r *Renderer) Extras(b content.Bundle, served string, entries []content.Entry, selected *Selected) ([]byte, error)
- render.go:264 func (r *Renderer) RenderText(kind string, data []byte) (template.HTML, error)
- render.go:282 func (r *Renderer) Bundle(b content.Bundle, served string, variants []string, seq *content.Sequence) ([]byte, error)
- render.go:327 func (r *Renderer) Listing(section, lang string, all []content.Bundle, page int) ([]byte, error)
- render.go:346 func (r *Renderer) Tag(section, slug, lang string, all []content.Bundle, page int) ([]byte, error)
- render.go:373 func (r *Renderer) sequence(seq *content.Sequence, lang string) *Sequence
- render.go:400 func (r *Renderer) item(b content.Bundle, lang string) Item
- render.go:405 func (r *Renderer) paginate(title, lang, canonical string, all []content.Bundle, page int, url func(int) string) (List, []content.Bundle)
- render.go:427 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:56 type Sequence struct
- view.go:72 type Extras struct
- view.go:83 type Selected struct
- view.go:92 type List struct
- view.go:106 type Group struct
- view.go:112 type Item struct
- view.go:123 type Alternate struct
- view.go:135 type Partial func(name string, data Fragment) ([]byte, error)
- view.go:138 type Fragment struct
- view.go:154 type Heading struct
- view.go:160 type Picture struct
- view.go:177 type Origin struct
internal/web — 747 lines + 1423 test
asset.go 58 · discover.go 71 · extras.go 93 · feed.go 125 · resolve.go 170 · web.go 230
- 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:39 func Handler(current Current, siteFS, derivedFS fs.FS, settings content.Settings) http.Handler
- web.go:73 func serveStatic(sub fs.FS) http.Handler
- web.go:89 func serveListing(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, res resolution) bool
- web.go:113 func serveTags(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, res resolution) bool
- web.go:138 func write(w http.ResponseWriter, out []byte, what string)
- web.go:147 func writeAs(w http.ResponseWriter, contentType string, out []byte, what string)
- web.go:155 func serve(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer, siteFS fs.FS, settings content.Settings)
- web.go:186 func serveBundle(w http.ResponseWriter, req *http.Request, site *content.Site, r *render.Renderer,