forked from speedie/spmenu
add the ability to read from file, been wanting this for a very long
time
This commit is contained in:
parent
442c40b732
commit
63e5be2884
|
@ -188,6 +188,7 @@ href="https://git.speedie.site/speedwm">speedwm</a>.</p>
|
||||||
<li>Vim-like modes, including indicator.</li>
|
<li>Vim-like modes, including indicator.</li>
|
||||||
<li>The ability to move around items with keybinds.</li>
|
<li>The ability to move around items with keybinds.</li>
|
||||||
<li>Customizable/dynamic line/column size.</li>
|
<li>Customizable/dynamic line/column size.</li>
|
||||||
|
<li>Ability to update entries dynamically by reading from file</li>
|
||||||
<li>IME support
|
<li>IME support
|
||||||
<ul>
|
<ul>
|
||||||
<li>Was removed from suckless dmenu years ago due to issues I’ve
|
<li>Was removed from suckless dmenu years ago due to issues I’ve
|
||||||
|
@ -330,7 +331,6 @@ easy to have LibreSSL compatibility.</li>
|
||||||
</ul></li>
|
</ul></li>
|
||||||
<li>Matching: Add support for contextual completions similar to
|
<li>Matching: Add support for contextual completions similar to
|
||||||
xprompt</li>
|
xprompt</li>
|
||||||
<li>Matching: FIFO, used to dynamically refresh entries.</li>
|
|
||||||
<li>Matching: Regex matching
|
<li>Matching: Regex matching
|
||||||
<ul>
|
<ul>
|
||||||
<li>Probably use some minimal public domain library for this, I’d like
|
<li>Probably use some minimal public domain library for this, I’d like
|
||||||
|
|
|
@ -22,6 +22,7 @@ It is designed to integrate well with my [dwm](https://dwm.suckless.org) fork, [
|
||||||
- Vim-like modes, including indicator.
|
- Vim-like modes, including indicator.
|
||||||
- The ability to move around items with keybinds.
|
- The ability to move around items with keybinds.
|
||||||
- Customizable/dynamic line/column size.
|
- Customizable/dynamic line/column size.
|
||||||
|
- Ability to update entries dynamically by reading from file
|
||||||
- IME support
|
- IME support
|
||||||
- Was removed from suckless dmenu years ago due to issues I've resolved
|
- Was removed from suckless dmenu years ago due to issues I've resolved
|
||||||
- Powerlines
|
- Powerlines
|
||||||
|
@ -130,7 +131,6 @@ have LibreSSL compatibility.
|
||||||
- Just need to `XMoveResizeWindow()` as well as `mh += bh` and `y += bh`
|
- Just need to `XMoveResizeWindow()` as well as `mh += bh` and `y += bh`
|
||||||
for each added line.
|
for each added line.
|
||||||
- Matching: Add support for contextual completions similar to xprompt
|
- Matching: Add support for contextual completions similar to xprompt
|
||||||
- Matching: FIFO, used to dynamically refresh entries.
|
|
||||||
- Matching: Regex matching
|
- Matching: Regex matching
|
||||||
- Probably use some minimal public domain library for this, I'd
|
- Probably use some minimal public domain library for this, I'd
|
||||||
like to avoid adding more external dependencies unless it's a
|
like to avoid adding more external dependencies unless it's a
|
||||||
|
|
|
@ -265,7 +265,11 @@ You may use long, descriptive arguments or the shorter arguments.
|
||||||
: Embed spmenu inside window id
|
: Embed spmenu inside window id
|
||||||
|
|
||||||
`-H, --hist-file hist file`
|
`-H, --hist-file hist file`
|
||||||
: Specify a path to save the history to
|
: Specify a file to save the history to
|
||||||
|
|
||||||
|
`-lf, --list-file list file`
|
||||||
|
: Specify a file to load entries from
|
||||||
|
|
||||||
|
|
||||||
`-ig, --image-gaps gaps`
|
`-ig, --image-gaps gaps`
|
||||||
: Set image gaps to gaps
|
: Set image gaps to gaps
|
||||||
|
|
|
@ -160,6 +160,7 @@ spmenu = {
|
||||||
preselected = 0; // Preselect an item, 0 is the first item (number)
|
preselected = 0; // Preselect an item, 0 is the first item (number)
|
||||||
accuratewidth = 0; // Enable accurate width, could be noticeably slower in some cases (0/1)
|
accuratewidth = 0; // Enable accurate width, could be noticeably slower in some cases (0/1)
|
||||||
delimiters = " "; // Word delimiter, used to delete words (text)
|
delimiters = " "; // Word delimiter, used to delete words (text)
|
||||||
|
listfile = "NULL"; // File to read entries from. If set to NULL standard input is read. This is read every time a key is pressed. (text)
|
||||||
} );
|
} );
|
||||||
|
|
||||||
/* Line options */
|
/* Line options */
|
||||||
|
|
|
@ -276,6 +276,8 @@ void readargs(int argc, char *argv[]) {
|
||||||
input = argv[++i];
|
input = argv[++i];
|
||||||
else if (!strcmp(argv[i], "-fn") || (!strcmp(argv[i], "--font"))) // font or font set
|
else if (!strcmp(argv[i], "-fn") || (!strcmp(argv[i], "--font"))) // font or font set
|
||||||
fonts[0] = argv[++i];
|
fonts[0] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-lf") || (!strcmp(argv[i], "--lf"))) // list file
|
||||||
|
listfile = argv[++i];
|
||||||
else if (!strcmp(argv[i], "-nmt") || (!strcmp(argv[i], "--normal-mode-text"))) // normal mode text
|
else if (!strcmp(argv[i], "-nmt") || (!strcmp(argv[i], "--normal-mode-text"))) // normal mode text
|
||||||
strcpy(normtext, argv[++i]);
|
strcpy(normtext, argv[++i]);
|
||||||
else if (!strcmp(argv[i], "-imt") || (!strcmp(argv[i], "--insert-mode-text"))) // insert mode text
|
else if (!strcmp(argv[i], "-imt") || (!strcmp(argv[i], "--insert-mode-text"))) // insert mode text
|
||||||
|
@ -531,7 +533,8 @@ void usage(void) {
|
||||||
"spmenu -ngbc, --no-global-colors Don't recognize global colors (such as *.color1) on runtime\n"
|
"spmenu -ngbc, --no-global-colors Don't recognize global colors (such as *.color1) on runtime\n"
|
||||||
"spmenu -m, --monitor <monitor> Specify a monitor to run spmenu on\n"
|
"spmenu -m, --monitor <monitor> Specify a monitor to run spmenu on\n"
|
||||||
"spmenu -w, --embed <window id> Embed spmenu inside <window id>\n"
|
"spmenu -w, --embed <window id> Embed spmenu inside <window id>\n"
|
||||||
"spmenu -H, --hist-file <hist file> Specify a path to save the history to\n"
|
"spmenu -H, --hist-file <hist file> Specify a file to save the history to\n"
|
||||||
|
"spmenu -lf, --list-file <list file> Specify a file to load entries from\n"
|
||||||
"spmenu -ig, --image-gaps <gaps> Set image gaps to <gaps>\n"
|
"spmenu -ig, --image-gaps <gaps> Set image gaps to <gaps>\n"
|
||||||
"spmenu -txp, --text-padding <padding> Set text padding to <padding>\n"
|
"spmenu -txp, --text-padding <padding> Set text padding to <padding>\n"
|
||||||
"spmenu -lp, --vertical-padding <padding> Set the vertical padding\n"
|
"spmenu -lp, --vertical-padding <padding> Set the vertical padding\n"
|
||||||
|
|
|
@ -443,6 +443,9 @@ void conf_init(void) {
|
||||||
config_setting_lookup_int(conf, "accuratewidth", &accuratewidth); // spmenu.match.accuratewidth
|
config_setting_lookup_int(conf, "accuratewidth", &accuratewidth); // spmenu.match.accuratewidth
|
||||||
config_setting_lookup_string(conf, "delimiters", &dest); // spmenu.match.delimiters
|
config_setting_lookup_string(conf, "delimiters", &dest); // spmenu.match.delimiters
|
||||||
worddelimiters = strdup(dest);
|
worddelimiters = strdup(dest);
|
||||||
|
if (config_setting_lookup_string(conf, "listfile", &dest)) // spmenu.match.listfile
|
||||||
|
if (dest && strcmp(strdup(dest), "NULL"))
|
||||||
|
listfile = strdup(dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
libs/event.c
10
libs/event.c
|
@ -7,6 +7,7 @@ void eventloop(void) {
|
||||||
while (!XNextEvent(dpy, &ev)) {
|
while (!XNextEvent(dpy, &ev)) {
|
||||||
if (XFilterEvent(&ev, None))
|
if (XFilterEvent(&ev, None))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
switch(ev.type) {
|
switch(ev.type) {
|
||||||
case DestroyNotify:
|
case DestroyNotify:
|
||||||
if (ev.xdestroywindow.window != win)
|
if (ev.xdestroywindow.window != win)
|
||||||
|
@ -31,6 +32,15 @@ void eventloop(void) {
|
||||||
grabfocus();
|
grabfocus();
|
||||||
break;
|
break;
|
||||||
case KeyPress: // read key array and call functions
|
case KeyPress: // read key array and call functions
|
||||||
|
if (listfile) {
|
||||||
|
readfile();
|
||||||
|
|
||||||
|
if (listchanged) {
|
||||||
|
match();
|
||||||
|
drawmenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (incremental) {
|
if (incremental) {
|
||||||
puts(text);
|
puts(text);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
|
@ -112,3 +112,75 @@ void readstdin(void) {
|
||||||
inputw = items ? TEXTWM(items[imax].text) : 0;
|
inputw = items ? TEXTWM(items[imax].text) : 0;
|
||||||
lines = MIN(lines, i);
|
lines = MIN(lines, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void readfile(void) {
|
||||||
|
if (passwd){
|
||||||
|
inputw = lines = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len;
|
||||||
|
static size_t cap = 0;
|
||||||
|
char *l;
|
||||||
|
|
||||||
|
FILE *ef = fopen(listfile, "r");
|
||||||
|
|
||||||
|
if (!ef) return;
|
||||||
|
|
||||||
|
items = NULL;
|
||||||
|
//list = NULL;
|
||||||
|
listsize = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
l = NULL;
|
||||||
|
len = 0;
|
||||||
|
|
||||||
|
if (-1 == getline(&l, &len, ef)) {
|
||||||
|
if (ferror(ef)) die("spmenu: failed to read file\n");
|
||||||
|
free(l);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cap == listsize) {
|
||||||
|
cap += 64 * sizeof(char*);
|
||||||
|
list = realloc(list, cap);
|
||||||
|
if (!list) die("spmenu: failed to realloc memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
strtok(l, "\n");
|
||||||
|
list[listsize] = l;
|
||||||
|
listsize++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fclose(ef)) {
|
||||||
|
die("spmenu: failed to close file %s\n", listfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!list_items) {
|
||||||
|
list_items = items;
|
||||||
|
items = calloc(listsize + 1, sizeof(struct item));
|
||||||
|
if (!items) die("spmenu: cannot alloc memory\n");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < listsize; i++) {
|
||||||
|
items[i].text = list[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == olistcount) {
|
||||||
|
listcount = i;
|
||||||
|
listchanged = 0;
|
||||||
|
} else {
|
||||||
|
olistcount = listcount;
|
||||||
|
listcount = i;
|
||||||
|
listchanged = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
free(items);
|
||||||
|
items = list_items;
|
||||||
|
list_items = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//match();
|
||||||
|
//drawmenu();
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
static void readstdin(void);
|
static void readstdin(void);
|
||||||
|
static void readfile(void);
|
||||||
|
|
|
@ -79,6 +79,7 @@ static int casesensitive = 0; /* Case-sensitive by default? (0/1)
|
||||||
static int preselected = 0; /* Which line should spmenu preselect? */
|
static int preselected = 0; /* Which line should spmenu preselect? */
|
||||||
static int accuratewidth = 0; /* Enable accurate width. May have a performance hit if you are matching a lot of items at once */
|
static int accuratewidth = 0; /* Enable accurate width. May have a performance hit if you are matching a lot of items at once */
|
||||||
static int fuzzy = 1; /* Whether or not to enable fuzzy matching by default */
|
static int fuzzy = 1; /* Whether or not to enable fuzzy matching by default */
|
||||||
|
static char *listfile = NULL; /* File to read entries from instead of stdin. NULL means read from stdin instead. */
|
||||||
|
|
||||||
/* Line options */
|
/* Line options */
|
||||||
static int lineheight = 1; /* Line height (0: Calculate automatically) */
|
static int lineheight = 1; /* Line height (0: Calculate automatically) */
|
||||||
|
|
5
spmenu.1
5
spmenu.1
|
@ -286,7 +286,10 @@ Specify a monitor to run spmenu on
|
||||||
Embed spmenu inside window id
|
Embed spmenu inside window id
|
||||||
.TP
|
.TP
|
||||||
\f[V]-H, --hist-file hist file\f[R]
|
\f[V]-H, --hist-file hist file\f[R]
|
||||||
Specify a path to save the history to
|
Specify a file to save the history to
|
||||||
|
.TP
|
||||||
|
\f[V]-lf, --list-file list file\f[R]
|
||||||
|
Specify a file to load entries from
|
||||||
.TP
|
.TP
|
||||||
\f[V]-ig, --image-gaps gaps\f[R]
|
\f[V]-ig, --image-gaps gaps\f[R]
|
||||||
Set image gaps to gaps
|
Set image gaps to gaps
|
||||||
|
|
20
spmenu.c
20
spmenu.c
|
@ -149,7 +149,7 @@ static int vp; // vertical padding for bar
|
||||||
static int sp; // side padding for bar
|
static int sp; // side padding for bar
|
||||||
static int cursorstate = 1; // cursor state
|
static int cursorstate = 1; // cursor state
|
||||||
static size_t cursor;
|
static size_t cursor;
|
||||||
static struct item *items = NULL, *backup_items;
|
static struct item *items = NULL, *backup_items, *list_items;
|
||||||
static struct item *matches, *matchend;
|
static struct item *matches, *matchend;
|
||||||
static struct item *prev, *curr, *next, *sel;
|
static struct item *prev, *curr, *next, *sel;
|
||||||
static int screen;
|
static int screen;
|
||||||
|
@ -229,6 +229,12 @@ static void setupdisplay(void);
|
||||||
static int max_textw(void);
|
static int max_textw(void);
|
||||||
static size_t nextrune(int inc);
|
static size_t nextrune(int inc);
|
||||||
|
|
||||||
|
static char **list;
|
||||||
|
static size_t listsize;
|
||||||
|
static int listcount;
|
||||||
|
static int olistcount;
|
||||||
|
static int listchanged = 0;
|
||||||
|
|
||||||
// user configuration
|
// user configuration
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
#include "keybinds.h"
|
#include "keybinds.h"
|
||||||
|
@ -256,8 +262,6 @@ static char *(*fstrstr)(const char *, const char *) = cistrstr;
|
||||||
#include "libs/img.c"
|
#include "libs/img.c"
|
||||||
#include "libs/rtl.h"
|
#include "libs/rtl.h"
|
||||||
#include "libs/rtl.c"
|
#include "libs/rtl.c"
|
||||||
#include "libs/event.h"
|
|
||||||
#include "libs/event.c"
|
|
||||||
#include "libs/key.c"
|
#include "libs/key.c"
|
||||||
#include "libs/mouse.c"
|
#include "libs/mouse.c"
|
||||||
#include "libs/sort.c"
|
#include "libs/sort.c"
|
||||||
|
@ -273,6 +277,8 @@ static char *(*fstrstr)(const char *, const char *) = cistrstr;
|
||||||
#include "libs/history.c"
|
#include "libs/history.c"
|
||||||
#include "libs/arg.c"
|
#include "libs/arg.c"
|
||||||
#include "libs/stream.c"
|
#include "libs/stream.c"
|
||||||
|
#include "libs/event.h"
|
||||||
|
#include "libs/event.c"
|
||||||
|
|
||||||
void appenditem(struct item *item, struct item **list, struct item **last) {
|
void appenditem(struct item *item, struct item **list, struct item **last) {
|
||||||
if (*last)
|
if (*last)
|
||||||
|
@ -736,9 +742,17 @@ int main(int argc, char *argv[]) {
|
||||||
// fast (-f) means we grab keyboard before reading standard input
|
// fast (-f) means we grab keyboard before reading standard input
|
||||||
if (fast && !isatty(0)) {
|
if (fast && !isatty(0)) {
|
||||||
grabkeyboard();
|
grabkeyboard();
|
||||||
|
|
||||||
|
if (!listfile)
|
||||||
readstdin();
|
readstdin();
|
||||||
|
else
|
||||||
|
readfile();
|
||||||
} else {
|
} else {
|
||||||
|
if (listfile)
|
||||||
|
readfile();
|
||||||
|
else
|
||||||
readstdin();
|
readstdin();
|
||||||
|
|
||||||
grabkeyboard();
|
grabkeyboard();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -505,7 +505,11 @@ Embed spmenu inside window id
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>-H, --hist-file hist file</code></dt>
|
<dt><code>-H, --hist-file hist file</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
Specify a path to save the history to
|
Specify a file to save the history to
|
||||||
|
</dd>
|
||||||
|
<dt><code>-lf, --list-file list file</code></dt>
|
||||||
|
<dd>
|
||||||
|
Specify a file to load entries from
|
||||||
</dd>
|
</dd>
|
||||||
<dt><code>-ig, --image-gaps gaps</code></dt>
|
<dt><code>-ig, --image-gaps gaps</code></dt>
|
||||||
<dd>
|
<dd>
|
||||||
|
|
Loading…
Reference in a new issue