dotfiles

My beautiful configs and dotfiles managed by Nix' home-manager
Log | Files | Refs | README | LICENSE

dmenu-dynamicoptions.diff (4473B)


      1 diff --git a/config.def.h b/config.def.h
      2 index 1edb647..035b877 100644
      3 --- a/config.def.h
      4 +++ b/config.def.h
      5 @@ -7,6 +7,7 @@ static const char *fonts[] = {
      6  	"monospace:size=10"
      7  };
      8  static const char *prompt      = NULL;      /* -p  option; prompt to the left of input field */
      9 +static const char *dynamic     = NULL;      /* -dy option; dynamic command to run on input change */
     10  static const char *colors[SchemeLast][2] = {
     11  	/*     fg         bg       */
     12  	[SchemeNorm] = { "#bbbbbb", "#222222" },
     13 diff --git a/dmenu.1 b/dmenu.1
     14 index 323f93c..1ae3fe3 100644
     15 --- a/dmenu.1
     16 +++ b/dmenu.1
     17 @@ -22,6 +22,8 @@ dmenu \- dynamic menu
     18  .IR color ]
     19  .RB [ \-w
     20  .IR windowid ]
     21 +.RB [ \-dy
     22 +.IR command ]
     23  .P
     24  .BR dmenu_run " ..."
     25  .SH DESCRIPTION
     26 @@ -80,6 +82,9 @@ prints version information to stdout, then exits.
     27  .TP
     28  .BI \-w " windowid"
     29  embed into windowid.
     30 +.TP
     31 +.BI \-dy " command"
     32 +runs command whenever input changes to update menu items.
     33  .SH USAGE
     34  dmenu is completely controlled by the keyboard.  Items are selected using the
     35  arrow keys, page up, page down, home, and end.
     36 diff --git a/dmenu.c b/dmenu.c
     37 index 7cf253b..e7731ae 100644
     38 --- a/dmenu.c
     39 +++ b/dmenu.c
     40 @@ -44,6 +44,7 @@ static struct item *items = NULL;
     41  static struct item *matches, *matchend;
     42  static struct item *prev, *curr, *next, *sel;
     43  static int mon = -1, screen;
     44 +static unsigned int max_lines = 0;
     45  
     46  static Atom clip, utf8;
     47  static Display *dpy;
     48 @@ -227,6 +228,47 @@ grabkeyboard(void)
     49  	die("cannot grab keyboard");
     50  }
     51  
     52 +static void readstdin(FILE* stream);
     53 +
     54 +static void
     55 +refreshoptions()
     56 +{
     57 +	int dynlen = strlen(dynamic);
     58 +	int cmdlen = dynlen + 4;
     59 +	char *cmd;
     60 +	char *c;
     61 +	char *t = text;
     62 +	while (*t)
     63 +		cmdlen += *t++ == '\'' ? 4 : 1;
     64 +	cmd = malloc(cmdlen);
     65 +	if (cmd == NULL)
     66 +		die("cannot malloc %u bytes:", cmdlen);
     67 +	strcpy(cmd, dynamic);
     68 +	t = text;
     69 +	c = cmd + dynlen;
     70 +	*(c++) = ' ';
     71 +	*(c++) = '\'';
     72 +	while (*t) {
     73 +		// prefix ' with '\'
     74 +		if (*t == '\'') {
     75 +			*(c++) = '\'';
     76 +			*(c++) = '\\';
     77 +			*(c++) = '\'';
     78 +		}
     79 +		*(c++) = *(t++);
     80 +	}
     81 +	*(c++) = '\'';
     82 +	*(c++) = 0;
     83 +	FILE *stream = popen(cmd, "r");
     84 +	if (!stream)
     85 +		die("could not popen dynamic command (%s):", cmd);
     86 +	readstdin(stream);
     87 +	int r = pclose(stream);
     88 +	if (r == -1)
     89 +		die("could not pclose dynamic command");
     90 +	free(cmd);
     91 +}
     92 +
     93  static void
     94  match(void)
     95  {
     96 @@ -238,6 +280,16 @@ match(void)
     97  	size_t len, textsize;
     98  	struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
     99  
    100 +	if (dynamic) {
    101 +		refreshoptions();
    102 +		matches = matchend = NULL;
    103 +		for (item = items; item && item->text; item++)
    104 +			appenditem(item, &matches, &matchend);
    105 +		curr = sel = matches;
    106 +		calcoffsets();
    107 +		return;
    108 +	}
    109 +
    110  	strcpy(buf, text);
    111  	/* separate input text into tokens to be matched individually */
    112  	for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
    113 @@ -547,14 +599,14 @@ paste(void)
    114  }
    115  
    116  static void
    117 -readstdin(void)
    118 +readstdin(FILE* stream)
    119  {
    120  	char *line = NULL;
    121  	size_t i, junk, size = 0;
    122  	ssize_t len;
    123  
    124  	/* read each line from stdin and add it to the item list */
    125 -	for (i = 0; (len = getline(&line, &junk, stdin)) != -1; i++, line = NULL) {
    126 +	for (i = 0; (len = getline(&line, &junk, stream)) != -1; i++, line = NULL) {
    127  		if (i + 1 >= size / sizeof *items)
    128  			if (!(items = realloc(items, (size += BUFSIZ))))
    129  				die("cannot realloc %zu bytes:", size);
    130 @@ -565,7 +617,7 @@ readstdin(void)
    131  	}
    132  	if (items)
    133  		items[i].text = NULL;
    134 -	lines = MIN(lines, i);
    135 +	lines = MIN(max_lines, i);
    136  }
    137  
    138  static void
    139 @@ -711,7 +763,8 @@ static void
    140  usage(void)
    141  {
    142  	die("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
    143 -	    "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]");
    144 +	    "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n"
    145 +		"             [-dy command]\n");
    146  }
    147  
    148  int
    149 @@ -753,6 +806,8 @@ main(int argc, char *argv[])
    150  			colors[SchemeSel][ColFg] = argv[++i];
    151  		else if (!strcmp(argv[i], "-w"))   /* embedding window id */
    152  			embed = argv[++i];
    153 +		else if (!strcmp(argv[i], "-dy"))  /* dynamic command to run */
    154 +			dynamic = argv[++i] && *argv[i] ? argv[i] : NULL;
    155  		else
    156  			usage();
    157  
    158 @@ -777,11 +832,14 @@ main(int argc, char *argv[])
    159  		die("pledge");
    160  #endif
    161  
    162 +	max_lines = lines;
    163  	if (fast && !isatty(0)) {
    164  		grabkeyboard();
    165 -		readstdin();
    166 +		if (!dynamic)
    167 +			readstdin(stdin);
    168  	} else {
    169 -		readstdin();
    170 +		if (!dynamic)
    171 +			readstdin(stdin);
    172  		grabkeyboard();
    173  	}
    174  	setup();