[Dmenu] Implement a select rows for dmenu multi-select.

Issue: #1802
This commit is contained in:
Dave Davenport 2023-02-11 12:42:35 +01:00
parent caa92637f1
commit 2003b7bd52
4 changed files with 92 additions and 7 deletions

View File

@ -147,6 +147,13 @@ Or any combination: '5,-3:,7:11,2,0,-9'
.PP
Urgent row, mark \fIX\fP as urgent. See \fB\fC-a\fR option for details.
.PP
\fB\fC-select-rows\fR \fIX\fP
.PP
If multi-select is enabled, pre-select rows, See \fB\fC-a\fR option for format details.
If same row is specified multiple times, it state is toggled on subsequential sets.
.PP
\fB\fC-only-match\fR

View File

@ -93,6 +93,11 @@ Active row, mark *X* as active. Where *X* is a comma-separated list of python(1)
Urgent row, mark *X* as urgent. See `-a` option for details.
`-select-rows` *X*
If multi-select is enabled, pre-select rows, See `-a` option for format details.
If same row is specified multiple times, it state is toggled on subsequential sets.
`-only-match`
Only return a selected item, do not allow custom entry.

View File

@ -1615,7 +1615,7 @@ property.
These cannot be changed using the \fB\fCchildren\fR property.
.PP
Each entries displayed by listview are captured by a \fB\fCbox\fR called \fB\fCelement\fR\&.
Each Entry displayed by listview is captured by a \fB\fCbox\fR called \fB\fCelement\fR\&.
An \fB\fCelement\fR widget can contain the following special child widgets:
.RS
@ -1630,7 +1630,8 @@ An \fB\fCelement\fR widget can contain the following special child widgets:
.PP
By default the \fB\fCelement-icon\fR and \fB\fCelement-text\fR child widgets are added to the
\fB\fCelement\fR\&. This can be modified using the \fB\fCchildren\fR property.
\fB\fCelement\fR\&. This can be modified using the \fB\fCchildren\fR property or the
\fB\fC[no]-show-icons\fR option.
.PP
A child added with another name is seen as a \fB\fCbox\fR, this can be used as dynamic

View File

@ -123,6 +123,66 @@ typedef struct {
DmenuModePrivateData *pd;
} Block;
static void dmenu_parse_multi_select_range ( DmenuModePrivateData *pd, const char *entries)
{
if ( entries == NULL ) {
return;
}
// Pre-alloc array.
if (pd->selected_list == NULL) {
pd->selected_list =
g_malloc0(sizeof(uint32_t) * (pd->cmd_list_length / 32 + 1));
}
char *entries_cp = g_strdup ( entries );
char *endp;
const char *const sep = ",";
for (char *token = strtok_r(entries_cp, sep, &endp); token != NULL;
token = strtok_r(NULL, sep, &endp)) {
const char *sep[] = {"-", ":"};
int pythonic = (strchr(token, ':') || token[0] == '-') ? 1 : 0;
int index = 0;
int start = -1;
int stop = -1;
for (char *inner_token = strsep(&token, sep[pythonic]); inner_token != NULL;
inner_token = strsep(&token, sep[pythonic])) {
if (index == 0) {
start = stop = (int)strtol(inner_token, NULL, 10);
index++;
continue;
}
if (inner_token[0] == '\0') {
stop = -1;
continue;
}
stop = (int)strtol(inner_token, NULL, 10);
if (pythonic) {
--stop;
}
}
// Fix negative numbers.
if ( start < 0 ) {
start = pd->cmd_list_length + start;
}
if ( stop < 0 ) {
stop = pd->cmd_list_length + stop;
}
// Fix starting
for ( int index = start; index <= stop; index++ ){
if ( index < 0 ) {
index = pd->cmd_list_length - index;
}
if ( index < (int)pd->cmd_list_length ) {
bittoggle(pd->selected_list, index);
}
}
}
g_free ( entries_cp );
}
static void read_add_block(DmenuModePrivateData *pd, Block **block, char *data,
gsize len) {
@ -514,14 +574,20 @@ static int dmenu_mode_init(Mode *sw) {
DmenuModePrivateData *pd = (DmenuModePrivateData *)mode_get_private_data(sw);
pd->async = TRUE;
pd->multi_select = FALSE;
// For now these only work in sync mode.
if (find_arg("-sync") >= 0 || find_arg("-dump") >= 0 ||
find_arg("-select") >= 0 || find_arg("-no-custom") >= 0 ||
find_arg("-only-match") >= 0 || config.auto_select ||
find_arg("-selected-row") >= 0) {
find_arg("-selected-row") >= 0 ) {
pd->async = FALSE;
}
// In multi-select mode we should disable async mode.
if ( find_arg("-multi-select") >= 0 ) {
pd->async = FALSE;
pd->multi_select = TRUE;
}
pd->separator = '\n';
pd->selected_line = UINT32_MAX;
@ -634,6 +700,14 @@ static int dmenu_mode_init(Mode *sw) {
read_input_sync(pd, -1);
}
if ( pd->multi_select ) {
char *entries = NULL;
if ( find_arg_str ( "-select-rows", &entries ) >= 0 ) {
dmenu_parse_multi_select_range(pd, entries);
}
}
gchar *columns = NULL;
if (find_arg_str("-display-columns", &columns)) {
pd->columns = g_strsplit(columns, ",", 0);
@ -907,14 +981,10 @@ int dmenu_mode_dialog(void) {
DmenuScriptEntry *cmd_list = pd->cmd_list;
pd->only_selected = FALSE;
pd->multi_select = FALSE;
pd->ballot_selected = "";
pd->ballot_unselected = "";
find_arg_str("-ballot-selected-str", &(pd->ballot_selected));
find_arg_str("-ballot-unselected-str", &(pd->ballot_unselected));
if (find_arg("-multi-select") >= 0) {
pd->multi_select = TRUE;
}
if (find_arg("-markup-rows") >= 0) {
pd->do_markup = TRUE;
}
@ -1006,6 +1076,8 @@ void print_dmenu_options(void) {
is_term);
print_help_msg("-a", "[list]", "List of row indexes to mark active", NULL,
is_term);
print_help_msg("-select-rows", "[list]", "List of row indexes to select when multi-select is enabled", NULL,
is_term);
print_help_msg("-l", "[integer] ", "Number of rows to display", NULL,
is_term);
print_help_msg("-window-title", "[string] ", "Set the dmenu window title",