Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions native/cmd/lich-native/sidebar_card.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) }))
}
Expand Down
37 changes: 37 additions & 0 deletions native/cmd/lich-native/sidebar_card_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
2 changes: 1 addition & 1 deletion native/cmd/lich-native/statusrung.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 != "":
Expand Down
Loading