diff -ruN a/config.def.h b/config.def.h --- a/config.def.h 2026-05-20 12:05:11.699957443 +0200 +++ b/config.def.h 2026-05-20 12:05:11.703957526 +0200 @@ -3,3 +3,8 @@ /* progress bar glyphs (ASCII default) */ static const char *const BAR_FILL = ">"; static const char *const BAR_EMPTY = "-"; + +/* default bar style: "" autodetects (unicode if locale is UTF-8, else ascii). + * Available: unicode | ascii | hash | dots | line | block | arrow | minimal. + */ +static const char *const BAR_STYLE = ""; diff -ruN a/ttym.c b/ttym.c --- a/ttym.c 2026-05-20 12:05:11.699957443 +0200 +++ b/ttym.c 2026-05-20 12:06:26.161496315 +0200 @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -23,6 +24,7 @@ typedef struct { int quiet; /* -q: suppress completion bell */ int silent; /* -s: no bell, no extras */ + char bar_style[32]; /* --bar STYLE */ } Config; static struct termios oldtios; @@ -186,7 +188,8 @@ /* ===== drawing ===== */ static void -draw_countdown(long total, long elapsed_ms, int paused, int barw) +draw_countdown(long total, long elapsed_ms, int paused, int barw, + const char *fill_glyph, const char *empty_glyph, int minimal) { if (total <= 0) return; long total_ms = total * 1000L; @@ -207,8 +210,15 @@ const char *status = paused ? "PAUSED " : " "; printf("\r%sT-%s\033[0m \033[2m+%s\033[0m [", color, rem, el); - for (int i = 0; i < fill; i++) fputs(BAR_FILL, stdout); - for (int i = 0; i < empty; i++) fputs(BAR_EMPTY, stdout); + if (minimal) { + fputs("\033[7m", stdout); + for (int i = 0; i < fill; i++) fputc(' ', stdout); + fputs("\033[27m", stdout); + for (int i = 0; i < empty; i++) fputc(' ', stdout); + } else { + for (int i = 0; i < fill; i++) fputs(fill_glyph, stdout); + for (int i = 0; i < empty; i++) fputs(empty_glyph, stdout); + } printf("] %3ld%% %s", pct, status); fflush(stdout); } @@ -226,6 +236,55 @@ fflush(stdout); } +/* ===== bar styles ===== */ + +typedef struct { const char *name, *fill, *empty; } BarStyle; + +static const BarStyle bar_styles[] = { + { "unicode", "\xe2\x96\x88", "\xe2\x96\x91" }, /* U+2588 U+2591 */ + { "ascii", "=", "-" }, + { "hash", "#", "." }, + { "dots", "\xe2\x80\xa2", "\xc2\xb7" }, /* U+2022 U+00B7 */ + { "line", "\xe2\x94\x81", "\xe2\x94\x80" }, /* U+2501 U+2500 */ + { "block", "\xe2\x96\x93", "\xe2\x96\x91" }, /* U+2593 U+2591 */ + { "arrow", "\xe2\x96\xb6", "\xe2\x96\xb7" }, /* U+25B6 U+25B7 */ + { "minimal", "", "" }, + { NULL, NULL, NULL } +}; + +static const BarStyle * +find_bar_style(const char *name) +{ + if (!name || !*name) return NULL; + for (int i = 0; bar_styles[i].name; i++) + if (!strcmp(bar_styles[i].name, name)) return &bar_styles[i]; + return NULL; +} + +static int +is_utf8(void) +{ + const char *l = setlocale(LC_CTYPE, ""); + if (!l) return 0; + return strstr(l, "UTF-8") || strstr(l, "utf8") || strstr(l, "utf-8"); +} + +static void +resolve_bar(const Config *c, const char **fill, const char **empty, int *minimal) +{ + *minimal = 0; + const char *name = (c->bar_style[0]) ? c->bar_style : BAR_STYLE; + const BarStyle *s = find_bar_style(name); + if (!s) s = find_bar_style(is_utf8() ? "unicode" : "ascii"); + if (s && !strcmp(s->name, "minimal")) { + *minimal = 1; + *fill = " "; *empty = " "; + return; + } + *fill = s ? s->fill : BAR_FILL; + *empty = s ? s->empty : BAR_EMPTY; +} + /* ===== usage ===== * Patches MUST update this in lockstep with new flags so -h always * reflects the build. @@ -243,6 +302,7 @@ "FLAGS:\n" " -q no sound\n" " -s silent\n" +" --bar STYLE bar style: unicode|ascii|hash|dots|line|block|arrow|minimal\n" " -- end of options\n" " -h help\n" "\n" @@ -259,6 +319,10 @@ int barw = cols - 40; if (barw < 10) barw = 10; + const char *fill_glyph, *empty_glyph; + int minimal = 0; + resolve_bar(cfg, &fill_glyph, &empty_glyph, &minimal); + ttyfd = open("/dev/tty", O_RDONLY); if (ttyfd >= 0 && isatty(ttyfd)) { if (tcgetattr(ttyfd, &oldtios) == 0) { @@ -300,7 +364,8 @@ draw_stopwatch(elapsed_ms, paused); } else { if (out_tty) - draw_countdown(total, elapsed_ms, paused, barw); + draw_countdown(total, elapsed_ms, paused, barw, + fill_glyph, empty_glyph, minimal); if (!paused && elapsed_ms >= total * 1000L) break; } @@ -399,6 +464,10 @@ new_argv[new_argc++] = argv[i]; continue; } + if (!past_dd && !strcmp(argv[i], "--bar") && i + 1 < argc) { + snprintf(cfg.bar_style, sizeof(cfg.bar_style), "%s", argv[++i]); + continue; + } new_argv[new_argc++] = argv[i]; } new_argv[new_argc] = NULL;