rdline: don't display prompt if stopped by user
[libcmdline.git] / src / lib / cmdline_rdline.c
index 16fda43..785a23c 100644 (file)
@@ -107,7 +107,7 @@ rdline_init(struct rdline *rdl,
        rdl->validate = validate;
        rdl->complete = complete;
        rdl->help = help;
-       rdl->status = RDLINE_INIT;
+       rdl->status = RDLINE_STOPPED;
 #ifndef NO_RDLINE_HISTORY
        cirbuf_init(&rdl->history, rdl->history_buf, 0, RDLINE_HISTORY_BUF_SIZE);
 #endif /* !NO_RDLINE_HISTORY */
@@ -135,7 +135,7 @@ rdline_newline(struct rdline *rdl, const char *prompt)
 void
 rdline_stop(struct rdline *rdl)
 {
-       rdl->status = RDLINE_INIT;
+       rdl->status = RDLINE_STOPPED;
 }
 
 void
@@ -214,20 +214,30 @@ rdline_parse_char(struct rdline *rdl, char c)
 #ifndef NO_PAGER
        /* display asynchrounous printf if any */
        if (rdl->pager_buf != NULL) {
-               if (cmd == VT100_STD_CHAR && c == 'q') {
-                       rdline_asyncpager_reset(rdl);
-                       // call cb()
-                       if (rdl->pager_buf == NULL)
-                               return RDLINE_RES_VALIDATED;
-               }
 
-               if (rdline_pager_next_page(rdl) == 0) {
+               /* user ask to exit pager, or last page is displayed*/
+               if ((cmd == VT100_STD_CHAR && c == 'q') ||
+                   rdline_pager_next_page(rdl) == 0) {
+                       int ret;
+
+                       ret = rdl->pager_ret;
                        rdline_asyncpager_reset(rdl);
-                       // call cb()
-                       if (rdl->pager_buf == NULL)
-                               return RDLINE_RES_VALIDATED;
+                       if (rdl->pager_cb != NULL) {
+                               rdl->pager_cb(rdl, rdl->pager_arg);
+                               rdl->pager_cb = NULL;
+                       }
+                       /* maybe the pager was reloaded in the
+                        * callback */
+                       if (rdl->pager_buf != NULL)
+                               return RDLINE_RES_SUCCESS;
+
+                       /* else, redisplay prompt and return the saved status */
+                       rdline_redisplay(rdl);
+                       return ret;
                }
-               /* async printf was called in cb() */
+
+               /* Some pages remain, lines were displayed in
+                * rdline_pager_next_page() */
                return RDLINE_RES_SUCCESS;
        }
 #endif
@@ -394,12 +404,14 @@ rdline_parse_char(struct rdline *rdl, char c)
                        cirbuf_align_left(&rdl->left);
                        rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
                        rdline_printf(rdl, "\r\n");
-                       rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
 #ifndef NO_PAGER
-                       if (rdl->pager_buf != NULL) {
-                               // XXX set cb
+                       rdl->help(rdl, rdl->left_buf, rdline_asyncpager_write, rdl);
+                       if (rdl->pager_buf != NULL)
                                return RDLINE_RES_SUCCESS;
-                       }
+                       else
+                               rdline_asyncpager_reset(rdl);
+#else
+                       rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
 #endif
                        rdline_redisplay(rdl);
                        break;
@@ -407,7 +419,7 @@ rdline_parse_char(struct rdline *rdl, char c)
 
                case CMDLINE_KEY_TAB: {
                        char tmp_buf[CMDLINE_MAX_TOKEN_SIZE];
-                       int ret; //, curline = 0;
+                       int ret;
                        unsigned int tmp_size;
 
                        if (rdl->complete == NULL)
@@ -425,12 +437,15 @@ rdline_parse_char(struct rdline *rdl, char c)
                                cirbuf_align_left(&rdl->left);
                                rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
                                rdline_printf(rdl, "\r\n");
-                               rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
 #ifndef NO_PAGER
-                               if (rdl->pager_buf != NULL) {
-                                       // XXX set cb
+                               rdl->help(rdl, rdl->left_buf, rdline_asyncpager_write,
+                                         rdl);
+                               if (rdl->pager_buf != NULL)
                                        return RDLINE_RES_SUCCESS;
-                               }
+                               else
+                                       rdline_asyncpager_reset(rdl);
+#else
+                               rdl->help(rdl, rdl->left_buf, rdline_write, rdl);
 #endif
                                rdline_redisplay(rdl);
                                break;
@@ -451,10 +466,15 @@ rdline_parse_char(struct rdline *rdl, char c)
                }
 
                case CMDLINE_KEY_RETURN:
-               case CMDLINE_KEY_RETURN2:
+               case CMDLINE_KEY_RETURN2: {
+                       char tmp;
+                       while (!CIRBUF_IS_EMPTY(&rdl->right) &&
+                              (tmp = cirbuf_get_head(&rdl->right))) {
+                               cirbuf_del_head(&rdl->right);
+                               cirbuf_add_tail(&rdl->left, tmp);
+                       }
                        cirbuf_align_left(&rdl->left);
-                       rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\n';
-                       rdl->left_buf[CIRBUF_GET_LEN(&rdl->left) + 1] = '\0';
+                       rdl->left_buf[CIRBUF_GET_LEN(&rdl->left)] = '\0';
                        rdline_printf(rdl, "\r\n");
 #ifndef NO_RDLINE_HISTORY
                        if (rdl->history_cur_line != -1)
@@ -462,24 +482,29 @@ rdline_parse_char(struct rdline *rdl, char c)
 #endif
 
                        if (rdl->validate)
-                               rdl->validate(rdl, rdl->left_buf, CIRBUF_GET_LEN(&rdl->left)+2);
+                               rdl->validate(rdl, rdl->left_buf,
+                                             CIRBUF_GET_LEN(&rdl->left)+2);
 #ifndef NO_PAGER
                        /* user may have stopped rdline */
                        if (rdl->status == RDLINE_EXITED) {
                                rdline_asyncpager_reset(rdl);
                                return RDLINE_RES_EXITED;
                        }
+                       /* there is something in pager buffer, save
+                        * return value that will be return once
+                        * paging is finished */
                        if (rdl->pager_buf != NULL) {
-                               // XXX set cb
+                               rdl->pager_ret = RDLINE_RES_VALIDATED;
                                return RDLINE_RES_SUCCESS;
                        }
-                       rdl->status = RDLINE_INIT;
+
+                       rdline_asyncpager_reset(rdl);
 #else
                        if (rdl->status == RDLINE_EXITED)
                                return RDLINE_RES_EXITED;
 #endif
                        return RDLINE_RES_VALIDATED;
-
+               }
 #ifndef NO_RDLINE_HISTORY
                case CMDLINE_KEY_UP_ARR:
                case CMDLINE_KEY_CTRL_P:
@@ -521,7 +546,6 @@ rdline_parse_char(struct rdline *rdl, char c)
                        break;
 #endif /* !NO_RDLINE_HISTORY */
 
-
                default:
                        break;
                }
@@ -767,6 +791,9 @@ rdline_asyncpager_reset(struct rdline *rdl)
        rdl->pager_lines = 0;
        rdl->pager_len = 0;
        rdl->pager_off = 0;
+       rdl->pager_cb = NULL;
+       rdl->pager_arg = NULL;
+       rdl->pager_ret = RDLINE_RES_SUCCESS;
 }
 
 /* Return the offset of the i-th occurence of char c in string s. If
@@ -828,9 +855,11 @@ rdline_pager_next_page(struct rdline *rdl)
 }
 
 /* push data in pager */
