I think ksh needs more love from the devs ;)

[PATCH 1/7] ksh/vi mode: complete as command on Ctrl-f.

 * adds a flag for x_cf_glob() to force completion like it was a command
 * new argument for complete_word() to pass the flag
 * reuse print_expansions() unused argument to pass the flag

 Why: useful for sudo or one-liner completion
 XXX: use different key combination?
---
 edit.c |    2 ++
 edit.h |    7 ++++---
 vi.c   |   22 +++++++++++-----------
 3 files changed, 17 insertions(+), 14 deletions(-)

diff --git a/edit.c b/edit.c
index 6c357a7..0b1ff7d 100644
--- a/edit.c
+++ b/edit.c
@@ -599,6 +599,8 @@ x_cf_glob(int flags, const char *buf, int buflen, int pos, 
int *startp,
        len = x_locate_word(buf, buflen, pos, startp, &is_command);
        if (!(flags & XCF_COMMAND))
                is_command = 0;
+       if (flags & XCF_FORCE_COMMAND)
+               is_command = 1;
        /* Don't do command globing on zero length strings - it takes too
         * long and isn't very useful.  File globs are more likely to be
         * useful, so allow these.
diff --git a/edit.h b/edit.h
index f966fe4..9c75ffc 100644
--- a/edit.h
+++ b/edit.h
@@ -38,9 +38,10 @@ typedef struct {
 EXTERN X_chars edchars;
 
 /* x_fc_glob() flags */
-#define XCF_COMMAND    BIT(0)  /* Do command completion */
-#define XCF_FILE       BIT(1)  /* Do file completion */
-#define XCF_FULLPATH   BIT(2)  /* command completion: store full path */
+#define XCF_COMMAND            BIT(0)  /* Do command completion */
+#define XCF_FILE               BIT(1)  /* Do file completion */
+#define XCF_FULLPATH           BIT(2)  /* command completion: store full path 
*/
+#define XCF_FORCE_COMMAND      BIT(3)  /* Force completion as a command */
 #define XCF_COMMAND_FILE (XCF_COMMAND|XCF_FILE)
 
 /* edit.c */
diff --git a/vi.c b/vi.c
index 889b35a..e4173c7 100644
--- a/vi.c
+++ b/vi.c
@@ -58,7 +58,7 @@ static int    newcol(int, int);
 static void    display(char *, char *, int);
 static void    ed_mov_opt(int, char *);
 static int     expand_word(int);
-static int     complete_word(int, int);
+static int     complete_word(int, int, int);
 static int     print_expansions(struct edstate *, int);
 static int     char_len(int);
 static void    x_vi_zotc(int);
@@ -651,7 +651,7 @@ vi_insert(int ch)
                break;
 
        case Ctrl('f'):
-               complete_word(0, 0);
+               complete_word(0, 0, XCF_FORCE_COMMAND);
                break;
 
        case Ctrl('e'):
@@ -660,7 +660,7 @@ vi_insert(int ch)
 
        case Ctrl('i'):
                if (Flag(FVITABCOMPLETE)) {
-                       complete_word(0, 0);
+                       complete_word(0, 0, 0);
                        break;
                }
                /* FALLTHROUGH */
@@ -1111,14 +1111,14 @@ vi_cmd(int argcnt, const char *cmd)
 
                case '=':                       /* at&t ksh */
                case Ctrl('e'):                 /* Nonstandard vi/ksh */
-                       print_expansions(es, 1);
+                       print_expansions(es, 0);
                        break;
 
 
                case Ctrl('i'):                 /* Nonstandard vi/ksh */
                        if (!Flag(FVITABCOMPLETE))
                                return -1;
-                       complete_word(1, argcnt);
+                       complete_word(1, argcnt, 0);
                        break;
 
                case Ctrl('['):                 /* some annoying at&t ksh's */
@@ -1126,7 +1126,7 @@ vi_cmd(int argcnt, const char *cmd)
                                return -1;
                case '\\':                      /* at&t ksh */
                case Ctrl('f'):                 /* Nonstandard vi/ksh */
-                       complete_word(1, argcnt);
+                       complete_word(1, argcnt, 0);
                        break;
 
 
@@ -1939,7 +1939,7 @@ expand_word(int command)
 }
 
 static int
