detached 541aedf

refactor(status): remove impossible ephemeral recent state

commit
541aedf038fc076c0e3dc36f95ae965c68522752
author
brice · · 2026-07-15 16:53 UTC
parent
2e6a467
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +13 -32
M internal/usecase/daemon/recent_sessions.go +3 -5
@@ -11,7 +11,6 @@ import (
1111 type recentSession struct {
1212 id domain.SessionID
1313 name string
14- ephemeral bool
1514 attention bool
1615 mruAt uint64
1716 }
@@ -34,10 +33,9 @@ func (d *Daemon) recentSessions(current *session) []recentSession {
3433 continue
3534 }
3635 entry := recentSession{
37- id: sess.id,
38- name: sess.name,
39- ephemeral: sess.ephemeral,
40- mruAt: sess.mruAt.Load(),
36+ id: sess.id,
37+ name: sess.name,
38+ mruAt: sess.mruAt.Load(),
4139 }
4240 for _, tb := range sess.tabs {
4341 if tb.attention {
@@ -11,7 +11,6 @@ import (
11 type recentSession struct {11 type recentSession struct {
12 id domain.SessionID12 id domain.SessionID
13 name string13 name string
14- ephemeral bool
15 attention bool14 attention bool
16 mruAt uint6415 mruAt uint64
17 }16 }
@@ -34,10 +33,9 @@ func (d *Daemon) recentSessions(current *session) []recentSession {
34 continue33 continue
35 }34 }
36 entry := recentSession{35 entry := recentSession{
37- id: sess.id,36+ id: sess.id,
38- name: sess.name,37+ name: sess.name,
39- ephemeral: sess.ephemeral,38+ mruAt: sess.mruAt.Load(),
40- mruAt: sess.mruAt.Load(),
41 }39 }
42 for _, tb := range sess.tabs {40 for _, tb := range sess.tabs {
43 if tb.attention {41 if tb.attention {
M internal/usecase/daemon/status.go +5 -22
@@ -93,7 +93,7 @@ func drawStatusBarState(row []renderer.Cell, state barState, styles themeStyles)
9393 fittedMRU := fitMRU(state.mru, len(row), x, rightText)
9494 for i, sess := range fittedMRU {
9595 style := mruStyle(styles.statusBar, state.theme, i, len(fittedMRU))
96- drawStatusSessionEntry(row, &x, sess.name, sess.ephemeral, sess.attention, style, state.attentionFrame)
96+ drawStatusSessionEntry(row, &x, sess.name, sess.attention, style, state.attentionFrame)
9797 }
9898 }
9999 drawRightPlainText(row, rightText, x, styles.statusBar)
@@ -102,7 +102,6 @@ func drawStatusBarState(row []renderer.Cell, state barState, styles themeStyles)
102102 type rankedRecent struct {
103103 rank int
104104 name string
105- ephemeral bool
106105 attention bool
107106 selected bool
108107 }
@@ -111,11 +110,7 @@ func drawRankedStatusSessionEntry(row []renderer.Cell, x *int, sess rankedRecent
111110 prefixStyle := style
112111 prefixStyle.Bold = true
113112 writeStatusText(row, x, " "+strconv.Itoa(sess.rank)+":", prefixStyle)
114- name := sess.name
115- if sess.ephemeral {
116- name += "*"
117- }
118- writeStatusText(row, x, name, style)
113+ writeStatusText(row, x, sess.name, style)
119114 if sess.attention {
120115 writeStatusText(row, x, " ", style)
121116 writeBell(row, x, attentionFrame, style)
@@ -123,10 +118,7 @@ func drawRankedStatusSessionEntry(row []renderer.Cell, x *int, sess rankedRecent
123118 writeStatusText(row, x, " ", style)
124119 }
125120
126-func drawStatusSessionEntry(row []renderer.Cell, x *int, name string, ephemeral, attention bool, style renderer.Style, attentionFrame int) {
127- if ephemeral {
128- name += "*"
129- }
121+func drawStatusSessionEntry(row []renderer.Cell, x *int, name string, attention bool, style renderer.Style, attentionFrame int) {
130122 writeStatusText(row, x, " "+name, style)
131123 if attention {
132124 writeStatusText(row, x, " ", style)
@@ -228,7 +220,6 @@ func rankedRecentForHints(hints *palette.ContextualHints, recent []recentSession
228220 // recent was copied with the hint under paletteMu, so this only enriches
229221 // the render snapshot and never performs a live domain lookup.
230222 if i < len(recent) {
231- entry.ephemeral = recent[i].ephemeral
232223 entry.attention = recent[i].attention
233224 }
234225 entries = append(entries, entry)
@@ -364,11 +355,7 @@ func fitRankedRecent(entries []rankedRecent, rowLen, leftUsed int, feedback stri
364355 return nil
365356 }
366357 cost := func(e rankedRecent) int {
367- name := e.name
368- if e.ephemeral {
369- name += "*"
370- }
371- width := 2 + statusTextWidth(strconv.Itoa(e.rank)+":") + statusTextWidth(name)
358+ width := 2 + statusTextWidth(strconv.Itoa(e.rank)+":") + statusTextWidth(e.name)
372359 if e.attention {
373360 width += 1 + renderer.RuneWidth(ui.AttentionGlyph)
374361 }
@@ -396,11 +383,7 @@ func fitMRU(entries []recentSession, rowLen, leftUsed int, feedback string) []re
396383 return nil
397384 }
398385 cost := func(e recentSession) int {
399- name := e.name
400- if e.ephemeral {
401- name += "*"
402- }
403- n := 2 + statusTextWidth(name)
386+ n := 2 + statusTextWidth(e.name)
404387 if e.attention {
405388 n += 1 + renderer.RuneWidth(ui.AttentionGlyph)
406389 }
@@ -93,7 +93,7 @@ func drawStatusBarState(row []renderer.Cell, state barState, styles themeStyles)
93 fittedMRU := fitMRU(state.mru, len(row), x, rightText)93 fittedMRU := fitMRU(state.mru, len(row), x, rightText)
94 for i, sess := range fittedMRU {94 for i, sess := range fittedMRU {
95 style := mruStyle(styles.statusBar, state.theme, i, len(fittedMRU))95 style := mruStyle(styles.statusBar, state.theme, i, len(fittedMRU))
96- drawStatusSessionEntry(row, &x, sess.name, sess.ephemeral, sess.attention, style, state.attentionFrame)96+ drawStatusSessionEntry(row, &x, sess.name, sess.attention, style, state.attentionFrame)
97 }97 }
98 }98 }
99 drawRightPlainText(row, rightText, x, styles.statusBar)99 drawRightPlainText(row, rightText, x, styles.statusBar)
@@ -102,7 +102,6 @@ func drawStatusBarState(row []renderer.Cell, state barState, styles themeStyles)
102 type rankedRecent struct {102 type rankedRecent struct {
103 rank int103 rank int
104 name string104 name string
105- ephemeral bool
106 attention bool105 attention bool
107 selected bool106 selected bool
108 }107 }
@@ -111,11 +110,7 @@ func drawRankedStatusSessionEntry(row []renderer.Cell, x *int, sess rankedRecent
111 prefixStyle := style110 prefixStyle := style
112 prefixStyle.Bold = true111 prefixStyle.Bold = true
113 writeStatusText(row, x, " "+strconv.Itoa(sess.rank)+":", prefixStyle)112 writeStatusText(row, x, " "+strconv.Itoa(sess.rank)+":", prefixStyle)
114- name := sess.name113+ writeStatusText(row, x, sess.name, style)
115- if sess.ephemeral {
116- name += "*"
117- }
118- writeStatusText(row, x, name, style)
119 if sess.attention {114 if sess.attention {
120 writeStatusText(row, x, " ", style)115 writeStatusText(row, x, " ", style)
121 writeBell(row, x, attentionFrame, style)116 writeBell(row, x, attentionFrame, style)
@@ -123,10 +118,7 @@ func drawRankedStatusSessionEntry(row []renderer.Cell, x *int, sess rankedRecent
123 writeStatusText(row, x, " ", style)118 writeStatusText(row, x, " ", style)
124 }119 }
125 120
126-func drawStatusSessionEntry(row []renderer.Cell, x *int, name string, ephemeral, attention bool, style renderer.Style, attentionFrame int) {121+func drawStatusSessionEntry(row []renderer.Cell, x *int, name string, attention bool, style renderer.Style, attentionFrame int) {
127- if ephemeral {
128- name += "*"
129- }
130 writeStatusText(row, x, " "+name, style)122 writeStatusText(row, x, " "+name, style)
131 if attention {123 if attention {
132 writeStatusText(row, x, " ", style)124 writeStatusText(row, x, " ", style)
@@ -228,7 +220,6 @@ func rankedRecentForHints(hints *palette.ContextualHints, recent []recentSession
228 // recent was copied with the hint under paletteMu, so this only enriches220 // recent was copied with the hint under paletteMu, so this only enriches
229 // the render snapshot and never performs a live domain lookup.221 // the render snapshot and never performs a live domain lookup.
230 if i < len(recent) {222 if i < len(recent) {
231- entry.ephemeral = recent[i].ephemeral
232 entry.attention = recent[i].attention223 entry.attention = recent[i].attention
233 }224 }
234 entries = append(entries, entry)225 entries = append(entries, entry)
@@ -364,11 +355,7 @@ func fitRankedRecent(entries []rankedRecent, rowLen, leftUsed int, feedback stri
364 return nil355 return nil
365 }356 }
366 cost := func(e rankedRecent) int {357 cost := func(e rankedRecent) int {
367- name := e.name358+ width := 2 + statusTextWidth(strconv.Itoa(e.rank)+":") + statusTextWidth(e.name)
368- if e.ephemeral {
369- name += "*"
370- }
371- width := 2 + statusTextWidth(strconv.Itoa(e.rank)+":") + statusTextWidth(name)
372 if e.attention {359 if e.attention {
373 width += 1 + renderer.RuneWidth(ui.AttentionGlyph)360 width += 1 + renderer.RuneWidth(ui.AttentionGlyph)
374 }361 }
@@ -396,11 +383,7 @@ func fitMRU(entries []recentSession, rowLen, leftUsed int, feedback string) []re
396 return nil383 return nil
397 }384 }
398 cost := func(e recentSession) int {385 cost := func(e recentSession) int {
399- name := e.name386+ n := 2 + statusTextWidth(e.name)
400- if e.ephemeral {
401- name += "*"
402- }
403- n := 2 + statusTextWidth(name)
404 if e.attention {387 if e.attention {
405 n += 1 + renderer.RuneWidth(ui.AttentionGlyph)388 n += 1 + renderer.RuneWidth(ui.AttentionGlyph)
406 }389 }
M internal/usecase/daemon/status_test.go +5 -5
@@ -978,7 +978,7 @@ func TestBarStateForContextualRecentUsesSnapshotAndNormalUsesLiveMRU(t *testing.
978978 done := make(chan struct{})
979979 d.mu.Lock()
980980 go func() {
981- contextual = d.barStateForPaletteHints(sess, "", &hints, []recentSession{{name: "captured", ephemeral: true, attention: true}})
981+ contextual = d.barStateForPaletteHints(sess, "", &hints, []recentSession{{name: "captured", attention: true}})
982982 close(done)
983983 }()
984984 select {
@@ -990,7 +990,7 @@ func TestBarStateForContextualRecentUsesSnapshotAndNormalUsesLiveMRU(t *testing.
990990 d.mu.Unlock()
991991
992992 require.Empty(t, contextual.mru, "contextual composition must not read the live MRU")
993- require.Equal(t, []rankedRecent{{rank: 1, name: "captured", ephemeral: true, attention: true, selected: true}}, contextual.rankedRecent)
993+ require.Equal(t, []rankedRecent{{rank: 1, name: "captured", attention: true, selected: true}}, contextual.rankedRecent)
994994
995995 normal := d.barStateFor(sess, "")
996996 require.Len(t, normal.mru, 1)
@@ -1128,20 +1128,20 @@ func TestCapturePrimaryRenderStatePreservesContextualMRUModeThroughScratchReuse(
11281128 require.Contains(t, draw(normalAfterPopulated), "vty")
11291129 }
11301130
1131-func TestStatusBarRendersMRUNamesEphemeralAndInlineBell(t *testing.T) {
1131+func TestStatusBarRendersMRUNamesAndInlineBell(t *testing.T) {
11321132 state := barState{
11331133 status: statusSnapshot{session: "cur"},
11341134 attentionFrame: 1,
11351135 mru: []recentSession{
11361136 {name: "fresh"},
1137- {name: "tmp", ephemeral: true, attention: true},
1137+ {name: "tmp", attention: true},
11381138 },
11391139 }
11401140 row := make([]renderer.Cell, 24)
11411141
11421142 drawStatusBarState(row, state, resolveThemeStyles(nil))
11431143
1144- require.Equal(t, " cur fresh tmp*  ", rowText(row))
1144+ require.Equal(t, " cur fresh tmp  ", rowText(row))
11451145 for _, c := range row {
11461146 if c.Rune == ui.AttentionGlyph {
11471147 require.True(t, c.Style.Bold)
@@ -978,7 +978,7 @@ func TestBarStateForContextualRecentUsesSnapshotAndNormalUsesLiveMRU(t *testing.
978 done := make(chan struct{})978 done := make(chan struct{})
979 d.mu.Lock()979 d.mu.Lock()
980 go func() {980 go func() {
981- contextual = d.barStateForPaletteHints(sess, "", &hints, []recentSession{{name: "captured", ephemeral: true, attention: true}})981+ contextual = d.barStateForPaletteHints(sess, "", &hints, []recentSession{{name: "captured", attention: true}})
982 close(done)982 close(done)
983 }()983 }()
984 select {984 select {
@@ -990,7 +990,7 @@ func TestBarStateForContextualRecentUsesSnapshotAndNormalUsesLiveMRU(t *testing.
990 d.mu.Unlock()990 d.mu.Unlock()
991 991
992 require.Empty(t, contextual.mru, "contextual composition must not read the live MRU")992 require.Empty(t, contextual.mru, "contextual composition must not read the live MRU")
993- require.Equal(t, []rankedRecent{{rank: 1, name: "captured", ephemeral: true, attention: true, selected: true}}, contextual.rankedRecent)993+ require.Equal(t, []rankedRecent{{rank: 1, name: "captured", attention: true, selected: true}}, contextual.rankedRecent)
994 994
995 normal := d.barStateFor(sess, "")995 normal := d.barStateFor(sess, "")
996 require.Len(t, normal.mru, 1)996 require.Len(t, normal.mru, 1)
@@ -1128,20 +1128,20 @@ func TestCapturePrimaryRenderStatePreservesContextualMRUModeThroughScratchReuse(
1128 require.Contains(t, draw(normalAfterPopulated), "vty")1128 require.Contains(t, draw(normalAfterPopulated), "vty")
1129 }1129 }
1130 1130
1131-func TestStatusBarRendersMRUNamesEphemeralAndInlineBell(t *testing.T) {1131+func TestStatusBarRendersMRUNamesAndInlineBell(t *testing.T) {
1132 state := barState{1132 state := barState{
1133 status: statusSnapshot{session: "cur"},1133 status: statusSnapshot{session: "cur"},
1134 attentionFrame: 1,1134 attentionFrame: 1,
1135 mru: []recentSession{1135 mru: []recentSession{
1136 {name: "fresh"},1136 {name: "fresh"},
1137- {name: "tmp", ephemeral: true, attention: true},1137+ {name: "tmp", attention: true},
1138 },1138 },
1139 }1139 }
1140 row := make([]renderer.Cell, 24)1140 row := make([]renderer.Cell, 24)
1141 1141
1142 drawStatusBarState(row, state, resolveThemeStyles(nil))1142 drawStatusBarState(row, state, resolveThemeStyles(nil))
1143 1143
1144- require.Equal(t, " cur fresh tmp*  ", rowText(row))1144+ require.Equal(t, " cur fresh tmp  ", rowText(row))
1145 for _, c := range row {1145 for _, c := range row {
1146 if c.Rune == ui.AttentionGlyph {1146 if c.Rune == ui.AttentionGlyph {
1147 require.True(t, c.Style.Bold)1147 require.True(t, c.Style.Bold)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 12

Tags 11

↑↓ moveenter openesc close