Commit c757113
Eric Bower
·
2026-05-12 00:06:58 -0400 EDT
parent cce1481
chore: better text file detection
1 files changed,
+64,
-6
M
main.go
M
main.go
+64,
-6
| ... | ... | @@ -9,7 +9,6 @@ import ( | |
| 9 | 9 | "html/template" | |
| 10 | 10 | "io" | |
| 11 | 11 | "log/slog" | |
| 12 | - | "math" | |
| 13 | 12 | "os" | |
| 14 | 13 | "path/filepath" | |
| 15 | 14 | "sort" |
| ... | ... | @@ -284,13 +283,72 @@ func isText(s string) bool { | |
| 284 | 283 | return true | |
| 285 | 284 | } | |
| 286 | 285 | ||
| 286 | + | // newSet builds a string set from a list of values for O(1) lookup. | |
| 287 | + | func newSet(vals ...string) map[string]struct{} { | |
| 288 | + | m := make(map[string]struct{}, len(vals)) | |
| 289 | + | for _, v := range vals { | |
| 290 | + | m[v] = struct{}{} | |
| 291 | + | } | |
| 292 | + | return m | |
| 293 | + | } | |
| 294 | + | ||
| 295 | + | // knownBinaryExts lists extensions that are always binary regardless of content. | |
| 296 | + | var knownBinaryExts = newSet( | |
| 297 | + | // images | |
| 298 | + | ".png", ".jpg", ".jpeg", ".gif", ".bmp", ".ico", ".webp", ".svg", ".tiff", ".tif", ".psd", | |
| 299 | + | // archives / compressed | |
| 300 | + | ".zip", ".tar", ".gz", ".bz2", ".xz", ".7z", ".rar", ".tgz", ".war", ".jar", | |
| 301 | + | // documents | |
| 302 | + | ".pdf", ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", | |
| 303 | + | // executables / libraries | |
| 304 | + | ".exe", ".dll", ".so", ".dylib", ".a", ".o", | |
| 305 | + | // fonts | |
| 306 | + | ".ttf", ".otf", ".woff", ".woff2", ".eot", | |
| 307 | + | // audio / video | |
| 308 | + | ".mp3", ".mp4", ".avi", ".mov", ".wav", ".flac", ".ogg", ".webm", | |
| 309 | + | // data / serialized | |
| 310 | + | ".pb", ".msgpack", ".parquet", ".avro", | |
| 311 | + | // other | |
| 312 | + | ".class", ".pyc", ".pyo", ".wasm", ".db", ".sqlite", ".sqlite3", | |
| 313 | + | ) | |
| 314 | + | ||
| 315 | + | // knownTextExts lists extensions that are always text regardless of content. | |
| 316 | + | var knownTextExts = newSet( | |
| 317 | + | // code | |
| 318 | + | ".go", ".py", ".js", ".ts", ".tsx", ".jsx", ".java", ".c", ".h", ".cpp", ".hpp", ".rs", ".rb", ".php", ".pl", ".sh", ".bash", ".zsh", ".fish", ".ps1", | |
| 319 | + | // markup / data | |
| 320 | + | ".html", ".htm", ".css", ".scss", ".less", ".xml", ".json", ".yaml", ".yml", ".toml", ".ini", ".cfg", ".conf", | |
| 321 | + | // docs | |
| 322 | + | ".md", ".markdown", ".txt", ".rst", ".tex", ".bib", ".csv", ".tsv", | |
| 323 | + | // config / build | |
| 324 | + | ".Dockerfile", ".dockerignore", ".gitignore", ".gitattributes", ".editorconfig", | |
| 325 | + | // other text | |
| 326 | + | ".diff", ".patch", ".log", ".sql", ".graphql", ".proto", ".makefile", ".cmake", | |
| 327 | + | ) | |
| 328 | + | ||
| 287 | 329 | // isTextFile reports whether the file has a known extension indicating | |
| 288 | 330 | // a text file, or if a significant chunk of the specified file looks like | |
| 289 | 331 | // correct UTF-8; that is, if it is likely that the file contains human- | |
| 290 | - | // readable text. | |
| 291 | - | func isTextFile(text string) bool { | |
| 292 | - | num := math.Min(float64(len(text)), 1024) | |
| 293 | - | return isText(text[0:int(num)]) | |
| 332 | + | // readable text. Extension check takes priority as a fast path. | |
| 333 | + | func isTextFile(filename, text string) bool { | |
| 334 | + | ext := strings.ToLower(filepath.Ext(filename)) | |
| 335 | + | ||
| 336 | + | // fast path: known binary extension | |
| 337 | + | if _, ok := knownBinaryExts[ext]; ok { | |
| 338 | + | return false | |
| 339 | + | } | |
| 340 | + | // fast path: known text extension | |
| 341 | + | if _, ok := knownTextExts[ext]; ok { | |
| 342 | + | return true | |
| 343 | + | } | |
| 344 | + | // also check the full filename for extensionless known text files | |
| 345 | + | nameLower := strings.ToLower(filename) | |
| 346 | + | if _, ok := knownTextExts["."+nameLower]; ok { | |
| 347 | + | return true | |
| 348 | + | } | |
| 349 | + | ||
| 350 | + | // fallback: inspect bytes | |
| 351 | + | return isText(text) | |
| 294 | 352 | } | |
| 295 | 353 | ||
| 296 | 354 | func toPretty(b int64) string { |
| ... | ... | @@ -454,7 +512,7 @@ func (c *Config) writeHTMLTreeFile(pageData *PageData, treeItem *TreeItem) strin | |
| 454 | 512 | bail(err) | |
| 455 | 513 | str := string(b) | |
| 456 | 514 | ||
| 457 | - | treeItem.IsTextFile = isTextFile(str) | |
| 515 | + | treeItem.IsTextFile = isTextFile(treeItem.Entry.Name(), str) | |
| 458 | 516 | ||
| 459 | 517 | contents := "binary file, cannot display" | |
| 460 | 518 | if treeItem.IsTextFile { |