From f436646b99b7fec976f300f12884c4a795de72a1 Mon Sep 17 00:00:00 2001 From: omartelo Date: Fri, 23 Oct 2026 20:23:23 -0300 Subject: [PATCH] fix(native): show a card's status line in place of its path The tool, Waiting, relay and compacting line was added above the path, so a card grew by a line when a turn started and shrank when it ended, pushing every card below it. The line now takes the path's place while it shows. --- CHANGELOG.md | 1 + native/cmd/lich-native/sidebar_card.go | 6 ++-- native/cmd/lich-native/sidebar_card_test.go | 37 +++++++++++++++++++++ native/cmd/lich-native/statusrung.go | 2 +- 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 native/cmd/lich-native/sidebar_card_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 210318c3..5dc86067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- A session card no longer grows and shrinks as its agent starts and stops a tool, waits on you or compacts, pushing every card below it up and down. That line now takes the place of the card's path while it shows, and the path comes back when it goes. - The native window holds less memory for its fonts. A font file asked for more than once, such as the interface and the terminal set in the same family or the bold face that also stands in for semibold, was parsed again each time, about 30MB for a Nerd Font face; it is now parsed once and shared while in use. An interface in a language other than Chinese, Japanese or Korean no longer loads a CJK font at start, tens of megabytes: it does on the first CJK text on screen, drawn meanwhile with a system font. With one Nerd Font for the interface, the terminal and the editor and no CJK on screen, the fonts take 119MB where they took 246MB. ## [0.78.1] - 2026-10-23 diff --git a/native/cmd/lich-native/sidebar_card.go b/native/cmd/lich-native/sidebar_card.go index 85c4f240..163aab09 100644 --- a/native/cmd/lich-native/sidebar_card.go +++ b/native/cmd/lich-native/sidebar_card.go @@ -158,10 +158,12 @@ func (s *sidebar) cardBody(gtx C, th *ui.Theme, sv *sessionView, prChip *widget. return layout.Flex{Alignment: layout.Middle}.Layout(gtx, s.titleRow(th, sv)...) }), } + // The rung takes the path's line so the card keeps its height through a turn. + second := func(gtx C) D { return pathRow(gtx, th, sv.layout, path) } if rung, ok := statusRung(th, sv); ok { - rows = append(rows, ui.VGap(2), layout.Rigid(rung)) + second = rung } - rows = append(rows, ui.VGap(2), layout.Rigid(func(gtx C) D { return pathRow(gtx, th, sv.layout, path) })) + rows = append(rows, ui.VGap(2), layout.Rigid(second)) if sv.git.Branch != "" { rows = append(rows, ui.VGap(2), layout.Rigid(func(gtx C) D { return s.branchRow(gtx, th, sv, prChip) })) } diff --git a/native/cmd/lich-native/sidebar_card_test.go b/native/cmd/lich-native/sidebar_card_test.go new file mode 100644 index 00000000..9fbba633 --- /dev/null +++ b/native/cmd/lich-native/sidebar_card_test.go @@ -0,0 +1,37 @@ +package main + +import ( + "image" + "testing" + + "gioui.org/font/gofont" + "gioui.org/layout" + "gioui.org/op" + "gioui.org/text" + "gioui.org/unit" + "gioui.org/widget" + "github.com/lichdotdev/lich/native/backend" + "github.com/lichdotdev/lich/native/ui" +) + +func cardBodyHeight(sv sessionView) int { + s := newSidebar(&ui.Root{}) + th := &ui.Theme{Palette: ui.Dark, Shaper: text.NewShaper(text.WithCollection(gofont.Collection())), Surface: ui.Dark.Sidebar} + var ops op.Ops + gtx := layout.Context{Ops: &ops, Metric: unit.Metric{PxPerDp: 1, PxPerSp: 1}, Constraints: layout.Constraints{Max: image.Pt(300, 4000)}} + return s.cardBody(gtx, th, &sv, new(widget.Clickable)).Size.Y +} + +func TestCardKeepsItsHeightWhileTheStatusRungShows(t *testing.T) { + idle := sessionView{Session: backend.Session{ID: "s1", Label: "Docs"}, shown: "/home/me/repo", git: backend.DiffStats{Branch: "main"}} + rest := cardBodyHeight(idle) + busy := idle + busy.status, busy.tool = statusBusy, sessionTool{Name: "Bash", Detail: "go test ./..."} + waiting := idle + waiting.status = statusWaiting + for name, sv := range map[string]sessionView{"tool": busy, "waiting": waiting} { + if got := cardBodyHeight(sv); got != rest { + t.Errorf("%s card is %dpx tall, at rest %dpx", name, got, rest) + } + } +} diff --git a/native/cmd/lich-native/statusrung.go b/native/cmd/lich-native/statusrung.go index f46a9e79..fd199438 100644 --- a/native/cmd/lich-native/statusrung.go +++ b/native/cmd/lich-native/statusrung.go @@ -41,7 +41,7 @@ const minDetail = 24 // statusRung is SessionStatusRung, cut to the rungs this window keeps: an // open request with another session, a block on the user, a compaction, and // the tool the turn is running, the first that holds. It reports false when -// none does, and the card stays its usual size. +// none does, and the card shows its path on that line. func statusRung(th *ui.Theme, sv *sessionView) (layout.Widget, bool) { switch { case sv.relay.Direction != "":