ref: 4a7a258c3973ea05fdbc340150b780c4155c02a9
parent: 5bb44c5f5c1bff3a930f8919f3a72c5d13c1f960
author: penny <penny@limitedideas.org>
date: Sat Aug 9 15:36:33 EDT 2025
Add a pause command and refactor a little to support it
--- a/commands.go
+++ b/commands.go
@@ -4,7 +4,7 @@
"strings"
)
-var commands = []string{"examine", "reply", "like", "thread", "open", "preview", "download", "dm", "rt", "parent", "children", "rm", "mark", "unmark", "account", "vim", "import"}+var commands = []string{"examine", "reply", "like", "thread", "open", "preview", "download", "dm", "rt", "parent", "children", "rm", "mark", "unmark", "account", "vim", "import", "pause", "resume"} func processInput(input string) (command string, arguments string) {--- /dev/null
+++ b/hellclient.go
@@ -1,0 +1,30 @@
+package main
+
+import (
+ "github.com/chzyer/readline"
+ "strings"
+)
+
+type Hellclient struct {+ isPaused bool
+ rl *readline.Instance
+}
+
+func NewHellclient() (*Hellclient, error) {+ rl, err := readline.New("> ")+ if err != nil {+ return nil, err
+ }
+ return &Hellclient{rl: rl}, nil+}
+
+func (hc *Hellclient) updatePrompt() {+ var sb strings.Builder
+ if hc.isPaused {+ sb.WriteString("STREAMING PAUSED ")+ }
+ sb.WriteString("> ")+ hc.rl.SetPrompt(sb.String())
+}
+
+
--- a/main.go
+++ b/main.go
@@ -8,7 +8,6 @@
"os/exec"
"strings"
- "github.com/chzyer/readline"
"github.com/mattn/go-mastodon"
)
@@ -21,7 +20,12 @@
client := initClient(account)
- rl, _ := readline.New("> ")+ hc, err := NewHellclient()
+ rl := hc.rl
+ if err != nil {+ fmt.Printf("Error creating client: %v\n", err)+ return
+ }
//Horrible io pipe hack
//Replaces system stdout with the readline one
@@ -44,7 +48,8 @@
return
}
- go StreamHomeTimeline(client, rl, homeMap)
+ pauseChan := make(chan bool)
+ go StreamHomeTimeline(client, homeMap, pauseChan)
for {line, err := rl.Readline()
@@ -70,6 +75,16 @@
//Contextual commands that need to handle their own requirements
switch command {+ case "pause":
+ hc.isPaused = true
+ hc.updatePrompt()
+ pauseChan <- true
+ continue
+ case "resume":
+ hc.isPaused = false
+ hc.updatePrompt()
+ pauseChan <- false
+ continue
case "rm":
if !postOK && recentpost != nil {err = client.DeleteStatus(context.Background(), recentpost.ID)
--- a/mastodon.go
+++ b/mastodon.go
@@ -8,7 +8,6 @@
"net/url"
"strings"
- "github.com/chzyer/readline"
"github.com/k3a/html2text"
"github.com/mattn/go-mastodon"
"golang.org/x/net/html"
@@ -229,7 +228,7 @@
return
}
-func StreamHomeTimeline(client *mastodon.Client, rl *readline.Instance, postMap map[string]*mastodon.Status) {+func StreamHomeTimeline(client *mastodon.Client, postMap map[string]*mastodon.Status, pauseChan <-chan bool) {ctx, cancel := context.WithCancel(context.Background())
defer cancel()
@@ -244,11 +243,27 @@
postref := "a"
plaintext := ""
idmap := make(map[mastodon.ID]*mastodon.Status)
+ isPaused := false
+ var actionBuffer []func()
// Enter a loop to continuously listen for events from the event channel.
for { select {+ case newPauseState := <-pauseChan:
+ if newPauseState == isPaused {+ continue
+ }
+ isPaused = newPauseState
+
+ if !isPaused {+ fmt.Println("Output resumed")+ for _, action := range actionBuffer {+ action()
+ }
+ actionBuffer = nil
+ }
case event, ok := <-eventCh: // Read from the event channel, checking 'ok' for closure
+
if !ok {// The channel was closed, which indicates the stream has ended.
fmt.Println("Stream closed.\n")@@ -257,14 +272,30 @@
switch post := event.(type) {case *mastodon.UpdateEvent:
- post.Status = printPost(postref, post.Status)
+ if isPaused {+ currentPostRef := postref
+ capturedPost := post
+ actionBuffer = append(actionBuffer, func() {+ capturedPost.Status = printPost(currentPostRef, capturedPost.Status)
+ })
+ } else {+ post.Status = printPost(postref, post.Status)
+ }
saveRef(postMap, post.Status, postref)
idmap[post.Status.ID] = post.Status
postref = IncrementString(postref)
case *mastodon.UpdateEditEvent:
+ if isPaused {+ currentPostRef := postref
+ capturedPost := post
+ actionBuffer = append(actionBuffer, func() {+ fmt.Println(formatEdit(capturedPost.Status, currentPostRef))
+ })
+ } else {+ fmt.Println(formatEdit(post.Status, postref))
+ }
saveRef(postMap, post.Status, postref)
- fmt.Println(formatEdit(post.Status, postref))
postref = IncrementString(postref)
idmap[post.Status.ID] = post.Status
@@ -272,27 +303,60 @@
deleted, ok := idmap[post.ID]
//didn't have this in the cache
if !ok {- fmt.Printf("Deleted: ID %v\n", post.ID)+ capturedID := post.ID
+ if isPaused {+ actionBuffer = append(actionBuffer, func() {+ fmt.Printf("Deleted: ID %v\n", capturedID)+ })
+ } else {+ fmt.Printf("Deleted: ID %v\n", capturedID)+ }
continue
}
- printPostDetailed("", deleted, "Deleted:")+ if isPaused {+ actionBuffer = append(actionBuffer, func() {+ printPostDetailed("", deleted, "Deleted:")+ })
+ } else {+ printPostDetailed("", deleted, "Deleted:")+ }
continue
case *mastodon.NotificationEvent:
if post.Notification.Status == nil { notification := fmt.Sprintf("Notification [%v] from <%v>\n", post.Notification.Type, post.Notification.Account.Acct)- fmt.Printf(hyphenate(notification))
+ if isPaused {+ actionBuffer = append(actionBuffer, func() {+ fmt.Printf(hyphenate(notification))
+ })
+ } else {+ fmt.Printf(hyphenate(notification))
+ }
continue
}
_, plaintext = RenderPostPlaintext(post.Notification.Status, postref, "")
notification := fmt.Sprintf("Notification [%v] from <%v>: %v\n", post.Notification.Type, post.Notification.Account.Acct, plaintext)- fmt.Printf(hyphenate(notification))
+ if isPaused {+ actionBuffer = append(actionBuffer, func() {+ fmt.Printf(hyphenate(notification))
+ })
+ } else {+ fmt.Printf(hyphenate(notification))
+ }
saveRef(postMap, post.Notification.Status, postref)
postref = IncrementString(postref)
default:
// Catch any other unexpected event types.
- fmt.Printf("Unhandled event: %T\n", post)+ unhandledEvent := event
+ if isPaused {+ actionBuffer = append(actionBuffer, func() {+ fmt.Printf("Unhandled event: %T\n", unhandledEvent)+ })
+ } else {+ fmt.Printf("Unhandled event: %T\n", unhandledEvent)+ }
}
}
}
}
+
--
⑨