feat: rebrand as Hermit — TUI palette, dual glyphs, binary 0.10.0
Ship hermit binary (cst-agent symlink), ~/.config/hermit with legacy fallback, Hermit color theme and mini crab frames, plus SVG→PUA font build pipeline. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,167 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "cst_hermit_glyph.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
const char *hermit_getenv(const char *suffix) {
|
||||
char hk[96], ck[96];
|
||||
if (!suffix || !suffix[0])
|
||||
return "";
|
||||
snprintf(hk, sizeof(hk), "HERMIT_%s", suffix);
|
||||
const char *e = getenv(hk);
|
||||
if (e && e[0])
|
||||
return e;
|
||||
snprintf(ck, sizeof(ck), "CST_%s", suffix);
|
||||
e = getenv(ck);
|
||||
return e ? e : "";
|
||||
}
|
||||
|
||||
hermit_icon_mode_t hermit_icon_mode(void) {
|
||||
const char *e = hermit_getenv("ICONS");
|
||||
if (!e[0] || !strcmp(e, "auto"))
|
||||
return HERMIT_ICON_AUTO;
|
||||
if (!strcmp(e, "font") || !strcmp(e, "ttf"))
|
||||
return HERMIT_ICON_FONT;
|
||||
return HERMIT_ICON_MINI;
|
||||
}
|
||||
|
||||
hermit_icon_mode_t hermit_icon_mode_eff(int ascii) {
|
||||
if (ascii)
|
||||
return HERMIT_ICON_MINI;
|
||||
hermit_icon_mode_t m = hermit_icon_mode();
|
||||
if (m != HERMIT_ICON_AUTO)
|
||||
return m;
|
||||
/* AUTO: font only when forced path exists or HERMIT_ICON_FONT=1. */
|
||||
if (hermit_getenv("ICON_FONT")[0] == '1')
|
||||
return HERMIT_ICON_FONT;
|
||||
return HERMIT_ICON_MINI;
|
||||
}
|
||||
|
||||
hermit_state_t hermit_state_from_ui(int busy, int ask, int error) {
|
||||
if (error)
|
||||
return HERMIT_ST_ERROR;
|
||||
if (ask)
|
||||
return HERMIT_ST_QUESTION;
|
||||
if (busy)
|
||||
return HERMIT_ST_CODING;
|
||||
return HERMIT_ST_IDLE;
|
||||
}
|
||||
|
||||
wchar_t hermit_font_codepoint(hermit_state_t st, int frame, int with_shell) {
|
||||
if (st < 0 || st >= HERMIT_ST_N)
|
||||
st = HERMIT_ST_IDLE;
|
||||
if (frame < 0)
|
||||
frame = 0;
|
||||
frame %= HERMIT_FONT_FRAMES;
|
||||
int shell = with_shell ? 1 : 0;
|
||||
return (wchar_t)(HERMIT_FONT_PUA_BASE +
|
||||
(shell * HERMIT_ST_N + (int)st) * HERMIT_FONT_FRAMES +
|
||||
frame);
|
||||
}
|
||||
|
||||
/* --- minimal badge ------------------------------------------------------- */
|
||||
|
||||
const char *hermit_mini_badge(hermit_state_t st, int frame, int ascii) {
|
||||
int f = frame < 0 ? 0 : frame;
|
||||
if (ascii) {
|
||||
switch (st) {
|
||||
case HERMIT_ST_QUESTION:
|
||||
return "||?";
|
||||
case HERMIT_ST_ERROR:
|
||||
return "\\/!";
|
||||
case HERMIT_ST_SUCCESS:
|
||||
return "||*";
|
||||
case HERMIT_ST_THINKING:
|
||||
return (f % 2) ? "~|" : "|~";
|
||||
case HERMIT_ST_CODING:
|
||||
case HERMIT_ST_IDLE:
|
||||
default: {
|
||||
static const char *const spin[] = {"||", ">_", "||", "-"};
|
||||
return spin[f % 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (st) {
|
||||
case HERMIT_ST_QUESTION:
|
||||
return "║║?";
|
||||
case HERMIT_ST_ERROR:
|
||||
return "╲╱!";
|
||||
case HERMIT_ST_SUCCESS:
|
||||
return "║║✦";
|
||||
case HERMIT_ST_THINKING:
|
||||
return (f % 2) ? "║~" : "~║";
|
||||
case HERMIT_ST_CODING:
|
||||
case HERMIT_ST_IDLE:
|
||||
default: {
|
||||
static const char *const spin[] = {"║║", ">_", "║║", "─"};
|
||||
return spin[f % 4];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --- home shell art (fixed grid) ----------------------------------------- */
|
||||
/* 6 rows x 14 cols. Roles: 0 body 1 shell 2 eye 3 leg 4 prompt 5 empty/mark */
|
||||
|
||||
#define ART_H 6
|
||||
#define ART_W 14
|
||||
|
||||
static const char *const ART_SHELL[ART_H] = {
|
||||
" ######## ", /* shell top */
|
||||
" ## >_ ## ", /* shell + prompt */
|
||||
" ########## ", /* shell bottom */
|
||||
" ###### ", /* body */
|
||||
" #::## ", /* eyes :: on body */
|
||||
" | | ", /* legs */
|
||||
};
|
||||
|
||||
static const char *const ART_NOSHELL[ART_H] = {
|
||||
" ",
|
||||
" ",
|
||||
" ###### ",
|
||||
" #::## ",
|
||||
" ###### ",
|
||||
" | | ",
|
||||
};
|
||||
|
||||
static const char *const ART_SHELL_ASC[ART_H] = {
|
||||
" ######## ",
|
||||
" ## >_ ## ",
|
||||
" ########## ",
|
||||
" ###### ",
|
||||
" #::## ",
|
||||
" | | ",
|
||||
};
|
||||
|
||||
int hermit_shell_art(hermit_state_t st, int with_shell, int ascii,
|
||||
const char **lines, int max_lines) {
|
||||
(void)st;
|
||||
if (!lines || max_lines < 1)
|
||||
return 0;
|
||||
const char *const *src =
|
||||
with_shell ? (ascii ? ART_SHELL_ASC : ART_SHELL) : ART_NOSHELL;
|
||||
int n = ART_H < max_lines ? ART_H : max_lines;
|
||||
for (int i = 0; i < n; i++)
|
||||
lines[i] = src[i];
|
||||
return n;
|
||||
}
|
||||
|
||||
int hermit_shell_cell_role(hermit_state_t st, int with_shell, int row, int col) {
|
||||
(void)st;
|
||||
if (row < 0 || row >= ART_H || col < 0 || col >= ART_W)
|
||||
return 5;
|
||||
const char *const *src = with_shell ? ART_SHELL : ART_NOSHELL;
|
||||
char c = src[row][col];
|
||||
if (c == ' ' || !c)
|
||||
return 5;
|
||||
if (c == '>' || c == '_')
|
||||
return 4;
|
||||
if (c == ':')
|
||||
return 2;
|
||||
if (c == '|')
|
||||
return 3;
|
||||
if (with_shell && row <= 2)
|
||||
return 1; /* shell */
|
||||
return 0; /* body */
|
||||
}
|
||||
Reference in New Issue
Block a user