diff --git a/Makefile b/Makefile index bfebac5..ba950e7 100644 --- a/Makefile +++ b/Makefile @@ -3,6 +3,7 @@ PREFIX=/usr/local MANDIR=$(PREFIX)/share/man ALL_CFLAGS=$(CFLAGS) -std=c99 -Wall -Wextra -Wpedantic +TERM=dumb # TERM=ansi for smart status printing (requires TIOCGWINSZ ioctl) OBJ=\ build.o\ deps.o\ @@ -13,6 +14,7 @@ OBJ=\ parse.o\ samu.o\ scan.o\ + term-$(TERM).o \ tool.o\ tree.o\ util.o @@ -26,6 +28,7 @@ HDR=\ log.h\ parse.h\ scan.h\ + term.h\ tool.h\ tree.h\ util.h diff --git a/build.c b/build.c index 83d51b7..4d2d22d 100644 --- a/build.c +++ b/build.c @@ -16,6 +16,7 @@ #include "env.h" #include "graph.h" #include "log.h" +#include "term.h" #include "util.h" struct job { @@ -33,6 +34,7 @@ static struct edge *work; static size_t nstarted, nfinished, ntotal; static bool consoleused; static struct timespec starttime; +static bool dumb, newline; void buildreset(void) @@ -255,13 +257,15 @@ static int jobstart(struct job *j, struct edge *e) { extern char **environ; - size_t i; + size_t i, statuslen; struct node *n; struct string *rspfile, *content, *description; int fd[2]; posix_spawn_file_actions_t actions; char *argv[] = {"/bin/sh", "-c", NULL, NULL}, status[256]; + newline = false; + ++nstarted; for (i = 0; i < e->nout; ++i) { n = e->out[i]; @@ -290,9 +294,12 @@ jobstart(struct job *j, struct edge *e) description = buildopts.verbose ? NULL : edgevar(e, "description", true); if (!description || description->n == 0) description = j->cmd; - formatstatus(status, sizeof(status)); + if (!dumb) + putchar('\r'); + statuslen = formatstatus(status, sizeof(status)); + statuslen = statuslen < sizeof(status) ? statuslen : sizeof(status) - 1; fputs(status, stdout); - puts(description->s); + printdesc(dumb, statuslen, description); } if ((errno = posix_spawn_file_actions_init(&actions))) { @@ -445,8 +452,12 @@ jobdone(struct job *j) j->failed = true; } close(j->fd); - if (j->buf.len && (!consoleused || j->failed)) + if (j->buf.len && (!consoleused || j->failed)) { + if (!dumb) + putchar('\n'); fwrite(j->buf.data, 1, j->buf.len, stdout); + newline = j->buf.data[j->buf.len - 1] == '\n'; + } j->buf.len = 0; e = j->edge; if (e->pool) { @@ -512,6 +523,8 @@ build(void) size_t i, next = 0, jobslen = 0, numjobs = 0, numfail = 0; struct edge *e; + dumb = buildopts.verbose || isdumb(); + clock_gettime(CLOCK_MONOTONIC, &starttime); formatstatus(NULL, 0); @@ -568,6 +581,8 @@ build(void) ++numfail; } } + if (!dumb && jobslen && !newline) + putchar('\n'); for (i = 0; i < jobslen; ++i) free(jobs[i].buf.data); free(jobs); diff --git a/build.ninja b/build.ninja index 1edea67..2b983b0 100644 --- a/build.ninja +++ b/build.ninja @@ -17,9 +17,10 @@ build log.o: cc log.c build parse.o: cc parse.c build samu.o: cc samu.c build scan.o: cc scan.c +build term-dumb.o: cc term-dumb.c build tool.o: cc tool.c build tree.o: cc tree.c build util.o: cc util.c -build samu: link build.o deps.o env.o graph.o htab.o log.o parse.o samu.o scan.o tool.o tree.o util.o +build samu: link build.o deps.o env.o graph.o htab.o log.o parse.o samu.o scan.o term-dumb.c tool.o tree.o util.o default samu diff --git a/term-ansi.c b/term-ansi.c new file mode 100644 index 0000000..c87a75e --- /dev/null +++ b/term-ansi.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include +#include "util.h" + +int +isdumb(void) +{ + const char *term; + + term = getenv("TERM"); + return !isatty(1) || !term || !strcmp(term, "dumb"); +} + +void +printdesc(bool dumb, size_t statuslen, struct string *description) +{ + struct winsize ws; + + if (dumb) { + puts(description->s); + return; + } + + ioctl(1, TIOCGWINSZ, &ws); + if (statuslen + description->n > ws.ws_col) { + switch (ws.ws_col) { + case 3: putchar('.'); /* fallthrough */ + case 2: putchar('.'); /* fallthrough */ + case 1: putchar('.'); /* fallthrough */ + case 0: break; + default: printf("%.*s...%s", + (ws.ws_col - 3) / 2 - (int)statuslen, description->s, + description->s + description->n - (ws.ws_col - 3) / 2); + } + } else { + fputs(description->s, stdout); + } + printf("\033[K"); + fflush(stdout); +} diff --git a/term-dumb.c b/term-dumb.c new file mode 100644 index 0000000..bf90790 --- /dev/null +++ b/term-dumb.c @@ -0,0 +1,19 @@ +#include +#include +#include +#include "util.h" + +int +isdumb(void) +{ + return 1; +} + +void +printdesc(bool dumb, size_t statuslen, struct string *description) +{ + /* don't warn for unused parameters */ + (void)dumb; + (void)statuslen; + puts(description->s); +} diff --git a/term.h b/term.h new file mode 100644 index 0000000..99d7cdb --- /dev/null +++ b/term.h @@ -0,0 +1,9 @@ +#include + +struct string; + +/* determine if terminal is dumb or not */ +int isdumb(void); + +/* print description */ +void printdesc(bool dumb, size_t statuslen, struct string *description);