From faf94409083f40ed096565b4f948852323bad697 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Mon, 9 Oct 2017 10:46:55 +0100 Subject: [PATCH] gdbus-tool: Add tab completion support to `gdbus emit` Signed-off-by: Philip Withnall https://bugzilla.gnome.org/show_bug.cgi?id=788594 --- gio/gdbus-tool.c | 136 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 25 deletions(-) diff --git a/gio/gdbus-tool.c b/gio/gdbus-tool.c index bb7d59894..286c507b5 100644 --- a/gio/gdbus-tool.c +++ b/gio/gdbus-tool.c @@ -137,9 +137,11 @@ modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command) /* ---------------------------------------------------------------------------------------------------- */ static void -print_methods (GDBusConnection *c, - const gchar *name, - const gchar *path) +print_methods_and_signals (GDBusConnection *c, + const gchar *name, + const gchar *path, + gboolean print_methods, + gboolean print_signals) { GVariant *result; GError *error; @@ -181,11 +183,16 @@ print_methods (GDBusConnection *c, for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++) { const GDBusInterfaceInfo *iface = node->interfaces[n]; - for (m = 0; iface->methods != NULL && iface->methods[m] != NULL; m++) + for (m = 0; print_methods && iface->methods != NULL && iface->methods[m] != NULL; m++) { const GDBusMethodInfo *method = iface->methods[m]; g_print ("%s.%s \n", iface->name, method->name); } + for (m = 0; print_signals && iface->signals != NULL && iface->signals[m] != NULL; m++) + { + const GDBusSignalInfo *signal = iface->signals[m]; + g_print ("%s.%s \n", iface->name, signal->name); + } } g_dbus_node_info_unref (node); @@ -565,6 +572,7 @@ handle_emit (gint *argc, gboolean skip_dashes; guint parm; guint n; + gboolean complete_names, complete_paths, complete_signals; ret = FALSE; c = NULL; @@ -580,6 +588,27 @@ handle_emit (gint *argc, g_option_context_add_main_entries (o, emit_entries, GETTEXT_PACKAGE); g_option_context_add_group (o, connection_get_group ()); + complete_names = FALSE; + if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0) + { + complete_names = TRUE; + remove_arg ((*argc) - 1, argc, argv); + } + + complete_paths = FALSE; + if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0) + { + complete_paths = TRUE; + remove_arg ((*argc) - 1, argc, argv); + } + + complete_signals = FALSE; + if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--signal") == 0) + { + complete_signals = TRUE; + remove_arg ((*argc) - 1, argc, argv); + } + if (!g_option_context_parse (o, argc, argv, NULL)) { if (!request_completion) @@ -616,36 +645,99 @@ handle_emit (gint *argc, goto out; } - /* All done with completion now */ - if (request_completion) - goto out; - - if (opt_emit_object_path == NULL) + /* validate and complete destination (bus name) */ + if (complete_names) { - g_printerr (_("Error: object path not specified.\n")); + print_names (c, FALSE); goto out; } - if (!g_variant_is_object_path (opt_emit_object_path)) + if (opt_emit_dest == NULL) + { + if (request_completion) + g_print ("--dest \n"); + else + g_printerr (_("Error: Destination is not specified\n")); + goto out; + } + if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0) + { + print_names (c, g_str_has_prefix (opt_emit_dest, ":")); + goto out; + } + + if (!request_completion && !g_dbus_is_unique_name (opt_emit_dest)) + { + g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest); + goto out; + } + + /* validate and complete object path */ + if (complete_paths) + { + print_paths (c, opt_emit_dest, "/"); + goto out; + } + if (opt_emit_object_path == NULL) + { + if (request_completion) + g_print ("--object-path \n"); + else + g_printerr (_("Error: Object path is not specified\n")); + goto out; + } + if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0) + { + gchar *p; + s = g_strdup (opt_emit_object_path); + p = strrchr (s, '/'); + if (p != NULL) + { + if (p == s) + p++; + *p = '\0'; + } + print_paths (c, opt_emit_dest, s); + g_free (s); + goto out; + } + if (!request_completion && !g_variant_is_object_path (opt_emit_object_path)) { g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path); goto out; } - if (opt_emit_signal == NULL) + /* validate and complete signal (interface + signal name) */ + if (complete_signals) { - g_printerr (_("Error: signal not specified.\n")); + print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE); goto out; } - - s = strrchr (opt_emit_signal, '.'); - if (s == NULL) + if (opt_emit_signal == NULL) { - g_printerr (_("Error: signal must be the fully-qualified name.\n")); + if (request_completion) + g_print ("--signal \n"); + else + g_printerr (_("Error: Signal name is not specified\n")); + goto out; + } + if (request_completion && g_strcmp0 ("--signal", completion_prev) == 0) + { + print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE); + goto out; + } + s = strrchr (opt_emit_signal, '.'); + if (!request_completion && s == NULL) + { + g_printerr (_("Error: Signal name ā€œ%sā€ is invalid\n"), opt_emit_signal); goto out; } signal_name = g_strdup (s + 1); interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal); + /* All done with completion now */ + if (request_completion) + goto out; + if (!g_dbus_is_interface_name (interface_name)) { g_printerr (_("Error: %s is not a valid interface name\n"), interface_name); @@ -658,12 +750,6 @@ handle_emit (gint *argc, goto out; } - if (opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest)) - { - g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest); - goto out; - } - /* Read parameters */ g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); skip_dashes = TRUE; @@ -925,7 +1011,7 @@ handle_call (gint *argc, /* validate and complete method (interface + method name) */ if (complete_methods) { - print_methods (c, opt_call_dest, opt_call_object_path); + print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE); goto out; } if (opt_call_method == NULL) @@ -938,7 +1024,7 @@ handle_call (gint *argc, } if (request_completion && g_strcmp0 ("--method", completion_prev) == 0) { - print_methods (c, opt_call_dest, opt_call_object_path); + print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE); goto out; } s = strrchr (opt_call_method, '.');