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();
}
}
}