Patch to ksh adding history-search-backward/forward

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Patch to ksh adding history-search-backward/forward

Martin Hedenfalk
Here is a patch adding a history-search-backward and -forward function
to ksh that many bash-users might be accustomed to. It's an implicitly
anchored version of "search-history" using the prefix of the current
line up to the cursor as search pattern, discarding duplicate matches.
Can be bound to up/down arrow.

The patch is also available at
http://hedenfalk.se/patches/ksh-history.patch in case it gets messed up
in the mail.

I've been using this patch for a week now. It seems to be stable.

/Martin

Index: emacs.c
===================================================================
RCS file: /cvs/src/bin/ksh/emacs.c,v
retrieving revision 1.39
diff -u -d -r1.39 emacs.c
--- emacs.c     26 Sep 2005 19:25:22 -0000      1.39
+++ emacs.c     16 Mar 2006 07:10:31 -0000
@@ -106,6 +106,7 @@
  static int     x_curprefix;
  static char    *macroptr;
  static int     prompt_skip;
+static char    x_search_hist_pattern [256+1];

  static int      x_ins(char *);
  static void     x_delete(int, int);
@@ -119,6 +120,8 @@
  static void     x_zotc(int);
  static void     x_load_hist(char **);
  static int      x_search(char *, int, int);
+static int     x_search_delta(char *, int, int, int);
+static int     x_search_delta_distinct(char *, int, int, int);
  static int      x_match(char *, char *);
  static void    x_redraw(int);
  static void     x_push(int);
@@ -190,6 +193,8 @@
         { x_search_char_forw,   "search-character-forward",     XF_ARG },
         { x_search_char_back,   "search-character-backward",    XF_ARG },
         { x_search_hist,        "search-history",               0 },
+       { x_search_hist_backward, "history-search-backward",    0 },
+       { x_search_hist_forward, "history-search-forward",      0 },
         { x_set_mark,           "set-mark-command",             0 },
         { x_stuff,              "stuff",                        0 },
         { x_stuffreset,         "stuff-reset",                  0 },
@@ -860,9 +865,7 @@
                 if ((c = x_e_getc()) < 0)
                         return KSTD;
                 f = x_tab[0][c&CHARMASK];
