interactive: Introduce i9e_print_status_bar().
authorAndre Noll <maan@systemlinux.org>
Thu, 12 Apr 2012 04:20:42 +0000 (06:20 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 18 Nov 2012 19:28:28 +0000 (20:28 +0100)
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
interactive.h

index a18d82b..44db6c5 100644 (file)
@@ -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;
 }
 
 /**
index fb39860..8e43675 100644 (file)
@@ -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,...);