neitzel@infbs (01/08/88)
This is tenexbuf(), a function for MicroEmacs to allow input of a buffer name using simple TENEX-style expansion. I put it in input.c right behind getname(), which served as model for it. Together with my changes to make the bufferlist Least-Recently-Used- orded (shall I post these, too?), MicroEmacs now behaves a lot more like the big one. Perhaps we should rename it to 'MilliEmacs' :-) ----- Martin Neitzel UUCP: ..!uunet!mcvax!unido!infbs!neitzel (this is cheaper! -->) BITNET: neitzel@dbsinf6.bitnet ---- application example -------------------------------------------- Use it where you like, I put it into usebuffer(), nextbuffer() and killbuffer(). For an example, here is what my usebuffer() now looks like. usebuffer(f, n) { register BUFFER *bp, *lru_buffer; extern BUFFER *tenexbuf(); /* get the least recently used, yet undisplayed, non-hidden buffer */ lru_buffer = [... 4 lines to find the LRU buffer ...]; bp = tenexbuf (TRUE, "use buffer ", lru_buffer ? lru_buffer->b_bname : NULL); if (!bp) return (ABORT); else return swbuffer(bp); } ---- tenexbuf() ---- put into input.c ----------------------------------- /* * Read in the name of an buffer using TENEX style expansion and * return the pointer to it. If argument 'createf' is non-zero, a new * buffer will be created, if requested. 'prompt' can be NULL, in * which case neither a prompt or the default is printed in the * minibuffer. 'def_name' may be a default buffer name or NULL. If * 'prompt' is present, it will be printed in the minibuffer and can * be chosen by simply hitting RETURN. * * returns NULL, iff the user ABORTs or can't / isn't allowed to * create a new buffer. */ BUFFER *tenexbuf(createf, prompt, def_bname) int createf; char *prompt, *def_bname; { #if ST520 & LATTICE #define register #endif register int cpos; /* current column on screen output */ register int c; register char *sp; /* pointer to string for output */ char bufname[NBUFN]; /* buffer to hold tentative buffer name */ extern BUFFER *bfind(); /* starting at the beginning of the string buffer */ cpos = 0; /* if we are executing a command line get the next arg and match it */ if (clexec) { if (macarg(bufname) != TRUE) return(NULL); return bfind(&bufname[0], createf, 0); } if (prompt) mlwrite ("%s [%s] ", prompt, def_bname ? def_bname : "no default"); /* build a name string from the keyboard */ while (TRUE) { c = tgetc(); /* if we are at the end, just match it */ if (c == '\n' || c == '\r') { if (def_bname && cpos==0) return bfind (def_bname, createf, 0); else { bufname[cpos] = 0; return bfind (&bufname[0], createf, 0); } } else if (c == ectoc(abortc)) { /* Bell, abort */ ctrlg(FALSE, 0); TTflush(); return NULL; } else if (c == 0x7F || c == 0x08) { /* rubout/erase */ if (cpos != 0) { TTputc('\b'); TTputc(' '); TTputc('\b'); --ttcol; --cpos; TTflush(); } } else if (c == 0x15) { /* C-U, kill */ while (cpos != 0) { TTputc('\b'); TTputc(' '); TTputc('\b'); --cpos; --ttcol; } TTflush(); } else if (c == ' ') { /* attempt a completion */ BUFFER *bp, *expbuf; int exp_pos, i; bufname[cpos] = 0; /* terminate it for us */ /* * Search for the next common expansion. expbuf points * to the first matching buffer, exp_pos gets * initialized to the full buffer name. Each further * matching buffer will shrink (via exp_pos) the most * common name prefix. */ for (expbuf=NULL, exp_pos=0, bp = bheadp; bp; bp = bp->b_bufp) { if ( strlen (bp->b_bname) > cpos+1 && 0==strncmp (bufname, bp->b_bname, cpos)) { /* * If you want a more * 'agressive' completion, you * could count the matches * right here after this * comment. Then, if we found * exactly one matching * buffer, we could directly * switch to it (expbuf). */ if ( ! expbuf ) { /* install first match */ expbuf = bp; exp_pos = strlen (expbuf->b_bname) -1; continue; } /* another match; reduce prefix size */ i=cpos; while (i<=exp_pos) if (bp->b_bname[i] != expbuf->b_bname[i]) break; else ++i; exp_pos = i-1; } } if (!expbuf) { TTbeep(); TTflush(); continue; } while (cpos <= exp_pos) { /* add the next char in */ bufname[cpos] = expbuf->b_bname[cpos]; TTputc(bufname[cpos++]); } TTflush(); } else { if (cpos < NBUFN-1 && c > ' ') { bufname[cpos++] = c; TTputc(c); } ++ttcol; TTflush(); } } }