shithub: hell

Download patch

ref: 906489cfcc61b985c2300936ea22ec5fedc2f013
parent: 20b1d780fd11bca49019e07c48f97fd0cfc35dd0
parent: 41fec90853f89f2b233f49d0ff9b238f54022036
author: penny64 <penny64@noreply.codeberg.org>
date: Sat Oct 4 20:34:11 EDT 2025

Merge pull request 'Some work on a new post formatting system + /cat to echo posts' (#4) from post_templates into main

--- a/commands.go
+++ b/commands.go
@@ -4,7 +4,7 @@
 	"strings"
 )
 
-var commands = []string{"examine", "reply", "like", "thread", "open", "prev", "download", "dm", "rt", "parent", "children", "rm", "mark", "unmark", "account", "import", "pause", "resume", "url", "fpost", "ufpost", "edit", "notice", "stats", "next", "view", "bookmarks", "follow", "unfollow", "likes", "help", "reload", "attach", "detach", "pinned"}
+var commands = []string{"examine", "reply", "like", "thread", "open", "prev", "download", "dm", "rt", "parent", "children", "rm", "mark", "unmark", "account", "import", "pause", "resume", "url", "fpost", "ufpost", "edit", "notice", "stats", "next", "view", "bookmarks", "follow", "unfollow", "likes", "help", "reload", "attach", "detach", "pinned", "cat"}
 
 func processInput(input string) (command string, arguments string, found bool) {
 
--- a/help.go
+++ b/help.go
@@ -14,6 +14,7 @@
   /reply <index> content       Reply to status by index.
   /like <index>                Favorite status by index.
   /thread <index>              View thread the indexed status is part of.
+  /cat <index>                 Output a status with details (liker, replies, etc).
   /open <index>                Open indexed status in the system web browser.
   /download <index>            Download attached files/media from status.
   /view <index>                Preview status media in media viewer.
--- a/main.go
+++ b/main.go
@@ -88,6 +88,11 @@
 			} else {
 				postItem, postOK = homeMap[lastindex]
 			}