-complete_word(int command, int count)
+complete_word(int command, int count, int flags)
 {
        static struct edstate *buf;
        int rval = 0;
@@ -1953,7 +1953,7 @@ complete_word(int command, int count)
 
        /* Undo previous completion */
        if (command == 0 && expanded == COMPLETE && buf) {
-               print_expansions(buf, 0);
+               print_expansions(buf, flags);
                expanded = PRINT;
                return 0;
        }
@@ -1971,7 +1971,7 @@ complete_word(int command, int count)
        /* XCF_FULLPATH for count 'cause the menu printed by print_expansions()
         * was done this way.
         */
-       nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0),
+       nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0) | 
flags,
            es->cbuf, es->linelen, es->cursor,
            &start, &end, &words, &is_command);
        if (nwords == 0) {
@@ -2044,14 +2044,14 @@ complete_word(int command, int count)
 }
 
 static int
-print_expansions(struct edstate *e, int command)
+print_expansions(struct edstate *e, int flags)
 {
        int nwords;
        int start, end;
        char **words;
        int is_command;
 
-       nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH,
+       nwords = x_cf_glob(XCF_COMMAND_FILE|XCF_FULLPATH|flags,
            e->cbuf, e->linelen, e->cursor,
            &start, &end, &words, &is_command);
        if (nwords == 0) {
-- 
1.7.5

[PATCH 2/7] edit.h: fix typo

---
 edit.h |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/edit.h b/edit.h
index 9c75ffc..37ccf28 100644
--- a/edit.h
+++ b/edit.h
@@ -37,7 +37,7 @@ typedef struct {
 
 EXTERN X_chars edchars;
 
-/* x_fc_glob() flags */
+/* x_cf_glob() flags */
 #define XCF_COMMAND            BIT(0)  /* Do command completion */
 #define XCF_FILE               BIT(1)  /* Do file completion */
 #define XCF_FULLPATH           BIT(2)  /* command completion: store full path 
*/
-- 
1.7.5

[PATCH 3/7] ksh/vi: Ctrl-l in insert mode to clear the screen.

 Why: typing "clear" is too slow.
---
 ksh.1 |    3 +++
 vi.c  |    6 ++++++
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/ksh.1 b/ksh.1
index f4b5815..01130ea 100644
--- a/ksh.1
+++ b/ksh.1
@@ -5215,6 +5215,9 @@ List all the commands or files that match the current 
big-word.
 Macro expansion.
 Execute the commands found in the alias
 .Ar c .
+.It ^L
+Clear the screen leaving the current line at the top of the
+screen.
 .El
 .Pp
 Intra-line movement commands:
diff --git a/vi.c b/vi.c
index e4173c7..d0de478 100644
--- a/vi.c
+++ b/vi.c
@@ -646,6 +646,12 @@ vi_insert(int ch)
                        return redo_insert(lastac - 1);
 
        /* { Begin nonstandard vi commands */
+       case Ctrl('l'):
+               /* Use ANSI escape codes to clear the screen */
+               x_puts("\033[2J\033[0;0H");
+               redraw_line(0);
+               break;
+
        case Ctrl('x'):
                expand_word(0);
                break;
-- 
1.7.5

[PATCH 4/7] ksh/vi: make Ctrl-f in command mode behave the same as
 in insert.

---
 vi.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/vi.c b/vi.c
index d0de478..6eb5d8c 100644
--- a/vi.c
+++ b/vi.c
@@ -1132,7 +1132,7 @@ vi_cmd(int argcnt, const char *cmd)
                                return -1;
                case '\\':                      /* at&t ksh */
                case Ctrl('f'):                 /* Nonstandard vi/ksh */
-                       complete_word(1, argcnt, 0);
+                       complete_word(1, argcnt, XCF_FORCE_COMMAND);
                        break;
 
 
-- 
1.7.5

[PATCH 5/7] ksh: print expansions like a "menu" (with numbers) in vi
 mode

 * adds an extra argument to x_print_expansions()
   - preserves the emacs mode behaviour

 Why: in vi mode one can use the expansion number to
      complete the word, but w/o numbers printed you
      have to *count* expansions with your eyes to
      find out the number. Stupid, huh?
---
 edit.c  |    7 +++++--
 edit.h  |    2 +-
 emacs.c |    4 ++--
 vi.c    |    4 ++--
 4 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/edit.c b/edit.c
index 0b1ff7d..9cdcc6d 100644
--- a/edit.c
+++ b/edit.c
@@ -292,7 +292,7 @@ static void glob_path(int flags, const char *pat, XPtrV *wp,
                                const char *path);
 
 void
-x_print_expansions(int nwords, char *const *words, int is_command)
+x_print_expansions(int nwords, char *const *words, int is_command, int menu)
 {
        int use_copy = 0;
        int prefix_len;
@@ -330,7 +330,10 @@ x_print_expansions(int nwords, char *const *words, int 
is_command)
         */
        x_putc('\r');
        x_putc('\n');
-       pr_list(use_copy ? (char **) XPptrv(l) : words);
+       if (menu)
+               pr_menu(use_copy ? (char **) XPptrv(l) : words);
+       else
+               pr_list(use_copy ? (char **) XPptrv(l) : words);
 
        if (use_copy)
                XPfree(l); /* not x_free_words() */
diff --git a/edit.h b/edit.h
index 37ccf28..258affe 100644
--- a/edit.h
+++ b/edit.h
@@ -52,7 +52,7 @@ void  x_puts(const char *);
 bool   x_mode(bool);
 int    promptlen(const char *, const char **);
 int    x_do_comment(char *, int, int *);
-void   x_print_expansions(int, char *const *, int);
+void   x_print_expansions(int, char *const *, int, int);
 int    x_cf_glob(int, const char *, int, int, int *, int *, char ***, int *);
 int    x_longest_prefix(int , char *const *);
 int    x_basename(const char *, const char *);
diff --git a/emacs.c b/emacs.c
index 0bfda96..3b2d083 100644
--- a/emacs.c
+++ b/emacs.c
@@ -1684,7 +1684,7 @@ do_complete(int flags,    /* 
XCF_{COMMAND,FILE,COMMAND_FILE} */
        }
 
        if (type == CT_LIST) {
-               x_print_expansions(nwords, words, is_command);
+               x_print_expansions(nwords, words, is_command, 0);
                x_redraw(0);
                x_free_words(nwords, words);
                return;
@@ -1707,7 +1707,7 @@ do_complete(int flags,    /* 
XCF_{COMMAND,FILE,COMMAND_FILE} */
        }
 
        if (type == CT_COMPLIST && !completed) {
-               x_print_expansions(nwords, words, is_command);
+               x_print_expansions(nwords, words, is_command, 0);
                completed = 1;
        }
 
diff --git a/vi.c b/vi.c
index 6eb5d8c..95d192c 100644
--- a/vi.c
+++ b/vi.c
@@ -1990,7 +1990,7 @@ complete_word(int command, int count, int flags)
                count--;
                if (count >= nwords) {
                        vi_error();
-                       x_print_expansions(nwords, words, is_command);
+                       x_print_expansions(nwords, words, is_command, 1);
                        x_free_words(nwords, words);
                        redraw_line(0);
                        return -1;
@@ -2064,7 +2064,7 @@ print_expansions(struct edstate *e, int flags)
                vi_error();
                return -1;
        }
-       x_print_expansions(nwords, words, is_command);
+       x_print_expansions(nwords, words, is_command, 1);
        x_free_words(nwords, words);
        redraw_line(0);
        return 0;
-- 
1.7.5

[PATCH 6/7] ksh: remove backslashes in filenames using lex.

 * this also removes the check for matching pattern and
   returned filename. if it returns 1 name, then it must
   be the filename of an existing file, right? i think
   so.

 Why:

  * less ugly code
  * working completion for special characters like [], () and so
  * suggested by martynas
---
 edit.c |   31 +++++++------------------------
 lex.c  |    4 ++++
 lex.h  |    1 +
 3 files changed, 12 insertions(+), 24 deletions(-)

diff --git a/edit.c b/edit.c
index 9cdcc6d..01c2fe6 100644
--- a/edit.c
+++ b/edit.c
@@ -351,7 +351,7 @@ x_file_glob(int flags, const char *str, int slen, char 
***wordsp)
 {
        char *toglob;
        char **words;
-       int nwords, i, idx, escaping;
+       int nwords;
        XPtrV w;
        struct source *s, *sold;
 
@@ -360,20 +360,6 @@ x_file_glob(int flags, const char *str, int slen, char 
***wordsp)
 
        toglob = add_glob(str, slen);
 
-       /* remove all escaping backward slashes */
-       escaping = 0;
-       for (i = 0, idx = 0; toglob[i]; i++) {
-               if (toglob[i] == '\\' && !escaping) {
-                       escaping = 1;
-                       continue;
-               }
-
-               toglob[idx] = toglob[i];
-               idx++;
-               if (escaping) escaping = 0;
-       }
-       toglob[idx] = '\0';
-
        /*
         * Convert "foo*" (toglob) to an array of strings (words)
         */
@@ -381,7 +367,7 @@ x_file_glob(int flags, const char *str, int slen, char 
***wordsp)
        s = pushs(SWSTR, ATEMP);
        s->start = s->str = toglob;
        source = s;
-       if (yylex(ONEWORD) != LWORD) {
+       if (yylex(ONEWORD|RMBKSLSH) != LWORD) {
                source = sold;
                internal_errorf(0, "fileglob: substitute error");
                return 0;
@@ -397,15 +383,12 @@ x_file_glob(int flags, const char *str, int slen, char 
***wordsp)
        if (nwords == 1) {
                struct stat statb;
 
-               /* Check if globbing failed (returned glob pattern),
-                * but be careful (E.g. toglob == "ab*" when the file
-                * "ab*" exists is not an error).
-                * Also, check for empty result - happens if we tried
-                * to glob something which evaluated to an empty
-                * string (e.g., "$FOO" when there is no FOO, etc).
+               /* Check if file exists, also, check for empty
+                * result - happens if we tried to glob something
+                * which evaluated to an empty string (e.g.,
+                * "$FOO" when there is no FOO, etc).
                 */
-               if ((strcmp(words[0], toglob) == 0 &&
-                   stat(words[0], &statb) < 0) ||
+                if((stat(words[0], &statb) < 0) ||
                    words[0][0] == '\0') {
                        x_free_words(nwords, words);
                        words = NULL;
diff --git a/lex.c b/lex.c
index ef741c6..fe3d91d 100644
--- a/lex.c
+++ b/lex.c
@@ -299,6 +299,10 @@ yylex(int cf)
                                        }
                                        /* FALLTHROUGH */
                                default:
+                                       if (cf & RMBKSLSH) {
+                                               *wp++ = QCHAR, *wp++ = c;
+                                               break;
+                                       }
                                        Xcheck(ws, wp);
                                        if (c) { /* trailing \ is lost */
                                                *wp++ = CHAR, *wp++ = '\\';
diff --git a/lex.h b/lex.h
index 0904fbd..6a0dbf9 100644
--- a/lex.h
+++ b/lex.h
@@ -113,6 +113,7 @@ typedef union {
 #define CMDWORD BIT(8)         /* parsing simple command (alias related) */
 #define HEREDELIM BIT(9)       /* parsing <<,<<- delimiter */
 #define HEREDOC BIT(10)                /* parsing heredoc */
+#define RMBKSLSH BIT(11)       /* remove backslashes */
 
 #define        HERES   10              /* max << in line */
 
-- 
1.7.5

[PATCH 7/7] ksh/vi: compensate for cursor move on command mode

 * move completion cursor one position right if the
   character is space
 * when we enter command mode, cursor is moved one
   position left, and the space on the end is "lost".
   So we are trying to complete "ls" instead of file
   while having "ls " and "file.c" when having "file.c ".
---
 vi.c |   15 ++++++++++++++-
 1 files changed, 14 insertions(+), 1 deletions(-)

diff --git a/vi.c b/vi.c
index 95d192c..0bac6be 100644
--- a/vi.c
+++ b/vi.c
@@ -1956,6 +1956,7 @@ complete_word(int command, int count, int flags)
        int match_len;
        int is_unique;
        int is_command;
+       int pos;
 
        /* Undo previous completion */
        if (command == 0 && expanded == COMPLETE && buf) {
@@ -1974,11 +1975,23 @@ complete_word(int command, int count, int flags)
                buf = 0;
        }
 
+       /* XXX: hack. When we enter command mode, the cursor is moved
+        * one position left. This means that the space at the end is
+        * eaten and file completion becomes command completion.
+        * (see x_locate_word() for more on this)
+        */
+       pos = es->cursor;
+       if (command) {
+               pos += (isspace(es->cbuf[es->cursor]) ? 1 : 0);
+               if (pos > es->linelen)
+                       pos = es->linelen;
+       }
+
        /* XCF_FULLPATH for count 'cause the menu printed by print_expansions()
         * was done this way.
         */
        nwords = x_cf_glob(XCF_COMMAND_FILE | (count ? XCF_FULLPATH : 0) | 
flags,
-           es->cbuf, es->linelen, es->cursor,
+           es->cbuf, es->linelen, pos,
            &start, &end, &words, &is_command);
        if (nwords == 0) {
                vi_error();
-- 
1.7.5

-- 
Alexander Polakov | plhk.ru

Reply via email to