-               if (c == CTRL('['))
-                       break;
-               else if (f == XFUNC_search_hist)
+                if (f == XFUNC_search_hist)
                         offset = x_search(pat, 0, offset);
                 else if (f == XFUNC_del_back) {
                         if (p == pat) {
@@ -904,14 +907,90 @@
         return KSTD;
  }

-/* search backward from current line */
+/* determine if prefix history searching should be performed, or plain
+ * up/down history traversing */
  static int
-x_search(char *pat, int sameline, int offset)
+x_search_hist_has_prefix(void)
+{
+       size_t pat_len;
+
+       /* skip prefix history search if at beginning of line */
+       if (xcp == xbuf)
+               return 0;
+
+       /* prepare the prefix search pattern */
+       pat_len = xcp - xbuf;
+       x_search_hist_pattern[0] = '^';
+       if (pat_len > 256)
+               pat_len = 256;
+       strlcpy(x_search_hist_pattern + 1, xbuf, pat_len + 1);
+       return 1;
+}
+
+/* a modal version of (up|down)-history, necessary in order not to
+ * confuse with prefix history searches */
+static void
+x_search_hist_modal(int delta)
+{
+       int c;
+       u_char f;
+
+       x_load_hist(x_histp + delta);
+
+       while(1) {
+               x_flush();
+               if ((c = x_e_getc()) < 0)
+                       break;
+               f = x_tab[x_curprefix][c&CHARMASK];
+               if (f == XFUNC_search_hist_backward) {
+                       x_load_hist(x_histp - 1);
+                       x_curprefix = 0;
+               } else if (f == XFUNC_search_hist_forward) {
+                       x_load_hist(x_histp + 1);
+                       x_curprefix = 0;
+               } else if (f == XFUNC_meta1)
+                       x_meta1(0);
+               else if (f == XFUNC_meta2)
+                       x_meta2(0);
+               else {
+                       x_e_ungetc(c);
+                       break;
+               }
+       }
+}
+
+/* search history backwards for line with same prefix */
+static int
+x_search_hist_backward(int c)
+{
+       if (x_search_hist_has_prefix())
+               x_search_delta_distinct(x_search_hist_pattern, 0, 0, -1);
+       else
+               x_search_hist_modal(-1);
+       return KSTD;
+}
+
+/* search history forwards for line with same prefix */
+static int
+x_search_hist_forward(int c)
+{
+       if (x_search_hist_has_prefix())
+               x_search_delta_distinct(x_search_hist_pattern, 0, 0, +1);
+       else
+               x_search_hist_modal(+1);
+       return KSTD;
+}
+
+/* search backward or forward from current line depending on delta */
+static int
+x_search_delta(char *pat, int sameline, int offset, int delta)
  {
         char **hp;
         int i;

-       for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
+       for (hp = x_histp + (sameline ? 0 : delta) ;
+                hp >= history && hp <= histptr ;
+                hp += delta) {
                 i = x_match(*hp, pat);
                 if (i >= 0) {
                         if (offset < 0)
@@ -924,6 +1003,31 @@
         x_e_putc(BEL);
         x_histp = histptr;
         return -1;
+}
+
+/* just as x_search_delta, but skips duplicate matches */
+static int
+x_search_delta_distinct(char *pat, int sameline, int offset, int delta)
+{
+    char *orig_xbuf;
+    int rc;
+
+    orig_xbuf = strdup(xbuf);
+
+    while(1) {
+        rc = x_search_delta(pat, sameline, offset, delta);
+        if(rc < 0 || strcmp(orig_xbuf, *x_histp) != 0)
+            break;
+    }
+    free(orig_xbuf);
+    return rc;
+}
+
+/* search backward from current line */
+static int
+x_search(char *pat, int sameline, int offset)
+{
+       return x_search_delta(pat, sameline, offset, -1);
  }

  /* return position of first match of pattern in string, else -1 */
Index: ksh.1
===================================================================
RCS file: /cvs/src/bin/ksh/ksh.1,v
retrieving revision 1.110
diff -u -d -r1.110 ksh.1
--- ksh.1       7 Mar 2006 09:31:02 -0000       1.110
+++ ksh.1       16 Mar 2006 07:10:31 -0000
@@ -4837,6 +4837,14 @@
  .Xc
  Goes to history number
  .Ar n .
+.It history-search-backward:
+Search the internal history list backwards for a line beginning with the
+current content of the input buffer up to the cursor. Duplicate matches
+are skipped.
+.It history-search-forward:
+Search the internal history list forwards for a line beginning with the
+current content of the input buffer up to the cursor. Duplicate matches
+are skipped.
  .It kill-line: KILL
  Deletes the entire input line.
  .It kill-region: ^W

Reply | Threaded
Open this post in threaded view
|

Re: Patch to ksh adding history-search-backward/forward

Martin Hedenfalk-3
Sorry for bumping and replying to myself, but I'd like to know what I
did wrong with this patch. Was the feature just not wanted, was it a
bad patch or was there some other reason it was so totally ignored?

An updated patch against -current is available at
http://bzero.se/patches/ksh-history.patch.
Any comment?

/Martin

On 3/22/06, Martin Hedenfalk <[hidden email]> wrote:

> Here is a patch adding a history-search-backward and -forward function
> to ksh that many bash-users might be accustomed to. It's an implicitly
> anchored version of "search-history" using the prefix of the current
> line up to the cursor as search pattern, discarding duplicate matches.
> Can be bound to up/down arrow.
>
> The patch is also available at
> http://hedenfalk.se/patches/ksh-history.patch in case it gets messed up
> in the mail.
>
> I've been using this patch for a week now. It seems to be stable.
>
> /Martin
>
> Index: emacs.c
> ===================================================================
> RCS file: /cvs/src/bin/ksh/emacs.c,v
> retrieving revision 1.39
> diff -u -d -r1.39 emacs.c
> --- emacs.c     26 Sep 2005 19:25:22 -0000      1.39
> +++ emacs.c     16 Mar 2006 07:10:31 -0000
> @@ -106,6 +106,7 @@
>   static int     x_curprefix;
>   static char    *macroptr;
>   static int     prompt_skip;
> +static char    x_search_hist_pattern [256+1];
>
>   static int      x_ins(char *);
>   static void     x_delete(int, int);
> @@ -119,6 +120,8 @@
>   static void     x_zotc(int);
>   static void     x_load_hist(char **);
>   static int      x_search(char *, int, int);
> +static int     x_search_delta(char *, int, int, int);
> +static int     x_search_delta_distinct(char *, int, int, int);
>   static int      x_match(char *, char *);
>   static void    x_redraw(int);
>   static void     x_push(int);
> @@ -190,6 +193,8 @@
>          { x_search_char_forw,   "search-character-forward",     XF_ARG },
>          { x_search_char_back,   "search-character-backward",    XF_ARG },
>          { x_search_hist,        "search-history",               0 },
> +       { x_search_hist_backward, "history-search-backward",    0 },
> +       { x_search_hist_forward, "history-search-forward",      0 },
>          { x_set_mark,           "set-mark-command",             0 },
>          { x_stuff,              "stuff",                        0 },
>          { x_stuffreset,         "stuff-reset",                  0 },
> @@ -860,9 +865,7 @@
>                  if ((c = x_e_getc()) < 0)
>                          return KSTD;
>                  f = x_tab[0][c&CHARMASK];
> -               if (c == CTRL('['))
> -                       break;
> -               else if (f == XFUNC_search_hist)
> +                if (f == XFUNC_search_hist)
>                          offset = x_search(pat, 0, offset);
>                  else if (f == XFUNC_del_back) {
>                          if (p == pat) {
> @@ -904,14 +907,90 @@
>          return KSTD;
>   }
>
> -/* search backward from current line */
> +/* determine if prefix history searching should be performed, or plain
> + * up/down history traversing */
>   static int
> -x_search(char *pat, int sameline, int offset)
> +x_search_hist_has_prefix(void)
> +{
> +       size_t pat_len;
> +
> +       /* skip prefix history search if at beginning of line */
> +       if (xcp == xbuf)
> +               return 0;
> +
> +       /* prepare the prefix search pattern */
> +       pat_len = xcp - xbuf;
> +       x_search_hist_pattern[0] = '^';
> +       if (pat_len > 256)
> +               pat_len = 256;
> +       strlcpy(x_search_hist_pattern + 1, xbuf, pat_len + 1);
> +       return 1;
> +}
> +
> +/* a modal version of (up|down)-history, necessary in order not to
> + * confuse with prefix history searches */
> +static void
> +x_search_hist_modal(int delta)
> +{
> +       int c;
> +       u_char f;
> +
> +       x_load_hist(x_histp + delta);
> +
> +       while(1) {
> +               x_flush();
> +               if ((c = x_e_getc()) < 0)
> +                       break;
> +               f = x_tab[x_curprefix][c&CHARMASK];
> +               if (f == XFUNC_search_hist_backward) {
> +                       x_load_hist(x_histp - 1);
> +                       x_curprefix = 0;
> +               } else if (f == XFUNC_search_hist_forward) {
> +                       x_load_hist(x_histp + 1);
> +                       x_curprefix = 0;
> +               } else if (f == XFUNC_meta1)
> +                       x_meta1(0);
> +               else if (f == XFUNC_meta2)
> +                       x_meta2(0);
> +               else {
> +                       x_e_ungetc(c);
> +                       break;
> +               }
> +       }
> +}
> +
> +/* search history backwards for line with same prefix */
> +static int
> +x_search_hist_backward(int c)
> +{
> +       if (x_search_hist_has_prefix())
> +               x_search_delta_distinct(x_search_hist_pattern, 0, 0, -1);
> +       else
> +               x_search_hist_modal(-1);
> +       return KSTD;
> +}
> +
> +/* search history forwards for line with same prefix */
> +static int
> +x_search_hist_forward(int c)
> +{
> +       if (x_search_hist_has_prefix())
> +               x_search_delta_distinct(x_search_hist_pattern, 0, 0, +1);
> +       else
> +               x_search_hist_modal(+1);
> +       return KSTD;
> +}
> +
> +/* search backward or forward from current line depending on delta */
> +static int
> +x_search_delta(char *pat, int sameline, int offset, int delta)
>   {
>          char **hp;
>          int i;
>
> -       for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
> +       for (hp = x_histp + (sameline ? 0 : delta) ;
> +                hp >= history && hp <= histptr ;
> +                hp += delta) {
>                  i = x_match(*hp, pat);
>                  if (i >= 0) {
>                          if (offset < 0)
> @@ -924,6 +1003,31 @@
>          x_e_putc(BEL);
>          x_histp = histptr;
>          return -1;
> +}
> +
> +/* just as x_search_delta, but skips duplicate matches */
> +static int
> +x_search_delta_distinct(char *pat, int sameline, int offset, int delta)
> +{
> +    char *orig_xbuf;
> +    int rc;
> +
> +    orig_xbuf = strdup(xbuf);
> +
> +    while(1) {
> +        rc = x_search_delta(pat, sameline, offset, delta);
> +        if(rc < 0 || strcmp(orig_xbuf, *x_histp) != 0)
> +            break;
> +    }
> +    free(orig_xbuf);
> +    return rc;
> +}
> +
> +/* search backward from current line */
> +static int
> +x_search(char *pat, int sameline, int offset)
> +{
> +       return x_search_delta(pat, sameline, offset, -1);
>   }
>
>   /* return position of first match of pattern in string, else -1 */
> Index: ksh.1
> ===================================================================
> RCS file: /cvs/src/bin/ksh/ksh.1,v
> retrieving revision 1.110
> diff -u -d -r1.110 ksh.1
> --- ksh.1       7 Mar 2006 09:31:02 -0000       1.110
> +++ ksh.1       16 Mar 2006 07:10:31 -0000
> @@ -4837,6 +4837,14 @@
>   .Xc
>   Goes to history number
>   .Ar n .
> +.It history-search-backward:
> +Search the internal history list backwards for a line beginning with the
> +current content of the input buffer up to the cursor. Duplicate matches
> +are skipped.
> +.It history-search-forward:
> +Search the internal history list forwards for a line beginning with the
> +current content of the input buffer up to the cursor. Duplicate matches
> +are skipped.
>   .It kill-line: KILL
>   Deletes the entire input line.
>   .It kill-region: ^W

Reply | Threaded
Open this post in threaded view
|

Re: Patch to ksh adding history-search-backward/forward

Otto Moerbeek
On Fri, 1 Sep 2006, Martin Hedenfalk wrote:

> Sorry for bumping and replying to myself, but I'd like to know what I
> did wrong with this patch. Was the feature just not wanted, was it a
> bad patch or was there some other reason it was so totally ignored?

Nobody found the feauture interesting enough, it seems.

        -Otto

>
> An updated patch against -current is available at
> http://bzero.se/patches/ksh-history.patch.
> Any comment?
>
> /Martin
>
> On 3/22/06, Martin Hedenfalk <[hidden email]> wrote:
> > Here is a patch adding a history-search-backward and -forward function
> > to ksh that many bash-users might be accustomed to. It's an implicitly
> > anchored version of "search-history" using the prefix of the current
> > line up to the cursor as search pattern, discarding duplicate matches.
> > Can be bound to up/down arrow.
> >
> > The patch is also available at
> > http://hedenfalk.se/patches/ksh-history.patch in case it gets messed up
> > in the mail.
> >
> > I've been using this patch for a week now. It seems to be stable.
> >
> > /Martin
> >
> > Index: emacs.c
> > ===================================================================
> > RCS file: /cvs/src/bin/ksh/emacs.c,v
> > retrieving revision 1.39
> > diff -u -d -r1.39 emacs.c
> > --- emacs.c     26 Sep 2005 19:25:22 -0000      1.39
> > +++ emacs.c     16 Mar 2006 07:10:31 -0000
> > @@ -106,6 +106,7 @@
> >   static int     x_curprefix;
> >   static char    *macroptr;
> >   static int     prompt_skip;
> > +static char    x_search_hist_pattern [256+1];
> >
> >   static int      x_ins(char *);
> >   static void     x_delete(int, int);
> > @@ -119,6 +120,8 @@
> >   static void     x_zotc(int);
> >   static void     x_load_hist(char **);
> >   static int      x_search(char *, int, int);
> > +static int     x_search_delta(char *, int, int, int);
> > +static int     x_search_delta_distinct(char *, int, int, int);
> >   static int      x_match(char *, char *);
> >   static void    x_redraw(int);
> >   static void     x_push(int);
> > @@ -190,6 +193,8 @@
> >          { x_search_char_forw,   "search-character-forward",     XF_ARG },
> >          { x_search_char_back,   "search-character-backward",    XF_ARG },
> >          { x_search_hist,        "search-history",               0 },
> > +       { x_search_hist_backward, "history-search-backward",    0 },
> > +       { x_search_hist_forward, "history-search-forward",      0 },
> >          { x_set_mark,           "set-mark-command",             0 },
> >          { x_stuff,              "stuff",                        0 },
> >          { x_stuffreset,         "stuff-reset",                  0 },
> > @@ -860,9 +865,7 @@
> >                  if ((c = x_e_getc()) < 0)
> >                          return KSTD;
> >                  f = x_tab[0][c&CHARMASK];
> > -               if (c == CTRL('['))
> > -                       break;
> > -               else if (f == XFUNC_search_hist)
> > +                if (f == XFUNC_search_hist)
> >                          offset = x_search(pat, 0, offset);
> >                  else if (f == XFUNC_del_back) {
> >                          if (p == pat) {
> > @@ -904,14 +907,90 @@
> >          return KSTD;
> >   }
> >
> > -/* search backward from current line */
> > +/* determine if prefix history searching should be performed, or plain
> > + * up/down history traversing */
> >   static int
> > -x_search(char *pat, int sameline, int offset)
> > +x_search_hist_has_prefix(void)
> > +{
> > +       size_t pat_len;
> > +
> > +       /* skip prefix history search if at beginning of line */
> > +       if (xcp == xbuf)
> > +               return 0;
> > +
> > +       /* prepare the prefix search pattern */
> > +       pat_len = xcp - xbuf;
> > +       x_search_hist_pattern[0] = '^';
> > +       if (pat_len > 256)
> > +               pat_len = 256;
> > +       strlcpy(x_search_hist_pattern + 1, xbuf, pat_len + 1);
> > +       return 1;
> > +}
> > +
> > +/* a modal version of (up|down)-history, necessary in order not to
> > + * confuse with prefix history searches */
> > +static void
> > +x_search_hist_modal(int delta)
> > +{
> > +       int c;
> > +       u_char f;
> > +
> > +       x_load_hist(x_histp + delta);
> > +
> > +       while(1) {
> > +               x_flush();
> > +               if ((c = x_e_getc()) < 0)
> > +                       break;
> > +               f = x_tab[x_curprefix][c&CHARMASK];
> > +               if (f == XFUNC_search_hist_backward) {
> > +                       x_load_hist(x_histp - 1);
> > +                       x_curprefix = 0;
> > +               } else if (f == XFUNC_search_hist_forward) {
> > +                       x_load_hist(x_histp + 1);
> > +                       x_curprefix = 0;
> > +               } else if (f == XFUNC_meta1)
> > +                       x_meta1(0);
> > +               else if (f == XFUNC_meta2)
> > +                       x_meta2(0);
> > +               else {
> > +                       x_e_ungetc(c);
> > +                       break;
> > +               }
> > +       }
> > +}
> > +
> > +/* search history backwards for line with same prefix */
> > +static int
> > +x_search_hist_backward(int c)
> > +{
> > +       if (x_search_hist_has_prefix())
> > +               x_search_delta_distinct(x_search_hist_pattern, 0, 0, -1);
> > +       else
> > +               x_search_hist_modal(-1);
> > +       return KSTD;
> > +}
> > +
> > +/* search history forwards for line with same prefix */
> > +static int
> > +x_search_hist_forward(int c)
> > +{
> > +       if (x_search_hist_has_prefix())
> > +               x_search_delta_distinct(x_search_hist_pattern, 0, 0, +1);
> > +       else
> > +               x_search_hist_modal(+1);
> > +       return KSTD;
> > +}
> > +
> > +/* search backward or forward from current line depending on delta */
> > +static int
> > +x_search_delta(char *pat, int sameline, int offset, int delta)
> >   {
> >          char **hp;
> >          int i;
> >
> > -       for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
> > +       for (hp = x_histp + (sameline ? 0 : delta) ;
> > +                hp >= history && hp <= histptr ;
> > +                hp += delta) {
> >                  i = x_match(*hp, pat);
> >                  if (i >= 0) {
> >                          if (offset < 0)
> > @@ -924,6 +1003,31 @@
> >          x_e_putc(BEL);
> >          x_histp = histptr;
> >          return -1;
> > +}
> > +
> > +/* just as x_search_delta, but skips duplicate matches */
> > +static int
> > +x_search_delta_distinct(char *pat, int sameline, int offset, int delta)
> > +{
> > +    char *orig_xbuf;
> > +    int rc;
> > +
> > +    orig_xbuf = strdup(xbuf);
> > +
> > +    while(1) {
> > +        rc = x_search_delta(pat, sameline, offset, delta);
> > +        if(rc < 0 || strcmp(orig_xbuf, *x_histp) != 0)
> > +            break;
> > +    }
> > +    free(orig_xbuf);
> > +    return rc;
> > +}
> > +
> > +/* search backward from current line */
> > +static int
> > +x_search(char *pat, int sameline, int offset)
> > +{
> > +       return x_search_delta(pat, sameline, offset, -1);
> >   }
> >
> >   /* return position of first match of pattern in string, else -1 */
> > Index: ksh.1
> > ===================================================================
> > RCS file: /cvs/src/bin/ksh/ksh.1,v
> > retrieving revision 1.110
> > diff -u -d -r1.110 ksh.1
> > --- ksh.1       7 Mar 2006 09:31:02 -0000       1.110
> > +++ ksh.1       16 Mar 2006 07:10:31 -0000
> > @@ -4837,6 +4837,14 @@
> >   .Xc
> >   Goes to history number
> >   .Ar n .
> > +.It history-search-backward:
> > +Search the internal history list backwards for a line beginning with the
> > +current content of the input buffer up to the cursor. Duplicate matches
> > +are skipped.
> > +.It history-search-forward:
> > +Search the internal history list forwards for a line beginning with the
> > +current content of the input buffer up to the cursor. Duplicate matches
> > +are skipped.
> >   .It kill-line: KILL
> >   Deletes the entire input line.
> >   .It kill-region: ^W

Reply | Threaded
Open this post in threaded view
|

Re: Patch to ksh adding history-search-backward/forward

Marco Peereboom
I actually think this might be useful.  The one thing that irritates me about
ksh is that when you use persistent history the search in history is for
everything that user has typed instead of what was typed on the current
terminal followed by the complete history (hope that sentence makes sense).

Removing dups from searches is also very nice.

FWIW,
/marco

On Fri, Sep 01, 2006 at 11:09:51AM +0200, Otto Moerbeek wrote:

> On Fri, 1 Sep 2006, Martin Hedenfalk wrote:
>
> > Sorry for bumping and replying to myself, but I'd like to know what I
> > did wrong with this patch. Was the feature just not wanted, was it a
> > bad patch or was there some other reason it was so totally ignored?
>
> Nobody found the feauture interesting enough, it seems.
>
> -Otto
>
> >
> > An updated patch against -current is available at
> > http://bzero.se/patches/ksh-history.patch.
> > Any comment?
> >
> > /Martin
> >
> > On 3/22/06, Martin Hedenfalk <[hidden email]> wrote:
> > > Here is a patch adding a history-search-backward and -forward function
> > > to ksh that many bash-users might be accustomed to. It's an implicitly
> > > anchored version of "search-history" using the prefix of the current
> > > line up to the cursor as search pattern, discarding duplicate matches.
> > > Can be bound to up/down arrow.
> > >
> > > The patch is also available at
> > > http://hedenfalk.se/patches/ksh-history.patch in case it gets messed up
> > > in the mail.
> > >
> > > I've been using this patch for a week now. It seems to be stable.
> > >
> > > /Martin
> > >
> > > Index: emacs.c
> > > ===================================================================
> > > RCS file: /cvs/src/bin/ksh/emacs.c,v
> > > retrieving revision 1.39
> > > diff -u -d -r1.39 emacs.c
> > > --- emacs.c     26 Sep 2005 19:25:22 -0000      1.39
> > > +++ emacs.c     16 Mar 2006 07:10:31 -0000
> > > @@ -106,6 +106,7 @@
> > >   static int     x_curprefix;
> > >   static char    *macroptr;
> > >   static int     prompt_skip;
> > > +static char    x_search_hist_pattern [256+1];
> > >
> > >   static int      x_ins(char *);
> > >   static void     x_delete(int, int);
> > > @@ -119,6 +120,8 @@
> > >   static void     x_zotc(int);
> > >   static void     x_load_hist(char **);
> > >   static int      x_search(char *, int, int);
> > > +static int     x_search_delta(char *, int, int, int);
> > > +static int     x_search_delta_distinct(char *, int, int, int);
> > >   static int      x_match(char *, char *);
> > >   static void    x_redraw(int);
> > >   static void     x_push(int);
> > > @@ -190,6 +193,8 @@
> > >          { x_search_char_forw,   "search-character-forward",     XF_ARG },
> > >          { x_search_char_back,   "search-character-backward",    XF_ARG },
> > >          { x_search_hist,        "search-history",               0 },
> > > +       { x_search_hist_backward, "history-search-backward",    0 },
> > > +       { x_search_hist_forward, "history-search-forward",      0 },
> > >          { x_set_mark,           "set-mark-command",             0 },
> > >          { x_stuff,              "stuff",                        0 },
> > >          { x_stuffreset,         "stuff-reset",                  0 },
> > > @@ -860,9 +865,7 @@
> > >                  if ((c = x_e_getc()) < 0)
> > >                          return KSTD;
> > >                  f = x_tab[0][c&CHARMASK];
> > > -               if (c == CTRL('['))
> > > -                       break;
> > > -               else if (f == XFUNC_search_hist)
> > > +                if (f == XFUNC_search_hist)
> > >                          offset = x_search(pat, 0, offset);
> > >                  else if (f == XFUNC_del_back) {
> > >                          if (p == pat) {
> > > @@ -904,14 +907,90 @@
> > >          return KSTD;
> > >   }
> > >
> > > -/* search backward from current line */
> > > +/* determine if prefix history searching should be performed, or plain
> > > + * up/down history traversing */
> > >   static int
> > > -x_search(char *pat, int sameline, int offset)
> > > +x_search_hist_has_prefix(void)
> > > +{
> > > +       size_t pat_len;
> > > +
> > > +       /* skip prefix history search if at beginning of line */
> > > +       if (xcp == xbuf)
> > > +               return 0;
> > > +
> > > +       /* prepare the prefix search pattern */
> > > +       pat_len = xcp - xbuf;
> > > +       x_search_hist_pattern[0] = '^';
> > > +       if (pat_len > 256)
> > > +               pat_len = 256;
> > > +       strlcpy(x_search_hist_pattern + 1, xbuf, pat_len + 1);
> > > +       return 1;
> > > +}
> > > +
> > > +/* a modal version of (up|down)-history, necessary in order not to
> > > + * confuse with prefix history searches */
> > > +static void
> > > +x_search_hist_modal(int delta)
> > > +{
> > > +       int c;
> > > +       u_char f;
> > > +
> > > +       x_load_hist(x_histp + delta);
> > > +
> > > +       while(1) {
> > > +               x_flush();
> > > +               if ((c = x_e_getc()) < 0)
> > > +                       break;
> > > +               f = x_tab[x_curprefix][c&CHARMASK];
> > > +               if (f == XFUNC_search_hist_backward) {
> > > +                       x_load_hist(x_histp - 1);
> > > +                       x_curprefix = 0;
> > > +               } else if (f == XFUNC_search_hist_forward) {
> > > +                       x_load_hist(x_histp + 1);
> > > +                       x_curprefix = 0;
> > > +               } else if (f == XFUNC_meta1)
> > > +                       x_meta1(0);
> > > +               else if (f == XFUNC_meta2)
> > > +                       x_meta2(0);
> > > +               else {
> > > +                       x_e_ungetc(c);
> > > +                       break;
> > > +               }
> > > +       }
> > > +}
> > > +
> > > +/* search history backwards for line with same prefix */
> > > +static int
> > > +x_search_hist_backward(int c)
> > > +{
> > > +       if (x_search_hist_has_prefix())
> > > +               x_search_delta_distinct(x_search_hist_pattern, 0, 0, -1);
> > > +       else
> > > +               x_search_hist_modal(-1);
> > > +       return KSTD;
> > > +}
> > > +
> > > +/* search history forwards for line with same prefix */
> > > +static int
> > > +x_search_hist_forward(int c)
> > > +{
> > > +       if (x_search_hist_has_prefix())
> > > +               x_search_delta_distinct(x_search_hist_pattern, 0, 0, +1);
> > > +       else
> > > +               x_search_hist_modal(+1);
> > > +       return KSTD;
> > > +}
> > > +
> > > +/* search backward or forward from current line depending on delta */
> > > +static int
> > > +x_search_delta(char *pat, int sameline, int offset, int delta)
> > >   {
> > >          char **hp;
> > >          int i;
> > >
> > > -       for (hp = x_histp - (sameline ? 0 : 1) ; hp >= history; --hp) {
> > > +       for (hp = x_histp + (sameline ? 0 : delta) ;
> > > +                hp >= history && hp <= histptr ;
> > > +                hp += delta) {
> > >                  i = x_match(*hp, pat);
> > >                  if (i >= 0) {
> > >                          if (offset < 0)
> > > @@ -924,6 +1003,31 @@
> > >          x_e_putc(BEL);
> > >          x_histp = histptr;
> > >          return -1;
> > > +}
> > > +
> > > +/* just as x_search_delta, but skips duplicate matches */
> > > +static int
> > > +x_search_delta_distinct(char *pat, int sameline, int offset, int delta)
> > > +{
> > > +    char *orig_xbuf;
> > > +    int rc;
> > > +
> > > +    orig_xbuf = strdup(xbuf);
> > > +
> > > +    while(1) {
> > > +        rc = x_search_delta(pat, sameline, offset, delta);
> > > +        if(rc < 0 || strcmp(orig_xbuf, *x_histp) != 0)
> > > +            break;
> > > +    }
> > > +    free(orig_xbuf);
> > > +    return rc;
> > > +}
> > > +
> > > +/* search backward from current line */
> > > +static int
> > > +x_search(char *pat, int sameline, int offset)
> > > +{
> > > +       return x_search_delta(pat, sameline, offset, -1);
> > >   }
> > >
> > >   /* return position of first match of pattern in string, else -1 */
> > > Index: ksh.1
> > > ===================================================================
> > > RCS file: /cvs/src/bin/ksh/ksh.1,v
> > > retrieving revision 1.110
> > > diff -u -d -r1.110 ksh.1
> > > --- ksh.1       7 Mar 2006 09:31:02 -0000       1.110
> > > +++ ksh.1       16 Mar 2006 07:10:31 -0000
> > > @@ -4837,6 +4837,14 @@
> > >   .Xc
> > >   Goes to history number
> > >   .Ar n .
> > > +.It history-search-backward:
> > > +Search the internal history list backwards for a line beginning with the
> > > +current content of the input buffer up to the cursor. Duplicate matches
> > > +are skipped.
> > > +.It history-search-forward:
> > > +Search the internal history list forwards for a line beginning with the
> > > +current content of the input buffer up to the cursor. Duplicate matches
> > > +are skipped.
> > >   .It kill-line: KILL
> > >   Deletes the entire input line.
> > >   .It kill-region: ^W

Reply | Threaded
Open this post in threaded view
|

Re: Patch to ksh adding history-search-backward/forward

Martin Hedenfalk-3
On 9/1/06, Marco Peereboom <[hidden email]> wrote:
> I actually think this might be useful.  The one thing that irritates me about
> ksh is that when you use persistent history the search in history is for
> everything that user has typed instead of what was typed on the current
> terminal followed by the complete history (hope that sentence makes sense).

Eh... not sure I'm following you there. All I want to do is start
typing a command, remembering I've done it before, then press up arrow
(or meta-p) and have it recalled from history.

/martin

> Removing dups from searches is also very nice.
>
> FWIW,
> /marco
>
> On Fri, Sep 01, 2006 at 11:09:51AM +0200, Otto Moerbeek wrote:
> > On Fri, 1 Sep 2006, Martin Hedenfalk wrote:
> >
> > > Sorry for bumping and replying to myself, but I'd like to know what I
> > > did wrong with this patch. Was the feature just not wanted, was it a
> > > bad patch or was there some other reason it was so totally ignored?
> >
> > Nobody found the feauture interesting enough, it seems.
> >
> >       -Otto
> >
> > >
> > > An updated patch against -current is available at
> > > http://bzero.se/patches/ksh-history.patch.
> > > Any comment?
> > >
> > > /Martin
> > >
> > > On 3/22/06, Martin Hedenfalk <[hidden email]> wrote:
> > > > Here is a patch adding a history-search-backward and -forward function
> > > > to ksh that many bash-users might be accustomed to. It's an implicitly
> > > > anchored version of "search-history" using the prefix of the current
> > > > line up to the cursor as search pattern, discarding duplicate matches.
> > > > Can be bound to up/down arrow.
> > > >
> > > > The patch is also available at
> > > > http://hedenfalk.se/patches/ksh-history.patch in case it gets messed up
> > > > in the mail.
> > > >
> > > > I've been using this patch for a week now. It seems to be stable.
> > > >
> > > > /Martin