* Alexander Polakov <polac...@gmail.com> [110721 22:01]:
> * Dmitrij D. Czarkoff <czark...@gmail.com> [110721 14:49]:
> > Hello!
> > 
> > I tried both documentation and google, and I could only figure out how to
> > enable arrow keys in emacs mode of ksh.
> > 
> > Is there a way to enable them in vi mode? Same goes for HOME and END 
> > buttons.
> 
> Try the patch below. 
> 
> You probably wonder why cursor movement is done in such a strange way,
> reimplementing both domove() and vi_cmd(), but I couldn't find a better
> way to go to "end of line + one".

This one should be a bit better..

diff --git a/edit.c b/edit.c
index 36f26ea..5d97dba 100644
--- a/edit.c
+++ b/edit.c
@@ -27,6 +27,7 @@ static int    x_file_glob(int, const char *, int, char ***);
 static int     x_command_glob(int, const char *, int, char ***);
 static int     x_locate_word(const char *, int, int, int *, int *);
 
+int inputq;
 
 /* Called from main */
 void
@@ -117,6 +118,12 @@ x_getc(void)
        char c;
        int n;
 
+       if (inputq) {
+               c = inputq;
+               inputq = 0;
+               return c;
+       }
+
        while ((n = blocking_read(STDIN_FILENO, &c, 1)) < 0 && errno == EINTR)
                if (trap) {
                        x_mode(false);
@@ -128,6 +135,26 @@ x_getc(void)
        return (int) (unsigned char) c;
 }
 
+int
+x_nbgetc(void)
+{
+       char c;
+       int n;
+       int flags;
+
+       if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) < 0)
+               return -1;
+       flags |= O_NONBLOCK;
+       if (fcntl(STDIN_FILENO, F_SETFL, flags) < 0)
+               return -1;
+       while ((n = read(STDIN_FILENO, &c, 1)) < 0 && errno == EAGAIN)
+               return -1;
+       if (n != 1)
+               return -1;
+       reset_nonblock(STDIN_FILENO);
+       return (int) (unsigned char) c;
+}
+
 void
 x_flush(void)
 {
@@ -135,6 +162,12 @@ x_flush(void)
 }
 
 void
+x_putback(int c) 
+{
+       inputq = c;
+}
+
+void
 x_putc(int c)
 {
        shf_putc(c, shl_out);
diff --git a/edit.h b/edit.h
index 258affe..87c52cc 100644
--- a/edit.h
+++ b/edit.h
@@ -46,7 +46,9 @@ EXTERN X_chars edchars;
 
 /* edit.c */
 int    x_getc(void);
+int    x_nbgetc(void);
 void   x_flush(void);
+void   x_putback(int);
 void   x_putc(int);
 void   x_puts(const char *);
 bool   x_mode(bool);
diff --git a/vi.c b/vi.c
index 0bac6be..5850b50 100644
--- a/vi.c
+++ b/vi.c
@@ -247,6 +247,47 @@ x_vi(char *buf, size_t len)
        return es->linelen;
 }
 
+static int keypad(int ch) {
+       int cur = 0;
+       char cmd;
+
+       switch (ch) {
+               case 'D': /* left */
+                       cur--;
+                       break;
+               case 'C': /* right */
+                       cur++;
+                       break;
+               case 'A': /* up */
+                       cmd = 'k';
+                       vi_cmd(1, &cmd);
+                       break;
+               case 'B': /* down */
+                       cmd = 'j';
+                       vi_cmd(1, &cmd);
+                       break;
+               case 'H': /* home */
+                       es->cursor = 0;
+                       break;
+               case 'F': /* end */
+                       es->cursor = es->linelen;
+                       break;
+               default:
+                       return 1;
+       }
+       if ((cur += es->cursor) >= 0) {
+               if (cur > es->linelen && cur != 0) {
+                       cur--;
+                       vi_error();
+               }
+               es->cursor = cur;
+       } else
+               vi_error();
+
+       refresh(0);
+       return 0;
+}
+
 static int
 vi_hook(int ch)
 {
@@ -559,6 +600,8 @@ static int
 vi_insert(int ch)
 {
        int     tcursor;
+       static  int escseq = 0;
+       int     c;
 
        if (ch == edchars.erase || ch == Ctrl('h')) {
                if (insert == REPLACE) {
@@ -629,6 +672,14 @@ vi_insert(int ch)
                return 1;
 
        case Ctrl('['):
+               if ((c = x_nbgetc()) != -1) {
+                       if (c == '[') {
+                               escseq = c;
+                               return 0;
+                       } else
+                               x_putback(c);
+               }
+escmode:
                expanded = NONE;
                if (first_insert) {
                        first_insert = 0;
@@ -673,6 +724,13 @@ vi_insert(int ch)
        /* End nonstandard vi commands } */
 
        default:
+               if (escseq) {
+                       escseq = 0;
+                       if (keypad(ch)) 
+                               goto escmode;
+                       return 0;
+               }
+
                if (es->linelen >= es->cbufsize - 1)
                        return -1;
                ibuf[inslen++] = ch;

-- 
Alexander Polakov | plhk.ru

Reply via email to