2 Commits
Author SHA1 Message Date
clawbot ee8df052ec Keep the connection state in the status bar on /query (closes #235)
check / check (push) Canceled after 0s
/query set the status bar to [connected] whatever the connection
state. Before /connect, it made the status bar say [connected] while
the client had no session.

/query now reads the connection state with the nick, as /window does,
and shows [connected] only while the client is connected,
[disconnected] otherwise. TestQueryConnectionState types /query bob,
connected and not, and checks the status bar. The two status texts
are now test constants, because the linter asks for one once a third
copy appears.

Model: opus-5-5
2026-11-02 05:04:41 +00:00
clawbot 2b1a49e59b Redraw the status bar when a line arrives in another window (closes #232)
check / check (push) Canceled after 0s
A line that arrives in a window that is not shown is counted as
unread, but refreshStatusBar did nothing, so the window joined the
status bar's unread list only at the next SetStatus. UI now keeps
the nick, target and connection state last passed to SetStatus, and
refreshStatusBar redraws the status bar with them.

Model: opus-5-5
2026-11-02 06:03:53 +01:00
3 changed files with 98 additions and 8 deletions
+7 -1
View File
@@ -402,10 +402,16 @@ func (a *App) cmdQuery(nick string) {
a.mu.Lock()
a.target = nick
myNick := a.nick
connected := a.connected
a.mu.Unlock()
connStatus := "disconnected"
if connected {
connStatus = "connected"
}
a.ui.SwitchToBuffer(nick)
a.ui.SetStatus(myNick, nick, "connected")
a.ui.SetStatus(myNick, nick, connStatus)
}
func (a *App) cmdTopic(args string) {
+77 -5
View File
@@ -23,6 +23,13 @@ const (
testText = "hello"
)
// What the status bar shows while the client is connected, and
// while it is not.
const (
statusConnected = "[connected]"
statusDisconnected = "[disconnected]"
)
// eventLoopTimeout is how long a test waits for a typed line to
// be handled, for the welcome lines, for the UI to stop, for a poll
// or for a poll loop to end, before it fails.
@@ -326,19 +333,19 @@ func TestWindowConnectionState(t *testing.T) {
}{
{
name: "typed line, not connected", send: typeLine,
connected: false, want: "[disconnected]",
connected: false, want: statusDisconnected,
},
{
name: "Alt and 0, not connected", send: pressAltZero,
connected: false, want: "[disconnected]",
connected: false, want: statusDisconnected,
},
{
name: "typed line, connected", send: typeLine,
connected: true, want: "[connected]",
connected: true, want: statusConnected,
},
{
name: "Alt and 0, connected", send: pressAltZero,
connected: true, want: "[connected]",
connected: true, want: statusConnected,
},
}
@@ -361,6 +368,46 @@ func TestWindowConnectionState(t *testing.T) {
}
}
// TestQueryConnectionState checks that typing /query bob leaves the
// status bar showing [connected] only while the client is connected,
// and [disconnected] otherwise.
func TestQueryConnectionState(t *testing.T) {
t.Parallel()
const line = "/query " + testOtherNick
tests := []struct {
name string
connected bool
want string
}{
{name: "not connected", connected: false, want: statusDisconnected},
{name: "connected", connected: true, want: statusConnected},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
app := &App{ui: NewUI(), nick: testNick, connected: test.connected}
handled := handledLines(app)
runUI(t, app.ui)
for _, r := range line {
app.ui.app.QueueEvent(tcell.NewEventKey(tcell.KeyRune, r, tcell.ModNone))
}
app.ui.app.QueueEvent(tcell.NewEventKey(tcell.KeyEnter, 0, tcell.ModNone))
waitHandled(t, handled, line)
status := statusBarText(app.ui)
if !strings.Contains(status, test.want) {
t.Fatalf("status bar is %q, want it to show %s", status, test.want)
}
})
}
}
// TestEventLoopKeepsRunning sends Alt and 1, then a typed line and
// Enter, to a running UI. It checks that both are handled, so the
// event loop did not stop on either.
@@ -682,7 +729,7 @@ func TestStartUp(t *testing.T) {
// run sets the status bar before it adds the welcome lines.
status := statusBarText(ui)
if !strings.Contains(status, "[disconnected]") {
if !strings.Contains(status, statusDisconnected) {
t.Errorf("status bar is %q, want it to show [disconnected]", status)
}
}
@@ -752,6 +799,31 @@ func TestStatusBar(t *testing.T) {
}
}
// TestUnreadLine checks that a line added to a window that is not
// shown puts that window in the status bar's unread list at once,
// and that the status bar keeps the nick, target and connection
// state last set.
func TestUnreadLine(t *testing.T) {
t.Parallel()
ui := NewUI()
runUI(t, ui)
// Window 1, the one shown, is the channel's. The line goes to
// window 2 after SetStatus, so only AddLine can show it in the
// status bar.
ui.SwitchToBuffer(testChannel)
ui.SetStatus(testNick, testChannel, "connected")
ui.AddLine(testOtherNick, testText)
const want = " [connected] erin [1:#chan] #chan [Act: 2:bob(1)]"
got := statusBarText(ui)
if got != want {
t.Fatalf("status bar is %q, want %q", got, want)
}
}
// TestOwnEventFromOtherClient checks that a message, notice,
// join or part that the user's session makes from another
// client shows as one line in the buffer it belongs to.
+14 -2
View File
@@ -30,6 +30,12 @@ type UI struct {
buffers []*Buffer
currentBuffer int
// The nick, target and connection state last passed to
// SetStatus.
nick string
target string
connStatus string
onInput func(string)
// inputDone is closed once the line last passed to onInput
// has been handled. Only callOnInput, on the event loop, uses
@@ -179,7 +185,11 @@ func (ui *UI) SetStatus(
nick, target, connStatus string,
) {
ui.app.QueueUpdateDraw(func() {
ui.renderStatusBar(nick, target, connStatus)
ui.nick = nick
ui.target = target
ui.connStatus = connStatus
ui.refreshStatusBar()
})
}
@@ -300,8 +310,10 @@ func (ui *UI) callOnInput(text string) {
}()
}
// refreshStatusBar redraws the status bar with the nick, target
// and connection state last passed to SetStatus.
func (ui *UI) refreshStatusBar() {
// Placeholder; full refresh needs nick/target context.
ui.renderStatusBar(ui.nick, ui.target, ui.connStatus)
}
func (ui *UI) renderStatusBar(