ref: 7d29d072f84e97ed311932b3a3cfdbeca317f4f9
parent: bc69d3c62762f155e54e487f2145cd7fe3224ce7
author: glenda <[email protected]>
date: Sun Sep 5 19:41:28 EDT 2021
renamed from sel/line to just dmenu
--- /dev/null
+++ b/dmenu.c
@@ -1,0 +1,367 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <event.h>
+#include <keyboard.h>
+
+#define Ctl(c) ((c) - 64)
+#define PROMPT " > "
+
+enum
+{
+ BACK,
+ HBACK,
+ TEXT,
+ HTEXT,
+ NCOLORS
+};
+
+Image *color[NCOLORS];
+char **lines, **matches, *buffer;
+usize nlines, nmatches, scroll;
+Rune kbinput[512];
+int selected;
+
+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");
+ memmove(matches, lines, nlines * sizeof *lines);
+ nmatches = nlines;
+}
+
+static Point
+linetopoint(int ln)
+{
+ ln -= scroll;
+ return Pt(screen->r.min.x, screen->r.min.y + (ln + 2) * font->height);
+}
+
+static int
+pointtoline(Point pt)
+{
+ return (pt.y - screen->r.min.y) / font->height - 2 + scroll;
+}
+
+static void
+drawbackground(Point pt, Image *color)
+{
+ draw(screen,
+ Rect(screen->r.min.x, pt.y, screen->r.max.x, pt.y + font->height),
+ color, nil, ZP);
+}
+
+static Point
+tabstring(Image *dst, Point dp, Image *src, Point sp, Font *f, char *s)
+{
+ Rune r[2] = {L'0', L'\0'};
+ int n, w0, x;
+ Point op;
+
+ op = dp;
+ w0 = stringwidth(f, "0");
+ for(; *s && (n = chartorune(r, s)) > 0; s += n){
+ if(r[0] == '\t'){
+ x = 8 * w0 - (dp.x - op.x) % (8 * w0);
+ sp.x += x;
+ dp.x += x;
+ }else{
+ dp = runestring(dst, dp, src, sp, f, r);
+ }
+ }
+ return dp;
+}
+
+static void
+drawprompt(void)
+{
+ Point pt;
+ char buf[512];
+
+ snprint(buf, sizeof buf, PROMPT"%S▏", kbinput);
+ pt = Pt(screen->r.max.x, screen->r.min.y + font->height * 2);
+ draw(screen, Rpt(screen->r.min, pt), color[BACK], nil, ZP);
+ pt = Pt(screen->r.min.x, screen->r.min.y + font->height);
+ tabstring(screen, pt, color[TEXT], ZP, font, buf);
+}
+
+static int
+drawline(int ln)
+{
+ Point pt = linetopoint(ln);
+ Image *bgcolor, *txcolor;
+
+ if(ln < scroll)
+ return 1;
+ if(ln == selected){
+ bgcolor = color[HBACK];
+ txcolor = color[HTEXT];
+ }else{
+ bgcolor = color[BACK];
+ txcolor = color[TEXT];
+ }
+ pt.x += stringwidth(font, PROMPT);
+ drawbackground(pt, bgcolor);
+ if(ln < nmatches)
+ tabstring(screen, pt, txcolor, ZP, font, matches[ln]);
+ return pt.y < screen->r.max.y;
+}
+
+void
+eresized(int new)
+{
+ int i;
+
+ if(new && getwindow(display, Refnone) < 0)
+ sysfatal("resize failed: %r");
+
+ drawprompt();
+ for(i = scroll; drawline(i); i++);
+}
+
+int
+match(char *s, char **words, int nwords)
+{
+ char **w;
+
+ if(nwords == 0)
+ return 1;
+ for(w = words; w < words + nwords; w++)
+ if(cistrstr(s, *w) == nil)
+ return 0;
+ return 1;
+}
+
+void
+filter(char **lines, int nlines)
+{
+ char *buf, *words[64], **l, **m;
+ int nwords;
+
+ if((buf = smprint("%S", kbinput)) == nil)
+ sysfatal("malloc");
+ nwords = tokenize(buf, words, sizeof words / sizeof *words);
+
+ nmatches = 0;
+ m = matches;
+ for(l = lines; l < lines + nlines; l++)
+ if(match(*l, words, nwords)){
+ *m++ = *l;
+ nmatches++;
+ }
+
+ selected = 0;
+ scroll = 0;
+ free(buf);
+ eresized(0); /* possibly different lines: redraw everything */
+}
+
+static void
+kbadd(Rune r)
+{
+ int len = runestrlen(kbinput);
+
+ if(len == sizeof kbinput / sizeof *kbinput)
+ return;
+ kbinput[len++] = r;
+ kbinput[len] = L'\0';
+
+ filter(matches, nmatches);
+}
+
+static void
+kbbackspace(void)
+{
+ usize len = runestrlen(kbinput);
+
+ if(len == 0)
+ return;
+ kbinput[len - 1] = L'\0';
+
+ filter(lines, nlines);
+}
+
+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';
+
+ filter(lines, nlines);
+}
+
+static void
+kbclear(void)
+{
+ kbinput[0] = L'\0';
+
+ filter(lines, nlines);
+}
+
+static void
+kbmove(int n)
+{
+ int old = selected;
+
+ if(selected + n < 0)
+ selected = 0;
+ else if(selected + n >= nmatches)
+ selected = nmatches - 1;
+ else
+ selected += n;
+
+ drawline(old);
+ drawline(selected);
+}
+
+static void
+kbscroll(int percent)
+{
+ int ln = Dy(screen->r) / font->height * percent / 100;
+
+ if(ln < 0 && abs(ln) > scroll)
+ scroll = 0;
+ else if(ln > 0 && scroll + ln >= nmatches)
+ scroll = nmatches - 1 + (nmatches > 0);
+ else
+ scroll += ln;
+
+ eresized(0);
+}
+
+static void
+mselect(Point pt)
+{
+ int old, sel = pointtoline(pt);
+
+ if(sel < 0)
+ sel = 0;
+ if(nmatches > 0 && sel >= nmatches)
+ sel = nmatches - 1;
+ if(sel != selected){
+ old = selected;
+ selected = sel;
+ drawline(old);
+ drawline(sel);
+ }
+}
+
+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();
+
+ if(initdraw(nil, nil, "linesel") < 0)
+ sysfatal("initdraw: %r");
+
+ if(bflag){
+ color[TEXT] = display->white;
+ color[BACK] = display->black;
+ }else{
+ color[TEXT] = display->black;
+ color[BACK] = display->white;
+ }
+ color[HTEXT] = display->black;
+ color[HBACK] = allocimage(display,
+ Rect(0,0,1,1), screen->chan, 1, DPaleyellow);
+
+ eresized(0);
+
+ einit(Emouse|Ekeyboard);
+ for(;;){
+ switch(event(&e)){
+ case -1:
+ sysfatal("watching events: %r");
+
+ 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;
+ case Kup:
+ kbmove(-1);
+ break;
+ case Kdown:
+ kbmove(+1);
+ break;
+ case Kpgdown:
+ kbscroll(+40);
+ break;
+ case Kpgup:
+ kbscroll(-40);
+ break;
+ default:
+ kbadd(e.kbdc);
+ break;
+ }
+ break;
+
+ case Emouse:
+ if(e.mouse.buttons&1)
+ mselect(e.mouse.xy);
+ if(e.mouse.buttons&4)
+ goto End;
+ if(e.mouse.buttons&8)
+ kbscroll(-40);
+ if(e.mouse.buttons&16)
+ kbscroll(+40);
+ break;
+ }
+ }
+End:
+ if(nmatches > 0)
+ print("%s\n", matches[selected]);
+ exits(nil);
+}
--- a/line.c
+++ /dev/null
@@ -1,365 +1,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <draw.h>
-#include <event.h>
-#include <keyboard.h>
-
-#define Ctl(c) ((c) - 64)
-#define PROMPT " > "
-
-enum
-{
- BACK,
- HBACK,
- TEXT,
- HTEXT,
- NCOLORS
-};
-
-Image *color[NCOLORS];
-char **lines, **matches, *buffer;
-usize nlines, nmatches, scroll;
-Rune kbinput[512];
-int selected;
-
-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");
- memmove(matches, lines, nlines * sizeof *lines);
- nmatches = nlines;
-}
-
-static Point
-linetopoint(int ln)
-{
- ln -= scroll;
- return Pt(screen->r.min.x, screen->r.min.y + (ln + 2) * font->height);
-}
-
-static int
-pointtoline(Point pt)
-{
- return (pt.y - screen->r.min.y) / font->height - 2 + scroll;
-}
-
-static void
-drawbackground(Point pt, Image *color)
-{
- draw(screen,
- Rect(screen->r.min.x, pt.y, screen->r.max.x, pt.y + font->height),
- color, nil, ZP);
-}
-
-static Point
-tabstring(Image *dst, Point dp, Image *src, Point sp, Font *f, char *s)
-{
- Rune r[2] = {L'0', L'\0'};
- int n, w0, x;
- Point op;
-
- op = dp;
- w0 = stringwidth(f, "0");
- for(; *s && (n = chartorune(r, s)) > 0; s += n){
- if(r[0] == '\t'){
- x = 8 * w0 - (dp.x - op.x) % (8 * w0);
- sp.x += x;
- dp.x += x;
- }else{
- dp = runestring(dst, dp, src, sp, f, r);
- }
- }
- return dp;
-}
-
-static void
-drawprompt(void)
-{
- Point pt;
- char buf[512];
-
- snprint(buf, sizeof buf, PROMPT"%S▏", kbinput);
- pt = Pt(screen->r.max.x, screen->r.min.y + font->height * 2);
- draw(screen, Rpt(screen->r.min, pt), color[BACK], nil, ZP);
- pt = Pt(screen->r.min.x, screen->r.min.y + font->height);
- tabstring(screen, pt, color[TEXT], ZP, font, buf);
-}
-
-static int
-drawline(int ln)
-{
- Point pt = linetopoint(ln);
- Image *bgcolor, *txcolor;
-
- if(ln < scroll)
- return 1;
- if(ln == selected){
- bgcolor = color[HBACK];
- txcolor = color[HTEXT];
- }else{
- bgcolor = color[BACK];
- txcolor = color[TEXT];
- }
- pt.x += stringwidth(font, PROMPT);
- drawbackground(pt, bgcolor);
- if(ln < nmatches)
- tabstring(screen, pt, txcolor, ZP, font, matches[ln]);
- return pt.y < screen->r.max.y;
-}
-
-void
-eresized(int new)
-{
- int i;
-
- if(new && getwindow(display, Refnone) < 0)
- sysfatal("resize failed: %r");
-
- drawprompt();
- for(i = scroll; drawline(i); i++);
-}
-
-int
-match(char *s, char **words, int nwords)
-{
- char **w;
-
- if(nwords == 0)
- return 1;
- for(w = words; w < words + nwords; w++)
- if(cistrstr(s, *w) == nil)
- return 0;
- return 1;
-}
-
-void
-filter(char **lines, int nlines)
-{
- char *buf, *words[64], **l, **m;
- int nwords;
-
- if((buf = smprint("%S", kbinput)) == nil)
- sysfatal("malloc");
- nwords = tokenize(buf, words, sizeof words / sizeof *words);
-
- nmatches = 0;
- m = matches;
- for(l = lines; l < lines + nlines; l++)
- if(match(*l, words, nwords)){
- *m++ = *l;
- nmatches++;
- }
-
- selected = 0;
- scroll = 0;
- free(buf);
- eresized(0); /* possibly different lines: redraw everything */
-}
-
-static void
-kbadd(Rune r)
-{
- int len = runestrlen(kbinput);
-
- if(len == sizeof kbinput / sizeof *kbinput)
- return;
- kbinput[len++] = r;
- kbinput[len] = L'\0';
-
- filter(matches, nmatches);
-}
-
-static void
-kbbackspace(void)
-{
- usize len = runestrlen(kbinput);
-
- if(len == 0)
- return;
- kbinput[len - 1] = L'\0';
-
- filter(lines, nlines);
-}
-
-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';
-
- filter(lines, nlines);
-}
-
-static void
-kbclear(void)
-{
- kbinput[0] = L'\0';
-
- filter(lines, nlines);
-}
-
-static void
-kbmove(int n)
-{
- int old = selected;
-
- if(selected + n < 0)
- selected = 0;
- else if(selected + n >= nmatches)
- selected = nmatches - 1;
- else
- selected += n;
- drawline(old);
- drawline(selected);
-}
-
-static void
-kbscroll(int percent)
-{
- int ln = Dy(screen->r) / font->height * percent / 100;
-
- if(ln < 0 && abs(ln) > scroll)
- scroll = 0;
- else if(ln > 0 && scroll + ln >= nmatches)
- scroll = nmatches - 1 + (nmatches > 0);
- else
- scroll += ln;
- eresized(0);
-}
-
-static void
-mselect(Point pt)
-{
- int old, sel = pointtoline(pt);
-
- if(sel < 0)
- sel = 0;
- if(nmatches > 0 && sel >= nmatches)
- sel = nmatches - 1;
- if(sel != selected){
- old = selected;
- selected = sel;
- drawline(old);
- drawline(sel);
- }
-}
-
-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();
-
- if(initdraw(nil, nil, "linesel") < 0)
- sysfatal("initdraw: %r");
-
- if(bflag){
- color[TEXT] = display->white;
- color[BACK] = display->black;
- }else{
- color[TEXT] = display->black;
- color[BACK] = display->white;
- }
- color[HTEXT] = display->black;
- color[HBACK] = allocimage(display,
- Rect(0,0,1,1), screen->chan, 1, DPaleyellow);
-
- eresized(0);
-
- einit(Emouse|Ekeyboard);
- for(;;){
- switch(event(&e)){
- case -1:
- sysfatal("watching events: %r");
-
- 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;
- case Kup:
- kbmove(-1);
- break;
- case Kdown:
- kbmove(+1);
- break;
- case Kpgdown:
- kbscroll(+40);
- break;
- case Kpgup:
- kbscroll(-40);
- break;
- default:
- kbadd(e.kbdc);
- break;
- }
- break;
-
- case Emouse:
- if(e.mouse.buttons&1)
- mselect(e.mouse.xy);
- if(e.mouse.buttons&4)
- goto End;
- if(e.mouse.buttons&8)
- kbscroll(-40);
- if(e.mouse.buttons&16)
- kbscroll(+40);
- break;
- }
- }
-End:
- if(nmatches > 0)
- print("%s\n", matches[selected]);
- exits(nil);
-}
--- a/mkfile
+++ b/mkfile
@@ -1,16 +1,9 @@
</$objtype/mkfile
-TARG=\
- line\
-
+TARG= dmenu
HFILES=
-
+OFILES= dmenu.$O
LIB= /$objtype/lib/libdraw.a
-BIN= /$objtype/bin/sel
+BIN= /$objtype/bin
-</sys/src/cmd/mkmany
-
-install: $BIN
-
-$BIN:
- mkdir -p $target
+</sys/src/cmd/mkone