From 245d6e0fa0b8caa29ae610f50404915bd2be8a23 Mon Sep 17 00:00:00 2001 From: zaire Date: Mon, 16 Mar 2026 20:41:16 +0100 Subject: [PATCH] fixed prior merge conflic causing double'd embed, added readme parser with full markdown, added readme render to HTML, renamed filepath to fpath to use FilePath.Join for case insensitivity, fixed ident in html src (inline css), added readme css with proper accents --- go.mod | 2 + go.sum | 2 + main.go | 185 ++++++++++++++++++++++++--------------- templates/dir.html | 214 ++++++++++++++++++++++++++++++++------------- 4 files changed, 270 insertions(+), 133 deletions(-) create mode 100644 go.sum diff --git a/go.mod b/go.mod index c1104b3..0b80eac 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module forge.arimelody.space/ari/indir go 1.24.3 + +require github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..52d2bfd --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab h1:VYNivV7P8IRHUam2swVUNkhIdp0LRRFKe4hXNnoZKTc= +github.com/gomarkdown/markdown v0.0.0-20260217112301-37c66b85d6ab/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA= diff --git a/main.go b/main.go index a00ecd0..778ec1b 100755 --- a/main.go +++ b/main.go @@ -1,6 +1,7 @@ package main import ( + _ "embed" "fmt" "html/template" "io/fs" @@ -8,11 +9,15 @@ import ( "net/http" "os" "path" + "path/filepath" "slices" "strconv" "strings" "time" - _ "embed" + + "github.com/gomarkdown/markdown" + "github.com/gomarkdown/markdown/html" + "github.com/gomarkdown/markdown/parser" ) //go:embed templates/dir.html @@ -20,25 +25,25 @@ var dirTemplateSrc string type ( Directory struct { - Name string - Root bool - Files []*File + Name string + Root bool + Files []*File + Readme template.HTML } File struct { - Name string - URI string - IsDir bool - Size string + Name string + URI string + IsDir bool + Size string ModifiedDate string } ) -//go:embed templates/dir.html -var dirHTML string - func main() { - if len(os.Args) < 2 { printHelp() } + if len(os.Args) < 2 { + printHelp() + } host := "127.0.0.1" port := 8080 @@ -47,7 +52,9 @@ func main() { filesDir := "" i := 1 for { - if i >= len(os.Args) { break } + if i >= len(os.Args) { + break + } switch os.Args[i] { case "-h": fallthrough @@ -55,7 +62,7 @@ func main() { printHelp() case "--host": - if i + 1 >= len(os.Args) { + if i+1 >= len(os.Args) { fmt.Fprintf(os.Stderr, "fatal: --host argument cannot be empty\n") os.Exit(1) } @@ -63,7 +70,7 @@ func main() { host = os.Args[i] case "--port": - if i + 1 >= len(os.Args) { + if i+1 >= len(os.Args) { fmt.Fprintf(os.Stderr, "fatal: --port argument cannot be empty\n") os.Exit(1) } @@ -76,14 +83,18 @@ func main() { } case "--root": - if i + 1 >= len(os.Args) { + if i+1 >= len(os.Args) { fmt.Fprintf(os.Stderr, "fatal: --root argument cannot be empty\n") os.Exit(1) } i++ root = os.Args[i] - if !strings.HasPrefix(root, "/") { root = "/" + root } - if !strings.HasSuffix(root, "/") { root += "/" } + if !strings.HasPrefix(root, "/") { + root = "/" + root + } + if !strings.HasSuffix(root, "/") { + root += "/" + } default: if len(filesDir) > 0 { @@ -111,7 +122,9 @@ func main() { } fmt.Printf("Now hosting \"%s\" at http://%s:%d", filesDir, host, port) - if root != "/" { fmt.Printf("%s", root) } + if root != "/" { + fmt.Printf("%s", root) + } fmt.Println(".") http.ListenAndServe(fmt.Sprintf("%s:%d", host, port), HTTPLog(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -121,8 +134,8 @@ func main() { } isRoot := r.URL.Path == root - filepath := path.Join(filesDir, strings.TrimPrefix(r.URL.Path, root)) - info, err := os.Stat(filepath) + fpath := path.Join(filesDir, strings.TrimPrefix(r.URL.Path, root)) + info, err := os.Stat(fpath) if err != nil { http.NotFound(w, r) return @@ -135,7 +148,7 @@ func main() { return } - file, err := os.Open(filepath) + file, err := os.Open(fpath) if err != nil { http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError) return @@ -144,7 +157,7 @@ func main() { defer func() { err := file.Close() if err != nil { - fmt.Fprintf(os.Stderr, "failed to close file %s: %v\n", filepath, err) + fmt.Fprintf(os.Stderr, "failed to close file %s: %v\n", fpath, err) } }() @@ -159,30 +172,54 @@ func main() { _, err = file.WriteTo(w) if err != nil { - fmt.Fprintf(os.Stderr, "failed to send file %s: %v\n", filepath, err) + fmt.Fprintf(os.Stderr, "failed to send file %s: %v\n", fpath, err) } return } if !strings.HasSuffix(r.URL.Path, "/") { - http.Redirect(w, r, r.URL.Path + "/", http.StatusFound) + http.Redirect(w, r, r.URL.Path+"/", http.StatusFound) return } - data := Directory{ - Root: isRoot, - Name: r.URL.Path, - Files: []*File{}, + // embeded readme + var readmeHTML template.HTML + entries, err := os.ReadDir(fpath) + if err == nil { + for _, entry := range entries { + if strings.EqualFold(entry.Name(), "readme.md") { + src, err := os.ReadFile(filepath.Join(fpath, entry.Name())) + if err == nil { + mdFlags := html.CommonFlags | html.HrefTargetBlank + mdRenderer := html.NewRenderer(html.RendererOptions{Flags: mdFlags}) + mdParser := parser.NewWithExtensions(parser.CommonExtensions | parser.AutoHeadingIDs) + md := mdParser.Parse(src) + readmeHTML = template.HTML(markdown.Render(md, mdRenderer)) + } + break + } + } } - fsDir := os.DirFS(filepath) + data := Directory{ + Root: isRoot, + Name: r.URL.Path, + Files: []*File{}, + Readme: readmeHTML, + } + + fsDir := os.DirFS(fpath) directories, err := fs.ReadDir(fsDir, ".") for _, dir := range directories { name := dir.Name() - if slices.Contains(ignoredFiles, name) { continue } + if slices.Contains(ignoredFiles, name) { + continue + } info, err := dir.Info() - if err != nil { continue } + if err != nil { + continue + } var uri string if isRoot { @@ -213,10 +250,10 @@ func main() { dateStr := info.ModTime().Format("02-Jan-2006 15:04") data.Files = append(data.Files, &File{ - Name: name, - URI: uri, - IsDir: info.IsDir(), - Size: sizeStr, + Name: name, + URI: uri, + IsDir: info.IsDir(), + Size: sizeStr, ModifiedDate: dateStr, }) } @@ -232,52 +269,60 @@ func main() { } type LoggingResponseWriter struct { - http.ResponseWriter - Status int + http.ResponseWriter + Status int } -var COL_Reset = "\033[0m" -var COL_Red = "\033[31m" -var COL_Green = "\033[32m" +var COL_Reset = "\033[0m" +var COL_Red = "\033[31m" +var COL_Green = "\033[32m" var COL_Yellow = "\033[33m" -var COL_Blue = "\033[34m" +var COL_Blue = "\033[34m" var COL_Purple = "\033[35m" -var COL_Cyan = "\033[36m" -var COL_Gray = "\033[37m" -var COL_White = "\033[97m" +var COL_Cyan = "\033[36m" +var COL_Gray = "\033[37m" +var COL_White = "\033[97m" func HTTPLog(next http.Handler) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - start := time.Now() + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + start := time.Now() - lrw := LoggingResponseWriter{w, http.StatusOK} + lrw := LoggingResponseWriter{w, http.StatusOK} - next.ServeHTTP(&lrw, r) + next.ServeHTTP(&lrw, r) - after := time.Now() - difference := (after.Nanosecond() - start.Nanosecond()) / 1_000_000 - elapsed := "<1" - if difference >= 1 { - elapsed = strconv.Itoa(difference) - } + after := time.Now() + difference := (after.Nanosecond() - start.Nanosecond()) / 1_000_000 + elapsed := "<1" + if difference >= 1 { + elapsed = strconv.Itoa(difference) + } - statusColour := COL_Reset + statusColour := COL_Reset - if lrw.Status - 600 <= 0 { statusColour = COL_Red } - if lrw.Status - 500 <= 0 { statusColour = COL_Yellow } - if lrw.Status - 400 <= 0 { statusColour = COL_White } - if lrw.Status - 300 <= 0 { statusColour = COL_Green } + if lrw.Status-600 <= 0 { + statusColour = COL_Red + } + if lrw.Status-500 <= 0 { + statusColour = COL_Yellow + } + if lrw.Status-400 <= 0 { + statusColour = COL_White + } + if lrw.Status-300 <= 0 { + statusColour = COL_Green + } - fmt.Printf("[%s] %s %s - %s%d%s (%sms) (%s)\n", - after.Format(time.UnixDate), - r.Method, - r.URL.Path, - statusColour, - lrw.Status, - COL_Reset, - elapsed, - r.Header["User-Agent"][0]) - }) + fmt.Printf("[%s] %s %s - %s%d%s (%sms) (%s)\n", + after.Format(time.UnixDate), + r.Method, + r.URL.Path, + statusColour, + lrw.Status, + COL_Reset, + elapsed, + r.Header["User-Agent"][0]) + }) } func printHelp() { diff --git a/templates/dir.html b/templates/dir.html index 562cc95..6d20006 100644 --- a/templates/dir.html +++ b/templates/dir.html @@ -1,82 +1,157 @@ - + - - + + Files in {{.Name}}

Files in {{.Name}}

-
+
@@ -89,8 +164,7 @@ footer { - {{end}} - {{range .Files}} + {{end}} {{range .Files}} @@ -98,10 +172,24 @@ footer { {{end}}
Name
{{.Name}} {{if .IsDir}}—{{else}}{{.Size}}{{end}}
-
+
+ {{if .Readme}} +
+

README

+
+ {{.Readme}} +
+ {{end}}