Skip to content

Added multiple selections #299

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pick.1
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
.Nd fuzzy select anything
.Sh SYNOPSIS
.Nm
.Op Fl hvKS
.Op Fl hvKSm
.Op Fl d Op Fl o
.Op Fl x | Fl X
.Op Fl q Ar query
Expand All @@ -32,6 +32,8 @@ Both parts will be displayed but only the first part will be used when
searching.
.It Fl h
Output a help message and exit.
.It Fl m
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this feature opt-in to begin with?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without -m (multiple choices), the caller waits for one line string. in 'multiple choices' mode the caller is prepared to receive a list of lines. So he had to specify which mode wants.

Allow to select multiple items by using INSERT or Ctrl+T key.
.It Fl K
Disable toggling of keypad transmit mode.
Useful when running
Expand Down Expand Up @@ -99,6 +101,8 @@ is true or the character is an underscore.
Delete to the beginning of the line in the search query input field.
.It Ic Ctrl-K
Delete to the end of the line in the search query input field.
.It Ic INSERT | Ctrl+T
Mark or unmark the current line (multiple selection mode).
.It Ic Printable characters
Added to the search query and will refine the current search.
.El
Expand Down
54 changes: 46 additions & 8 deletions pick.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@
#include <wchar.h>
#include <wctype.h>

static int opt_mark; /* option: multiple choices */
/* multiple choices: print_line now takes bit-flags instead of boolean standout */
#define PL_STDOUT 0x01 /* standout flag */
#define PL_MARKED 0x02 /* marked item */

#define tty_putp(capability, fatal) do { \
if (tputs((capability), 1, tty_putc) == ERR && (fatal)) \
errx(1, #capability ": unknown terminfo capability"); \
Expand All @@ -27,12 +32,14 @@ enum key {
BACKSPACE,
DEL,
ENTER,
INSERT,
CTRL_A,
CTRL_C,
CTRL_E,
CTRL_K,
CTRL_L,
CTRL_O,
CTRL_T,
CTRL_U,
CTRL_W,
CTRL_Z,
Expand All @@ -54,6 +61,7 @@ struct choice {
ssize_t match_start; /* inclusive match start offset */
ssize_t match_end; /* exclusive match end offset */
double score;
int mark; /* true if its marked */
};

static int choicecmp(const void *, const void *);
Expand Down Expand Up @@ -115,7 +123,7 @@ main(int argc, char *argv[])
if (pledge("stdio tty rpath wpath cpath", NULL) == -1)
err(1, "pledge");

while ((c = getopt(argc, argv, "dhoq:KSvxX")) != -1)
while ((c = getopt(argc, argv, "dhmoq:KSvxX")) != -1)
switch (c) {
case 'd':
descriptions = 1;
Expand Down Expand Up @@ -150,6 +158,9 @@ main(int argc, char *argv[])
case 'X':
use_alternate_screen = 0;
break;
case 'm': /* enable multiple selections */
opt_mark = 1;
break;
default:
usage(1);
}
Expand All @@ -173,10 +184,22 @@ main(int argc, char *argv[])
choice = selected_choice();
tty_restore(1);
if (choice != NULL) {
printf("%s\n", choice->string);
if (output_description)
printf("%s\n", choice->description);
} else {
if ( opt_mark ) { /* if multiple choices, print out all selected strings */
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If multiple choices are always enabled, you could drop the conditional and always iterate over all choices, printing the marked ones. In case ENTER just set mark = 1 there as well then this logic should be applicable to all methods of chosing lines.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it cloud be and opt_mark = 0 case it could return immediately so no way to mess up with more marked lines.

for ( size_t i = 0; i < choices.length; i ++ ) {
if ( choices.v[i].mark ) {
printf("%s\n", choices.v[i].string);
if (output_description)
printf("%s\n", choices.v[i].description);
}
}
}
else {
printf("%s\n", choice->string);
if (output_description)
printf("%s\n", choice->description);
}
}
else {
rc = 1;
}

Expand All @@ -197,6 +220,7 @@ usage(int status)
" -S disable sorting\n"
" -d read and display descriptions\n"
" -o output description of selected on exit\n"
" -m enable multiple selections\n"
" -x enable alternate screen\n"
" -X disable alternate screen\n"
" -q query supply an initial search query\n");
Expand Down Expand Up @@ -252,6 +276,7 @@ get_choices(void)
choices.v[choices.length].match_start = -1;
choices.v[choices.length].match_end = -1;
choices.v[choices.length].score = 0;
choices.v[choices.length].mark = 0;

start = stop + 1;

Expand Down Expand Up @@ -347,6 +372,11 @@ selected_choice(void)
choices.v[choices.length].string = query;
choices.v[choices.length].description = "";
return &choices.v[choices.length];
case INSERT: /* Norton Commander (nc,mc,total-comander,dblcmd,krusader,...) */
case CTRL_T: /* mark/unmark selection */
if ( opt_mark )
choices.v[selection].mark = (choices.v[selection].mark) ? 0 : 1;
break;
case CTRL_C:
return NULL;
case CTRL_Z:
Expand Down Expand Up @@ -759,15 +789,19 @@ tty_size(void)
}

void
print_line(const char *str, size_t len, int standout,
print_line(const char *str, size_t len, int flags,
ssize_t enter_underline, ssize_t exit_underline)
{
size_t i;
wchar_t wc;
unsigned int col;
int nbytes, width;

if (standout)
if ( flags & PL_MARKED ) { // *commander uses yellow...
// tty_putp(enter_bold_mode, 1); // it works but i liked without it
tty_putp(tty_parm1(set_a_foreground, 3), 1);
}
if ( flags & PL_STDOUT )
tty_putp(enter_standout_mode, 1);

col = i = 0;
Expand Down Expand Up @@ -851,7 +885,8 @@ print_choices(size_t offset, size_t selection)

if (i - offset < choices_lines)
print_line(choice->string, choice->length,
i == selection, choice->match_start,
((i == selection) ? PL_STDOUT : 0) |\
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant parens, odd indent, redundant line continuation and redundant spaces below...

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont use spaces, only tabs, in a few cases spaces used to so more clear the one expression down of the other like this one. Try it with tab-width=4... Anyway, it is your code now rewrite it as you wish.

((choice->mark ) ? PL_MARKED : 0), choice->match_start,
choice->match_end);
}

Expand Down Expand Up @@ -904,6 +939,7 @@ get_key(const char **key)
KEY(CTRL_K, "\013"),
KEY(CTRL_L, "\014"),
KEY(CTRL_O, "\017"),
KEY(CTRL_T, "\024"),
KEY(CTRL_U, "\025"),
KEY(CTRL_W, "\027"),
KEY(CTRL_W, "\033\177"),
Expand Down Expand Up @@ -933,6 +969,8 @@ get_key(const char **key)
CAP(RIGHT, "kcuf1"),
KEY(RIGHT, "\006"),
KEY(RIGHT, "\033OC"),
CAP(INSERT, "kich1"),
KEY(INSERT, "\033[2~"),
KEY(UNKNOWN, NULL),
};
static unsigned char buf[8];
Expand Down