ref: 342d92a22a97b02235abe83f4ec420c8aa6622ef
dir: /linesel.c/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <draw.h>
#include <event.h>
#include <keyboard.h>
#define Ctl(c) ((c) - 64)
Image *fgcolor, *bgcolor;
char **lines, **matches, *buffer, *selected;
usize nlines, nmatches;
Rune kbinput[512];
static void
readbuffer(void)
{
Biobuf *bp;
char *line, *s;
if((bp = Bfdopen(0, OREAD)) == nil)
sysfatal("setting buffering on fd0: %r");
if ((buffer = Brdstr(bp, '\0', 1)) == nil)
sysfatal("reading input lines: %r");
for(line = s = buffer; s = strchr(s, '\n'); line = ++s){
*s = '\0';
if((lines = realloc(lines, ++nlines * sizeof *lines)) == nil)
sysfatal("malloc: %r");
lines[nlines-1] = line;
}
if((matches = malloc(nlines * sizeof *lines)) == nil)
sysfatal("malloc: %r");
}
#define PROMPT " > "
static void
redraw(Image *screen)
{
short fh = font->height;
Point pt = screen->r.min;
usize i;
char buf[512];
draw(screen, screen->r, bgcolor, nil, ZP);
pt = addpt(pt, Pt(0, fh));
snprint(buf, sizeof buf, PROMPT"%S▏", kbinput);
string(screen, pt, fgcolor, ZP, font, buf);
pt = addpt(pt, Pt(stringwidth(font, PROMPT), fh));
for(i = 0; i < nmatches; i++){
if (pt.y > screen->r.max.y)
break;
string(screen, pt, fgcolor, ZP, font, matches[i]);
pt = addpt(pt, Pt(0, fh));
}
}
static void
resetmatches(void)
{
memmove(matches, lines, nlines * sizeof *lines);
nmatches = nlines;
}
static void
kbadd(Rune r)
{
usize len = runestrlen(kbinput);
if (len == sizeof kbinput / sizeof *kbinput)
return;
kbinput[len++] = r;
kbinput[len] = L'\0';
}
static void
kbbackspace(void)
{
usize len = runestrlen(kbinput);
if (len == 0)
return;
kbinput[len - 1] = L'\0';
}
static void
kbdelword(void)
{
usize len = runestrlen(kbinput);
if(len == 0)
return;
while(len > 0 && isspacerune(kbinput[len-1]))
len--;
while(len > 0 && !isspacerune(kbinput[len-1]))
len--;
kbinput[len] = L'\0';
}
static void
kbclear(void)
{
kbinput[0] = L'\0';
}
void
eresized(int new)
{
if(new && getwindow(display, Refnone) < 0)
sysfatal("resize failed: %r");
redraw(screen);
}
static void
usage(void)
{
print("usage: %s [-b] <choices\n", argv0);
exits("usage");
}
void
main(int argc, char **argv)
{
Event e;
int bflag = 0;
ARGBEGIN{
case 'b':
bflag = 1;
break;
default:
usage();
}ARGEND;
readbuffer();
resetmatches();
selected = matches[0];
if(initdraw(nil, nil, "linesel") < 0)
sysfatal("initdraw: %r");
if(bflag){
fgcolor = display->white;
bgcolor = display->black;
}else{
fgcolor = display->black;
bgcolor = display->white;
}
einit(Emouse|Ekeyboard);
redraw(screen);
for(;;){
switch(event(&e)){
case -1:
sysfatal("watching channels: %r\n");
case Ekeyboard:
switch(e.kbdc){
case Kdel:
exits("interrupted with Del");
case '\n':
goto End;
case Kbs:
kbbackspace();
break;
case Ctl('W'):
kbdelword();
break;
case Ctl('U'):
kbclear();
break;
default:
kbadd(e.kbdc);
break;
}
redraw(screen);
break;
case Emouse:
break;
}
}
End:
print("%s\n", selected);
exits(nil);
}