]> rtime.felk.cvut.cz Git - sysless.git/blobdiff - libs4c/cmdproc/cmd_io_line.c
cmdproc: Make backspace work even in sterm
[sysless.git] / libs4c / cmdproc / cmd_io_line.c
index 324eebd219ce89747140868b8792c8d0c42d7ca1..3bcca497d9695b31a52a1f27279f30f087a85cc0 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 */
 
@@ -40,7 +41,7 @@ int cmd_ed_line_buf(ed_line_buf_t *elb, int ch)
   if(!lastch){
     elb->inbuf=0;               /* Start new line */
   }
-  if(ch == '\b') {             /* backspace */
+  if(ch == '\b' || ch == 127) {                /* backspace, del (sometimes backspace = 127) */
     if (elb->inbuf > 0)
       elb->inbuf--;
     return 0;
@@ -90,31 +91,119 @@ 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)
 {
   int ch;
   cmd_io_t* io_stack = cmd_io->priv.ed_line.io_stack;
-  ed_line_buf_t *ed_line_in = cmd_io->priv.ed_line.in;
+  ed_line_buf_t *el = cmd_io->priv.ed_line.in;
 
   if(!io_stack)
       return -1;
 
   while((ch=cmd_io_getc(io_stack))>=0){
 //    DPRINT("Added %c (%d)\n", ch, ch);
-    int eol = cmd_ed_line_buf(ed_line_in,ch);
+    if (handle_history(el, ch, io_stack) == 1)
+      continue;
+    int eol = cmd_ed_line_buf(el,ch);
     if (eol == -1)
       return -1;
     if(eol){
-      if(ed_line_in->flg&FL_ELB_ECHO){
+      if(el->flg&FL_ELB_ECHO){
         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
-      if(ed_line_in->flg&FL_ELB_ECHO) {
+      if(el->flg&FL_ELB_ECHO) {
         while(cmd_io_putc(io_stack,ch)<0);
+        if (ch == 127)
+                 while(cmd_io_putc(io_stack,'\b')<0);
+               if (ch == '\b' || ch == 127)
+                 cmd_io_puts(io_stack, "\033[K"); /* Erase End of Line */
       }
   }
   return 0;