fix: align topbar/sidebar so the top-right is not a dead hole
ci / tcc-check (push) Failing after 38s
ci / linux (aarch64, 0) (push) Skipped
ci / linux (x86, 1) (push) Skipped
ci / linux (x86_64, 1) (push) Skipped
ci / windows (push) Skipped

Topbar spans the full width; seat deck starts under it. Compact badge
and a seat chip on the right of the chrome. Hermit 1.0.2.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WHC
2026-10-29 22:08:58 +08:00
co-authored by Cursor
parent f29c1000b6
commit 15c6c4a02a
2 changed files with 77 additions and 18 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
#define CST_VERSION_MAJOR 1 #define CST_VERSION_MAJOR 1
#define CST_VERSION_MINOR 0 #define CST_VERSION_MINOR 0
#define CST_VERSION_PATCH 1 #define CST_VERSION_PATCH 2
#define CST_VERSION_STR_(x) #x #define CST_VERSION_STR_(x) #x
#define CST_VERSION_STR(x) CST_VERSION_STR_(x) #define CST_VERSION_STR(x) CST_VERSION_STR_(x)
+76 -17
View File
@@ -2791,8 +2791,28 @@ static void draw_hermit_badge(WINDOW *win, int y, int x, const tui_t *t) {
return; return;
} }
} }
const char *b = hermit_mini_badge(st, t->spin, g_ascii); /* Compact topbar mark — avoid wide ║║ which reads as an orange slab. */
draw_ansi_at(win, y, x, (int)strlen(b), b, CP_TOOL, 0, 0); const char *b;
if (g_ascii) {
b = (st == HERMIT_ST_CODING) ? ">_" : "<>";
} else {
switch (st) {
case HERMIT_ST_QUESTION:
b = "◇?";
break;
case HERMIT_ST_ERROR:
b = "◇!";
break;
case HERMIT_ST_CODING:
b = ">_";
break;
default:
b = "◇";
break;
}
}
(void)t;
draw_ansi_at(win, y, x, 2, b, CP_TOOL, 0, 0);
} }
static const char *const TIPS[] = { static const char *const TIPS[] = {
@@ -2971,7 +2991,7 @@ static void draw_side(tui_t *t) {
char line[512]; char line[512];
int bottom = h - 3; /* where + version */ int bottom = h - 3; /* where + version */
/* SEAT — local role + instance + short realm fp */ /* SEAT — role on one line; instance + realm indented under it */
draw_ansi_at(s, y++, x, mw, "seat", CP_SIDE_MUTED, 0, 0); draw_ansi_at(s, y++, x, mw, "seat", CP_SIDE_MUTED, 0, 0);
{ {
char sid[64] = {0}; char sid[64] = {0};
@@ -2980,21 +3000,28 @@ static void draw_side(tui_t *t) {
const char *role = !sess ? "logged-out" : chair ? "chair" : "member"; const char *role = !sess ? "logged-out" : chair ? "chair" : "member";
int pair = !sess ? CP_SIDE_MUTED int pair = !sess ? CP_SIDE_MUTED
: chair ? CP_SIDE_SUCCESS : CP_SIDE_PRIMARY; : chair ? CP_SIDE_SUCCESS : CP_SIDE_PRIMARY;
int dx = x + draw_ansi_at(s, y, x, 2, seat_pulse_dot(t), pair, 0, 0); int dx = x;
snprintf(line, sizeof(line), "%s", role); dx += draw_ansi_at(s, y, dx, 2, seat_pulse_dot(t), pair, 0, 0);
dx += draw_ansi_at(s, y, dx + 1, mw - (dx + 1 - x), line, pair, 1, 0); dx += draw_ansi_at(s, y, dx, 1, " ", pair, 0, 0);
draw_ansi_at(s, y, dx, mw - (dx - x), role, pair, 1, 0);
y++; y++;
int ix = x + 2; /* align under role text, past the pulse */
int imw = mw - 2;
if (imw < 6) {
ix = x;
imw = mw;
}
if (!sid[0]) if (!sid[0])
cst_parliament_default_instance(sid, sizeof(sid)); cst_parliament_default_instance(sid, sizeof(sid));
if (sid[0] && y < bottom) { if (sid[0] && y < bottom) {
size_t fit = utf8_fit_cols(sid, strlen(sid), mw); size_t fit = utf8_fit_cols(sid, strlen(sid), imw);
snprintf(line, sizeof(line), "%.*s", (int)fit, sid); snprintf(line, sizeof(line), "%.*s", (int)fit, sid);
draw_ansi_at(s, y++, x, mw, line, CP_SIDE_MUTED, 0, 0); draw_ansi_at(s, y++, ix, imw, line, CP_SIDE_MUTED, 0, 0);
} }
char fp[9]; char fp[9];
if (realm_fp_short(fp) == 0 && y < bottom) { if (realm_fp_short(fp) == 0 && y < bottom) {
snprintf(line, sizeof(line), "realm %.8s", fp); snprintf(line, sizeof(line), "realm %.8s", fp);
draw_ansi_at(s, y++, x, mw, line, CP_SIDE_MUTED, 0, 0); draw_ansi_at(s, y++, ix, imw, line, CP_SIDE_MUTED, 0, 0);
} }
} }
y++; y++;
@@ -3301,27 +3328,56 @@ static void draw_topbar(tui_t *t) {
if (hexish) if (hexish)
title = "New session"; title = "New session";
} }
/* Hermit badge + title + model. Role lives only in the Seat Deck. */ /* Badge + brand + title on the left; model then seat chip on the right. */
int x = 1; int x = 1;
draw_hermit_badge(w, 0, x, t); draw_hermit_badge(w, 0, x, t);
x += 4; x += 3;
x += draw_ansi_at(w, 0, x, 6, "Hermit", CP_TOPBAR_ACCENT, 1, 0); x += draw_ansi_at(w, 0, x, 6, "Hermit", CP_TOPBAR_ACCENT, 1, 0);
x += draw_ansi_at(w, 0, x, 1, " ", CP_TOPBAR_MUTED, 0, 0); x += draw_ansi_at(w, 0, x, 1, " ", CP_TOPBAR_MUTED, 0, 0);
int model_room = 0;
char seat_chip[48] = "";
int seat_w = 0;
{
char sid[64] = {0};
int sess = cst_parliament_session_ok(sid, sizeof(sid));
int chair = sess && cst_parliament_is_chair();
if (cst_parliament_is_active()) {
snprintf(seat_chip, sizeof(seat_chip), "%s %s",
seat_pulse_dot(t),
!sess ? "login" : chair ? "chair" : "member");
seat_w = utf8_cols(seat_chip, strlen(seat_chip)) + 2;
}
}
char mid[160] = ""; char mid[160] = "";
int model_room = 0;
if (cfg) { if (cfg) {
snprintf(mid, sizeof(mid), "%.40s%s%.20s", cfg->model, snprintf(mid, sizeof(mid), "%.40s%s%.20s", cfg->model,
cfg->provider[0] ? " · " : "", cfg->provider); cfg->provider[0] ? " · " : "", cfg->provider);
model_room = utf8_cols(mid, strlen(mid)) + 2; model_room = utf8_cols(mid, strlen(mid)) + 2;
} }
int title_max = bw - x - 1 - model_room; int title_max = bw - x - 1 - model_room - seat_w;
if (title_max < 8) if (title_max < 8)
title_max = 8; title_max = 8;
size_t tfit = utf8_fit_cols(title, strlen(title), title_max); size_t tfit = utf8_fit_cols(title, strlen(title), title_max);
snprintf(left, sizeof(left), "%.*s", (int)tfit, title); snprintf(left, sizeof(left), "%.*s", (int)tfit, title);
x += draw_ansi_at(w, 0, x, bw - x, left, CP_TOPBAR, 1, 0); x += draw_ansi_at(w, 0, x, bw - x, left, CP_TOPBAR, 1, 0);
if (mid[0] && x + 2 < bw) int right = bw - 1;
draw_ansi_at(w, 0, x + 2, bw - (x + 2), mid, CP_TOPBAR_MUTED, 0, 0); if (seat_chip[0]) {
int sw = utf8_cols(seat_chip, strlen(seat_chip));
int sx = right - sw;
if (sx > x + 2) {
int pair = strstr(seat_chip, "chair") ? CP_TOPBAR_ACCENT : CP_TOPBAR_MUTED;
draw_ansi_at(w, 0, sx, sw, seat_chip, pair, 0, 0);
right = sx - 2;
}
}
if (mid[0] && x + 2 < right) {
int mw = utf8_cols(mid, strlen(mid));
int mx = right - mw;
if (mx < x + 2)
mx = x + 2;
draw_ansi_at(w, 0, mx, right - mx + 1, mid, CP_TOPBAR_MUTED, 0, 0);
}
wrefresh(w); wrefresh(w);
} }
@@ -3698,8 +3754,10 @@ static void layout(tui_t *t) {
t->todo_rows = 1 + (total < TODO_PANEL_MAX ? total : TODO_PANEL_MAX); t->todo_rows = 1 + (total < TODO_PANEL_MAX ? total : TODO_PANEL_MAX);
t->log_x = 1; t->log_x = 1;
t->log_y = topbar; t->log_y = topbar;
/* Topbar spans the full width so the sidebar does not leave a dead
* hole next to "Hermit …" in the top-right corner. */
if (topbar) if (topbar)
t->header = tui_newwin(1, mw, 0, 0); t->header = tui_newwin(1, t->cols, 0, 0);
int log_h = t->in_y - 1 - t->todo_rows - t->log_y; int log_h = t->in_y - 1 - t->todo_rows - t->log_y;
if (log_h < 1) { if (log_h < 1) {
t->todo_rows = 0; t->todo_rows = 0;
@@ -3709,8 +3767,9 @@ static void layout(tui_t *t) {
if (t->todo_rows) if (t->todo_rows)
t->todow = tui_newwin(t->todo_rows, mw - 2, t->log_y + log_h, 1); t->todow = tui_newwin(t->todo_rows, mw - 2, t->log_y + log_h, 1);
t->status = tui_newwin(1, mw - 2, t->rows - 1, 1); t->status = tui_newwin(1, mw - 2, t->rows - 1, 1);
/* Sidebar starts under the topbar, aligned with the transcript. */
if (t->side_w) if (t->side_w)
t->side = tui_newwin(t->rows, t->side_w, 0, mw); t->side = tui_newwin(t->rows - topbar, t->side_w, topbar, mw);
} }
t->input = tui_newwin(t->in_h, t->in_w, t->in_y, t->in_x); t->input = tui_newwin(t->in_h, t->in_w, t->in_y, t->in_x);
if (HAS_COLOR()) { if (HAS_COLOR()) {