cli: move completion for master connections to meta data

This change (improves) behavior.

Before, we would only complete
  if (g_strcmp0 (con_type, nmc_tab_completion.con_type) != 0)
which doesn't really make sense as it depends on the slave-type,
not nmc_tab_completion.con_type.
This commit is contained in:
Thomas Haller 2017-04-11 15:48:04 +02:00
parent 1e4bc51a4a
commit 2a760897f2
6 changed files with 123 additions and 48 deletions

View file

@ -3346,10 +3346,14 @@ _meta_abstract_complete (const NMMetaAbstractInfo *abstract_info, const char *te
{
const char *const*values;
char **values_to_free = NULL;
const NMMetaOperationContext ctx = {
.connection = nmc_tab_completion.connection,
};
values = nm_meta_abstract_info_complete (abstract_info,
nmc_meta_environment,
nmc_meta_environment_arg,
&ctx,
text,
&values_to_free);
if (values)
@ -3717,42 +3721,6 @@ gen_func_bond_lacp_rate (const char *text, int state)
return nmc_rl_gen_func_basic (text, state, words);
}
static char *
gen_func_master_ifnames (const char *text, int state)
{
int i;
GPtrArray *ifnames;
char *ret;
NMConnection *con;
NMSettingConnection *s_con;
const char *con_type, *ifname;
const GPtrArray *connections;
connections = nm_client_get_connections (nm_cli.client);
/* Disable appending space after completion */
rl_completion_append_character = '\0';
ifnames = g_ptr_array_sized_new (20);
for (i = 0; i < connections->len; i++) {
con = NM_CONNECTION (connections->pdata[i]);
s_con = nm_connection_get_setting_connection (con);
g_assert (s_con);
con_type = nm_setting_connection_get_connection_type (s_con);
if (g_strcmp0 (con_type, nmc_tab_completion.con_type) != 0)
continue;
ifname = nm_connection_get_interface_name (con);
g_ptr_array_add (ifnames, (gpointer) ifname);
}
g_ptr_array_add (ifnames, (gpointer) NULL);
ret = nmc_rl_gen_func_basic (text, state, (const char **) ifnames->pdata);
g_ptr_array_free (ifnames, TRUE);
return ret;
}
/*----------------------------------------------------------------------------*/
static gboolean
@ -4036,7 +4004,7 @@ _meta_abstract_get_option_info (const NMMetaAbstractInfo *abstract_info)
}
OPTION_INFO (CONNECTION, NM_SETTING_CONNECTION_TYPE, "type", set_connection_type, gen_connection_types),
OPTION_INFO (CONNECTION, NM_SETTING_CONNECTION_INTERFACE_NAME, "ifname", set_connection_iface, NULL),
OPTION_INFO (CONNECTION, NM_SETTING_CONNECTION_MASTER, "master", set_connection_master, gen_func_master_ifnames),
OPTION_INFO (CONNECTION, NM_SETTING_CONNECTION_MASTER, "master", set_connection_master, NULL),
OPTION_INFO (BLUETOOTH, NM_SETTING_BLUETOOTH_TYPE, "bt-type", set_bluetooth_type, gen_func_bt_type),
OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "mode", set_bond_option, gen_func_bond_mode),
OPTION_INFO (BOND, NM_SETTING_BOND_OPTIONS, "primary", set_bond_option, nmc_rl_gen_func_ifnames),
@ -4164,15 +4132,19 @@ run_rl_generator (rl_compentry_func_t *generator_func, const char *prefix)
}
static gboolean
complete_option (const NMMetaAbstractInfo *abstract_info, const gchar *prefix)
complete_option (const NMMetaAbstractInfo *abstract_info, const gchar *prefix, NMConnection *context_connection)
{
const OptionInfo *candidate;
const char *const*values;
gs_strfreev char **values_to_free = NULL;
const NMMetaOperationContext ctx = {
.connection = context_connection,
};
values = nm_meta_abstract_info_complete (abstract_info,
nmc_meta_environment,
nmc_meta_environment_arg,
&ctx,
prefix,
&values_to_free);
if (values) {
@ -4191,21 +4163,19 @@ complete_option (const NMMetaAbstractInfo *abstract_info, const gchar *prefix)
}
static void
complete_property (const gchar *setting_name, const gchar *property, const gchar *prefix)
complete_property (const gchar *setting_name, const gchar *property, const gchar *prefix, NMConnection *connection)
{
const NMMetaPropertyInfo *property_info;
property_info = nm_meta_property_info_find_by_name (setting_name, property);
if (property_info) {
if (complete_option ((const NMMetaAbstractInfo *) property_info, prefix))
if (complete_option ((const NMMetaAbstractInfo *) property_info, prefix, connection))
return;
}
if (strcmp (setting_name, NM_SETTING_CONNECTION_SETTING_NAME) == 0) {
if (strcmp (property, NM_SETTING_CONNECTION_TYPE) == 0)
run_rl_generator (gen_connection_types, prefix);
else if (strcmp (property, NM_SETTING_CONNECTION_MASTER) == 0)
run_rl_generator (gen_func_master_ifnames, prefix);
} else if ( strcmp (setting_name, NM_SETTING_BLUETOOTH_SETTING_NAME) == 0
&& strcmp (property, NM_SETTING_BLUETOOTH_TYPE) == 0)
run_rl_generator (gen_func_bt_type, prefix);
@ -4299,7 +4269,7 @@ nmc_read_connection_properties (NmCli *nmc,
return FALSE;
if (!*argc && nmc->complete)
complete_property (setting, strv[1], value ? value : "");
complete_property (setting, strv[1], value ? value : "", connection);
if (!set_property (connection, setting_name, strv[1], value, modifier, error))
return FALSE;
@ -4378,7 +4348,7 @@ nmc_read_connection_properties (NmCli *nmc,
return FALSE;
if (!*argc && nmc->complete)
complete_option (chosen, value ? value : "");
complete_option (chosen, value ? value : "", connection);
if (!set_option (nmc, connection, chosen, value, error))
return FALSE;
@ -4513,8 +4483,6 @@ nmcli_con_add_tab_completion (const char *text, int start, int end)
next:
if (g_str_has_prefix (rl_prompt, NM_META_TEXT_PROMPT_CON_TYPE))
generator_func = gen_connection_types;
else if (g_str_has_prefix (rl_prompt, NM_META_TEXT_PROMPT_MASTER))
generator_func = gen_func_master_ifnames;
else if (g_str_has_prefix (rl_prompt, NM_META_TEXT_PROMPT_BT_TYPE))
generator_func = gen_func_bt_type;
else if (g_str_has_prefix (rl_prompt, NM_META_TEXT_PROMPT_BOND_MODE))
@ -8422,7 +8390,7 @@ do_connection_import (NmCli *nmc, int argc, char **argv)
}
if (argc == 1 && nmc->complete)
complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type, *argv);
complete_option ((const NMMetaAbstractInfo *) nm_meta_property_info_vpn_service_type, *argv, NULL);
if (!type)
type = *argv;

View file

@ -480,11 +480,36 @@ _env_get_nm_devices (const NMMetaEnvironment *environment,
return (NMDevice *const*) devices->pdata;
}
static NMRemoteConnection *const*
_env_get_nm_connections (const NMMetaEnvironment *environment,
gpointer environment_user_data,
guint *out_len)
{
NmCli *nmc = environment_user_data;
const GPtrArray *values;
nm_assert (nmc);
/* the returned list is *not* NULL terminated. Need to
* provide and honor the out_len argument. */
nm_assert (out_len);
values = nm_client_get_connections (nmc->client);
if (!values) {
*out_len = 0;
return NULL;
}
*out_len = values->len;
return (NMRemoteConnection *const*) values->pdata;
}
/*****************************************************************************/
const NMMetaEnvironment *const nmc_meta_environment = &((NMMetaEnvironment) {
.warn_fcn = _env_warn_fcn_handle,
.get_nm_devices = _env_get_nm_devices,
.get_nm_connections = _env_get_nm_connections,
});
NmCli *const nmc_meta_environment_arg = &nm_cli;

View file

@ -263,6 +263,7 @@ const char *const*
nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info,
const NMMetaEnvironment *environment,
gpointer environment_user_data,
const NMMetaOperationContext *operation_context,
const char *text,
char ***out_to_free)
{
@ -281,6 +282,7 @@ nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info,
values = abstract_info->meta_type->complete_fcn (abstract_info,
environment,
environment_user_data,
operation_context,
text,
out_to_free);

View file

@ -62,6 +62,7 @@ gconstpointer nm_meta_abstract_info_get (const NMMetaAbstractInfo *abstract_info
const char *const*nm_meta_abstract_info_complete (const NMMetaAbstractInfo *abstract_info,
const NMMetaEnvironment *environment,
gpointer environment_user_data,
const NMMetaOperationContext *operation_context,
const char *text,
char ***out_to_free);

View file

@ -524,7 +524,7 @@ _env_warn_fcn (const NMMetaEnvironment *environment,
const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, NMSetting *setting, const char *value, guint32 idx, GError **error
#define ARGS_COMPLETE_FCN \
const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, const char *text, char ***out_to_free
const NMMetaPropertyInfo *property_info, const NMMetaEnvironment *environment, gpointer environment_user_data, const NMMetaOperationContext *operation_context, const char *text, char ***out_to_free
#define ARGS_VALUES_FCN \
const NMMetaPropertyInfo *property_info, char ***out_to_free
@ -2359,6 +2359,68 @@ _set_fcn_connection_master (ARGS_SET_FCN)
return TRUE;
}
static const char *const*
_complete_fcn_connection_master (ARGS_COMPLETE_FCN)
{
NMRemoteConnection *const*connections = NULL;
guint len = 0;
guint i, j;
char **result;
NMSettingConnection *s_con;
const char *expected_type = NULL;
gsize text_len;
if ( environment
&& environment->get_nm_connections) {
connections = environment->get_nm_connections (environment,
environment_user_data,
&len);
}
if (!len)
return NULL;
if ( (!text || !*text)
&& operation_context
&& operation_context->connection) {
/* if we have no text yet, initially only complete for matching
* slave-type. */
s_con = nm_connection_get_setting_connection (operation_context->connection);
if (s_con)
expected_type = nm_setting_connection_get_slave_type (s_con);
}
text_len = strlen (text);
result = g_new (char *, (2 * len) + 1);
for (i = 0, j = 0; i < len; i++) {
const char *v;
s_con = nm_connection_get_setting_connection (NM_CONNECTION (connections[i]));
if (!s_con)
continue;
if ( expected_type
&& !nm_streq0 (nm_setting_connection_get_connection_type (s_con),
expected_type))
continue;
if (text && text[0]) {
/* if we have text, also complete for the UUID. */
v = nm_setting_connection_get_uuid (s_con);
if (v && (!text || strncmp (text, v, text_len) == 0))
result[j++] = g_strdup (v);
}
v = nm_setting_connection_get_interface_name (s_con);
if (v && (!text || strncmp (text, v, text_len) == 0))
result[j++] = g_strdup (v);
}
result[j++] = NULL;
*out_to_free = NULL;
return (const char *const*) result;
}
static gboolean
_set_fcn_connection_secondaries (ARGS_SET_FCN)
{
@ -5452,6 +5514,7 @@ static const NMMetaPropertyInfo property_infos_CONNECTION[] = {
.property_type = DEFINE_PROPERTY_TYPE (
.get_fcn = _get_fcn_gobject,
.set_fcn = _set_fcn_connection_master,
.complete_fcn = _complete_fcn_connection_master,
),
},
{
@ -7510,6 +7573,7 @@ static const char *const*
_meta_type_property_info_complete_fcn (const NMMetaAbstractInfo *abstract_info,
const NMMetaEnvironment *environment,
gpointer environment_user_data,
const NMMetaOperationContext *operation_context,
const char *text,
char ***out_to_free)
{
@ -7521,6 +7585,7 @@ _meta_type_property_info_complete_fcn (const NMMetaAbstractInfo *abstract_info,
return info->property_type->complete_fcn (info,
environment,
environment_user_data,
operation_context,
text,
out_to_free);
}

View file

@ -168,6 +168,14 @@ typedef struct _NMMetaSettingInfoEditor NMMetaSettingInfoEditor;
typedef struct _NMMetaPropertyInfo NMMetaPropertyInfo;
typedef struct _NMMetaPropertyType NMMetaPropertyType;
typedef struct _NMMetaPropertyTypData NMMetaPropertyTypData;
typedef struct _NMMetaOperationContext NMMetaOperationContext;
/* this gives some context information for virtual functions.
* This command actually violates layering, and should be considered
* a hack. In the future, try to replace it's use. */
struct _NMMetaOperationContext {
NMConnection *connection;
};
struct _NMMetaPropertyType {
@ -201,6 +209,7 @@ struct _NMMetaPropertyType {
const char *const*(*complete_fcn) (const NMMetaPropertyInfo *property_info,
const NMMetaEnvironment *environment,
gpointer environment_user_data,
const NMMetaOperationContext *operation_context,
const char *text,
char ***out_to_free);
};
@ -319,6 +328,7 @@ struct _NMMetaType {
const char *const*(*complete_fcn) (const NMMetaAbstractInfo *info,
const NMMetaEnvironment *environment,
gpointer environment_user_data,
const NMMetaOperationContext *operation_context,
const char *text,
char ***out_to_free);
};
@ -359,6 +369,10 @@ struct _NMMetaEnvironment {
gpointer environment_user_data,
guint *out_len);
struct _NMRemoteConnection *const*(*get_nm_connections) (const NMMetaEnvironment *environment,
gpointer environment_user_data,
guint *out_len);
};
/*****************************************************************************/