Screen: dabbrevエミュレーション

前に移植したdabbrevをエミュレートするパッチを少しだけ修正。
以前は[a-zA-Z0-9_.@:%!-+']を含むに単語にマッチしていたけど、記号が鬱陶しいので[a-zA-Z0-9_]にマッチするようにした。

diff -ur screen-4.0.3.orig/comm.c screen-4.0.3/comm.c
--- screen-4.0.3.orig/comm.c	2003-09-08 23:25:08.000000000 +0900
+++ screen-4.0.3/comm.c	2008-01-23 02:07:39.953125000 +0900
@@ -122,6 +122,9 @@
 #ifdef COPY_PASTE
   { "copy",		NEED_FORE|ARGS_0 },
   { "crlf",		ARGS_01 },
+#ifdef DABBREV
+  { "dabbrev",		NEED_FORE|ARGS_0 },
+#endif
 #endif
   { "debug",		ARGS_01 },
 #ifdef AUTO_NUKE
diff -ur screen-4.0.3.orig/config.h.in screen-4.0.3/config.h.in
--- screen-4.0.3.orig/config.h.in	2006-10-23 22:06:32.000000000 +0900
+++ screen-4.0.3/config.h.in	2008-01-23 02:07:40.093750000 +0900
@@ -178,6 +178,7 @@
 # define COLORS16
 # define ZMODEM
 # define BLANKER_PRG
+# define DABBREV
 #endif /* SIMPLESCREEN */
 
 #undef BUILTIN_TELNET
diff -ur screen-4.0.3.orig/mark.c screen-4.0.3/mark.c
--- screen-4.0.3.orig/mark.c	2003-09-08 23:26:00.000000000 +0900
+++ screen-4.0.3/mark.c	2008-01-23 02:22:21.000000000 +0900
@@ -81,6 +81,9 @@
 
 static struct markdata *markdata;
 
+#ifdef DABBREV
+int restart_dabbrev = 1;                        /* used in process.c */
+#endif
 
 /*
  * VI like is_letter: 0 - whitespace
@@ -104,6 +107,19 @@
   return 0;
 }
 
+static int is_word(c)
+char c;
+{
+  if ((c >= 'a' && c <= 'z') ||
+      (c >= 'A' && c <= 'Z') ||
+      (c >= '0' && c <= '9') ||
+      (c == '_')) {
+    return 1;
+  } else {
+    return 0;
+  }
+}
+
 static int
 linestart(y)
 int y;
@@ -428,6 +444,131 @@
 
 /**********************************************************************/
 
+#ifdef DABBREV
+/* The following code implements `dynamic abbreviation' expansion a la
+  Emacs.  It looks in the preceding visible screen and its history to find
+  expansions of a typed word.  It checks consecutive expansions and
+  ignores one of them if they are identical. (Tomasz J. Cholewo,
+  t.cholewo@ieee.org) */
+
+int
+getprevchar (xp, yp)
+int *xp, *yp;
+{
+    static char *linep;
+    static int y = -1;
+    while (*yp >= 0) {
+        if (*yp != y) {                         /* cache last |linep| value */
+            y = *yp;
+            linep = WIN (y)->image;
+        }
+        if (--*xp >= 0)
+            return linep[*xp];
+        *xp = D_width;
+        (*yp)--;                                /* go to previous line */
+        if (!fore->w_wrap)
+            return ' ';                         /* separate lines */
+    }
+    return -1;
+}
+
+char *
+getprevword (xp, yp)
+int *xp, *yp;
+{
+#define MAXWLEN 1000
+    static char ab[MAXWLEN];                    /* initialized to zeros */
+    char *abword;
+    int c;
+
+    abword = ab + MAXWLEN - 1;
+
+    while ((c = getprevchar (xp, yp)) >= 0 && is_letter (c))
+        if (abword > ab)                        /* store only |MAXWLEN| last chars */
+            *(--abword) = c;                    
+    if (c < 0) {
+        if (abword < ab + MAXWLEN - 1)
+            return abword;
+        else
+            return 0;
+    }
+
+    while ((c = getprevchar (xp, yp)) >= 0 && !is_letter (c)); /* skip preceding spaces */
+    (*xp)++;                                    /* can be | >= D_width| */
+    return abword;
+}
+
+/* return value 1 if u_plop.buf changed */
+int
+DabbrevExpand ()
+{
+    static int x, y, hintlen;
+    static char *hint = 0, *lastexpansion = 0;
+
+    char *expansion;
+    int del_cnt, buf_cnt, i;
+
+    if (restart_dabbrev) {                      /* initialize */
+        restart_dabbrev = 0;
+        x = fore->w_x;
+        if (x > D_width)
+            x = D_width;
+        y = fore->w_y + fore->w_histheight;
+
+        free (hint);                            /* |free (NULL)| is OK */
+        hint = getprevword (&x, &y);
+        if (!hint)
+            return 0;                           /* no preceding word? */
+        free (lastexpansion);
+        lastexpansion = strdup (hint);
+        hint = strdup (hint);                   /* make our own copy */
+        if (!hint || !lastexpansion)
+            {
+                Msg(0, "Not enough memory... Sorry.");
+                return 0;
+            }
+        hintlen = strlen (hint);
+    }
+
+    while ((expansion = getprevword (&x, &y))) {
+        if (!strncmp (hint, expansion, hintlen) && /* empty hint matches everything */
+            strlen (expansion) > hintlen &&     /* trivia disallowed */
+            strcmp (expansion, lastexpansion))  /* different from previous */
+            break;
+    }
+    if (!expansion)                             /* no expansion found */
+        return 0;
+
+    UserFreeCopyBuffer(D_user);
+
+    del_cnt = strlen (lastexpansion) - hintlen;
+    buf_cnt = del_cnt + strlen (expansion) - hintlen;
+    if (!(D_user->u_plop.buf = malloc((unsigned) (buf_cnt + 1))))
+        {
+            Msg(0, "Not enough memory... Sorry.");
+            return 0;
+        }
+    for (i = 0; i < del_cnt; i++) {             /* delete previous expansion */
+        D_user->u_plop.buf[i]                 /* is this the best way to find out the ERASE character? */
+#ifdef POSIX
+            = D_OldMode.tio.c_cc[VERASE];
+#else
+            = D_OldMode.m_ttyb.sg_erase;
+#endif
+    }
+    bcopy (expansion + hintlen, D_user->u_plop.buf + del_cnt, strlen (expansion) - hintlen);
+    D_user->u_plop.len = buf_cnt;
+
+    free (lastexpansion);
+    lastexpansion = strdup (expansion);
+    if (!lastexpansion)
+        {
+            Msg(0, "Not enough memory... Sorry.");
+            return 0;
+        }
+    return 1;
+}
+#endif /* DABBREV */
 
 void
 MarkRoutine()
@@ -697,20 +838,20 @@
 	case '|':
 	  revto(--rep_cnt, cy);
 	  break;
-	case 'w':
+	case 'w':                               /* word forward */
 	  if (rep_cnt == 0)
 	    rep_cnt = 1;
 	  nextword(&cx, &cy, NW_MUSTMOVE, rep_cnt);
 	  revto(cx, cy);
 	  break;
-	case 'e':
+	case 'e':                               /* word forward last letter */
 	case 'E':
 	  if (rep_cnt == 0)
 	    rep_cnt = 1;
 	  nextword(&cx, &cy, NW_ENDOFWORD|NW_MUSTMOVE | (od == 'E' ? NW_BIG : 0), rep_cnt);
 	  revto(cx, cy);
 	  break;
-	case 'b':
+	case 'b':                               /* word back */
 	case 'B':
 	  if (rep_cnt == 0)
 	    rep_cnt = 1;
diff -ur screen-4.0.3.orig/process.c screen-4.0.3/process.c
--- screen-4.0.3.orig/process.c	2003-09-18 21:53:54.000000000 +0900
+++ screen-4.0.3/process.c	2008-01-23 02:07:40.109375000 +0900
@@ -45,6 +45,10 @@
 #include "extern.h"
 #include "logfile.h"
 
+#ifdef DABBREV
+extern int restart_dabbrev;
+#endif
+
 extern struct comm comms[];
 extern char *rc_name;
 extern char *RcFileName, *home;
@@ -552,6 +556,9 @@
   ktab['X'].nr = RC_REMOVE;
   ktab['F'].nr = RC_FIT;
   ktab['\t'].nr = RC_FOCUS;
+#ifdef DABBREV
+  ktab['/'].nr = RC_DABBREV;
+#endif
   /* These come last; they may want overwrite others: */
   if (DefaultEsc >= 0)
     {
@@ -806,9 +813,13 @@
 	      ilen--;
 	    }
 	  slen -= ilen;
+#ifdef DABBREV
+          if (slen > 0)                         /* normal keystroke */
+              restart_dabbrev = 1;
+#endif
 	  if (slen)
 	    DoProcess(fore, &ibuf, &slen, 0);
-	  if (--ilen == 0)
+	  if (--ilen == 0)                      /* ESC was last */
 	    D_ESCseen = ktab;
 	}
       if (ilen <= 0)
