Skip to content

Commit

Permalink
Also display images when serving Markdown documents with -m
Browse files Browse the repository at this point in the history
  • Loading branch information
xyproto committed Oct 20, 2023
1 parent ecbfc47 commit c315f83
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 3 deletions.
33 changes: 32 additions & 1 deletion engine/static.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"strings"
"time"

"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/parser"
log "github.com/sirupsen/logrus"
"github.com/xyproto/algernon/utils"
"github.com/xyproto/datablock"
Expand Down Expand Up @@ -63,6 +65,7 @@ func (ac *Config) shortInfoAndOpen(filename, colonPort string, cancelChannel cha

// ServeStaticFile is a convenience function for serving only a single file.
// It can be used as a quick and easy way to view a README.md file.
// Will also serve local images if the resulting HTML contains them.
func (ac *Config) ServeStaticFile(filename, colonPort string) error {
log.Info("Single file mode. Not using the regular parameters.")

Expand All @@ -71,15 +74,42 @@ func (ac *Config) ServeStaticFile(filename, colonPort string) error {
ac.shortInfoAndOpen(filename, colonPort, cancelChannel)

mux := http.NewServeMux()

// 64 MiB cache, use cache compression, no per-file size limit, use best gzip compression, compress for size not for speed
ac.cache = datablock.NewFileCache(defaultStaticCacheSize, true, 0, false, 0)

if ac.markdownMode {
// Discover all local images mentioned in the Markdown document
var localImages []string
if markdownData, err := ac.cache.Read(filename, true); err == nil { // success
// Create a Markdown parser with the desired extensions
extensions := parser.CommonExtensions | parser.AutoHeadingIDs
mdParser := parser.NewWithExtensions(extensions)
// Convert from Markdown to HTML
htmlbody := markdown.ToHTML(markdownData.MustData(), mdParser, nil)
localImages = utils.ExtractLocalImagePaths(string(htmlbody))
}

// Serve all local images mentioned in the Markdown document.
// If a file is not found, then the FilePage function will handle it.
for _, localImage := range localImages {
mux.HandleFunc("/"+localImage, func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Server", ac.versionString)
ac.FilePage(w, req, localImage, ac.defaultLuaDataFilename)
})
}
}

// Prepare to serve the given filename

mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Server", ac.versionString)
ac.FilePage(w, req, filename, ac.defaultLuaDataFilename)
})

HTTPserver := ac.NewGracefulServer(mux, false, ac.serverHost+colonPort)

// Attempt to serve just the single file
// Attempt to serve the handler functions above
if errServe := HTTPserver.ListenAndServe(); errServe != nil {
// If it fails, try several times, increasing the port by 1 each time
for i := 0; i < maxAttemptsAtIncreasingPortNumber; i++ {
Expand All @@ -106,5 +136,6 @@ func (ac *Config) ServeStaticFile(filename, colonPort string) error {
// Several attempts failed
return errServe
}

return nil
}
4 changes: 2 additions & 2 deletions utils/stringmanip.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ func WriteStatus(sb *strings.Builder, title string, flags map[string]bool) {

// ExtractLocalImagePaths can be used to find local image filenames that are included in the given HTML
func ExtractLocalImagePaths(html string) []string {
// Regular expression to match image paths in <img ref="...">
r := regexp.MustCompile(`<img ref="([^"]+)"`)
// Regular expression to match image paths in <img src="...">
r := regexp.MustCompile(`<img src="([^"]+)"`)
matches := r.FindAllStringSubmatch(html, -1)
paths := make([]string, 0, len(matches))
for _, match := range matches {
Expand Down

0 comments on commit c315f83

Please sign in to comment.