spmenu/libs/arg.c

773 lines
16 KiB
C
Raw Normal View History

2023-05-14 00:21:16 +02:00
/* See LICENSE file for copyright and license details. */
void moveleft(Arg *arg) {
struct item *tmpsel;
int i, offscreen = 0;
int argu = arg->i ? arg->i : 1;
2023-07-16 02:57:38 +02:00
// If we cannot move left because !lines, moving left should move to the next item. Calling moveup() does this.
2023-07-12 14:16:08 +02:00
if (!lines) {
moveup(arg);
return;
}
if (columns > 1) {
if (!selecteditem) {
2023-05-08 23:00:45 +02:00
return;
2023-07-16 02:57:38 +02:00
}
tmpsel = selecteditem;
2023-05-08 23:00:45 +02:00
for (i = 0; i < lines; i++) {
if (!tmpsel->left || tmpsel->left->right != tmpsel) {
if (offscreen)
drawmenu();
return;
}
if (tmpsel == currentitem)
2023-05-08 23:00:45 +02:00
offscreen = 1;
tmpsel = tmpsel->left;
}
selecteditem = tmpsel;
2023-05-08 23:00:45 +02:00
if (offscreen) {
for (int j = 0; j < argu; j++) {
currentitem = previousitem;
}
2023-05-08 23:00:45 +02:00
}
2023-05-08 23:00:45 +02:00
drawmenu();
calcoffsets();
2023-05-08 23:00:45 +02:00
}
}
void moveright(Arg *arg) {
struct item *tmpsel;
int i, offscreen = 0;
int argu = arg->i ? arg->i : 1;
2023-07-16 02:57:38 +02:00
if (!lines) { // If we cannot move right because !lines, moving right should move to the previous item. Calling down() does this.
2023-07-12 14:16:08 +02:00
movedown(arg);
return;
}
if (columns > 1) {
if (!selecteditem)
2023-05-08 23:00:45 +02:00
return;
tmpsel = selecteditem;
2023-05-08 23:00:45 +02:00
for (i = 0; i < lines; i++) {
if (!tmpsel->right || tmpsel->right->left != tmpsel) {
if (offscreen)
drawmenu();
return;
}
tmpsel = tmpsel->right;
if (tmpsel == nextitem)
2023-05-08 23:00:45 +02:00
offscreen = 1;
}
selecteditem = tmpsel;
2023-05-08 23:00:45 +02:00
if (offscreen) {
for (int j = 0; j < argu; j++)
currentitem = nextitem;
2023-05-08 23:00:45 +02:00
}
calcoffsets();
}
2023-05-08 23:00:45 +02:00
drawmenu();
}
void movedown(Arg *arg) {
int argu = arg->i ? arg->i : 1;
for (int j = 0; j < argu; j++) {
if (selecteditem && selecteditem->right && (selecteditem = selecteditem->right) == nextitem) {
currentitem = nextitem; // Current item is now the next item
2023-05-08 23:00:45 +02:00
}
}
calcoffsets();
2023-05-08 23:00:45 +02:00
drawmenu();
}
void moveup(Arg *arg) {
int argu = arg->i ? arg->i : 1;
for (int j = 0; j < argu; j++) {
if (selecteditem && selecteditem->left && (selecteditem = selecteditem->left)->right == currentitem) {
currentitem = previousitem; // Current item is now the previous item
2023-05-08 23:00:45 +02:00
}
}
2023-05-08 23:00:45 +02:00
calcoffsets();
drawmenu();
}
void complete(Arg *arg) {
2023-07-05 02:02:35 +02:00
int itc = 0;
struct item *item;
if (hideitem) return;
2023-07-05 02:02:35 +02:00
if (matchend) {
itc++;
for (item = matchend; item && item->left; item = item->left)
itc++;
}
if (!itc) {
return;
}
strncpy(tx.text, selecteditem->nsgrtext, sizeof tx.text - 1);
2023-06-23 03:38:21 +02:00
tx.text[sizeof tx.text - 1] = '\0';
sp.cursor = strlen(tx.text);
2023-05-08 23:00:45 +02:00
match();
drawmenu();
}
void movenext(Arg *arg) {
if (!nextitem) {
2023-05-08 23:00:45 +02:00
return;
}
selecteditem = currentitem = nextitem; // next page
drawmenu();
}
void moveprev(Arg *arg) {
if (!previousitem) {
return;
}
selecteditem = currentitem = previousitem; // previous page
calcoffsets();
drawmenu();
}
2023-05-22 16:35:57 +02:00
void moveitem(Arg *arg) {
for (int i = 0; i < arg->i; i++) {
if (selecteditem && selecteditem->right && (selecteditem = selecteditem->right) == nextitem) {
currentitem = nextitem;
2023-05-22 16:35:57 +02:00
calcoffsets();
}
}
drawmenu();
}
void movestart(Arg *arg) {
if (selecteditem == matches) {
2023-06-23 03:38:21 +02:00
sp.cursor = 0;
drawmenu();
return;
2023-05-08 23:00:45 +02:00
}
selecteditem = currentitem = matches;
2023-05-08 23:00:45 +02:00
calcoffsets();
drawmenu();
}
void moveend(Arg *arg) {
2023-06-23 03:38:21 +02:00
if (tx.text[sp.cursor] != '\0') {
sp.cursor = strlen(tx.text);
drawmenu();
return;
2023-05-08 23:00:45 +02:00
}
if (nextitem) {
currentitem = matchend;
2023-05-08 23:00:45 +02:00
calcoffsets();
currentitem = previousitem;
2023-05-08 23:00:45 +02:00
calcoffsets();
while (nextitem && (currentitem = currentitem->right))
2023-05-08 23:00:45 +02:00
calcoffsets();
}
selecteditem = matchend;
drawmenu();
}
void paste(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if WAYLAND
if (protocol) {
paste_wl();
} else {
2023-08-07 06:37:38 +02:00
#if X11
paste_x11(arg->i);
#endif
}
2023-08-07 06:37:38 +02:00
#elif X11
paste_x11(arg->i);
#endif
}
void viewhist(Arg *arg) {
int i;
if (histfile) {
if (!history_items) {
history_items = items;
2023-05-08 23:00:45 +02:00
items = calloc(histsz + 1, sizeof(struct item));
if (!items) {
die("spmenu: cannot allocate memory");
}
for (i = 0; i < histsz; i++) {
items[i].text = history[i];
}
} else {
free(items);
items = history_items;
history_items = NULL;
2023-05-08 23:00:45 +02:00
}
}
match();
drawmenu();
}
void deleteword(Arg *arg) {
2023-06-23 03:38:21 +02:00
if (sp.cursor == 0) return;
2023-06-23 03:38:21 +02:00
while (sp.cursor > 0 && strchr(worddelimiters, tx.text[nextrune(-1)])) {
insert(NULL, nextrune(-1) - sp.cursor);
} while (sp.cursor > 0 && !strchr(worddelimiters, tx.text[nextrune(-1)])) {
insert(NULL, nextrune(-1) - sp.cursor);
}
drawmenu();
}
void moveword(Arg *arg) {
2023-06-23 03:38:21 +02:00
if (arg->i < 0) { // move sp.cursor to the start of the word
while (sp.cursor > 0 && strchr(worddelimiters, tx.text[nextrune(-1)])) {
sp.cursor = nextrune(-1);
} while (sp.cursor > 0 && !strchr(worddelimiters, tx.text[nextrune(-1)])) {
sp.cursor = nextrune(-1);
}
2023-06-23 03:38:21 +02:00
} else { // move sp.cursor to the end of the word
while (tx.text[sp.cursor] && strchr(worddelimiters, tx.text[sp.cursor])) {
sp.cursor = nextrune(+1);
} while (tx.text[sp.cursor] && !strchr(worddelimiters, tx.text[sp.cursor])) {
sp.cursor = nextrune(+1);
}
2023-05-08 23:00:45 +02:00
}
drawmenu();
}
void movecursor(Arg *arg) {
2023-03-24 14:38:28 +01:00
if (arg->i < 0) {
2023-06-23 03:38:21 +02:00
if (sp.cursor > 0) {
sp.cursor = nextrune(-1);
2023-03-24 14:38:28 +01:00
}
2023-05-08 23:00:45 +02:00
} else {
2023-06-23 03:38:21 +02:00
if (tx.text[sp.cursor]) {
sp.cursor = nextrune(+1);
2023-03-24 14:38:28 +01:00
}
2023-05-08 23:00:45 +02:00
}
2023-03-24 14:38:28 +01:00
drawmenu();
}
void backspace(Arg *arg) {
2023-06-23 03:38:21 +02:00
if (sp.cursor == 0)
return;
2023-06-23 03:38:21 +02:00
insert(NULL, nextrune(-1) - sp.cursor);
drawmenu();
}
void markitem(Arg *arg) {
if (!mark) return;
if (selecteditem && is_selected(selecteditem->index)) {
for (int i = 0; i < sel_size; i++) {
if (sel_index[i] == selecteditem->index) {
sel_index[i] = -1;
}
}
} else {
for (int i = 0; i < sel_size; i++) {
if (sel_index[i] == -1) {
sel_index[i] = selecteditem->index;
return;
}
}
sel_size++;
sel_index = realloc(sel_index, (sel_size + 1) * sizeof(int));
sel_index[sel_size - 1] = selecteditem->index;
}
}
void selectitem(Arg *arg) {
char *selection;
// print index
if (printindex && selecteditem && arg->i) {
fprintf(stdout, "%d\n", selecteditem->index);
cleanup();
exit(0);
}
// selected item or input?
if (selecteditem && arg->i && !hideitem) {
selection = selecteditem->text;
} else {
2023-06-23 03:38:21 +02:00
selection = tx.text;
}
for (int i = 0; i < sel_size; i++) {
if (sel_index[i] != -1 && (!selecteditem || selecteditem->index != sel_index[i])) {
puts(items[sel_index[i]].text);
}
}
if (!selection)
return;
puts(selection);
savehistory(selection);
2023-05-08 23:00:45 +02:00
cleanup();
exit(0);
}
void navhistory(Arg *arg) {
navigatehistfile(arg->i);
drawmenu();
}
void restoresel(Arg *arg) {
2023-06-23 03:38:21 +02:00
tx.text[sp.cursor] = '\0';
match();
drawmenu();
}
void clear(Arg *arg) {
2023-06-23 03:38:21 +02:00
insert(NULL, 0 - sp.cursor);
drawmenu();
}
void clearins(Arg *arg) {
2023-06-23 03:38:21 +02:00
insert(NULL, 0 - sp.cursor);
2023-06-23 03:38:21 +02:00
sp.mode = 1;
sp.allowkeys = 0;
strncpy(tx.modetext, instext, 15);
2023-04-21 09:49:38 +02:00
calcoffsets();
drawmenu();
}
void quit(Arg *arg) {
2023-05-08 23:00:45 +02:00
cleanup();
exit(0);
}
void savehistory(char *input) {
2023-05-08 23:00:45 +02:00
unsigned int i;
FILE *fp;
if (!histfile ||
0 == maxhist ||
0 == strlen(input)) {
goto out;
}
fp = fopen(histfile, "w");
if (!fp) {
die("spmenu: failed to open %s", histfile);
}
for (i = histsz < maxhist ? 0 : histsz - maxhist; i < histsz; i++) {
if (0 >= fprintf(fp, "%s\n", history[i])) {
die("spmenu: failed to write to %s", histfile);
}
}
if (histsz == 0 || histdup || (histsz > 0 && strcmp(input, history[histsz-1]) != 0)) {
if (0 >= fputs(input, fp)) {
die("spmenu: failed to write to %s", histfile);
}
}
if (fclose(fp)) {
die("spmenu: failed to close file %s", histfile);
}
out:
2023-05-08 23:00:45 +02:00
for (i = 0; i < histsz; i++) {
free(history[i]);
}
free(history);
}
2023-07-16 18:59:08 +02:00
void setlineheight(Arg *arg) {
lineheight += arg->i;
sp.bh = MAX(draw->font->h, draw->font->h + 2 + lineheight);
2023-08-29 19:41:03 +02:00
2023-07-16 18:59:08 +02:00
resizeclient();
2023-08-29 19:41:03 +02:00
drawmenu();
2023-07-16 18:59:08 +02:00
}
void setimgsize(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if IMAGE
setimagesize(img.imagewidth + arg->i, img.imageheight + arg->i);
drawmenu();
2023-05-08 23:00:45 +02:00
#endif
}
void flipimg(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if IMAGE
if (!image) return;
2023-06-23 03:38:21 +02:00
img.flip = img.flip ? 0 : arg->i ? 1 : 2;
drawmenu();
2023-05-08 23:00:45 +02:00
#endif
}
void setimgpos(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if IMAGE
if (!image || hideimage) return;
2023-03-08 20:13:39 +01:00
if (imageposition < 3) {
imageposition += arg->i;
} else {
2023-03-08 20:13:39 +01:00
imageposition = 0;
}
drawmenu();
2023-05-08 23:00:45 +02:00
#endif
}
void setimggaps(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if IMAGE
img.imagegaps += arg->i;
2023-03-08 20:13:39 +01:00
if (img.imagegaps < 0)
img.imagegaps = 0;
2023-03-08 20:13:39 +01:00
// limitation to make sure we have a reasonable gap size
if (img.imagegaps > (sp.mw - 2 * img.imagegaps) / 3)
img.imagegaps -= arg->i;
2023-03-08 20:13:39 +01:00
drawmenu();
2023-05-08 23:00:45 +02:00
#endif
2023-03-08 20:13:39 +01:00
}
2023-07-16 18:44:35 +02:00
void toggleinput(Arg *arg) {
hideinput = !hideinput;
drawmenu();
}
2023-08-09 20:49:23 +02:00
void togglepretext(Arg *arg) {
hidepretext = !hidepretext;
drawmenu();
}
2023-07-16 18:44:35 +02:00
void togglelarrow(Arg *arg) {
hidelarrow = !hidelarrow;
drawmenu();
}
void togglerarrow(Arg *arg) {
hiderarrow = !hiderarrow;
drawmenu();
}
void toggleitem(Arg *arg) {
hideitem = !hideitem;
drawmenu();
}
void toggleprompt(Arg *arg) {
hideprompt = !hideprompt;
drawmenu();
}
void togglecaps(Arg *arg) {
hidecaps = !hidecaps;
drawmenu();
}
void togglepowerline(Arg *arg) {
hidepowerline = !hidepowerline;
drawmenu();
}
void togglecaret(Arg *arg) {
hidecaret = !hidecaret;
drawmenu();
}
void togglematchcount(Arg *arg) {
hidematchcount = !hidematchcount;
drawmenu();
}
void togglemode(Arg *arg) {
hidemode = !hidemode;
drawmenu();
}
void togglehighlight(Arg *arg) {
hidehighlight = !hidehighlight;
drawmenu();
}
void toggleregex(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if REGEX
2023-07-16 18:44:35 +02:00
regex = !regex;
match();
drawmenu();
#endif
}
2023-07-22 19:13:02 +02:00
void togglefuzzy(Arg *arg) {
fuzzy = !fuzzy;
match();
drawmenu();
}
void toggleimg(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if IMAGE
hideimage = !hideimage;
drawmenu();
2023-05-08 23:00:45 +02:00
#endif
}
2023-08-09 05:48:32 +02:00
void toggleimgtype(Arg *arg) {
#if IMAGE
imagetype = !imagetype;
#endif
}
void defaultimg(Arg *arg) {
2023-08-07 06:37:38 +02:00
#if IMAGE
if (hideimage || !image) return;
img.imagewidth = imagewidth;
img.imageheight = imageheight;
img.imagegaps = imagegaps;
drawmenu();
2023-05-08 23:00:45 +02:00
#endif
}
2023-03-13 22:45:04 +01:00
void setlines(Arg *arg) {
if (!overridelines) return;
2023-07-03 23:40:30 +02:00
insert(NULL, 0 - sp.cursor);
selecteditem = currentitem = matches;
2023-08-17 14:56:37 +02:00
if (lines + arg->i >= minlines) {
lines += arg->i;
}
2023-03-13 22:45:04 +01:00
if (lines < 0) {
lines = 0;
}
if (lines == 0) {
match();
}
2023-03-13 22:45:04 +01:00
resizeclient();
calcoffsets();
2023-03-13 22:45:04 +01:00
drawmenu();
}
void setcolumns(Arg *arg) {
if (!overridecolumns) return;
2023-03-13 22:45:04 +01:00
columns += arg->i;
if (columns < 1) {
columns = 1;
}
if (lines == 0) {
match();
}
2023-03-13 22:45:04 +01:00
resizeclient();
calcoffsets();
2023-03-13 22:45:04 +01:00
drawmenu();
}
2023-03-29 23:45:54 +02:00
void setx(Arg *arg) {
xpos += arg->i;
resizeclient();
drawmenu();
}
void sety(Arg *arg) {
ypos += arg->i;
resizeclient();
drawmenu();
}
void setw(Arg *arg) {
menuwidth += arg->i;
resizeclient();
drawmenu();
}
void spawn(Arg *arg) {
if (!system(arg->c))
die("spmenu: failed to execute command '%s'", arg->c);
else
exit(0);
2023-04-21 09:49:38 +02:00
}
void setprofile(Arg *arg) {
if (!system("command -v spmenu_profile > /dev/null && spmenu_profile --spmenu-set-profile")) {
die("spmenu: failed to run profile menu\n");
} else {
exit(0);
}
}
void switchmode(Arg *arg) {
if (forceinsertmode) {
return;
}
2023-06-23 03:38:21 +02:00
sp.mode = !sp.mode;
2023-06-23 03:38:21 +02:00
if (!type) sp.mode = 0; // only normal mode allowed
2023-06-23 03:38:21 +02:00
sp.allowkeys = !sp.mode;
2023-06-23 03:38:21 +02:00
strncpy(tx.modetext, sp.mode ? instext : normtext, 15);
drawmenu();
}
/* This function is basically a copy of the selectitem function.
* The only difference is "selectitem" was replaced with "mouseitem" and tx.text output
* was removed.
*/
void outputhover(Arg *arg) {
char *selection;
if (printindex && mouseitem && arg->i) {
fprintf(stdout, "%d\n", mouseitem->index);
cleanup();
exit(0);
}
selection = mouseitem->text;
for (int i = 0; i < sel_size; i++) {
if (sel_index[i] != -1 && (!mouseitem || mouseitem->index != sel_index[i])) {
puts(items[sel_index[i]].text);
}
}
if (!selection)
return;
puts(selection);
savehistory(selection);
cleanup();
exit(0);
}
void selecthover(Arg *arg) {
if (selecteditem != mouseitem) {
selecteditem = mouseitem;
} else {
selecteditem = mouseitem;
outputhover(arg);
return;
}
drawmenu();
}
void markhover(Arg *arg) {
if (!mark) return;
if (mouseitem && is_selected(mouseitem->index)) {
for (int i = 0; i < sel_size; i++) {
if (sel_index[i] == mouseitem->index) {
sel_index[i] = -1;
}
}
} else {
for (int i = 0; i < sel_size; i++) {
if (sel_index[i] == -1) {
sel_index[i] = mouseitem->index;
return;
}
}
sel_size++;
sel_index = realloc(sel_index, (sel_size + 1) * sizeof(int));
sel_index[sel_size - 1] = mouseitem->index;
}
drawmenu();
}
void screenshot(Arg *arg) {
char *file = NULL;
char *home = NULL;
time_t time_ = time(NULL);
struct tm t = *localtime(&time_);
if (!screenshotfile) {
if (!(home = getenv("HOME"))) {
fprintf(stderr, "spmenu: failed to determine home directory\n");
return;
}
if (!screenshotdir && !screenshotname) { // default
if (!(file = malloc(snprintf(NULL, 0, "%s/%s-%02d-%02d-%02d%s", home, "spmenu-screenshot", t.tm_hour, t.tm_min, t.tm_sec, ".png") + 1))) {
die("spmenu: failed to malloc screenshot file");
}
sprintf(file, "%s/%s-%02d-%02d-%02d%s", home, "spmenu-screenshot", t.tm_hour, t.tm_min, t.tm_sec, ".png");
} else if (!screenshotdir && screenshotname) { // no dir but name
if (!(file = malloc(snprintf(NULL, 0, "%s/%s", home, screenshotname) + 1))) {
die("spmenu: failed to malloc screenshot file");
}
sprintf(file, "%s/%s", home, screenshotname);
} else if (screenshotdir && !screenshotname) { // dir but no name
if (!(file = malloc(snprintf(NULL, 0, "%s/%s-%02d-%02d-%02d%s", screenshotdir, "spmenu-screenshot", t.tm_hour, t.tm_min, t.tm_sec, ".png") + 1))) {
die("spmenu: failed to malloc screenshot file");
}
sprintf(file, "%s/%s-%02d-%02d-%02d%s", screenshotdir, "spmenu-screenshot", t.tm_hour, t.tm_min, t.tm_sec, ".png");
} else { // dir and name
if (!(file = malloc(snprintf(NULL, 0, "%s/%s", screenshotdir, screenshotname) + 1))) {
die("spmenu: failed to malloc screenshot file");
}
sprintf(file, "%s/%s", screenshotdir, screenshotname);
}
} else { // custom file
if (!(file = malloc(snprintf(NULL, 0, "%s", screenshotfile) + 1))) {
die("spmenu: failed to malloc screenshot file");
}
sprintf(file, "%s", screenshotfile);
}
draw_save_screen(draw, file);
}