The following patch (against color_xterm-beta3) implements dabbrev expansion with functionality similar to one found in Emacs. It is more useful than tcsh or bash implementations because it searches also the output of commands, not only the input line history. All programs running in an xterm window can use it. ============= CUT HERE ================== diff -urd color_xterm-beta3/charproc.c color_xterm-work/charproc.c --- color_xterm-beta3/charproc.c Fri Jan 17 23:55:47 1997 +++ color_xterm-work/charproc.c Thu Feb 20 15:47:28 1997 @@ -61,6 +61,9 @@ static debug = 1; #endif +int dabbrev_restart = 1; +unsigned char dabbrev_erase_char = '\b'; /* initialized in main() */ + /* * Check for both EAGAIN and EWOULDBLOCK, because some supposedly POSIX * systems are broken and return EWOULDBLOCK when they should return EAGAIN. @@ -247,6 +250,7 @@ extern Boolean SendMousePosition(); extern void ScrnSetAttributes(); +static void HandleDabbrevExpand(); /* * NOTE: VTInitialize zeros out the entire ".screen" component of the @@ -269,7 +273,7 @@ /* * Warning, the following must be kept under 1024 bytes or else some * compilers (particularly AT&T 6386 SVR3.2) will barf). Workaround is to - * declare a static buffer and copy in at run time (the the Athena text widget + * declare a static buffer and copy in at run time (the Athena text widget * does). Yuck. */ static char defaultTranslations[] = @@ -278,6 +282,7 @@ Shift Next:scroll-forw(1,halfpage) \n\ Shift Select:select-cursor-start() select-cursor-end(PRIMARY, CUT_BUFFER0) \n\ Shift Insert:insert-selection(PRIMARY, CUT_BUFFER0) \n\ + Meta /:dabbrev-expand() \n\ ~Meta :insert-seven-bit() \n\ Meta :insert-eight-bit() \n\ !Ctrl :popup-menu(mainMenu) \n\ @@ -352,7 +357,8 @@ { "tek-reset", HandleTekReset }, { "tek-copy", HandleTekCopy }, { "visual-bell", HandleVisualBell }, - { "cursor-warp-button", CursorButton } + { "cursor-warp-button", CursorButton }, + { "dabbrev-expand", HandleDabbrevExpand} }; static XtResource resources[] = { @@ -1492,6 +1498,7 @@ */ if (len > 0) { + dabbrev_restart = 1; /* break dabbrev sequence */ if (v_bufend < v_bufptr + len) { /* we've run out of room */ if (v_bufstr != v_buffer) { /* there is unused space, move everything down */ @@ -3817,4 +3824,130 @@ screen->cursorGC = new_cursorGC; screen->reversecursorGC = new_reversecursorGC; screen->cursoroutlineGC = new_cursoroutlineGC; +} + +/* The following code implements `dynamic abbreviation' expansion a la + * Emacs. It looks in the preceding visible screen and its scrollback 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) + */ + +#define IS_WORD_CONSTITUENT(x) ((x) != ' ' && (x) != '\0') +#define MAXWLEN 1024 /* maximum word length as in tcsh */ + +int dabbrev_prev_char (xp, yp, screen) +int *xp, *yp; +TScreen *screen; +{ + char *linep; + while (*yp >= 0) { + linep = screen->allbuf[4 * *yp]; + if (--*xp >= 0) + return linep[*xp]; + if (--*yp < 0) /* go to previous line */ + break; + *xp = screen->max_col + 1; + if (!(screen->allbuf[4 * *yp + 1][0] & LINEWRAPPED)) + return ' '; /* treat lines as separate */ + } + return -1; +} + +char *dabbrev_prev_word (xp, yp, screen) +int *xp, *yp; +TScreen *screen; +{ + static char ab[MAXWLEN]; + char *abword; + int c; + + abword = ab + MAXWLEN - 1; + *abword = '\0'; /* end of string marker */ + + while ((c = dabbrev_prev_char (xp, yp, screen)) >= 0 && IS_WORD_CONSTITUENT (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 = dabbrev_prev_char (xp, yp, screen)) >= 0 && !IS_WORD_CONSTITUENT (c)); /* skip preceding spaces */ + (*xp)++; /* can be | > screen->max_col| */ + return abword; +} + + +int dabbrev_expand (screen) +TScreen *screen; +{ + int pty = screen->respond; /* file descriptor of pty */ + + static int x, y; + static char *dabbrev_hint = 0, *lastexpansion = 0; + + char *expansion, *copybuffer; + int hint_len, del_cnt, buf_cnt, i; + + if (dabbrev_restart) { /* initialize */ + x = screen->cur_col; + y = screen->cur_row + screen->savelines; + + free (dabbrev_hint); /* |free (NULL)| is OK */ + dabbrev_hint = dabbrev_prev_word (&x, &y, screen); + if (!dabbrev_hint) + return 0; /* no preceding word? */ + free (lastexpansion); + if (!(lastexpansion = strdup (dabbrev_hint))) /* make own copy */ + return 0; + if (!(dabbrev_hint = strdup (dabbrev_hint))) { + free (lastexpansion); + return 0; + } + dabbrev_restart = 0; + } + + hint_len = strlen (dabbrev_hint); + while ((expansion = dabbrev_prev_word (&x, &y, screen))) { + if (!strncmp (dabbrev_hint, expansion, hint_len) && /* empty hint matches everything */ + strlen (expansion) > hint_len && /* trivial expansion disallowed */ + strcmp (expansion, lastexpansion)) /* different from previous */ + break; + } + if (!expansion) /* no expansion found */ + return 0; + + del_cnt = strlen (lastexpansion) - hint_len; + buf_cnt = del_cnt + strlen (expansion) - hint_len; + if (!(copybuffer = (char *) malloc (buf_cnt))) + return 0; + for (i = 0; i < del_cnt; i++) { /* delete previous expansion */ + copybuffer[i] = dabbrev_erase_char; + } + bcopy (expansion + hint_len, copybuffer + del_cnt, strlen (expansion) - hint_len); + v_write (pty, copybuffer, buf_cnt); + dabbrev_restart = 0; /* |v_write| set it to 1 */ + free (copybuffer); + + free (lastexpansion); + lastexpansion = strdup (expansion); + if (!lastexpansion) + return 0; + return 1; +} + +/*ARGSUSED*/ +void HandleDabbrevExpand (gw, event, params, nparams) + Widget gw; + XEvent *event; + String *params; + Cardinal *nparams; +{ + XtermWidget w = (XtermWidget) gw; + TScreen *screen = &w->screen; + if (!dabbrev_expand (screen)) + Bell (); } diff -urd color_xterm-beta3/color_xterm.man color_xterm-work/color_xterm.man --- color_xterm-beta3/color_xterm.man Mon Oct 28 22:33:01 1996 +++ color_xterm-work/color_xterm.man Wed Feb 19 19:20:42 1997 @@ -1,15 +1,17 @@ -.TH COLOR_XTERM 1 +.TH color_xterm 1 .SH NAME color_xterm \- color terminal emulator for X .SH DESCRIPTION -\fIColor_xterm\fP is essentially the same as +.I color_xterm +is essentially the same as .IR xterm (1). The main differences are described below. .TP 8 .B ISO 6429 color text support. .PP -In addition to the Escape sequences supported by xterm, color_xterm +In addition to the Escape sequences supported by xterm, +.I color_xterm supports the following sequences: .TP 8 .B ESC [ 3 Ps m @@ -28,10 +30,13 @@ 6) cyan 7) white .TP 8 -The actual colors that color_xterm uses are customizable as the X +The actual colors that +.I color_xterm +uses are customizable as the X resources "color0", "color1", etc. .PP -Color_xterm includes the 'Dynamic Colors' patch +.I color_xterm +includes the 'Dynamic Colors' patch by Erik Fortune (erik@esd.sgi.com). This allows you to change the foreground, background, etc. colors dynamically using the "ESC ] Ps ; name BEL" escape sequence, where @@ -52,17 +57,36 @@ The dynamic colors are controlled using the -dc/+dc command line option or the *dynamicColor X resource. .PP -The UGCS color_xterm contains the Cursor Warp patch. If the +The UGCS +.I color_xterm +contains the Cursor Warp patch. If the cursorWarpTranslation X resource is set to -an X event, then whenever the color_xterm receives the event, the terminal +an X event, then whenever the +.I color_xterm +receives the event, the terminal generates the cursor movement keys to move the text cursor to the mouse cursor. .PP -The UGCS color_xterm supports the -jobs option, which disables termination +The UGCS +.I color_xterm +supports the -jobs option, which disables termination upon receipt of a SIGCHILD. This is generally only useful with the -e option. - - +.PP +The +.I color_xterm +supports a new \fBdabbrev-expand()\fP action, by +default bound to \fBMeta /\fP. It expands the word before +cursor by searching in the preceding text on the screen and in the +scrollback buffer for words starting with that abbreviation. Repeating +\fBdabbrev-expand()\fP several times in sequence searches for an +alternative expansion by looking farther back. Lack of more matches is +signalled by a \fBbeep()\fP. Attempts to expand an empty word (i.e., +when cursor is preceded by a space) succesively yield all previous +words. Consecutive identical expansions are ignored. The word here is +defined as a sequence of non-whitespace characters. This feature +partially emulates the behavior of `dynamic abbreviation' expansion in +Emacs (also bound there to M-/). (Tomasz J. Cholewo, t.cholewo@ieee.org) .SH AUTHORS .I of xterm: @@ -78,12 +102,13 @@ .TP 0 Tom Weinstein, Erik Fortune, Paul Shupak .TP 16 -Manual page, UGCS hacks and maintaince courtesy of +Manual page, UGCS hacks and maintenance courtesy of Jacob Mandelson (jlm@ugcs.caltech.edu). .SH NOTICE -Color_xterm is derived from xterm, whose copyright requires the following +.I color_xterm +is derived from xterm, whose copyright requires the following to appear in the documentation: .PP Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, diff -urd color_xterm-beta3/main.c color_xterm-work/main.c --- color_xterm-beta3/main.c Sat Jan 18 00:18:52 1997 +++ color_xterm-work/main.c Wed Feb 19 17:57:22 1997 @@ -69,7 +69,9 @@ #endif #ifdef SVR4 +#ifndef SYSV #define SYSV /* SVR4 is (approx) superset of SVR3 */ +#endif #define USE_SYSV_UTMP #define ATT #define USE_TERMIOS @@ -806,6 +808,7 @@ char *base_name(); int xerror(), xioerror(); int jobs=0; /* Automatic/manual job control. -- JLM */ + extern unsigned char dabbrev_erase_char; /* see charproc.c */ #ifdef DEBUGGING fprintf(stderr, "entered Main\n"); @@ -1234,6 +1237,12 @@ mode = 1; if (ioctl (pty, FIONBIO, (char *)&mode) == -1) SysError (ERROR_FIONBIO); #endif /* USE_SYSV_TERMIO */ + +#ifdef USE_SYSV_TERMIO + dabbrev_erase_char = d_tio.c_cc[VERASE]; +#else + dabbrev_erase_char = d_sg.sg_erase; +#endif pty_mask = 1 << pty; X_mask = 1 << Xsocket;