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