dmenu-dynamicoptions-5.0.diff - sites - public wiki contents of suckless.org
 (HTM) git clone git://git.suckless.org/sites
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       dmenu-dynamicoptions-5.0.diff (5263B)
       ---
            1 From f70735c476c25da46f9e44b835ac967e0dfa4d85 Mon Sep 17 00:00:00 2001
            2 From: Ziad EL KHOURY HANNA <me@ziadkh.ovh>
            3 Date: Mon, 29 Nov 2021 17:36:35 +0100
            4 Subject: [PATCH] add `-dy` flag for dynamic menu updating
            5 
            6 `-dy` flag makes dmenu run the command given to it whenever input is
            7 changed with the current input as the last argument and update the
            8 option list according to the output of that command.
            9 
           10 Based on dynamic options patch by ttmx <tiago.sequeira.teles@gmail.com>.
           11 Adds proper quoting of the given command.
           12 Adds option to man file documentation.
           13 ---
           14  config.def.h |  1 +
           15  dmenu.1      |  5 ++++
           16  dmenu.c      | 70 +++++++++++++++++++++++++++++++++++++++++++++++-----
           17  3 files changed, 70 insertions(+), 6 deletions(-)
           18 
           19 diff --git a/config.def.h b/config.def.h
           20 index 1edb647..035b877 100644
           21 --- a/config.def.h
           22 +++ b/config.def.h
           23 @@ -7,6 +7,7 @@ static const char *fonts[] = {
           24          "monospace:size=10"
           25  };
           26  static const char *prompt      = NULL;      /* -p  option; prompt to the left of input field */
           27 +static const char *dynamic     = NULL;      /* -dy option; dynamic command to run on input change */
           28  static const char *colors[SchemeLast][2] = {
           29          /*     fg         bg       */
           30          [SchemeNorm] = { "#bbbbbb", "#222222" },
           31 diff --git a/dmenu.1 b/dmenu.1
           32 index 323f93c..1ae3fe3 100644
           33 --- a/dmenu.1
           34 +++ b/dmenu.1
           35 @@ -22,6 +22,8 @@ dmenu \- dynamic menu
           36  .IR color ]
           37  .RB [ \-w
           38  .IR windowid ]
           39 +.RB [ \-dy
           40 +.IR command ]
           41  .P
           42  .BR dmenu_run " ..."
           43  .SH DESCRIPTION
           44 @@ -80,6 +82,9 @@ prints version information to stdout, then exits.
           45  .TP
           46  .BI \-w " windowid"
           47  embed into windowid.
           48 +.TP
           49 +.BI \-dy " command"
           50 +runs command whenever input changes to update menu items.
           51  .SH USAGE
           52  dmenu is completely controlled by the keyboard.  Items are selected using the
           53  arrow keys, page up, page down, home, and end.
           54 diff --git a/dmenu.c b/dmenu.c
           55 index 65f25ce..6780122 100644
           56 --- a/dmenu.c
           57 +++ b/dmenu.c
           58 @@ -44,6 +44,7 @@ static struct item *items = NULL;
           59  static struct item *matches, *matchend;
           60  static struct item *prev, *curr, *next, *sel;
           61  static int mon = -1, screen;
           62 +static unsigned int max_lines = 0;
           63  
           64  static Atom clip, utf8;
           65  static Display *dpy;
           66 @@ -210,6 +211,47 @@ grabkeyboard(void)
           67          die("cannot grab keyboard");
           68  }
           69  
           70 +static void readstdin(FILE* stream);
           71 +
           72 +static void
           73 +refreshoptions()
           74 +{
           75 +        int dynlen = strlen(dynamic);
           76 +        int cmdlen = dynlen + 4;
           77 +        char *cmd;
           78 +        char *c;
           79 +        char *t = text;
           80 +        while (*t)
           81 +                cmdlen += *t++ == '\'' ? 4 : 1;
           82 +        cmd = malloc(cmdlen);
           83 +        if (cmd == NULL)
           84 +                die("cannot malloc %u bytes:", cmdlen);
           85 +        strcpy(cmd, dynamic);
           86 +        t = text;
           87 +        c = cmd + dynlen;
           88 +        *(c++) = ' ';
           89 +        *(c++) = '\'';
           90 +        while (*t) {
           91 +                // prefix ' with '\'
           92 +                if (*t == '\'') {
           93 +                        *(c++) = '\'';
           94 +                        *(c++) = '\\';
           95 +                        *(c++) = '\'';
           96 +                }
           97 +                *(c++) = *(t++);
           98 +        }
           99 +        *(c++) = '\'';
          100 +        *(c++) = 0;
          101 +        FILE *stream = popen(cmd, "r");
          102 +        if (!stream)
          103 +                die("could not popen dynamic command (%s):", cmd);
          104 +        readstdin(stream);
          105 +        int r = pclose(stream);
          106 +        if (r == -1)
          107 +                die("could not pclose dynamic command");
          108 +        free(cmd);
          109 +}
          110 +
          111  static void
          112  match(void)
          113  {
          114 @@ -221,6 +263,16 @@ match(void)
          115          size_t len, textsize;
          116          struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
          117  
          118 +        if (dynamic) {
          119 +                refreshoptions();
          120 +                matches = matchend = NULL;
          121 +                for (item = items; item && item->text; item++)
          122 +                        appenditem(item, &matches, &matchend);
          123 +                curr = sel = matches;
          124 +                calcoffsets();
          125 +                return;
          126 +        }
          127 +
          128          strcpy(buf, text);
          129          /* separate input text into tokens to be matched individually */
          130          for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
          131 @@ -519,14 +571,14 @@ paste(void)
          132  }
          133  
          134  static void
          135 -readstdin(void)
          136 +readstdin(FILE* stream)
          137  {
          138          char buf[sizeof text], *p;
          139          size_t i, imax = 0, size = 0;
          140          unsigned int tmpmax = 0;
          141  
          142          /* read each line from stdin and add it to the item list */
          143 -        for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
          144 +        for (i = 0; fgets(buf, sizeof buf, stream); i++) {
          145                  if (i + 1 >= size / sizeof *items)
          146                          if (!(items = realloc(items, (size += BUFSIZ))))
          147                                  die("cannot realloc %u bytes:", size);
          148 @@ -544,7 +596,7 @@ readstdin(void)
          149          if (items)
          150                  items[i].text = NULL;
          151          inputw = items ? TEXTW(items[imax].text) : 0;
          152 -        lines = MIN(lines, i);
          153 +        lines = MIN(max_lines, i);
          154  }
          155  
          156  static void
          157 @@ -690,7 +742,8 @@ static void
          158  usage(void)
          159  {
          160          fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
          161 -              "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
          162 +              "             [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n"
          163 +              "             [-dy command]\n", stderr);
          164          exit(1);
          165  }
          166  
          167 @@ -733,6 +786,8 @@ main(int argc, char *argv[])
          168                          colors[SchemeSel][ColFg] = argv[++i];
          169                  else if (!strcmp(argv[i], "-w"))   /* embedding window id */
          170                          embed = argv[++i];
          171 +                else if (!strcmp(argv[i], "-dy"))  /* dynamic command to run */
          172 +                        dynamic = argv[++i] && *argv[i] ? argv[i] : NULL;
          173                  else
          174                          usage();
          175  
          176 @@ -757,11 +812,14 @@ main(int argc, char *argv[])
          177                  die("pledge");
          178  #endif
          179  
          180 +        max_lines = lines;
          181          if (fast && !isatty(0)) {
          182                  grabkeyboard();
          183 -                readstdin();
          184 +                if (!dynamic)
          185 +                        readstdin(stdin);
          186          } else {
          187 -                readstdin();
          188 +                if (!dynamic)
          189 +                        readstdin(stdin);
          190                  grabkeyboard();
          191          }
          192          setup();
          193 -- 
          194 2.34.1
          195