Introduction
Introduction Statistics Contact Development Disclaimer Help
[dmenu][patches][sort_by_popularity] - sites - public wiki contents of suckless…
git clone git://git.suckless.org/sites
Log
Files
Refs
---
commit 0975feac72d28558cf49a47385c10e790e982d73
parent a3fd687904a5a548a6405fe3654efd329d447bc7
Author: Wojciech Madry <[email protected]>
Date: Fri, 17 Jan 2025 18:47:56 +0100
[dmenu][patches][sort_by_popularity]
Added patch for dmenu.
sort_by_popularity sorts items by popularity
Diffstat:
A tools.suckless.org/dmenu/patches/s… | 280 +++++++++++++++++++++++++++…
A tools.suckless.org/dmenu/patches/s… | 42 +++++++++++++++++++++++++++…
2 files changed, 322 insertions(+), 0 deletions(-)
---
diff --git a/tools.suckless.org/dmenu/patches/sort_by_popularity/dmenu-sort_by_…
@@ -0,0 +1,280 @@
+From e2cbe709046b733d2a770beb315ef5511abe9a19 Mon Sep 17 00:00:00 2001
+From: Wojciech Madry <[email protected]>
+Date: Fri, 17 Jan 2025 17:11:48 +0100
+Subject: [PATCH] Sort matches by popularity
+
+Patch will sort all matched instances by popularity.
+Each time you open any program, the popularity is increased by 1.
+The popularity is stored in the .cache folder.
+---
+ dmenu.c | 186 +++++++++++++++++++++++++++++++++++++++++++++++++-------
+ 1 file changed, 165 insertions(+), 21 deletions(-)
+
+diff --git a/dmenu.c b/dmenu.c
+index 804da64..cb26068 100644
+--- a/dmenu.c
++++ b/dmenu.c
+@@ -35,11 +35,13 @@ struct item {
+
+ static char text[BUFSIZ] = "";
+ static char *embed;
++static char *popcache = NULL;
+ static int bh, mw, mh;
+ static int inputw = 0, promptw;
+ static int lrpad; /* sum of left and right padding */
+ static size_t cursor;
+ static struct item *items = NULL;
++static struct item *popitems = NULL;
+ static struct item *matches, *matchend;
+ static struct item *prev, *curr, *next, *sel;
+ static int mon = -1, screen;
+@@ -105,7 +107,13 @@ cleanup(void)
+ free(scheme[i]);
+ for (i = 0; items && items[i].text; ++i)
+ free(items[i].text);
++ for (i = 0; popitems && popitems[i].text; ++i)
++ free(popitems[i].text);
+ free(items);
++ free(popitems);
++ if(popcache != NULL)
++ free(popcache);
++
+ drw_free(drw);
+ XSync(dpy, False);
+ XCloseDisplay(dpy);
+@@ -226,6 +234,57 @@ grabkeyboard(void)
+ die("cannot grab keyboard");
+ }
+
++static void
++sortitemsbypop(struct item* first, struct item* last)
++{
++ struct item* item = NULL;
++ struct item* pop = NULL;
++ size_t idx = 0;
++ for (pop = popitems; pop && pop->text; ++pop) {
++ for (item = first; item && item->text && (item <= last || las…
++ if(strcmp(item->text, pop->text) == 0) {
++ char* lhs = first[idx].text;
++ first[idx].text = item->text;
++ item->text = lhs;
++ ++idx;
++ break;
++ }
++ }
++ }
++}
++
++static void
++incpop(struct item* sel) {
++ if(!(sel && sel->text))
++ return;
++ struct item* pop = NULL;
++ int found = 0;
++ FILE *out;
++ out = fopen(popcache, "w");
++ if (out == NULL) {
++ printf("Cannot open file '%s'", popcache);
++ return;
++ }
++ char decimal[16] = {'\0'};
++ for (pop = popitems; pop && pop->text; ++pop) {
++ if(found == 0 && strcmp(pop->text, sel->text) == 0) {
++ pop->out += 1;
++ found = 1;
++ }
++ fputs(pop->text, out);
++ fputs(" ", out);
++ sprintf(decimal, "%i", MIN(pop->out, 999));
++ fputs(decimal, out);
++ fputs("\n", out);
++ }
++ if(found == 0) {
++ fputs(sel->text, out);
++ fputs(" 1", out);
++ fputs("\n", out);
++ }
++ fclose(out);
++}
++
+ static void
+ match(void)
+ {
+@@ -234,17 +293,16 @@ match(void)
+
+ char buf[sizeof text], *s;
+ int i, tokc = 0;
+- size_t len, textsize;
+- struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
++ size_t textsize;
++ struct item *item, *others, *othersend;
+
+ strcpy(buf, text);
+ /* separate input text into tokens to be matched individually */
+ for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " …
+ if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *…
+ die("cannot realloc %zu bytes:", tokn * sizeof *tokv);
+- len = tokc ? strlen(tokv[0]) : 0;
+
+- matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
++ matches = others = matchend = othersend = NULL;
+ textsize = strlen(text) + 1;
+ for (item = items; item && item->text; item++) {
+ for (i = 0; i < tokc; i++)
+@@ -252,29 +310,20 @@ match(void)
+ break;
+ if (i != tokc) /* not all tokens match */
+ continue;
+- /* exact matches go first, then prefixes, then substrings */
++ /* exact matches go first, then others */
+ if (!tokc || !fstrncmp(text, item->text, textsize))
+ appenditem(item, &matches, &matchend);
+- else if (!fstrncmp(tokv[0], item->text, len))
+- appenditem(item, &lprefix, &prefixend);
+ else
+- appenditem(item, &lsubstr, &substrend);
+- }
+- if (lprefix) {
+- if (matches) {
+- matchend->right = lprefix;
+- lprefix->left = matchend;
+- } else
+- matches = lprefix;
+- matchend = prefixend;
++ appenditem(item, &others, &othersend);
+ }
+- if (lsubstr) {
++ if (others) {
++ sortitemsbypop(others, othersend);
+ if (matches) {
+- matchend->right = lsubstr;
+- lsubstr->left = matchend;
++ matchend->right = others;
++ others->left = matchend;
+ } else
+- matches = lsubstr;
+- matchend = substrend;
++ matches = others;
++ matchend = othersend;
+ }
+ curr = sel = matches;
+ calcoffsets();
+@@ -489,6 +538,7 @@ insert:
+ break;
+ case XK_Return:
+ case XK_KP_Enter:
++ incpop(sel);
+ puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
+ if (!(ev->state & ControlMask)) {
+ cleanup();
+@@ -711,6 +761,98 @@ setup(void)
+ drawmenu();
+ }
+
++static void
++itemize(struct item* item, const char* line, const ssize_t size)
++{
++ const size_t UNDEF = size + 1;
++ size_t firstchar = UNDEF, lastchar = UNDEF;
++ size_t firstnum = UNDEF;
++ size_t i;
++ int afterspace = 0;
++ for (i = 0 ; i < size ; ++i) {
++ const char c = line[i];
++ if (c == ' ') {
++ if (firstchar != UNDEF)
++ afterspace = 1;
++ continue;
++ }
++ if (afterspace == 1 && (c >= '0' && c <= '9')) {
++ firstnum = i;
++ break;
++ }
++ if (firstchar == UNDEF)
++ firstchar = i;
++ lastchar = i;
++ }
++ size_t len = lastchar - firstchar + 2;
++ item->text = (char*)malloc(sizeof(char) * len);
++ memcpy(item->text, line + firstchar, len);
++ item->text[len - 1] = '\0';
++
++ item->out = 0;
++ if (firstnum != UNDEF)
++ item->out = atoi(line + firstnum);
++}
++
++static int
++compareitembyoutrev(const void* lhs, const void* rhs)
++{
++ return ((struct item*)rhs)->out - ((struct item*)lhs)->out;
++}
++
++static void
++loadpopitems(void)
++{
++ const char* xdg_cache_home = getenv("XDG_CACHE_HOME");
++ const char* home = getenv("HOME");
++ char* cache = NULL;
++ const char* CACHE_FILENAME = "/dmenu_pop.txt";
++ if(xdg_cache_home != NULL) {
++ size_t xdglen = strlen(xdg_cache_home);
++ cache = (char*)malloc(xdglen + 1);
++ cache[xdglen] = '\0';
++ strcpy(cache, xdg_cache_home);
++ } else {
++ const char* cachefolder = "/.cache";
++ size_t hclen = strlen(home) + strlen(cachefolder) + 1;
++ cache = (char*)malloc(hclen + 1);
++ cache[hclen - 1] = '\0';
++ strcpy(cache, home);
++ strcpy(cache + strlen(home), cachefolder);
++ }
++ const size_t cache_size = strlen(cache) + strlen(CACHE_FILENAME) + 1;
++ popcache = (char*)malloc(sizeof(char) * cache_size);
++ popcache[cache_size - 1] = '\0';
++ strcpy(popcache, cache);
++ strcpy(popcache + strlen(cache), CACHE_FILENAME);
++ free(cache);
++
++ FILE * fp;
++ char * line = NULL;
++ size_t i, itemsiz = 0, linesiz = 0;
++ ssize_t len;
++
++ fp = fopen(popcache, "r");
++ if (fp == NULL)
++ return;
++
++ for (i = 0; (len = getline(&line, &linesiz, fp)) != -1; i++) {
++ if (i + 1 >= itemsiz) {
++ itemsiz += 256;
++ if (!(popitems = realloc(popitems, itemsiz * sizeof(*…
++ die("cannot realloc %zu bytes:", itemsiz * si…
++ }
++ itemize((struct item*)&popitems[i], line, len);
++ }
++ fclose(fp);
++ if (line)
++ free(line);
++
++ if (popitems)
++ popitems[i].text = NULL;
++ qsort(popitems, i, sizeof(struct item), compareitembyoutrev);
++}
++
+ static void
+ usage(void)
+ {
+@@ -788,6 +930,8 @@ main(int argc, char *argv[])
+ readstdin();
+ grabkeyboard();
+ }
++ loadpopitems();
++ sortitemsbypop(items, NULL);
+ setup();
+ run();
+
+--
+2.48.1
+
diff --git a/tools.suckless.org/dmenu/patches/sort_by_popularity/index.md b/too…
@@ -0,0 +1,42 @@
+sort_by_popularity
+=============
+
+The list of programs is sorted by popularity.
+
+Each time you run the program, its popularity will increase by 1.
+
+The popularity cache file is stored in: `{CACHE_PATH}/dmenu_pop.txt`.
+
+Requirements
+------------
+
+* One of the following system env **shall** be set `XDG_CACHE_HOME` or `HOME`
+* Folder `$XDG_CACHE_HOME` or `$HOME/.cache` **shall** exist
+
+How it works
+------------
+
+The order of programs is determined by popularity.
+
+Programs with higher popularity come first.
+
+The order of programs with the same popularity depends on their position in th…
+
+Let's assume that we have the following programs: `A`, `B1`, `B2`, `C`
+
+`[User input] -> [dmenu output] -> [User's choice] -> {PROGRAM: POPULARITY}`
+
+1. ` ` -> `A`, `B1`, `B2`, `C` -> `C` -> `{}`
+2. ` ` -> `C`, `B1`, `B2`, `A` -> `B2` -> `{C: 1}`
+3. ` ` -> `C`, `B2`, `B1`, `A` -> ` ` -> `{C: 1, B2: 1}`
+4. `B` -> `B2`, `B1` -> `B1` -> `{C: 1, B2: 1}`
+5. `B` -> `B2`, `B1` -> `B1` -> `{C: 1, B2: 1, B1: 1}`
+6. `B` -> `B1`, `B2` -> ` ` -> `{C: 1, B2: 1, B1: 2}`
+
+Download
+--------
+* [dmenu-sort_by_popularity-20250117-86f0b51.diff](dmenu-sort_by_popularity-20…
+
+Author
+------
+* Wojciech Madry - <[email protected]>
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.