+			
+			// "." refers to most recently acted on status
+			if !foundindex && index == "." {
+				index = lastindex
+			}
 
 			//Okay now see if the post we end up with is a reblog
 			if postOK {
@@ -245,6 +250,18 @@
 
 			//Commands require status indexes
 			switch command {
+			case "cat":
+				if !postOK {
+					fmt.Println("cat: no valid status")
+					return
+				}
+				if index == "" {
+					index = lastindex
+				}
+				formatter := &StatusFormatter{hc: hc, status: postItem, postContext: hc.ctxref}
+				fmt.Println(hyphenate(fmt.Sprintf("%s> %s %s\n", index, formatter.username(), formatter.statusContent())))
+				fmt.Print(formatter.detailLine())
+				return
 			case "like":
 				_, err := client.Favourite(context.Background(), postItem.ID)
 				if err != nil {
--- a/mastodon.go
+++ b/mastodon.go
@@ -1,7 +1,6 @@
 package main
 
 import (
-	"bytes"
 	"context"
 	"fmt"
 	"log"
@@ -11,7 +10,6 @@
 
 	mastodon "codeberg.org/penny64/hellclient-go-mastodon"
 	"github.com/k3a/html2text"
-	"golang.org/x/net/html"
 )
 
 func ConfigureClient() *mastodon.Client {
@@ -74,74 +72,6 @@
 
 	c := mastodon.NewClient(config)
 	return c
-}
-
-func (hc *Hellclient) renderStatus(content string, index string) (string, map[string]string) {
-	doc, err := html.Parse(strings.NewReader(content))
-	if err != nil {
-		fmt.Printf("Failed to parse status\n")
-		return "", nil
-	}
-
-	//clear out the url map
-	hc.urlMap[index] = []string{}
-	preformats := make(map[string]string)
-
-	for node := range doc.Descendants() {
-		if (node.Data == "pre" || node.Data == "") && node.FirstChild != nil {
-			preformats[fmt.Sprintf("%p%p", hc, node.FirstChild)] = node.FirstChild.Data
-			node.FirstChild.Data = fmt.Sprintf("%p%p", hc, node.FirstChild)
-		}
-		if node.Data == "a" && node.Type == html.ElementNode {
-			ismention := false
-			href := ""
-
-			for attr := range node.Attr {
-				if node.Attr[attr].Key == "class" && strings.Contains(node.Attr[attr].Val, "mention") {
-					node.Data = "div"
-					ismention = true
-					continue
-				}
-				if node.Attr[attr].Key == "href" {
-					href = node.Attr[attr].Val
-					//Replace the href with the description if the URL has one
-					if node.FirstChild != nil && node.FirstChild.Type == html.TextNode && !ismention {
-						node.Attr[attr].Val = fmt.Sprintf("(%s)", node.FirstChild.Data)
-					} else {
-						href = href + " "
-					}
-				}
-			}
-			if !ismention {
-				hc.urlMap[index] = append(hc.urlMap[index], href)
-				refnode := &html.Node{
-					Type: html.TextNode,
-					Data: fmt.Sprintf(" [%v]", len(hc.urlMap[index]))}
-				if node.Parent != nil {
-					node.Parent.InsertBefore(refnode, node.NextSibling)
-				}
-			}
-		}
-	}
-
-	//Rip off the HTML body the parser made for us
-	for node := range doc.Descendants() {
-		if node.Data == "body" {
-			node.Type = html.DocumentNode
-			doc = node
-		}
-	}
-
-	var rendered bytes.Buffer
-	err = html.Render(&rendered, doc)
-
-	if err != nil {
-		return "", nil
-	}
-
-	renderedPlainText := rendered.String()
-
-	return renderedPlainText, preformats
 }
 
 func processStatusHints(toot *mastodon.Toot, postpointer *string) {
--- /dev/null
+++ b/renderer.go
@@ -1,0 +1,127 @@
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"strings"
+
+	"github.com/k3a/html2text"
+
+	mastodon "codeberg.org/penny64/hellclient-go-mastodon"
+	"golang.org/x/net/html"
+)
+
+type StatusFormatter struct {
+	hc          *Hellclient
+	status      *mastodon.Status
+	postContext *postref
+}
+
+// Returns the rendered content of a status
+func (st *StatusFormatter) statusContent() string {
+	renderedPost, plaintexts := st.hc.renderStatus(st.status.Content, st.postContext.ref)
+	for key, plaintext := range plaintexts {
+		renderedPost = strings.Replace(renderedPost, key, plaintext, 1)
+	}
+	renderedPost = html2text.HTML2Text(renderedPost)
+	return renderedPost
+}
+
+func (st *StatusFormatter) username() string {
+	var sb strings.Builder
+	sb.WriteString("<")
+	sb.WriteString(st.status.Account.Username)
+	sb.WriteString(">")
+	return sb.String()
+}
+
+func (st *StatusFormatter) detailLine() string {
+	var sb strings.Builder
+	var items []string
+	if st.status.FavouritesCount > 0 {
+		items = append(items, fmt.Sprintf("Likes:%v", st.status.FavouritesCount))
+	}
+	if st.status.ReblogsCount > 0 {
+		items = append(items, fmt.Sprintf("Reblogs:%v", st.status.ReblogsCount))	
+	}
+	if st.status.RepliesCount > 0 {
+		items = append(items, fmt.Sprintf("Replies:%v", st.status.RepliesCount))
+	}
+
+	for i := range items {
+		sb.WriteString(items[i])
+		if i != len(items) - 1 {
+			sb.WriteString(" ")
+		}
+	}
+	sb.WriteString("\n")
+	return sb.String()
+}
+
+func (hc *Hellclient) renderStatus(content string, index string) (string, map[string]string) {
+	doc, err := html.Parse(strings.NewReader(content))
+	if err != nil {
+		fmt.Printf("Failed to parse status\n")
+		return "", nil
+	}
+
+	//clear out the url map
+	hc.urlMap[index] = []string{}
+	preformats := make(map[string]string)
+
+	for node := range doc.Descendants() {
+		if (node.Data == "pre" || node.Data == "") && node.FirstChild != nil {
+			preformats[fmt.Sprintf("%p%p", hc, node.FirstChild)] = node.FirstChild.Data
+			node.FirstChild.Data = fmt.Sprintf("%p%p", hc, node.FirstChild)
+		}
+		if node.Data == "a" && node.Type == html.ElementNode {
+			ismention := false
+			href := ""
+
+			for attr := range node.Attr {
+				if node.Attr[attr].Key == "class" && strings.Contains(node.Attr[attr].Val, "mention") {
+					node.Data = "div"
+					ismention = true
+					continue
+				}
+				if node.Attr[attr].Key == "href" {
+					href = node.Attr[attr].Val
+					//Replace the href with the description if the URL has one
+					if node.FirstChild != nil && node.FirstChild.Type == html.TextNode && !ismention {
+						node.Attr[attr].Val = fmt.Sprintf("(%s)", node.FirstChild.Data)
+					} else {
+						href = href + " "
+					}
+				}
+			}
+			if !ismention {
+				hc.urlMap[index] = append(hc.urlMap[index], href)
+				refnode := &html.Node{
+					Type: html.TextNode,
+					Data: fmt.Sprintf(" [%v]", len(hc.urlMap[index]))}
+				if node.Parent != nil {
+					node.Parent.InsertBefore(refnode, node.NextSibling)
+				}
+			}
+		}
+	}
+
+	//Rip off the HTML body the parser made for us
+	for node := range doc.Descendants() {
+		if node.Data == "body" {
+			node.Type = html.DocumentNode
+			doc = node
+		}
+	}
+
+	var rendered bytes.Buffer
+	err = html.Render(&rendered, doc)
+
+	if err != nil {
+		return "", nil
+	}
+
+	renderedPlainText := rendered.String()
+
+	return renderedPlainText, preformats
+}
--