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 @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- A pull request badge on a session card, its Pull request menu item and the footer's pull request button no longer open the wrong pull request after the session's shell moved into another repository. The badge shows that repository's pull request, and the click used to look its number up among the project's own on Pulls; it now opens the pull request on GitHub instead.
- The collapsed sidebar shows the profile new sessions are born in, at the bottom of the rail, and opens the same menu the open sidebar's footer does. It used to show no profile at all.
- A tab in the top bar can no longer get stuck lifted, drawn in the accent color as if it were being dragged, with no tab moving again until lich restarted. A tab focused by a click and then given Space or Enter was picked up to reorder from the keyboard, and once a click elsewhere took the keyboard it could neither be dropped nor cancelled; it now goes back to its place when it loses focus. A layout tab renamed in the middle of a drag no longer gets stuck the same way.
- 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.
Expand Down
5 changes: 3 additions & 2 deletions native/cmd/lich-native/cardmenu.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,9 @@ func forkItem(sv *sessionView, act *sidebarAction) (ui.MenuEntry, bool) {
func pullRequestItem(sv *sessionView, act *sidebarAction) ui.MenuEntry {
item := ui.MenuEntry{Label: i18n.T("sidebar.sessionCard.pullRequest"), Icon: icMenuPR, Disabled: sv.pr == nil}
if sv.pr != nil {
id, number := sv.ID, sv.pr.Number
item.OnClick = func() { act.activate, act.openPR = id, number }
id := sv.ID
number, url := prTarget(sv.pr, sv.shown, sv.path)
item.OnClick = func() { act.activate, act.openPR, act.openPRURL = id, number, url }
}
return item
}
27 changes: 27 additions & 0 deletions native/cmd/lich-native/cardmenu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,30 @@ func TestCardMenuForkEntry(t *testing.T) {
}
}
}

