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 != "":