diff --git a/pkg/web/webui_blob.go b/pkg/web/webui_blob.go index 6fa96238c6d7706bbc5952fa9148936109b77ecd..a3e2177fee8b8ce9d0b3e775254c98b2602fd8ac 100644 --- a/pkg/web/webui_blob.go +++ b/pkg/web/webui_blob.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" + "github.com/alecthomas/chroma/v2" "github.com/alecthomas/chroma/v2/formatters/html" "github.com/alecthomas/chroma/v2/lexers" "github.com/alecthomas/chroma/v2/styles" @@ -88,7 +89,7 @@ func repoBlob(w http.ResponseWriter, r *http.Request) { defaultBranch := getDefaultBranch(gr) - isMarkdown := isMarkdownFile(path) + isMarkdown := isMarkdownFile(path, content) showSource := r.URL.Query().Get("source") == "1" var renderedHTML template.HTML @@ -170,10 +171,20 @@ func repoBlobRaw(w http.ResponseWriter, r *http.Request) { return } - contentType := mime.TypeByExtension(filepath.Ext(path)) - if contentType == "" { + ext := filepath.Ext(path) + var contentType string + + // For files without extensions, prioritize content detection + if ext == "" { contentType = http.DetectContentType(content) + } else { + // For files with extensions, try MIME type lookup first + contentType = mime.TypeByExtension(ext) + if contentType == "" { + contentType = http.DetectContentType(content) + } } + if strings.HasPrefix(contentType, "text/") && !strings.Contains(contentType, "charset") { contentType += "; charset=utf-8" } @@ -198,18 +209,45 @@ func isBinaryContent(content []byte) bool { return false } -// isMarkdownFile checks if a file has a markdown extension. -func isMarkdownFile(path string) bool { +// isMarkdownFile checks if a file has a markdown extension or contains markdown content. +func isMarkdownFile(path string, content []byte) bool { ext := strings.ToLower(filepath.Ext(path)) - return ext == ".md" || ext == ".markdown" + if ext == ".md" || ext == ".markdown" { + return true + } + + // For files without extensions, use Chroma's lexer detection + if ext == "" && len(content) > 0 { + lexer := lexers.Analyse(string(content)) + if lexer != nil { + config := lexer.Config() + name := strings.ToLower(config.Name) + return name == "markdown" || name == "md" + } + } + + return false } // highlightCode applies syntax highlighting to code and returns HTML. func highlightCode(path string, content []byte) template.HTML { - lexer := lexers.Match(path) - if lexer == nil { + var lexer chroma.Lexer + ext := filepath.Ext(path) + + // For files without extensions, prioritize content analysis to detect shebangs + if ext == "" { lexer = lexers.Analyse(string(content)) + if lexer == nil { + lexer = lexers.Match(path) + } + } else { + // For files with extensions, try filename matching first + lexer = lexers.Match(path) + if lexer == nil { + lexer = lexers.Analyse(string(content)) + } } + if lexer == nil { lexer = lexers.Fallback }