]> rtime.felk.cvut.cz Git - sysless.git/commitdiff
cmdproc: Add history handling
authorMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 1 Aug 2013 09:08:17 +0000 (11:08 +0200)
committerMichal Sojka <sojkam1@fel.cvut.cz>
Thu, 1 Aug 2013 09:09:31 +0000 (11:09 +0200)
Now, command processor can remember several last entered lines. The user can
naviagte the history with Up/Down or Ctrl-P/Ctrl-N keys.

When hist and hist_size fields of ed_line are zero, the behavior of
the cmdproc should be the same as without this change.

libs4c/cmdproc/cmd_io_line.c
libs4c/cmdproc/cmd_proc.h
libs4c/cmdproc/cmdio_std_line.c

index 7209d0f54fbc652e3f595c6229eb5567ed1d5a51..7ad0ec8e7aaf77e486bcb10eb6c6c6d96be2a897 100644 (file)
@@ -20,6 +20,7 @@
 #include <cmd_proc.h>
 #include "cmd_proc_priv.h"
 #include <string.h>
+#include <ctype.h>
 
 /* cmd_io line editor */
 
@@ -90,6 +91,80 @@ int cmd_io_line_out(cmd_io_t *cmd_io)
   return 1;
 }
 
+static void replace_history(ed_line_buf_t *el, cmd_io_t* io_stack)
+{
+  if(!el->lastch)
+    el->inbuf=0;               /* Make inbuf consistent */
+  while (el->inbuf) {          /* Delete previous input */
+    el->inbuf--;
+    while (cmd_io_putc(io_stack,'\b') < 0);
+  }
+  if (el->hist_idx >= 0) {
+    strncpy(el->buf, el->hist + el->hist_idx*el->alloc, el->alloc);
+    while (el->buf[el->inbuf]) {
+      el->lastch = el->buf[el->inbuf++];
+      while (cmd_io_putc(io_stack, el->lastch) < 0);
+    }
+  }
+  cmd_io_puts(io_stack, "\033[K"); /* Erase End of Line */
+}
+
+/**
+ * @return One when the character was consumed, zero otherwise.
+ */
+static int handle_history(ed_line_buf_t *el, char ch, cmd_io_t* io_stack)
+{
+  enum { NONE, UP, DOWN } dir = NONE;
+
+  if (!(el->hist && el->hist_size && el->hist_size >= 2*el->alloc))
+    return 0;
+
+  switch (ch) {
+  case 14: /* Ctrl-N */
+    dir = DOWN;
+    break;
+  case 16: /* Ctrl-P */
+    dir = UP;
+    break;
+  case '\033': /* ESC */
+    strcpy(el->esc, "\033");
+    return 1;
+  default:
+    if (!el->esc[0])
+      return 0;
+
+    char *p = el->esc+1;
+    while (*p && p < el->esc + sizeof(el->esc) - 2) p++;
+    if (!*p) {
+      p[0] = ch;
+      p[1] = 0;
+    }
+    if (isalpha(ch)) {
+      if (strcmp(el->esc, "\033[A") == 0) dir = UP;
+      else if (strcmp(el->esc, "\033[B") == 0) dir = DOWN;
+      el->esc[0] = 0;
+    }
+    if (dir == NONE)
+      return 1;
+  }
+
+  if (dir == DOWN) {
+    if (el->hist_idx >= 0)
+      el->hist_idx--;
+    else
+      return 1;
+  } else if (dir == UP) {
+    if ((el->hist_idx+2) * el->alloc <= el->hist_size &&
+       el->hist[(el->hist_idx+1) * el->alloc])
+      el->hist_idx++;
+    else
+      return 1;
+  }
+
+  replace_history(el, io_stack);
+  return 1;
+}
+
 /* process input & perform echo if requested */
 int cmd_io_line_in(cmd_io_t *cmd_io)
 {
@@ -102,6 +177,8 @@ int cmd_io_line_in(cmd_io_t *cmd_io)
 
   while((ch=cmd_io_getc(io_stack))>=0){
 //    DPRINT("Added %c (%d)\n", ch, ch);
+    if (handle_history(el, ch, io_stack) == 1)
+      continue;
     int eol = cmd_ed_line_buf(el,ch);
     if (eol == -1)
       return -1;
@@ -110,6 +187,14 @@ int cmd_io_line_in(cmd_io_t *cmd_io)
         while(cmd_io_putc(io_stack,'\r')<0);
         while(cmd_io_putc(io_stack,'\n')<0);
       }
+      if (el->hist && el->hist_size) {
+       el->hist_idx = -1;
+       if ((el->hist[0] && strcmp(el->buf, el->hist) == 0) || /* The same command as before */
+           !el->buf[0])        /* Empty line */
+         return 1;             /* Don't add to the history */
+       memmove(el->hist + el->alloc, el->hist, el->hist_size - el->alloc);
+       strncpy(el->hist, el->buf, el->alloc);
+      }
       return 1;
     }
     else
index db6d423d1f38ba592c0e047ccd8f8af8ddcfeb27..badbe6a01f1a9a9f68b4cd62852e8f654049c4f1 100644 (file)
@@ -48,6 +48,10 @@ typedef struct{
                                  * If FL_ELB_INSEND is set, lastch is
                                  * index of last sent char. */
   char *buf;
+  char *hist;                  /* Previous input lines (history) */
+  int  hist_size;              /* Size of the history buffer (must be at least 2*alloc) */
+  int  hist_idx;               /* Index of the last selected history line or -1 if no history was yet selected */
+  char esc[6];                 /* Buffer for ESC sequence processing */
 } ed_line_buf_t;
 
 /* Structure for character input output. It is used either for direct
index 63cb615292201fadfd0112b16f2cdbc7fc21bece..48f366f0da23a7e6e12a965ce488ae37936fdcef 100644 (file)
@@ -14,6 +14,7 @@
 #define ED_LINE_CHARS 80
 
 char ed_line_in_std[ED_LINE_CHARS+1];
+char ed_line_in_std_history[10*(ED_LINE_CHARS+1)];
 char ed_line_out_std[ED_LINE_CHARS+1];
 
 
@@ -23,7 +24,9 @@ ed_line_buf_t ed_line_buf_in_std={
     alloc:sizeof(ed_line_in_std),
     maxlen:0,
     lastch:0,
-    buf:ed_line_in_std
+    buf:ed_line_in_std,
+    hist:ed_line_in_std_history,
+    hist_size:sizeof(ed_line_in_std_history),
 };
 
 ed_line_buf_t ed_line_buf_out_std={