Show the connection state in the neoirc-cli status bar (closes #229)
check / check (push) Canceled after 0s

The status bar has colour tags turned on, so tview read "[connected]"
and "[disconnected]" as colour names and dropped them. It dropped the
bracketed part of a nick such as "erin[away]" the same way.

renderStatusBar now passes the whole status line through tview.Escape,
so every bracket shows as it is. TestStartUp checks that the status
bar shows [disconnected] at start-up. TestStatusBar checks [connected]
with plain nicks and with nicks that hold brackets.

Model: opus-5-5
This commit is contained in:
clawbot
2026-11-02 01:14:37 +00:00
parent 59f1208d8d
commit d1cb9f8044
2 changed files with 75 additions and 3 deletions
+70 -1
View File
@@ -362,7 +362,8 @@ func TestLinesKeepOrder(t *testing.T) {
// TestStartUp runs the client's start-up path on a simulation
// screen. It fails unless the event loop starts and the status
// window gets two lines: first the one that holds "Welcome to
// neoirc-cli", then the /connect hint.
// neoirc-cli", then the /connect hint. The status bar must show
// [disconnected].
func TestStartUp(t *testing.T) {
t.Parallel()
@@ -429,6 +430,62 @@ func TestStartUp(t *testing.T) {
if !strings.Contains(lines[1], "/connect <server-url>") {
t.Errorf("second status line is %q, want the /connect hint", lines[1])
}
// run sets the status bar before it adds the welcome lines.
status := statusBarText(ui)
if !strings.Contains(status, "[disconnected]") {
t.Errorf("status bar is %q, want it to show [disconnected]", status)
}
}
// TestStatusBar checks that the status bar shows [connected], and
// shows a nick, target or window name with square brackets as it
// is.
func TestStatusBar(t *testing.T) {
t.Parallel()
tests := []struct {
name string
nick string
target string
unread string
want string
}{
{
name: "plain names",
nick: testNick,
target: testChannel,
unread: testOtherNick,
want: " [connected] erin [1:#chan] #chan [Act: 2:bob(1)]",
},
{
name: "nicks with brackets",
nick: "erin[away]",
target: "bob[m]",
unread: "dave[afk]",
want: " [connected] erin[away] [1:bob[m]] bob[m] [Act: 2:dave[afk](1)]",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
ui := NewUI()
runUI(t, ui)
// Window 1, the one shown, is the target's. Window 2
// gets one unread line.
ui.SwitchToBuffer(test.target)
ui.AddLine(test.unread, testText)
ui.SetStatus(test.nick, test.target, "connected")
got := statusBarText(ui)
if got != test.want {
t.Fatalf("status bar is %q, want %q", got, test.want)
}
})
}
}
// TestOwnEventFromOtherClient checks that a message, notice,
@@ -513,6 +570,18 @@ func bufferState(ui *UI, name string) (int, int) {
return lines, unread
}
// statusBarText returns the text the status bar shows, without
// its colour tags.
func statusBarText(ui *UI) string {
var text string
ui.app.QueueUpdate(func() {
text = ui.statusBar.GetText(true)
})
return text
}
// handledLines makes app.ui pass each typed line to
// app.handleInput, as Run does, and returns a channel that
// receives each line once it has been handled.