From e541d7bea7febed8cb9f8a65ae4bd9bdd1b5c8a0 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Thu, 12 Apr 2012 06:20:42 +0200 Subject: [PATCH] interactive: Introduce i9e_print_status_bar(). When operating in single key mode, the users of the i9e API may write a single line, called status bar, to stderr. This patch adds a new public function to the i9e subsystem for this purpose. It honors the width of the terminal and shortens the given status bar string to fit in one line if necessary. --- interactive.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- interactive.h | 1 + 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/interactive.c b/interactive.c index a18d82b7..44db6c58 100644 --- a/interactive.c +++ b/interactive.c @@ -31,6 +31,7 @@ struct i9e_private { char empty_line[1000]; struct task task; struct btr_node *stdout_btrn; + bool last_write_was_status; bool line_handler_running; bool input_eof; bool caught_sigint; @@ -311,7 +312,7 @@ static void i9e_post_select(__a_unused struct sched *s, struct task *t) int ret; struct i9e_client_info *ici = i9ep->ici; char *buf; - size_t sz; + size_t sz, consumed = 0; ret = -E_I9E_EOF; if (i9ep->input_eof) @@ -333,16 +334,24 @@ static void i9e_post_select(__a_unused struct sched *s, struct task *t) } if (ret == 0) goto out; +again: sz = btr_next_buffer(i9ep->stdout_btrn, &buf); if (sz == 0) goto out; + if (i9ep->last_write_was_status) + fprintf(i9ep->stderr_stream, "\n"); + i9ep->last_write_was_status = false; ret = xwrite(ici->fds[1], buf, sz); if (ret < 0) goto rm_btrn; btr_consume(i9ep->stdout_btrn, ret); + consumed += ret; + if (ret == sz && consumed < 10000) + goto again; goto out; rm_btrn: if (i9ep->stdout_btrn) { + wipe_bottom_line(); btr_remove_node(&i9ep->stdout_btrn); rl_set_keymap(i9ep->standard_km); rl_set_prompt(i9ep->ici->prompt); @@ -503,6 +512,41 @@ __printf_2_3 void i9e_log(int ll, const char* fmt,...) vfprintf(i9ep->stderr_stream, fmt, argp); va_end(argp); reset_line_state(); + i9ep->last_write_was_status = false; +} + +/** + * Print the current status to stderr. + * + * \param buf The text to print. + * \param len The number of bytes in \a buf. + * + * This clears the bottom line, moves to the beginning of the line and prints + * the given text. If the length of this text exceeds the width of the + * terminal, the text is shortened by leaving out a part in the middle. + */ +void ie9_print_status_bar(char *buf, unsigned len) +{ + size_t x = i9ep->num_columns, y = (x - 4) / 2; + + assert(x >= 6); + if (len > x) { + buf[y] = '\0'; + fprintf(i9ep->stderr_stream, "\r%s", buf); + fprintf(i9ep->stderr_stream, " .. "); + fprintf(i9ep->stderr_stream, "%s", buf + len - y); + } else { + char scratch[1000]; + + y = x - len; + scratch[0] = '\r'; + strcpy(scratch + 1, buf); + memset(scratch + 1 + len, ' ', y); + scratch[1 + len + y] = '\r'; + scratch[2 + len + y] = '\0'; + fprintf(i9ep->stderr_stream, "\r%s", scratch); + } + i9ep->last_write_was_status = true; } /** diff --git a/interactive.h b/interactive.h index fb398605..8e436755 100644 --- a/interactive.h +++ b/interactive.h @@ -84,6 +84,7 @@ struct i9e_client_info { int i9e_open(struct i9e_client_info *ici, struct sched *s); void i9e_attach_to_stdout(struct btr_node *producer); +void ie9_print_status_bar(char *buf, unsigned len); void i9e_close(void); void i9e_signal_dispatch(int sig_num); __printf_2_3 void i9e_log(int ll, const char* fmt,...); -- 2.39.2