diff --git a/cli/src/connections.c b/cli/src/connections.c index f1d973d53..83a94010f 100644 --- a/cli/src/connections.c +++ b/cli/src/connections.c @@ -71,6 +71,7 @@ #define PROMPT_BOND_MASTER _("Bond master: ") #define PROMPT_TEAM_MASTER _("Team master: ") #define PROMPT_BRIDGE_MASTER _("Bridge master: ") +#define PROMPT_CONNECTION _("Connection (name, UUID, or path): ") static const char *nmc_known_vpns[] = { "openvpn", "vpnc", "pptp", "openconnect", "openswan", "libreswan", @@ -1963,10 +1964,8 @@ do_connection_up (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) { - line = nmc_readline (_("Connection (name, UUID, or path): ")); + line = nmc_readline (PROMPT_CONNECTION); name = line ? line : ""; - // TODO: enhancement: when just Enter is pressed (line is NULL), list - // available connections so that the user can select one } } else if (strcmp (*argv, "ifname") != 0) { if ( strcmp (*argv, "id") == 0 @@ -2075,7 +2074,7 @@ do_connection_down (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) { - line = nmc_readline (_("Connection (name, UUID, or path): ")); + line = nmc_readline (PROMPT_CONNECTION); nmc_string_to_arg_array (line, "", &arg_arr, &arg_num); arg_ptr = arg_arr; } @@ -8199,7 +8198,7 @@ do_connection_delete (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) { - line = nmc_readline (_("Connection (name, UUID, or path): ")); + line = nmc_readline (PROMPT_CONNECTION); nmc_string_to_arg_array (line, "", &arg_arr, &arg_num); arg_ptr = arg_arr; } @@ -8375,12 +8374,53 @@ connection_editor_thread_func (gpointer data) return NULL; } +static char * +gen_func_connection_names (char *text, int state) +{ + int i = 0; + GSList *iter; + const char **connections; + char *ret; + + if (!nm_cli.system_connections) + return NULL; + + connections = g_new (const char *, g_slist_length (nm_cli.system_connections) + 1); + for (iter = nm_cli.system_connections; iter; iter = g_slist_next (iter)) { + NMConnection *con = NM_CONNECTION (iter->data); + const char *id = nm_connection_get_id (con); + connections[i++] = id; + } + connections[i] = NULL; + + ret = nmc_rl_gen_func_basic (text, state, connections); + + g_free (connections); + return ret; +} + static char ** nmcli_con_tab_completion (char *text, int start, int end) { + char **match_array = NULL; + CPFunction *generator_func = NULL; + /* Disable readline's default filename completion */ rl_attempted_completion_over = 1; - return NULL; + + /* Disable appending space after completion */ + rl_completion_append_character = '\0'; + + if (!is_single_word (rl_line_buffer)) + return NULL; + + if (g_strcmp0 (rl_prompt, PROMPT_CONNECTION) == 0) + generator_func = gen_func_connection_names; + + if (generator_func) + match_array = rl_completion_matches (text, generator_func); + + return match_array; } static NMCResultCode diff --git a/cli/src/devices.c b/cli/src/devices.c index a4d54bd44..f362449ee 100644 --- a/cli/src/devices.c +++ b/cli/src/devices.c @@ -66,6 +66,8 @@ #include "common.h" #include "devices.h" +/* define some prompts */ +#define PROMPT_INTERFACE _("Interface: ") /* Available fields for 'device status' */ static NmcOutputField nmc_fields_dev_status[] = { @@ -1383,7 +1385,7 @@ do_device_connect (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) - ifname = ifname_ask = nmc_readline (_("Interface: ")); + ifname = ifname_ask = nmc_readline (PROMPT_INTERFACE); if (!ifname_ask) { g_string_printf (nmc->return_text, _("Error: No interface specified.")); @@ -1517,7 +1519,7 @@ do_device_disconnect (NmCli *nmc, int argc, char **argv) if (argc == 0) { if (nmc->ask) - ifname = ifname_ask = nmc_readline (_("Interface: ")); + ifname = ifname_ask = nmc_readline (PROMPT_INTERFACE); if (!ifname_ask) { g_string_printf (nmc->return_text, _("Error: No interface specified.")); @@ -2559,12 +2561,73 @@ do_device_wimax (NmCli *nmc, int argc, char **argv) } #endif +static gboolean +is_single_word (const char* line) +{ + size_t n1, n2, n3; + + n1 = strspn (line, " \t"); + n2 = strcspn (line+n1, " \t\0") + n1; + n3 = strspn (line+n2, " \t"); + + if (n3 == 0) + return TRUE; + else + return FALSE; +} + +/* Global variable defined in nmcli.c */ +extern NmCli nm_cli; + +static char * +gen_func_ifnames (char *text, int state) +{ + int i, j = 0; + const GPtrArray *devices; + const char **ifnames; + char *ret; + + nm_cli.get_client (&nm_cli); + devices = nm_client_get_devices (nm_cli.client); + if (!devices || devices->len < 1) + return NULL; + + ifnames = g_new (const char *, devices->len + 1); + for (i = 0; i < devices->len; i++) { + NMDevice *dev = g_ptr_array_index (devices, i); + const char *ifname = nm_device_get_iface (dev); + ifnames[j++] = ifname; + } + ifnames[j] = NULL; + + ret = nmc_rl_gen_func_basic (text, state, ifnames); + + g_free (ifnames); + return ret; +} + static char ** nmcli_device_tab_completion (char *text, int start, int end) { + char **match_array = NULL; + CPFunction *generator_func = NULL; + /* Disable readline's default filename completion */ rl_attempted_completion_over = 1; - return NULL; + + /* Disable appending space after completion */ + rl_completion_append_character = '\0'; + + if (!is_single_word (rl_line_buffer)) + return NULL; + + if (g_strcmp0 (rl_prompt, PROMPT_INTERFACE) == 0) + generator_func = gen_func_ifnames; + + if (generator_func) + match_array = rl_completion_matches (text, generator_func); + + return match_array; } NMCResultCode