From 77e594145c6c3da49f5e65a793d7cba90091f6bd Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 3 Nov 2020 13:29:57 -0500 Subject: New -status option to display a status bar --- eval.c | 111 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 100 insertions(+), 11 deletions(-) (limited to 'eval.c') diff --git a/eval.c b/eval.c index e3806d8..09c253f 100644 --- a/eval.c +++ b/eval.c @@ -19,6 +19,7 @@ */ #include "eval.h" +#include "bar.h" #include "bftw.h" #include "color.h" #include "darray.h" @@ -929,17 +930,17 @@ static int eval_gettime(struct eval_state *state, struct timespec *ts) { } /** - * Record the time that elapsed evaluating an expression. + * Record an elapsed time. */ -static void add_elapsed(struct expr *expr, const struct timespec *start, const struct timespec *end) { - expr->elapsed.tv_sec += end->tv_sec - start->tv_sec; - expr->elapsed.tv_nsec += end->tv_nsec - start->tv_nsec; - if (expr->elapsed.tv_nsec < 0) { - expr->elapsed.tv_nsec += 1000000000L; - --expr->elapsed.tv_sec; - } else if (expr->elapsed.tv_nsec >= 1000000000L) { - expr->elapsed.tv_nsec -= 1000000000L; - ++expr->elapsed.tv_sec; +static void timespec_elapsed(struct timespec *elapsed, const struct timespec *start, const struct timespec *end) { + elapsed->tv_sec += end->tv_sec - start->tv_sec; + elapsed->tv_nsec += end->tv_nsec - start->tv_nsec; + if (elapsed->tv_nsec < 0) { + elapsed->tv_nsec += 1000000000L; + --elapsed->tv_sec; + } else if (elapsed->tv_nsec >= 1000000000L) { + elapsed->tv_nsec -= 1000000000L; + ++elapsed->tv_sec; } } @@ -961,7 +962,7 @@ static bool eval_expr(struct expr *expr, struct eval_state *state) { if (time) { if (eval_gettime(state, &end) == 0) { - add_elapsed(expr, &start, &end); + timespec_elapsed(&expr->elapsed, &start, &end); } } @@ -1030,6 +1031,71 @@ bool eval_comma(const struct expr *expr, struct eval_state *state) { return eval_expr(expr->rhs, state); } +/** Update the status bar. */ +static void eval_status(struct eval_state *state, struct bfs_bar *bar, struct timespec *last_status, size_t count) { + struct timespec now; + if (eval_gettime(state, &now) == 0) { + struct timespec elapsed = {0}; + timespec_elapsed(&elapsed, last_status, &now); + + // Update every 0.1s + if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= 100000000L) { + *last_status = now; + } else { + return; + } + } + + size_t width = bfs_bar_width(bar); + if (width < 3) { + return; + } + + const struct BFTW *ftwbuf = state->ftwbuf; + + char *rhs = dstrprintf(" (visited: %zu, depth: %2zu)", count, ftwbuf->depth); + if (!rhs) { + return; + } + + size_t rhslen = dstrlen(rhs); + if (3 + rhslen > width) { + dstresize(&rhs, 0); + rhslen = 0; + } + + size_t pathmax = width - rhslen - 3; + size_t pathlen = ftwbuf->nameoff; + if (ftwbuf->depth == 0) { + pathlen = strlen(ftwbuf->path); + } + if (pathlen > pathmax) { + pathlen = pathmax; + } + + char *status = dstrndup(ftwbuf->path, pathlen); + if (!status) { + goto out_rhs; + } + if (dstrcat(&status, "...") != 0) { + goto out_rhs; + } + while (dstrlen(status) < pathmax + 3) { + if (dstrapp(&status, ' ') != 0) { + goto out_rhs; + } + } + if (dstrcat(&status, rhs) != 0) { + goto out_rhs; + } + + bfs_bar_update(bar, status); + + dstrfree(status); +out_rhs: + dstrfree(rhs); +} + /** Check if we've seen a file before. */ static bool eval_file_unique(struct eval_state *state, struct trie *seen) { const struct bfs_stat *statbuf = eval_stat(state); @@ -1172,8 +1238,17 @@ static const char *dump_bftw_action(enum bftw_action action) { struct callback_args { /** The bfs context. */ const struct bfs_ctx *ctx; + + /** The status bar. */ + struct bfs_bar *bar; + /** The time of the last status update. */ + struct timespec last_status; + /** The number of files visited so far. */ + size_t count; + /** The set of seen files. */ struct trie *seen; + /** Eventual return value from bfs_eval(). */ int ret; }; @@ -1183,6 +1258,7 @@ struct callback_args { */ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) { struct callback_args *args = ptr; + ++args->count; const struct bfs_ctx *ctx = args->ctx; @@ -1193,6 +1269,10 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) { state.ret = &args->ret; state.quit = false; + if (args->bar) { + eval_status(&state, args->bar, &args->last_status, args->count); + } + if (ftwbuf->type == BFTW_ERROR) { if (!eval_should_ignore(&state, ftwbuf->error)) { args->ret = EXIT_FAILURE; @@ -1341,6 +1421,13 @@ int bfs_eval(const struct bfs_ctx *ctx) { .ret = EXIT_SUCCESS, }; + if (ctx->status) { + args.bar = bfs_bar_show(); + if (!args.bar) { + bfs_warning(ctx, "Couldn't show status bar: %m.\n"); + } + } + struct trie seen; if (ctx->unique) { trie_init(&seen); @@ -1395,5 +1482,7 @@ int bfs_eval(const struct bfs_ctx *ctx) { trie_destroy(&seen); } + bfs_bar_hide(args.bar); + return args.ret; } -- cgit v1.2.3