gotextlog

gotextlog
git clone https://git.ryansepassi.com/git/gotextlog.git
Log | Files | Refs

commit 3805112bc376460f6da1ff6eaac97f399ec94a1d
parent 0d8c68c1cc2088aefbb213dd59fb2d8a2d2fd1dd
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 25 Aug 2026 22:38:31 -0700

Render reply parents in latest feed

Diffstat:
Minternal/tui/model_test.go | 20++++++++++++++++++++
Minternal/tui/view.go | 19++++++++++++++-----
2 files changed, 34 insertions(+), 5 deletions(-)

diff --git a/internal/tui/model_test.go b/internal/tui/model_test.go @@ -318,6 +318,26 @@ func TestPostListUsesDenseRowsAndShowsActivityContext(t *testing.T) { t.Fatalf("activity context is missing:\n%s", view) } } +func TestLatestReplyRendersItsParentAboveIt(t *testing.T) { + parent := textlog.Post{ID: 10, Body: "parent body", CreatedAt: time.Now().Add(-time.Minute), Author: textlog.UserReference{Handle: "parent"}} + reply := textlog.Post{ID: 11, ParentID: intPtr(parent.ID), Parent: &parent, Body: "reply body", CreatedAt: time.Now(), Author: textlog.UserReference{Handle: "child"}} + model := New(&acceptanceBackend{}, config.Config{NoColor: true}, Options{}) + model.width, model.height = 80, 40 + s := model.current() + s.loading = false + s.feed = string(config.FeedLatest) + s.posts = []textlog.Post{reply} + + view := model.View() + parentAt, replyAt := strings.Index(view, "parent body"), strings.Index(view, "reply body") + if parentAt < 0 || replyAt < 0 || parentAt >= replyAt { + t.Fatalf("latest reply did not render parent above reply:\n%s", view) + } + if !strings.Contains(view[:replyAt], "· parent") || !strings.Contains(view[parentAt:replyAt], "│") { + t.Fatalf("latest reply did not show parent context and reply indentation:\n%s", view) + } +} + func TestPostListFillsAvailableHeight(t *testing.T) { model := New(&acceptanceBackend{}, config.Config{BaseURL: "https://example.test", Theme: config.ThemeLight, NoColor: true}, Options{}) model.width, model.height = 120, 40 diff --git a/internal/tui/view.go b/internal/tui/view.go @@ -206,11 +206,11 @@ func (m *Model) postsView(s *screen, p palette) string { } note := renderNote(s.posts[i], i == s.selected, focused, context, max(20, m.width-depth*2), bodyLines, p) if depth > 0 { - lines := strings.Split(note, "\n") - for j := range lines { - lines[j] = strings.Repeat("│ ", depth) + lines[j] - } - note = strings.Join(lines, "\n") + note = indentNote(note, depth) + } + if s.kind == screenFeed && s.feed == string(config.FeedLatest) && s.posts[i].Parent != nil { + parent := renderNote(*s.posts[i].Parent, false, -1, "parent", m.width, 3, p) + note = parent + "\n" + indentNote(note, 1) } if i < len(s.more) && s.more[i] > 0 { label := fmt.Sprintf("more · %d replies", s.more[i]) @@ -279,6 +279,15 @@ func (m *Model) postsView(s *screen, p palette) string { return strings.Join(parts, "\n") } +func indentNote(note string, depth int) string { + lines := strings.Split(note, "\n") + prefix := strings.Repeat("│ ", depth) + for i := range lines { + lines[i] = prefix + lines[i] + } + return strings.Join(lines, "\n") +} + func renderNote(post textlog.Post, selected bool, focused int, context string, width, maxBodyLines int, p palette) string { if post.Body == "↑ top" && post.Author.Handle == "" && post.CreatedAt.IsZero() { style := lipgloss.NewStyle().Foreground(p.accent).Width(max(10, width-2))