// A shell that cd'd into another repository has that repository's pull request
// on its card; its number means nothing on the Pulls screen, which lists the
// project's, so the click opens it in the browser.
func TestTheCardsPullRequestOpensWhereItBelongs(t *testing.T) {
pr := &backend.PullRequest{Number: 7, URL: "https://github.com/o/r/pull/7"}
cases := []struct {
name, shown string
number int
url string
}{
{"in its checkout", "/wt/feat", 7, ""},
{"in a folder of its checkout", "/wt/feat/internal", 7, ""},
{"in another repository", "/src/other", 0, pr.URL},
{"in a sibling with the same prefix", "/wt/feat-2", 0, pr.URL},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
sv := &sessionView{Session: backend.Session{ID: "s1"}, path: "/wt/feat", shown: c.shown, pr: pr}
var act sidebarAction
pullRequestItem(sv, &act).OnClick()
if act.activate != "s1" || act.openPR != c.number || act.openPRURL != c.url {
t.Fatalf("click asked activate %q, Pulls #%d, browser %q; want s1, #%d, %q", act.activate, act.openPR, act.openPRURL, c.number, c.url)
}
})
}
}
6 changes: 3 additions & 3 deletions native/cmd/lich-native/footer.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ type footer struct {
client *backend.Client
root *ui.Root
invalidate func()
// openPullRequest opens the Pulls screen on a pull request.
openPullRequest func(number int)
// openPullRequest opens a pull request where prTarget says.
openPullRequest func(number int, url string)
// showDelegates lays a session's delegates out beside it.
showDelegates func(id string)
usage *footerUsage
Expand Down Expand Up @@ -221,7 +221,7 @@ func (f *footer) act(gtx C, in footerInput) {
f.w("files").pressed = f.dock.tab == dockCode
f.w("changes").pressed = f.dock.tab == dockReview
if f.w("pr").click.Clicked(gtx) && in.pr != nil && f.openPullRequest != nil {
f.openPullRequest(in.pr.Number)
f.openPullRequest(prTarget(in.pr, in.path, in.checkout))
}
if f.w("delegates").click.Clicked(gtx) && in.delegates > 0 {
f.showDelegates(in.sessionID)
Expand Down
6 changes: 2 additions & 4 deletions native/cmd/lich-native/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ func run(w *app.Window, rt backend.Runtime) error {
u.settings.theme = newThemePicker(ctx, client, u.appearance, &u.toaster, &u.root)
u.dock.tab = map[string]dockTab{"code": dockCode, "review": dockReview}[*flagTab]
u.footer.dock = u.dock
u.footer.openPullRequest = u.showPulls
u.footer.openPullRequest = u.openPR
u.footer.writePaste = u.terms.writePaste
u.footer.showDelegates = func(id string) { u.layoutStage.delegates = id }
u.settings.footer = u.footer
Expand Down Expand Up @@ -894,9 +894,7 @@ func (u *window) apply(act sidebarAction) {
if act.close != "" {
u.closeSession(act.close)
}
if act.openPR != 0 {
u.showPulls(act.openPR)
}
u.openPR(act.openPR, act.openPRURL)
if act.pin != "" && u.model.setPinned(act.pin, act.pinTo) {
u.model.invalidate()
id, pinned := act.pin, act.pinTo
Expand Down
24 changes: 24 additions & 0 deletions native/cmd/lich-native/pulls_actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@ func (u *window) showPulls(number int) {
u.model.invalidate()
}

// openPR opens a card's pull request where prTarget sent it: number on the
// Pulls screen, else url in the browser; neither set opens nothing.
func (u *window) openPR(number int, url string) {
switch {
case number != 0:
u.showPulls(number)
case url != "":
go func() { u.logErr("open pull request", u.client.OpenExternal(u.ctx, url)) }()
}
}

// prTarget is where a click on a card's pull request goes. The badge reads the
// pull request where the shell is (shown); the Pulls screen lists the
// project's, so a shell that left the session's checkout for another
// repository has one whose number names something else there, and it opens
// in the browser instead. Another worktree of the same project goes there too:
// a cleaned path cannot tell it from another repository.
func prTarget(pr *backend.PullRequest, shown, checkout string) (number int, url string) {
if under(checkout, shown) {
return pr.Number, ""
}
return 0, pr.URL
}

// checkoutPR is the active session's branch and its open PR, the project's
// own checkout's without a session.
func (u *window) checkoutPR(p backend.Project) (string, int) {
Expand Down
5 changes: 4 additions & 1 deletion native/cmd/lich-native/sidebar.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,9 @@ type sidebarAction struct {
pin string // session id
pinTo bool // the pin the click asked for
openPR int // a pull request to show on the Pulls screen
launch launchRequest
// openPRURL is a pull request to open in the browser instead (prTarget).
openPRURL string
launch launchRequest
// Open in, from the card menu: a directory for a shell session, the
// editor or the file manager.
terminalAt, editorAt, folderAt string
Expand Down Expand Up @@ -192,6 +194,7 @@ func (a *sidebarAction) takeCard(c sidebarAction) {
if c.openPR != 0 {
a.openPR = c.openPR
}
pick(&a.openPRURL, c.openPRURL)
pick(&a.terminalAt, c.terminalAt)
pick(&a.editorAt, c.editorAt)
pick(&a.folderAt, c.folderAt)
Expand Down
3 changes: 2 additions & 1 deletion native/cmd/lich-native/sidebar_card.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ func (s *sidebar) card(gtx C, th *ui.Theme, sv *sessionView, active bool, folder
}
prChip := clickable(s.prChips, sv.ID)
if prChip.Clicked(gtx) && sv.pr != nil {
act.activate, act.openPR = sv.ID, sv.pr.Number
act.activate = sv.ID
act.openPR, act.openPRURL = prTarget(sv.pr, sv.shown, sv.path)
}
fill := cardFill(th, sv.Color, active, click.Hovered())
th = th.On(fill)
Expand Down
Loading