commit - 1e4bc498ceeced65a0c628df0ea0fbb6a57db10a
commit + 3518f203a8c88d02744ed9c36ca1e6b71703bc2d
blob - 8a923b24966f085bec28c4d164617200f57f98fc
blob + 26f91ddfb179ecd5f751f702f28a339a7508b35c
--- mymenu.1
+++ mymenu.1
.Sh SYNOPSIS
.Nm
.Bk -words
-.Op Fl hva
+.Op Fl hvaA
.Op Fl p Ar prompt
.Op Fl x Ar coord
.Op Fl y Ar coord
.Op Fl s Ar color
.Op Fl S Ar color
.Op Fl w Ar window
+.Op Fl d Ar separator
.Ek
.Sh DESCRIPTION
The
Print version and exit.
.It Fl a
The first completion (if any) is always selected. This is like dmenu.
+.It Fl A
+The user must chose one of the option (or none) and is not able to
+arbitrary enter text
.It Fl p Ar prompt
Override the prompt
.It Fl x Ar val
.It Fl T Ar color
Override the prompt background color. See MyMenu.prompt.background.
.It Fl c Ar color
-Override the completion foreground color. See MyMenu.completion.foreground.
+Override the completion foreground color. See
+MyMenu.completion.foreground.
.It Fl C Ar color
-Override the completion background color. See MyMenu.completion.background.
+Override the completion background color. See
+MyMenu.completion.background.
.It Fl s Ar color
-Override the highlighted completion foreground color. See MyMenu.completion_highlighted.foreground.
+Override the highlighted completion foreground color. See
+MyMenu.completion_highlighted.foreground.
.It Fl S Ar color
-Override the highlighted completion background color. See MyMenu.completion_highlighted.background.
+Override the highlighted completion background color. See
+MyMenu.completion_highlighted.background.
.It Fl w Ar window
Embed into the given window id.
+.It Fl d Ar sep
+Show to the user only the text after the specified separator. If a
+line does not contain the given separator, the whole line will be
+showed to the user.
.El
.Sh RESOURCES
.Bl -tag -width Ds
keybinding is a more elegant way to change, at runtime, the behaviour
of the first completion.
.El
+.Sh EXIT STATUS
+0 when the user select an entry, 1 when the user press Esc, EX_USAGE
+if used with wrong flags and EX_UNAVAILABLE if the connection to X
+fails.
+.Sh EXAMPLES
+.Bl -bullet -bullet
+.It
+Create a simple menu with a couple of entry
+.Bd -literal -offset indent
+cat <<EOF | $SHELL -c "$(mymenu -p "Exec: ")"
+firefox
+zzz
+xcalc -stipple
+xlock
+gimp
+EOF
+.Ed
+.It
+Select and play a song from the current mpd playlist
+.Bd -literal -offset indent
+filter="%position%) %artist% - %title%"
+if song=$(mpc playlist -f "$filter" | mymenu -p "Song: " -A -d ") "); then
+ mpc play $(echo $song | sed "s/).*$//")
+fi
+.Ed
+.El
+
+.Sh SEE ALSO
+.Xr dmenu 1
+.Xr sysexits 3
+
+.Sh AUTHORS
+.An Omar Polo <omar.polo@europecom.net>
+
.Sh BUGS
.Bl -bullet
.It
height of the window, remember to override the x and y coordinates as
well.
.El
-
-.Sh EXIT STATUS
-
-0 when the user select an entry, 1 when the user press Esc, EX_USAGE
-if used with wrong flags and EX_UNAVAILABLE if the connection to X
-fails.
-
-.Sh SEE ALSO
-.Xr dmenu 1
-.Xr sysexits 3
-
-.Sh AUTHORS
-.An Omar Polo <omar.polo@europecom.net>
-
blob - 6ecbe3714c2f20f59d4a1877e065a438678f074f
blob + 6f169f18f8edde24ddcd507f07917ffe99636c60
--- mymenu.1.md
+++ mymenu.1.md
# SYNOPSIS
**mymenu**
-\[**-hva**]
+\[**-hvaA**]
\[**-p** *prompt*]
\[**-x** *coord*]
\[**-y** *coord*]
\[**-s** *color*]
\[**-S** *color*]
\[**-w** *window*]
+\[**-d** *separator*]
# DESCRIPTION
> The first completion (if any) is always selected. This is like dmenu.
+**-A**
+
+> The user must chose one of the option (or none) and is not able to
+> arbitrary enter text
+
**-p** *prompt*
> Override the prompt
**-c** *color*
-> Override the completion foreground color. See MyMenu.completion.foreground.
+> Override the completion foreground color. See
+> MyMenu.completion.foreground.
**-C** *color*
-> Override the completion background color. See MyMenu.completion.background.
+> Override the completion background color. See
+> MyMenu.completion.background.
**-s** *color*
-> Override the highlighted completion foreground color. See MyMenu.completion\_highlighted.foreground.
+> Override the highlighted completion foreground color. See
+> MyMenu.completion\_highlighted.foreground.
**-S** *color*
-> Override the highlighted completion background color. See MyMenu.completion\_highlighted.background.
+> Override the highlighted completion background color. See
+> MyMenu.completion\_highlighted.background.
**-w** *window*
> Embed into the given window id.
+**-d** *sep*
+
+> Show to the user only the text after the specified separator. If a
+> line does not contain the given separator, the whole line will be
+> showed to the user.
+
# RESOURCES
MyMenu.font
> keybinding is a more elegant way to change, at runtime, the behaviour
> of the first completion.
+# EXIT STATUS
+
+0 when the user select an entry, 1 when the user press Esc, EX\_USAGE
+if used with wrong flags and EX\_UNAVAILABLE if the connection to X
+fails.
+
+# EXAMPLES
+
+* Create a simple menu with a couple of entry
+
+ cat <<EOF | $SHELL -c "$(mymenu -p "Exec: ")"
+ firefox
+ zzz
+ xcalc -stipple
+ xlock
+ gimp
+ EOF
+
+* Select and play a song from the current mpd playlist
+
+ filter="%position%) %artist% - %title%"
+ if song=$(mpc playlist -f "$filter" | mymenu -p "Song: " -A -d ") "); then
+ mpc play $(echo $song | sed "s/).*$//")
+ fi
+
+# SEE ALSO
+
+dmenu(1)
+sysexits(3)
+
+# AUTHORS
+
+Omar Polo <omar.polo@europecom.net>
+
# BUGS
* If, instead of a numeric value, a not-valid number that terminates
height of the window, remember to override the x and y coordinates as
well.
-# EXIT STATUS
-
-0 when the user select an entry, 1 when the user press Esc, EX\_USAGE
-if used with wrong flags and EX\_UNAVAILABLE if the connection to X
-fails.
-
-# SEE ALSO
-
-dmenu(1)
-sysexits(3)
-
-# AUTHORS
-
-Omar Polo <omar.polo@europecom.net>
-
-OpenBSD 6.3 - July 15, 2018
+OpenBSD 6.3 - July 21, 2018
blob - f5789da33349677611233547d7155d13b669856e
blob + 99ff4bf294821b3dd6c2e9116a5d8626da7b07c3
--- mymenu.c
+++ mymenu.c
# define default_fontname "fixed"
#endif
-#define ARGS "hvae:p:P:l:f:W:H:x:y:b:B:t:T:c:C:s:S:"
+#define ARGS "hvae:p:P:l:f:W:H:x:y:b:B:t:T:c:C:s:S:d:A"
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
// A simple linked list to store the completions.
struct completion {
char *completion;
+ char *rcompletion;
struct completion *next;
};
return c;
c->completion = nil;
+ c->rcompletion = nil;
c->next = nil;
return c;
}
}
// create a completion list from a text and the list of possible
-// completions (null terminated). Expects a non-null `cs'.
-void filter(struct completions *cs, char *text, char **lines) {
+// completions (null terminated). Expects a non-null `cs'. lines and
+// vlines should have the same lenght OR vlines is null
+void filter(struct completions *cs, char *text, char **lines, char **vlines) {
struct completion *c = compl_new();
if (c == nil) {
return;
int index = 0;
int matching = 0;
+ if (vlines == nil)
+ vlines = lines;
+
while (true) {
- char *l = lines[index];
+ char *l = vlines[index] ? vlines[index] : lines[index];
if (l == nil)
break;
return;
}
c->completion = l;
+ c->rcompletion = lines[index];
}
index++;
}
// update the given completion, that is: clean the old cs & generate a new one.
-void update_completions(struct completions *cs, char *text, char **lines, bool first_selected) {
+void update_completions(struct completions *cs, char *text, char **lines, char **vlines, bool first_selected) {
compl_delete_rec(cs->completions);
- filter(cs, text, lines);
+ filter(cs, text, lines, vlines);
if (first_selected && cs->lenght > 0)
cs->selected = 0;
}
// `realloc(3)` to store more line. Return the number of lines
// read. The last item will always be a NULL pointer. It ignore the
// "null" (empty) lines
-int readlines (char ***lns, int items) {
+int readlines(char ***lns, int items) {
bool finished = false;
int n = 0;
char **lines = *lns;
// unix: to connect to Xorg
pledge("stdio rpath unix", "");
#endif
+
+ char *sep = nil;
// by default the first completion isn't selected
bool first_selected = false;
// our parent window
char *parent_window_id = nil;
+ // the user can input arbitrary text
+ bool free_text = true;
+
// first round of args parsing
int ch;
while ((ch = getopt(argc, argv, ARGS)) != -1) {
parent_window_id = strdup(optarg);
check_allocation(parent_window_id);
break;
+ case 'd': {
+ sep = strdup(optarg);
+ check_allocation(sep);
+ }
+ case 'A': {
+ free_text = false;
+ break;
+ }
default:
break;
}
// read the lines from stdin
char **lines = calloc(INITIAL_ITEMS, sizeof(char*));
- readlines(&lines, INITIAL_ITEMS);
+ check_allocation(lines);
+ int nlines = readlines(&lines, INITIAL_ITEMS);
+ char **vlines = nil;
+ if (sep != nil) {
+ int l = strlen(sep);
+ vlines = calloc(nlines, sizeof(char*));
+ check_allocation(vlines);
+ for (int i = 0; lines[i] != nil; i++) {
+ char *t = strstr(lines[i], sep);
+ if (t == nil)
+ vlines[i] = lines[i];
+ else
+ vlines[i] = t + l;
+ }
+ }
+
setlocale(LC_ALL, getenv("LANG"));
enum state status = LOOPING;
int d_height;
get_wh(d, &parent_window, &d_width, &d_height);
- fprintf(stderr, "d_width %d, d_height %d\n", d_width, d_height);
-
#ifdef USE_XINERAMA
if (!embed && XineramaIsActive(d)) {
// find the mice
case 'a':
first_selected = true;
break;
+ case 'A':
+ // free_text -- this case was already catched
+ break;
+ case 'd':
+ // separator -- this case was already catched
+ break;
case 'e':
// (embedding mymenu) this case was already catched.
break;
// since only now we know if the first should be selected, update
// the completion here
- update_completions(cs, text, lines, first_selected);
+ update_completions(cs, text, lines, vlines, first_selected);
// load the font
#ifdef USE_XFT
status = ERR;
break;
- case CONFIRM:
+ case CONFIRM: {
status = OK;
-
- // if first_selected is active and the first completion is
- // active be sure to 'expand' the text to match the selection
- if (first_selected && cs && cs->selected == 0) {
- free(text);
- text = strdup(cs->completions->completion);
+ if ((cs->selected != -1) || (cs->lenght > 0 && first_selected)) {
+ // if there is something selected expand it and return
+ int index = cs->selected == -1 ? 0 : cs->selected;
+ struct completion *c = cs->completions;
+ while (true) {
+ if (index == 0)
+ break;
+ c = c->next;
+ index--;
+ }
+ char *t = c->rcompletion;
+ free(text);
+ text = strdup(t);
if (text == nil) {
- fprintf(stderr, "Memory allocation error");
+ fprintf(stderr, "Memory allocation error\n");
status = ERR;
}
textlen = strlen(text);
+ } else {
+ if (!free_text) {
+ // cannot accept arbitrary text
+ status = LOOPING;
+ }
}
break;
+ }
case PREV_COMPL: {
complete(cs, first_selected, true, &text, &textlen, &status);
case DEL_CHAR:
popc(text);
- update_completions(cs, text, lines, first_selected);
+ update_completions(cs, text, lines, vlines, first_selected);
break;
case DEL_WORD: {
popw(text);
- update_completions(cs, text, lines, first_selected);
+ update_completions(cs, text, lines, vlines, first_selected);
break;
}
case DEL_LINE: {
for (int i = 0; i < textlen; ++i)
text[i] = 0;
- update_completions(cs, text, lines, first_selected);
+ update_completions(cs, text, lines, vlines, first_selected);
break;
}
}
}
if (status != ERR) {
- update_completions(cs, text, lines, first_selected);
+ update_completions(cs, text, lines, vlines, first_selected);
free(input);
}
break;
}
free(lines);
+ free(vlines);
compls_delete(cs);
XDestroyWindow(r.d, r.w);
XCloseDisplay(r.d);
- return status;
+ return status != OK;
}