diff --git a/internal/web/web.go b/internal/web/web.go index 3a91577..cea7bb1 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -10,6 +10,7 @@ import ( "encoding/hex" "fmt" "html/template" + "io" "io/fs" "log" "net/http" @@ -232,6 +233,10 @@ func (h *Handlers) renderPageStatus(w http.ResponseWriter, name string, status i } func (h *Handlers) renderPaste(w http.ResponseWriter, row *store.PasteRow, justCreated bool, deletionToken string, readsRemaining *int) { + // #221: a non-image attachment is real text; derive its line count from + // the blob instead of the (empty) stored content, or details show 1 line. + // Image pastes render no code box, so their line count is meaningless + // and pinned to 1 below. lines := strings.Count(row.Content, "\n") + 1 gutter := "" for i := 1; i <= lines; i++ { @@ -257,6 +262,20 @@ func (h *Handlers) renderPaste(w http.ResponseWriter, row *store.PasteRow, justC sizeBytes := len(row.Content) if attachment != nil { sizeBytes = int(attachment.Size) + // #221: the blob replaced the stored text. For non-image + // attachments read the real text back to derive the line count + // (details showed "1 line" for any attachment); image pastes + // render no code box, so leave the meaningless 1. + isImage := strings.HasPrefix(attachment.Mime, "image/") + if !isImage { + if rc, err := h.Store.Blobs().Get(attachment.PasteID + "/" + attachment.SHA256); err == nil { + b, rerr := io.ReadAll(rc) + rc.Close() + if rerr == nil { + lines = strings.Count(string(b), "\n") + 1 + } + } + } } summary := fmt.Sprintf("%s · %s · %d views · %s", lang, humanSize(sizeBytes), row.ViewCount, agoString(row.CreatedAt)) data := map[string]any{