3
0
mirror of https://git.kernel.org/pub/scm/network/wireless/iwd.git synced 2024-11-22 14:49:24 +01:00

client: allow entity name to be passed to completion

There is a limitation of libreadline where no context/userdata
can be passed to completion functions. Thi affects iwctl since
the entity value isn't known to completion functions.

Workarounds such as getting the default device are employed but
its not a great solution.

Instead hack around this limitation by parsing the prompt to
extract the entity (second arg). Then use a generic match function
given to readline which can call the actual match function and
include the entity.
This commit is contained in:
James Prestwood 2022-08-11 11:47:32 -07:00 committed by Denis Kenzior
parent 8091d5a53d
commit 9aefec6124
6 changed files with 54 additions and 9 deletions

View File

@ -319,7 +319,8 @@ static enum cmd_status cmd_set_property(const char *adapter_name,
return CMD_STATUS_TRIGGERED; return CMD_STATUS_TRIGGERED;
} }
static char *set_property_cmd_arg_completion(const char *text, int state) static char *set_property_cmd_arg_completion(const char *text, int state,
const char *phy)
{ {
return proxy_property_completion(adapter_properties, text, state); return proxy_property_completion(adapter_properties, text, state);
} }

View File

@ -213,20 +213,57 @@ bool command_line_find_token(const char *token, uint8_t num_to_inspect)
return false; return false;
} }
/*
* Work around readline limitations of not being able to pass a context pointer
* to match functions. Set the command match function/entity to these globals
* and call a generic match function which can call the _real_ match function
* and include the entity.
*/
static command_completion_func_t cmd_current_completion_func = NULL;
static const char *cmd_current_entity = NULL;
static char *cmd_completion_generic(const char *text, int state)
{
return cmd_current_completion_func(text, state, cmd_current_entity);
}
static char **cmd_completion_match_entity_cmd(const char *cmd, const char *text, static char **cmd_completion_match_entity_cmd(const char *cmd, const char *text,
const struct command *cmd_list) const struct command *cmd_list)
{ {
char **matches = NULL; char **matches = NULL;
size_t i; size_t i;
char *family = NULL;
char *entity = NULL;
char *prompt = NULL;
for (i = 0; cmd_list[i].cmd; i++) { for (i = 0; cmd_list[i].cmd; i++) {
char *tmp;
if (strcmp(cmd_list[i].cmd, cmd)) if (strcmp(cmd_list[i].cmd, cmd))
continue; continue;
if (!cmd_list[i].completion) if (!cmd_list[i].completion)
break; break;
matches = rl_completion_matches(text, cmd_list[i].completion); if (cmd_list[i].entity) {
prompt = rl_copy_text(0, rl_end);
family = strtok_r(prompt, " ", &tmp);
if (!family)
goto done;
entity = strtok_r(NULL, " ", &tmp);
}
done:
cmd_current_completion_func = cmd_list[i].completion;
cmd_current_entity = entity;
matches = rl_completion_matches(text, cmd_completion_generic);
l_free(prompt);
cmd_current_completion_func = NULL;
cmd_current_entity = NULL;
break; break;
} }

View File

@ -25,7 +25,10 @@
#define COMMAND_OPTION_PASSPHRASE "passphrase" #define COMMAND_OPTION_PASSPHRASE "passphrase"
#define COMMAND_OPTION_DONTASK "dont-ask" #define COMMAND_OPTION_DONTASK "dont-ask"
typedef char *(*command_completion_func_t) (const char *text, int state); typedef char *(*command_completion_func_t)(const char *text, int state,
const char *entity);
typedef char *(*command_rl_completion_func_t)(const char *text, int state);
enum cmd_status { enum cmd_status {
CMD_STATUS_TRIGGERED, CMD_STATUS_TRIGGERED,
@ -51,8 +54,8 @@ struct command_family {
const char *caption; const char *caption;
const char *name; const char *name;
const struct command *command_list; const struct command *command_list;
command_completion_func_t family_arg_completion; command_rl_completion_func_t family_arg_completion;
command_completion_func_t entity_arg_completion; command_rl_completion_func_t entity_arg_completion;
void (*set_default_entity)(const char *entity); void (*set_default_entity)(const char *entity);
void (*reset_default_entity)(void); void (*reset_default_entity)(void);
}; };

View File

@ -398,7 +398,8 @@ static enum cmd_status cmd_set_property(const char *device_name,
return CMD_STATUS_TRIGGERED; return CMD_STATUS_TRIGGERED;
} }
static char *set_property_cmd_arg_completion(const char *text, int state) static char *set_property_cmd_arg_completion(const char *text, int state,
const char *device_name)
{ {
return proxy_property_completion(device_properties, text, state); return proxy_property_completion(device_properties, text, state);
} }

View File

@ -387,7 +387,8 @@ static enum cmd_status cmd_set_property(const char *network_name,
return CMD_STATUS_TRIGGERED; return CMD_STATUS_TRIGGERED;
} }
static char *set_property_cmd_arg_completion(const char *text, int state) static char *set_property_cmd_arg_completion(const char *text, int state,
const char *network_name)
{ {
return proxy_property_completion(known_network_properties, text, state); return proxy_property_completion(known_network_properties, text, state);
} }

View File

@ -277,7 +277,8 @@ static enum cmd_status cmd_list(const char *device_name, char **argv, int argc)
return CMD_STATUS_DONE; return CMD_STATUS_DONE;
} }
static char *connect_cmd_arg_completion(const char *text, int state) static char *connect_cmd_arg_completion(const char *text, int state,
const char *device_name)
{ {
const struct proxy_interface *device = device_get_default(); const struct proxy_interface *device = device_get_default();
@ -489,7 +490,8 @@ static void ordered_networks_callback(struct l_dbus_message *message,
l_queue_destroy(networks, ordered_networks_destroy); l_queue_destroy(networks, ordered_networks_destroy);
} }
static char *get_networks_cmd_arg_completion(const char *text, int state) static char *get_networks_cmd_arg_completion(const char *text, int state,
const char *device_name)
{ {
static int index; static int index;
static int len; static int len;