package renderkit import ( stdhtml "html" "path" "regexp" "strings" ) // Snippet describes one fenced code block in an assistant reply that is // worth offering as a download. type Snippet struct { Index int // position among ALL fenced blocks in the reply (matches the DOM order of .code-block) Lang string // lower-cased fence language Ext string // file extension including the dot, e.g. ".go" Label string // display name of the type, e.g. "Go" Lines int Bytes int // Filename is set when the block's first line is a comment naming a // file with the matching extension (e.g. "// internal/db/users.go"), // which models often write; only the base name is kept. Filename string } var firstLineFilename = regexp.MustCompile(`^\s*(?://|#|--|/\*|)?\s*$`) func filenameHint(body, ext string) string { first, _, _ := strings.Cut(body, "\n") m := firstLineFilename.FindStringSubmatch(first) if m == nil { return "" } base := path.Base(m[1]) if path.Ext(base) != ext || base == ext { return "" } return base } type snippetType struct{ ext, label string } var snippetTypes = map[string]snippetType{ "go": {".go", "Go"}, "golang": {".go", "Go"}, "js": {".js", "JavaScript"}, "javascript": {".js", "JavaScript"}, "jsx": {".jsx", "JSX"}, "ts": {".ts", "TypeScript"}, "typescript": {".ts", "TypeScript"}, "tsx": {".tsx", "TSX"}, "py": {".py", "Python"}, "python": {".py", "Python"}, "sh": {".sh", "Shell"}, "bash": {".sh", "Shell"}, "shell": {".sh", "Shell"}, "zsh": {".sh", "Shell"}, "json": {".json", "JSON"}, "sql": {".sql", "SQL"}, "c": {".c", "C"}, "h": {".h", "C header"}, "cpp": {".cpp", "C++"}, "c++": {".cpp", "C++"}, "java": {".java", "Java"}, "rust": {".rs", "Rust"}, "rs": {".rs", "Rust"}, "diff": {".patch", "Patch"}, "patch": {".patch", "Patch"}, "yaml": {".yml", "YAML"}, "yml": {".yml", "YAML"}, "toml": {".toml", "TOML"}, "html": {".html", "HTML"}, "css": {".css", "CSS"}, "md": {".md", "Markdown"}, "markdown": {".md", "Markdown"}, } // Snippets lists the fenced code blocks in src that have a recognised // language, in the order Markdown renders them. Blocks with no language (or // an unknown one) are skipped, but still counted in Index. func Snippets(src string) []Snippet { var out []Snippet for i, m := range fencedCodeBlock.FindAllStringSubmatch(rawMarkdown(src), -1) { lang := strings.ToLower(m[1]) t, ok := snippetTypes[lang] if !ok { continue } body := stdhtml.UnescapeString(m[2]) out = append(out, Snippet{ Index: i, Lang: lang, Ext: t.ext, Label: t.label, Lines: strings.Count(strings.TrimRight(body, "\n"), "\n") + 1, Bytes: len(body), Filename: filenameHint(body, t.ext), }) } return out }