Commit 00c700bf authored by Jiří Klimeš's avatar Jiří Klimeš

cli: implement TAB completion for connection and interface names

For commands like
nmcli -a dev disconnect
nmcli -a con up
...
parent bfb1200b
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment