Re: [dev] [hack] Having dmenu provide hints about current selected entry
The following patch does what I proposed. 'seq 1 100 | ./dmenu' just feels as fast as the vanilla dmenu. After each select(), the file descriptors are read until there is no data left on them (and match() is called only once all the data in stdin has been read). Cheers, Christophe-Marie diff -r 2b9683c50723 dmenu.c --- a/dmenu.c Wed Dec 01 20:25:10 2010 + +++ b/dmenu.c Tue Dec 07 14:31:01 2010 +0100 @@ -4,6 +4,8 @@ #include stdlib.h #include string.h #include unistd.h +#include fcntl.h +#include sys/select.h #include X11/Xlib.h #include X11/Xatom.h #include X11/Xutil.h @@ -34,6 +36,7 @@ static size_t nextrune(int incr); static void paste(void); static void readstdin(void); +static void readXEvent(void); static void run(void); static void setup(void); static void usage(void); @@ -59,6 +62,7 @@ static Item *items = NULL; static Item *matches, *sel; static Item *prev, *curr, *next; +static Item **end = items; static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -102,7 +106,6 @@ dc = initdc(); initfont(dc, font); - readstdin(); setup(); run(); @@ -433,9 +436,9 @@ void readstdin(void) { char buf[sizeof text], *p; - Item *item, **end; + Item *item; - for(end = items; fgets(buf, sizeof buf, stdin); *end = item, end = item-next) { + while (fgets(buf, sizeof buf, stdin)) { if((p = strchr(buf, '\n'))) *p = '\0'; if(!(item = malloc(sizeof *item))) @@ -444,14 +447,17 @@ eprintf(cannot strdup %u bytes\n, strlen(buf)+1); item-next = item-left = item-right = NULL; inputw = MAX(inputw, textw(dc, item-text)); + *end = item; + end = item-next; } + match(); } void -run(void) { +readXEvent(void) { XEvent ev; - while(!XNextEvent(dc-dpy, ev)) + while(XPending(dc-dpy) !XNextEvent(dc-dpy, ev)) switch(ev.type) { case Expose: if(ev.xexpose.count == 0) @@ -472,6 +478,35 @@ } void +run(void) { + fd_set fds; + int x11_fd, n, nfds, flags; + struct timeval tv; + + flags = fcntl(STDIN_FILENO, F_GETFL); + flags |= O_NONBLOCK; + fcntl(STDIN_FILENO, F_SETFL, flags); + + x11_fd = XConnectionNumber(dc-dpy); + nfds = MAX(STDIN_FILENO, x11_fd) + 1; + while(1) { + tv.tv_sec = 1; + tv.tv_usec = 0; + FD_ZERO(fds); + if (!feof(stdin)) + FD_SET(STDIN_FILENO, fds); + FD_SET(x11_fd, fds); + n = select(nfds, fds, NULL, NULL, tv); + if(n 0) + eprintf(cannot select\n); + if (FD_ISSET(STDIN_FILENO, fds)) + readstdin(); + if (FD_ISSET(x11_fd, fds)) + readXEvent(); + } +} + +void setup(void) { int x, y, screen; XSetWindowAttributes wa; @@ -531,7 +566,7 @@ promptw = prompt ? textw(dc, prompt) : 0; XMapRaised(dc-dpy, win); text[0] = '\0'; - match(); + drawmenu(); } void
Re: [dev] [hack] Having dmenu provide hints about current selected entry
This patch includes a small correction I forgot to put in the previous patch. There is no need to specify a timeval to wait for (select should block until some data arrives either on stdin or on the x11 file descriptor, as recommended by the select() man page). diff -r 2b9683c50723 dmenu.c --- a/dmenu.c Wed Dec 01 20:25:10 2010 + +++ b/dmenu.c Tue Dec 07 17:32:54 2010 +0100 @@ -4,6 +4,8 @@ #include stdlib.h #include string.h #include unistd.h +#include fcntl.h +#include sys/select.h #include X11/Xlib.h #include X11/Xatom.h #include X11/Xutil.h @@ -34,6 +36,7 @@ static size_t nextrune(int incr); static void paste(void); static void readstdin(void); +static void readXEvent(void); static void run(void); static void setup(void); static void usage(void); @@ -59,6 +62,7 @@ static Item *items = NULL; static Item *matches, *sel; static Item *prev, *curr, *next; +static Item **end = items; static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -102,7 +106,6 @@ dc = initdc(); initfont(dc, font); - readstdin(); setup(); run(); @@ -433,9 +436,9 @@ void readstdin(void) { char buf[sizeof text], *p; - Item *item, **end; + Item *item; - for(end = items; fgets(buf, sizeof buf, stdin); *end = item, end = item-next) { + while (fgets(buf, sizeof buf, stdin)) { if((p = strchr(buf, '\n'))) *p = '\0'; if(!(item = malloc(sizeof *item))) @@ -444,14 +447,17 @@ eprintf(cannot strdup %u bytes\n, strlen(buf)+1); item-next = item-left = item-right = NULL; inputw = MAX(inputw, textw(dc, item-text)); + *end = item; + end = item-next; } + match(); } void -run(void) { +readXEvent(void) { XEvent ev; - while(!XNextEvent(dc-dpy, ev)) + while(XPending(dc-dpy) !XNextEvent(dc-dpy, ev)) switch(ev.type) { case Expose: if(ev.xexpose.count == 0) @@ -472,6 +478,32 @@ } void +run(void) { + fd_set fds; + int x11_fd, n, nfds, flags; + + flags = fcntl(STDIN_FILENO, F_GETFL); + flags |= O_NONBLOCK; + fcntl(STDIN_FILENO, F_SETFL, flags); + + x11_fd = XConnectionNumber(dc-dpy); + nfds = MAX(STDIN_FILENO, x11_fd) + 1; + while(1) { + FD_ZERO(fds); + if (!feof(stdin)) + FD_SET(STDIN_FILENO, fds); + FD_SET(x11_fd, fds); + n = select(nfds, fds, NULL, NULL, NULL); + if(n 0) + eprintf(cannot select\n); + if (FD_ISSET(STDIN_FILENO, fds)) + readstdin(); + if (FD_ISSET(x11_fd, fds)) + readXEvent(); + } +} + +void setup(void) { int x, y, screen; XSetWindowAttributes wa; @@ -531,7 +563,7 @@ promptw = prompt ? textw(dc, prompt) : 0; XMapRaised(dc-dpy, win); text[0] = '\0'; - match(); + drawmenu(); } void
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Wed, Dec 1, 2010 at 2:34 AM, Ramil Farkhshatov ra...@gmx.co.uk wrote: it doesn't run match() on each item, that increases speed and reduces cpu usage. But conditions to run match() must be reconsidered: in this patch it is called once a second. Would it make sense to call match() only when there is nothing left to read on stdin (in your example, that would be when readstdin() returns 0)?
Re: [dev] [hack] Having dmenu provide hints about current selected entry
Christophe-Marie Duquesne chm.duque...@gmail.com wrote: On Wed, Dec 1, 2010 at 2:34 AM, Ramil Farkhshatov ra...@gmx.co.uk wrote: it doesn't run match() on each item, that increases speed and reduces cpu usage. But conditions to run match() must be reconsidered: in this patch it is called once a second. Would it make sense to call match() only when there is nothing left to read on stdin (in your example, that would be when readstdin() returns 0)? If dmenu starts matching after exhausting of data then it will not differ in behaviour from synchronous vanilla version. The condition may be something like: (time_since_last_match_ms threshold_ms || items_since_last_match threshold_nitems || data_exhausted)
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Wed, Dec 1, 2010 at 12:12 PM, Ramil Farkhshatov ra...@gmx.co.uk wrote: Christophe-Marie Duquesne chm.duque...@gmail.com wrote: If dmenu starts matching after exhausting of data then it will not differ in behaviour from synchronous vanilla version. Except it won't block if it does not read EOF, which was more or less the initial goal, wasn't it? This way, if data arrives on stdin, it is read as fast as possible (blocking the user from typing stuff meanwhile, but minimizing the time needed for reading) and if there is no data left to read, dmenu will read X events. If there is not too much data to read (in a case like a google_suggest script, which feeds 10 lines to stdin at each stroke) this should feel instantaneous.
Re: [dev] [hack] Having dmenu provide hints about current selected entry
Ramil Farkhshatov ra...@gmx.co.uk wrote: The condition may be something like: (time_since_last_match_ms threshold_ms || items_since_last_match threshold_nitems || data_exhausted) Stupid me. We can just match added single item.
Re: [dev] [hack] Having dmenu provide hints about current selected entry
Christophe-Marie Duquesne chm.duque...@gmail.com wrote: On Mon, Nov 29, 2010 at 2:44 AM, Connor Lane Smith c...@lubutu.com wrote: Great, it's a lot cleaner this way. One problem with this approach, though, is that if data is written to stdin it isn't displayed until the next X event. This is likely fine for your use case, and dmenu_run, but perhaps not for other cases. To fix that we'd have to select between stdin and XConnectionNumber(dc-dpy). Here is a patch that implements this idea (still available on my bitbucket repo). It actually makes dmenu pretty slow to read stdin. comments/fix are welcome. Attached patch against dmenu-4.2.1 is based on yours but with some changes. It reads stdin by blocks not by line that is noticeably reduces number of invokes of readstdin() and whole select() machinery. And it doesn't run match() on each item, that increases speed and reduces cpu usage. But conditions to run match() must be reconsidered: in this patch it is called once a second. From 57071c903d82ab9f7ea5184e2b974ce3e5d2ab21 Mon Sep 17 00:00:00 2001 From: Ramil Farkhshatov ra...@gmx.co.uk Date: Wed, 1 Dec 2010 04:25:25 +0300 Subject: [PATCH] Added asynchronous. --- dmenu.c | 96 +++--- 1 files changed, 79 insertions(+), 17 deletions(-) diff --git a/dmenu.c b/dmenu.c index a24dfe3..d50604d 100644 --- a/dmenu.c +++ b/dmenu.c @@ -4,6 +4,8 @@ #include stdlib.h #include string.h #include unistd.h +#include fcntl.h +#include sys/select.h #include X11/Xlib.h #include X11/Xatom.h #include X11/Xutil.h @@ -33,7 +35,8 @@ static void keypress(XKeyEvent *ev); static void match(void); static size_t nextrune(int incr); static void paste(void); -static void readstdin(void); +static int readstdin(void); +static void readXEvent(void); static void run(void); static void setup(void); static void usage(void); @@ -59,6 +62,7 @@ static DC *dc; static Item *items = NULL; static Item *matches, *sel; static Item *prev, *curr, *next; +static Item **end = items; static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -102,7 +106,6 @@ main(int argc, char *argv[]) { dc = initdc(); initfont(dc, font); - readstdin(); setup(); run(); @@ -431,27 +434,59 @@ paste(void) { } void +add_item(const char *buf) { + static time_t tm, prev_tm = 0; + Item *item; + + if (!(item = malloc(sizeof *item))) + eprintf(cannot malloc %u bytes\n, sizeof *item); + if (!(item-text = strdup(buf))) + eprintf(cannot strdup %u bytes\n, strlen(buf) + 1); + item-next = item-left = item-right = NULL; + inputw = MAX(inputw, textw(dc, item-text)); + *end = item; + end = item-next; + + /* + We don't want to call match on every new item. + It makes asynchronous dmenu very slow and cpu consuming. + */ + tm = time(0); + if (tm - prev_tm 1) + match(); + prev_tm = tm; +} + +int readstdin(void) { - char buf[sizeof text], *p; - Item *item, **end; - - for(end = items; fgets(buf, sizeof buf, stdin); *end = item, end = item-next) { - if((p = strchr(buf, '\n'))) - *p = '\0'; - if(!(item = malloc(sizeof *item))) - eprintf(cannot malloc %u bytes\n, sizeof *item); - if(!(item-text = strdup(buf))) - eprintf(cannot strdup %u bytes\n, strlen(buf)+1); - item-next = item-left = item-right = NULL; - inputw = MAX(inputw, textw(dc, item-text)); + static char buf[BUFSIZ]; + static int off = 0; + int n, start, i; + char *p; + + n = read(0, buf + off, sizeof(buf) - off); + if (!n) + return 0; + start = 0; + for (i = off; i n + off; ++i) { + if (buf[i] == '\n') { + if (i start) { + buf[i] = 0; + add_item(buf + start); + } + start = i + 1; + } } + memmove(buf, buf + start, off + n - start); + off = off + n - start; + return 1; } void -run(void) { +readXEvent(void) { XEvent ev; - while(!XNextEvent(dc-dpy, ev)) + if(!XNextEvent(dc-dpy, ev)) switch(ev.type) { case Expose: if(ev.xexpose.count == 0) @@ -472,6 +507,33 @@ run(void) { } void +run(void) { + fd_set fds; + int x11_fd, n, nfds, flags, do_stdin = 1; + + flags = fcntl(0, F_GETFL); + flags |= O_NONBLOCK; + fcntl(0, F_SETFL, flags); + x11_fd = XConnectionNumber(dc-dpy); + nfds = MAX(STDIN_FILENO, x11_fd) + 1; + while(1) { + FD_ZERO(fds); +if (do_stdin) + FD_SET(STDIN_FILENO, fds); + FD_SET(x11_fd, fds); + n =
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Mon, Nov 29, 2010 at 2:44 AM, Connor Lane Smith c...@lubutu.com wrote: Great, it's a lot cleaner this way. One problem with this approach, though, is that if data is written to stdin it isn't displayed until the next X event. This is likely fine for your use case, and dmenu_run, but perhaps not for other cases. To fix that we'd have to select between stdin and XConnectionNumber(dc-dpy). Yes, this would be even better. I've also attached a slightly neater version of your patch, plus a bugfix. Thank you!
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Mon, Nov 29, 2010 at 2:44 AM, Connor Lane Smith c...@lubutu.com wrote: Great, it's a lot cleaner this way. One problem with this approach, though, is that if data is written to stdin it isn't displayed until the next X event. This is likely fine for your use case, and dmenu_run, but perhaps not for other cases. To fix that we'd have to select between stdin and XConnectionNumber(dc-dpy). Here is a patch that implements this idea (still available on my bitbucket repo). It actually makes dmenu pretty slow to read stdin. comments/fix are welcome. diff -r a79e4a9cb167 dmenu.c --- a/dmenu.c Sat Nov 20 09:25:08 2010 + +++ b/dmenu.c Mon Nov 29 23:47:52 2010 +0100 @@ -4,6 +4,7 @@ #include stdlib.h #include string.h #include unistd.h +#include sys/select.h #include X11/Xlib.h #include X11/Xatom.h #include X11/Xutil.h @@ -34,6 +35,7 @@ static size_t nextrune(int incr); static void paste(void); static void readstdin(void); +static void readXEvent(void); static void run(void); static void setup(void); static void usage(void); @@ -54,11 +56,13 @@ static unsigned long normcol[ColLast]; static unsigned long selcol[ColLast]; static Atom utf8; +static Bool eof = False; static Bool topbar = True; static DC *dc; static Item *items = NULL; static Item *matches, *sel; static Item *prev, *curr, *next; +static Item **end = items; static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -102,7 +106,6 @@ dc = initdc(); initfont(dc, font); - readstdin(); setup(); run(); @@ -433,9 +436,10 @@ void readstdin(void) { char buf[sizeof text], *p; - Item *item, **end; + Item *item; - for(end = items; fgets(buf, sizeof buf, stdin); *end = item, end = item-next) { + eof = eof || !fgets(buf, sizeof buf, stdin); + if (!eof) { if((p = strchr(buf, '\n'))) *p = '\0'; if(!(item = malloc(sizeof *item))) @@ -444,14 +448,17 @@ eprintf(cannot strdup %u bytes\n, strlen(buf)+1); item-next = item-left = item-right = NULL; inputw = MAX(inputw, textw(dc, item-text)); + *end = item; + end = item-next; + match(); } } void -run(void) { +readXEvent(void) { XEvent ev; - while(!XNextEvent(dc-dpy, ev)) + if(!XNextEvent(dc-dpy, ev)) switch(ev.type) { case Expose: if(ev.xexpose.count == 0) @@ -472,6 +479,32 @@ } void +run(void) { + fd_set fds; + int x11_fd, n, nfds; + struct timeval tv; + + x11_fd = XConnectionNumber(dc-dpy); + nfds = MAX(STDIN_FILENO, x11_fd) + 1; + while(1) { + tv.tv_sec = 1; + tv.tv_usec = 0; + FD_ZERO(fds); + FD_SET(STDIN_FILENO, fds); + FD_SET(x11_fd, fds); + n = select(nfds, fds, NULL, NULL, tv); + if(n 0) + eprintf(cannot select\n); + if(n 0) { + if (FD_ISSET(STDIN_FILENO, fds)) +readstdin(); + if (FD_ISSET(x11_fd, fds)) +readXEvent(); + } + } +} + +void setup(void) { int x, y, screen; XSetWindowAttributes wa; @@ -531,7 +564,7 @@ promptw = prompt ? textw(dc, prompt) : 0; XMapRaised(dc-dpy, win); text[0] = '\0'; - match(); + drawmenu(); } void
Re: [dev] [hack] Having dmenu provide hints about current selected entry
Hi, I rewrote my proposal with select(). Now readstdin() will return if it cannot read data from stdin during more than 1 u_sec. It will set the static flag 'eof' to 1 if it has read the end of file character. This way while eof is 0, you know you should call readstdin() again. Attached is a patch that you can also pull from https://bitbucket.org/chmduquesne/dmenu diff -r a79e4a9cb167 dmenu.c --- a/dmenu.c Sat Nov 20 09:25:08 2010 + +++ b/dmenu.c Mon Nov 29 01:14:46 2010 +0100 @@ -10,6 +10,8 @@ #ifdef XINERAMA #include X11/extensions/Xinerama.h #endif +#include sys/time.h +#include sys/types.h #include draw.h #define INRECT(x,y,rx,ry,rw,rh) ((x) = (rx) (x) (rx)+(rw) (y) = (ry) (y) (ry)+(rh)) @@ -44,6 +46,7 @@ static int lines = 0; static int monitor = -1; static int promptw; +static int eof = 0; static size_t cursor = 0; static const char *font = NULL; static const char *prompt = NULL; @@ -59,6 +62,7 @@ static Item *items = NULL; static Item *matches, *sel; static Item *prev, *curr, *next; +static Item **end = items; static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -432,26 +436,44 @@ void readstdin(void) { + fd_set rfds; + struct timeval tv; + int canread; char buf[sizeof text], *p; - Item *item, **end; + Item *item; - for(end = items; fgets(buf, sizeof buf, stdin); *end = item, end = item-next) { - if((p = strchr(buf, '\n'))) - *p = '\0'; - if(!(item = malloc(sizeof *item))) - eprintf(cannot malloc %u bytes\n, sizeof *item); - if(!(item-text = strdup(buf))) - eprintf(cannot strdup %u bytes\n, strlen(buf)+1); - item-next = item-left = item-right = NULL; - inputw = MAX(inputw, textw(dc, item-text)); - } + do { + tv.tv_sec = 0; + tv.tv_usec = 1; + FD_ZERO(rfds); + FD_SET(0, rfds); + canread = select(1, rfds, NULL, NULL, tv); + if(canread == -1) + perror(select()); + if(canread) { + eof = (fgets(buf, sizeof buf, stdin) == NULL); + if(!eof) { +if((p = strchr(buf, '\n'))) + *p = '\0'; +if(!(item = malloc(sizeof *item))) + eprintf(cannot malloc %u bytes\n, sizeof *item); +if(!(item-text = strdup(buf))) + eprintf(cannot strdup %u bytes\n, strlen(buf)+1); +item-next = item-left = item-right = NULL; +inputw = MAX(inputw, textw(dc, item-text)); + +*end = item; +end = item-next; + } + } + } while(canread !eof); } void run(void) { XEvent ev; - while(!XNextEvent(dc-dpy, ev)) + while(!XNextEvent(dc-dpy, ev)) { switch(ev.type) { case Expose: if(ev.xexpose.count == 0) @@ -469,6 +491,9 @@ XRaiseWindow(dc-dpy, win); break; } + if (!eof) + readstdin(); + } } void
Re: [dev] [hack] Having dmenu provide hints about current selected entry
Hey, On 29 November 2010 00:17, Christophe-Marie Duquesne chm.duque...@gmail.com wrote: I rewrote my proposal with select(). Now readstdin() will return if it cannot read data from stdin during more than 1 u_sec. It will set the static flag 'eof' to 1 if it has read the end of file character. This way while eof is 0, you know you should call readstdin() again. Great, it's a lot cleaner this way. One problem with this approach, though, is that if data is written to stdin it isn't displayed until the next X event. This is likely fine for your use case, and dmenu_run, but perhaps not for other cases. To fix that we'd have to select between stdin and XConnectionNumber(dc-dpy). I've also attached a slightly neater version of your patch, plus a bugfix. Thanks, cls diff -r a79e4a9cb167 dmenu.c --- a/dmenu.c Sat Nov 20 09:25:08 2010 + +++ b/dmenu.c Mon Nov 29 01:40:44 2010 + @@ -4,6 +4,7 @@ #include stdlib.h #include string.h #include unistd.h +#include sys/select.h #include X11/Xlib.h #include X11/Xatom.h #include X11/Xutil.h @@ -54,11 +55,13 @@ static unsigned long normcol[ColLast]; static unsigned long selcol[ColLast]; static Atom utf8; +static Bool eof = False; static Bool topbar = True; static DC *dc; static Item *items = NULL; static Item *matches, *sel; static Item *prev, *curr, *next; +static Item **end = items; static Window root, win; static int (*fstrncmp)(const char *, const char *, size_t) = strncmp; @@ -102,7 +105,6 @@ dc = initdc(); initfont(dc, font); - readstdin(); setup(); run(); @@ -433,9 +435,20 @@ void readstdin(void) { char buf[sizeof text], *p; - Item *item, **end; + fd_set fds; + int n; + struct timeval tv; + Item *item; - for(end = items; fgets(buf, sizeof buf, stdin); *end = item, end = item-next) { + while(!eof) { + tv.tv_sec = 0; + tv.tv_usec = 1; + FD_ZERO(fds); + FD_SET(STDIN_FILENO, fds); + if((n = select(1, fds, NULL, NULL, tv)) 0) + eprintf(cannot select stdin\n); + if(n == 0 || (eof = !fgets(buf, sizeof buf, stdin))) + break; if((p = strchr(buf, '\n'))) *p = '\0'; if(!(item = malloc(sizeof *item))) @@ -444,6 +457,9 @@ eprintf(cannot strdup %u bytes\n, strlen(buf)+1); item-next = item-left = item-right = NULL; inputw = MAX(inputw, textw(dc, item-text)); + *end = item; + end = item-next; + match(); } } @@ -451,7 +467,7 @@ run(void) { XEvent ev; - while(!XNextEvent(dc-dpy, ev)) + while(!XNextEvent(dc-dpy, ev)) { switch(ev.type) { case Expose: if(ev.xexpose.count == 0) @@ -469,6 +485,8 @@ XRaiseWindow(dc-dpy, win); break; } + readstdin(); + } } void @@ -531,7 +549,7 @@ promptw = prompt ? textw(dc, prompt) : 0; XMapRaised(dc-dpy, win); text[0] = '\0'; - match(); + drawmenu(); } void
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Fri, 26 Nov 2010 14:38:10 +0100 Christophe-Marie Duquesne chm.duque...@gmail.com wrote: Hi there, I wanted a menu that would allow me to select entries both from the uzbl history and from google suggest 'as you type' (like in firefox). While dmenu allows selecting entries in a static list (like uzbl history) easily, modifying this list and providing hints to google suggest did not seem to be possible. Since I did not see any other way to do that, I wrote a patch to dmenu. It adds 2 features: 1) if invoked with the option -s (-s for stream) dmenu will output selected entry on every keystroke (so you can feed a tool with the current entry). 2) in order to avoid waiting for the input stream to finish before allowing the user for select entries (and so that you can continue feeding it from stdin while you type), dmenu reads stdin in a thread. The idea is to feed dmenu with hints deduced from its stdout. As an example, here is how this can be used: #!/bin/bash socat UNIX-LISTEN:/tmp/dmenu_suggest - | dmenu -s | tee /tmp/results | \ while read line; do echo $line | ./google_suggest; done | \ socat - UNIX-CONNECT:/tmp/dmenu_suggest tail -n1 /tmp/results rm /tmp/results google_suggest is a python script I wrote. It reads search terms from stdin and outputs suggestions from google suggest API (I have attached it). If you are interested, you can pull my dmenu patch from https://bitbucket.org/chmduquesne/dmenu. Although the script above works correctly on my machine, the patch breaks dmenu in other situations. I would be interested if the persons who find this idea interesting would be kind enough to provide some constructive advices about the way to do that, e.g. if you see any cleaner method or if you have suggestions for doing that in a better way without patching dmenu. Advices like don't do that or stop rewriting firefox will probably not help. Cool. I've been pondering this feature before. Because if feeding dmenu stdin is time-consuming (i have some sorts and whatnot when reading my most often invoked entries) the delay caused by dmenu waiting for stdin input to be complete is noticeable. I would prefer if it works like this: - when you invoke dmenu, it immediately appears, and user can start typing input. as soon as dmenu is started, it starts reading stdin, however fast or slow it goes until EOF. - anytime anything happens (user changes his query or new line is read on stdin) the search results are updated in realtime accordingly. I think the code/algorithms to realize this must be pretty complicated for it to work nicely (high performance).. But your patches seem trivial, so did I miss something? Also, what do you do if the user types something, you feed google suggest results to stdin, and then the user erases the line and types something completely different? the old suggestions are still in dmenu's datastructure so they can still appear in the search result? And how exactly do you make sure the suggestions are shown for the corresponding query? I would expect you would prefix the suggestions with the query, but don't see anything like that in your python code. Dieter
Re: [dev] [hack] Having dmenu provide hints about current selected entry
Hey, On 26 November 2010 14:04, Dieter Plaetinck die...@plaetinck.be wrote: I would prefer if it works like this: - when you invoke dmenu, it immediately appears, and user can start typing input. as soon as dmenu is started, it starts reading stdin, however fast or slow it goes until EOF. - anytime anything happens (user changes his query or new line is read on stdin) the search results are updated in realtime accordingly. I think the code/algorithms to realize this must be pretty complicated for it to work nicely (high performance).. But your patches seem trivial, so did I miss something? No, to do this would be trivial. It's just that certain suckless people are rather aggressive to the idea of using pthreads for anything. On 26 November 2010 13:38, Christophe-Marie Duquesne chm.duque...@gmail.com wrote: 1) if invoked with the option -s (-s for stream) dmenu will output selected entry on every keystroke (so you can feed a tool with the current entry). 2) in order to avoid waiting for the input stream to finish before allowing the user for select entries (and so that you can continue feeding it from stdin while you type), dmenu reads stdin in a thread. The first aspect of your patch, the incremental output, already exists.[1] The threaded input is neat, and I am perfectly willing to add it into dmenu proper. Though I expect others will not share that willingness. [1]: http://tools.suckless.org/dmenu/patches/incremental Thanks, cls
Re: [dev] [hack] Having dmenu provide hints about current selected entry
Connor Lane Smith c...@lubutu.com writes: Hey, On 26 November 2010 14:04, Dieter Plaetinck die...@plaetinck.be wrote: I would prefer if it works like this: - when you invoke dmenu, it immediately appears, and user can start typing input. as soon as dmenu is started, it starts reading stdin, however fast or slow it goes until EOF. - anytime anything happens (user changes his query or new line is read on stdin) the search results are updated in realtime accordingly. I think the code/algorithms to realize this must be pretty complicated for it to work nicely (high performance).. But your patches seem trivial, so did I miss something? No, to do this would be trivial. It's just that certain suckless people are rather aggressive to the idea of using pthreads for anything. If threads are the problem, you could do this with select() easily enough. I think people object to the complexity, however. (I don't - especially when the alternative is to loose out on a very useful feature that cannot be implemented in a simpler way.) -- \ Troels /\ Henriksen
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On 26 November 2010 15:43, Connor Lane Smith c...@lubutu.com wrote: On 26 November 2010 14:04, Dieter Plaetinck die...@plaetinck.be wrote: I would prefer if it works like this: - when you invoke dmenu, it immediately appears, and user can start typing input. as soon as dmenu is started, it starts reading stdin, however fast or slow it goes until EOF. - anytime anything happens (user changes his query or new line is read on stdin) the search results are updated in realtime accordingly. I think the code/algorithms to realize this must be pretty complicated for it to work nicely (high performance).. But your patches seem trivial, so did I miss something? No, to do this would be trivial. It's just that certain suckless people are rather aggressive to the idea of using pthreads for anything. Well the question is if the bottleneck is the input writer or dmenu reading the input. The problems I remember from the past where all related to the input writer (for example dmenu_path taking some time to create it's output) but not dmenu creating the input item list. If the latter is a problem now I would like to hear how many input items are read and what the time penalty is to process them in dmenu, before considering putting the read into a worker thread. Cheers, Anselm
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On 26 November 2010 15:27, Anselm R Garbe garb...@gmail.com wrote: Well the question is if the bottleneck is the input writer or dmenu reading the input. The problems I remember from the past where all related to the input writer (for example dmenu_path taking some time to create it's output) but not dmenu creating the input item list. That's fair. We could do some testing to see whether dmenu reading a *lot* of data from a pipe is noticeably slow, or whether it's just dmenu_path's sorting (which obviously we can't do anything about). cls
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Fri, Nov 26, 2010 at 3:04 PM, Dieter Plaetinck die...@plaetinck.be wrote: the delay caused by dmenu waiting for stdin input to be complete is noticeable. Actually, while performance also matters, the thread thing is not primarily a matter of fast processing. It is just that if you wait for the input to finish before allowing the user to interact, you miss the point of allowing feeding additional entries to this input from the suggestions (since these suggestions can only happen once user can interact). On Fri, Nov 26, 2010 at 3:43 PM, Connor Lane Smith c...@lubutu.com wrote: No, to do this would be trivial. It's just that certain suckless people are rather aggressive to the idea of using pthreads for anything. I was more or less aware of this but did not see any other options. @Troels: I did not know select(), but I am going to read about it. The first aspect of your patch, the incremental output, already exists. Thank you, I did not know about it. The threaded input is neat, and I am perfectly willing to add it into dmenu proper. Though I expect others will not share that willingness. It isn't. I experimented a crash when messing with it, so expect to find bugs.
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On 26 November 2010 15:30, Connor Lane Smith c...@lubutu.com wrote: That's fair. We could do some testing to see whether dmenu reading a *lot* of data from a pipe is noticeably slow, or whether it's just dmenu_path's sorting (which obviously we can't do anything about). That said, if the source of the pipe prints items incrementally (because it doesn't have to sort, for example) it would speed up dmenu significantly, even though dmenu is not the source of the block. In that respect threading could be useful. Running `find | dmenu` would take an age to bring up dmenu with the current model, but with threading it would appear instantly and then start to be populated. (readstdin would need to make calls to drawmenu). cls
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On 26 November 2010 16:30, Connor Lane Smith c...@lubutu.com wrote: On 26 November 2010 15:27, Anselm R Garbe garb...@gmail.com wrote: Well the question is if the bottleneck is the input writer or dmenu reading the input. The problems I remember from the past where all related to the input writer (for example dmenu_path taking some time to create it's output) but not dmenu creating the input item list. That's fair. We could do some testing to see whether dmenu reading a *lot* of data from a pipe is noticeably slow, or whether it's just dmenu_path's sorting (which obviously we can't do anything about). With vanilla dmenu seq 10 | dmenu works instantaneously for me. I see some 2s lack if I increase to seq 100 | dmenu though. But is 1M items a usual scenario? I kind of doubt that and the 2s penalty doesn't sound too bad imho. Cheers, Anselm
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On 26 November 2010 15:33, Christophe-Marie Duquesne chm.duque...@gmail.com wrote: The threaded input is neat, and I am perfectly willing to add it into dmenu proper. Though I expect others will not share that willingness. It isn't. I experimented a crash when messing with it, so expect to find bugs. I meant 'neat' in the sense of 'cool'... If we were to integrate it we would definitely do a thorough debugging beforehand. Though it does occur to me that we may need to use locking. Which ... suddenly makes the whole idea look a lot less quick and easy. On 26 November 2010 15:36, Anselm R Garbe garb...@gmail.com wrote: works instantaneously for me. I see some 2s lack if I increase to seq 100 | dmenu though. But is 1M items a usual scenario? I kind of doubt that and the 2s penalty doesn't sound too bad imho. Yeah, that seems pretty fast, though obviously seq is a very fast process: my second response was a stronger argument. But having remembered locking, I'm a lot less eager to do this. . cls
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On 26 November 2010 16:33, Christophe-Marie Duquesne chm.duque...@gmail.com wrote: On Fri, Nov 26, 2010 at 3:04 PM, Dieter Plaetinck die...@plaetinck.be wrote: the delay caused by dmenu waiting for stdin input to be complete is noticeable. Actually, while performance also matters, the thread thing is not primarily a matter of fast processing. It is just that if you wait for the input to finish before allowing the user to interact, you miss the point of allowing feeding additional entries to this input from the suggestions (since these suggestions can only happen once user can interact). Ok that's a better reason for it. On Fri, Nov 26, 2010 at 3:43 PM, Connor Lane Smith c...@lubutu.com wrote: No, to do this would be trivial. It's just that certain suckless people are rather aggressive to the idea of using pthreads for anything. I was more or less aware of this but did not see any other options. @Troels: I did not know select(), but I am going to read about it. The first aspect of your patch, the incremental output, already exists. Thank you, I did not know about it. The threaded input is neat, and I am perfectly willing to add it into dmenu proper. Though I expect others will not share that willingness. It isn't. I experimented a crash when messing with it, so expect to find bugs. I guess those crashes are related to concurrent accesses to the same data structure. In the end the thread would need to work on a copy and the items propagation would need to be protected by a mutex. Hence things will become a bit ugly. I don't think the select() approach would increase the readability a lot, but at least it would implicitly disallow concurrent accesses to items. I think overall the threaded version should be favored, for now as a patch I would say. Cheers, Anselm
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Fri, Nov 26, 2010 at 04:42:36PM +0100, Christophe-Marie Duquesne wrote: On Fri, Nov 26, 2010 at 4:36 PM, Anselm R Garbe garb...@gmail.com wrote: With vanilla dmenu seq 10 | dmenu works instantaneously for me. I see some 2s lack if I increase to seq 100 | dmenu though. But is 1M items a usual scenario? I kind of doubt that and the 2s penalty doesn't sound too bad imho. Again, this is not a matter of performance. Hints can be provided only once the user can interact. If you read, _then_ allow user interaction, you cannot add hints since you don't read anymore. You have to allow interaction _while_ still reading if you want to feed dmenu with hints from what is currently being typed. Ok, but for this scenario select() would be a better candidate, as you can also block input processing from the X server until your incremental input has been read and you can avoid synchronising with some ugly mutex. -Anselm
Re: [dev] [hack] Having dmenu provide hints about current selected entry
On Fri, 26 Nov 2010 16:33:51 +0100 Christophe-Marie Duquesne chm.duque...@gmail.com wrote: On Fri, Nov 26, 2010 at 3:04 PM, Dieter Plaetinck die...@plaetinck.be wrote: the delay caused by dmenu waiting for stdin input to be complete is noticeable. Actually, while performance also matters, the thread thing is not primarily a matter of fast processing. It is just that if you wait for the input to finish before allowing the user to interact, you miss the point of allowing feeding additional entries to this input from the suggestions (since these suggestions can only happen once user can interact). Yes, I just wanted to explain my use case, which is different then yours. Anselm questioned earlier whether the writer (dmenu_path and whatnot) or the reader (dmenu) is the slow one, as far as i've seen it's always the writer. But that doesn't change my point at all. I just want to be able to start typing asap, the input writer is usually fast enough to catch up before I'm done typing anyway. But I don't like to needlessly wait before dmenu appears. Again, this is the concern in my use case, which is different then yours. Dieter