ref: cc0a7c8fabcfdfbabf270af105e157a0f2cab7b7
dir: /main.c/
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <bio.h>
#include <thread.h>
#include <draw.h>
#include <mouse.h>
#include <keyboard.h>
#include <plumb.h>
#include "a.h"
enum
{
Emouse,
Eresize,
Ekeyboard,
};
enum
{
Maxlines = 4096,
Padding = 4,
};
Mousectl *mctl;
Keyboardctl *kctl;
Image *selbg;
Rectangle ir;
Rectangle lr;
int lh;
int lcount;
int loff;
int lsel;
int pmode;
int plumbfd;
char* lines[Maxlines];
int nlines;
Match matches[Maxlines];
int nmatches;
char input[255] = {0};
int ninput = 0;
char pwd[255] = {0};
int
matchcmp(void *a, void *b)
{
Match m, n;
m = *(Match*)a;
n = *(Match*)b;
return n.s - m.s;
}
void
match(char *pat)
{
int i, s;
nmatches = 0;
for(i = 0; i < nlines; i++){
s = fuzzymatch(pat, lines[i]);
if(s >= 0){
matches[nmatches].n = lines[i];
matches[nmatches].s = s;
nmatches++;
}
}
if(nmatches > 0)
qsort(matches, nmatches, sizeof(Match), matchcmp);
}
void
loadlines(void)
{
Biobuf *bp;
char *s;
nlines = 0;
bp = Bfdopen(0, OREAD);
for(;;){
s = Brdstr(bp, '\n', 1);
if(s == nil)
break;
lines[nlines++] = s;
matches[nmatches++].n = s;
if(nlines >= Maxlines)
break;
}
Bterm(bp);
}
Rectangle
linerect(int i)
{
Rectangle r;
r.min.x = 0;
r.min.y = i * (font->height + Padding);
r.max.x = lr.max.x;
r.max.y = (i + 1) * (font->height + Padding);
r = rectaddpt(r, lr.min);
return r;
}
void
redraw(void)
{
Point p;
int i, n;
Match m;
draw(screen, screen->r, display->white, nil, ZP);
p = string(screen, addpt(screen->r.min, Pt(Padding, Padding)), display->black, ZP, font, "> ");
stringn(screen, p, display->black, ZP, font, input, ninput);
for(i = 0; i < lcount; i++){
n = loff + i;
if(n >= nmatches)
break;
m = matches[n];
p = addpt(lr.min, Pt(0, i * (font->height + Padding)));
if(lsel == i)
draw(screen, linerect(i), selbg, nil, ZP);
string(screen, p, display->black, ZP, font, matches[i].n);
}
flushimage(display, 1);
}
void
eresize(void)
{
ir = Rect(Padding, Padding, screen->r.max.x - Padding, Padding + font->height + Padding);
ir = rectaddpt(ir, screen->r.min);
lr = Rect(screen->r.min.x + Padding, ir.max.y, ir.max.x, screen->r.max.y - Padding);
lh = font->height + Padding;
lcount = Dy(lr) / lh;
redraw();
}
void
emouse(Mouse *m)
{
USED(m);
}
void
inputchanged(void)
{
int i;
input[ninput] = 0;
if(ninput > 0){
match(input);
}else{
nmatches = 0;
for(i = 0; i < nlines; i++)
matches[nmatches++].n = lines[i];
}
if(lsel >= (nmatches - 1))
lsel = 0;
if(nmatches == 0)
lsel = -1;
redraw();
}
void
ekeyboard(Rune k)
{
Match m;
switch(k){
case Kdel:
threadexitsall(nil);
break;
case Kup:
if(lsel > 0)
--lsel;
redraw();
break;
case Kdown:
if(lsel < (nmatches - 1))
++lsel;
redraw();
break;
case '\n':
if(lsel >= 0){
m = matches[lsel + loff];
if(pmode){
print("%s", m.n);
threadexitsall(nil);
}else
plumbsendtext(plumbfd, argv0, nil, pwd, m.n);
}
break;
case Kesc:
if(ninput > 0){
ninput = 0;
inputchanged();
}else
threadexitsall(nil);
break;
case Kbs:
if(ninput > 0){
ninput--;
inputchanged();
}
break;
case Knack: /* ^U */
if(ninput > 0){
ninput = 0;
inputchanged();
}
default:
if(isprint(k)){
input[ninput++] = (char)k; /* XXX */
inputchanged();
}
}
}
void
usage(void)
{
fprint(2, "usage: %s [-p]\n", argv0);
exits("usage");
}
void
threadmain(int argc, char **argv)
{
Mouse m;
Rune k;
Alt a[] = {
{ nil, &m, CHANRCV },
{ nil, nil, CHANRCV },
{ nil, &k, CHANRCV },
{ nil, nil, CHANEND },
};
pmode = 0;
ARGBEGIN{
case 'p':
pmode = 1;
break;
default:
usage();
}ARGEND;
getwd(pwd, sizeof pwd);
if(pmode == 0){
plumbfd = plumbopen("send", OWRITE|OCEXEC);
if(plumbfd < 0)
sysfatal("plumbopen: %r");
}
loadlines();
if(initdraw(nil, nil, "fm") < 0)
sysfatal("initdraw: %r");
display->locking = 0;
if((mctl = initmouse(nil, screen)) == nil)
sysfatal("initmouse: %r");
if((kctl = initkeyboard(nil)) == nil)
sysfatal("initkeyboard: %r");
a[Emouse].c = mctl->c;
a[Eresize].c = mctl->resizec;
a[Ekeyboard].c = kctl->c;
selbg = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0xEFEFEFFF);
loff = 0;
lsel = 0;
eresize();
for(;;){
switch(alt(a)){
case Emouse:
emouse(&m);
break;
case Eresize:
if(getwindow(display, Refnone) < 0)
sysfatal("getwindow: %r");
eresize();
case Ekeyboard:
ekeyboard(k);
break;
}
}
}