@@ -1071,6 +1082,12 @@
 #endif /* MULTIUSER */
 
   msgok = display && !*rc_name;
+
+#ifdef DABBREV                                  /* all commands assumed to disrupt */
+  if (nr != RC_DABBREV)
+      restart_dabbrev = 1;
+#endif
+
   switch(nr)
     {
     case RC_SELECT:
@@ -2087,6 +2104,10 @@
 	}
       MarkRoutine();
       break;
+
+#ifdef DABBREV
+    case RC_DABBREV:                            /* tjc */
+#endif
     case RC_HISTORY:
       {
         static char *pasteargs[] = {".", 0};
@@ -2097,6 +2118,15 @@
 	    Msg(0, "Must be on a window layer");
 	    break;
 	  }
+
+#ifdef DABBREV
+        if (nr == RC_DABBREV) {
+            if (DabbrevExpand() == 0) {
+                AddCStr(D_BL);
+                break;
+            }
+        } else
+#endif /* DABBREV */
 	if (GetHistory() == 0)
 	  break;
 	if (user->u_plop.buf == NULL)
@@ -3823,7 +3853,7 @@
       break;
     default:
 #ifdef HAVE_BRAILLE
-      /* key == -2: input from braille keybord, msgok always 0 */
+      /* key == -2: input from braille keyboard, msgok always 0 */
       DoBrailleAction(act, key == -2 ? 0 : msgok);
 #endif
       break;
Only in screen-4.0.3: process.c.orig