-static int
-rdline_pager_push(struct rdline *rdl, char *s, int len)
+ssize_t
+rdline_asyncpager_write(struct rdline *rdl, void *buf, size_t len)
 {
+       char *s = buf;
+
        /* display as many lines as we can */
        if (rdl->pager_lines < RDLINE_MAX_LINES) {
                int lines = RDLINE_MAX_LINES - rdl->pager_lines;
@@ -865,8 +894,7 @@ rdline_pager_push(struct rdline *rdl, char *s, int len)
        return 0;
 }
 
-/* XXX we should have a specific return value when displaying will be
- * asynchronous, we may also have a callback */
+/* Print data asynchronously (using pager if needed) */
 int
 rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...)
 {
@@ -888,8 +916,19 @@ rdline_asyncpager_printf(struct rdline *rdl, const char *fmt, ...)
        if (n >= BUFSIZ)
                n = BUFSIZ-1;
        if (n > 0)
-               rdline_pager_push(rdl, buf, n);
+               rdline_asyncpager_write(rdl, buf, n);
        free(buf);
        return n;
 }
+
+int rdline_asyncpager_set_cb(struct rdline *rdl, rdline_asyncpager_cb_t *cb,
+                            void *arg)
+{
+       if (rdl->pager_buf == NULL)
+               return -1;
+
+       rdl->pager_cb = cb;
+       rdl->pager_arg = arg;
+       return 0;
+}
 #endif /* !NO_PAGER */