commit 3518f203a8c88d02744ed9c36ca1e6b71703bc2d from: Omar Polo date: Sat Jul 21 11:20:33 2018 UTC new options `-A` and `-d` + documentation -A force the user to choose one of the completion -d defines a separator. Only the substring from separator and the end of the string is showed to the user, but the original line will be printed commit - 1e4bc498ceeced65a0c628df0ea0fbb6a57db10a commit + 3518f203a8c88d02744ed9c36ca1e6b71703bc2d blob - 8a923b24966f085bec28c4d164617200f57f98fc blob + 26f91ddfb179ecd5f751f702f28a339a7508b35c --- mymenu.1 +++ mymenu.1 @@ -7,7 +7,7 @@ .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 @@ -25,6 +25,7 @@ .Op Fl s Ar color .Op Fl S Ar color .Op Fl w Ar window +.Op Fl d Ar separator .Ek .Sh DESCRIPTION The @@ -45,6 +46,9 @@ Print a small usage message to stderr. 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 @@ -70,15 +74,23 @@ Override the prompt foreground color. See MyMenu.promp .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 @@ -192,7 +204,41 @@ really want to choose ``fire''. While you can type som 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 < + .Sh BUGS .Bl -bullet .It @@ -215,17 +261,3 @@ As a general rule of thumb, if you're overriding the w 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 - blob - 6ecbe3714c2f20f59d4a1877e065a438678f074f blob + 6f169f18f8edde24ddcd507f07917ffe99636c60 --- mymenu.1.md +++ mymenu.1.md @@ -7,7 +7,7 @@ MYMENU(1) - General Commands Manual # SYNOPSIS **mymenu** -\[**-hva**] +\[**-hvaA**] \[**-p** *prompt*] \[**-x** *coord*] \[**-y** *coord*] @@ -25,6 +25,7 @@ MYMENU(1) - General Commands Manual \[**-s** *color*] \[**-S** *color*] \[**-w** *window*] +\[**-d** *separator*] # DESCRIPTION @@ -52,6 +53,11 @@ over the (respective) ones defined in the > 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 @@ -102,24 +108,34 @@ over the (respective) ones defined in the **-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 @@ -292,6 +308,40 @@ C-i > 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 < (b) ? (a) : (b)) @@ -134,6 +134,7 @@ struct rendering { // A simple linked list to store the completions. struct completion { char *completion; + char *rcompletion; struct completion *next; }; @@ -164,6 +165,7 @@ struct completion *compl_new() { return c; c->completion = nil; + c->rcompletion = nil; c->next = nil; return c; } @@ -192,8 +194,9 @@ void compls_delete(struct completions *cs) { } // 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; @@ -204,8 +207,11 @@ void filter(struct completions *cs, char *text, char * 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; @@ -219,6 +225,7 @@ void filter(struct completions *cs, char *text, char * return; } c->completion = l; + c->rcompletion = lines[index]; } index++; @@ -232,9 +239,9 @@ void filter(struct completions *cs, char *text, char * } // 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; } @@ -415,7 +422,7 @@ char *readline(bool *eof) { // `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; @@ -890,6 +897,8 @@ int main(int argc, char **argv) { // 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; @@ -897,6 +906,9 @@ int main(int argc, char **argv) { // 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) { @@ -911,6 +923,14 @@ int main(int argc, char **argv) { 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; } @@ -918,8 +938,23 @@ int main(int argc, char **argv) { // 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; @@ -981,8 +1016,6 @@ int main(int argc, char **argv) { 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 @@ -1170,6 +1203,12 @@ int main(int argc, char **argv) { 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; @@ -1271,7 +1310,7 @@ int main(int argc, char **argv) { // 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 @@ -1468,21 +1507,34 @@ int main(int argc, char **argv) { 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); @@ -1496,19 +1548,19 @@ int main(int argc, char **argv) { 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; } @@ -1530,7 +1582,7 @@ int main(int argc, char **argv) { } } if (status != ERR) { - update_completions(cs, text, lines, first_selected); + update_completions(cs, text, lines, vlines, first_selected); free(input); } break; @@ -1573,10 +1625,11 @@ int main(int argc, char **argv) { } free(lines); + free(vlines); compls_delete(cs); XDestroyWindow(r.d, r.w); XCloseDisplay(r.d); - return status; + return status != OK; }