/* * autocompleters.c * vim: expandtab:ts=4:sts=4:sw=4 * * Copyright (C) 2012 - 2019 James Booth * * This file is part of Profanity. * * Profanity is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Profanity is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Profanity. If not, see . * * In addition, as a special exception, the copyright holders give permission to * link the code of portions of this program with the OpenSSL library under * certain conditions as described in each individual source file, and * distribute linked combinations including the two. * * You must obey the GNU General Public License in all respects for all of the * code used other than OpenSSL. If you modify file(s) with this exception, you * may extend this exception to your version of the file(s), but you are not * obligated to do so. If you do not wish to do so, delete this exception * statement from your version. If you delete this exception statement from all * source files in the program, then also delete it here. * */ #include "config.h" #include #include #include "tools/autocomplete.h" #include "command/cmd_ac.h" static GHashTable* plugin_to_acs; static GHashTable* plugin_to_filepath_acs; static void _free_autocompleters(GHashTable* key_to_ac) { g_hash_table_destroy(key_to_ac); } static void _free_filepath_autocompleters(GHashTable* prefixes) { g_hash_table_destroy(prefixes); } void autocompleters_init(void) { plugin_to_acs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_autocompleters); plugin_to_filepath_acs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_free_filepath_autocompleters); } void autocompleters_add(const char* const plugin_name, const char* key, char** items) { GHashTable* key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name); if (key_to_ac) { if (g_hash_table_contains(key_to_ac, key)) { Autocomplete existing_ac = g_hash_table_lookup(key_to_ac, key); autocomplete_add_all(existing_ac, items); } else { Autocomplete new_ac = autocomplete_new(); autocomplete_add_all(new_ac, items); g_hash_table_insert(key_to_ac, strdup(key), new_ac); } } else { key_to_ac = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)autocomplete_free); Autocomplete new_ac = autocomplete_new(); autocomplete_add_all(new_ac, items); g_hash_table_insert(key_to_ac, strdup(key), new_ac); g_hash_table_insert(plugin_to_acs, strdup(plugin_name), key_to_ac); } } void autocompleters_remove(const char* const plugin_name, const char* key, char** items) { GHashTable* key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name); if (!key_to_ac) { return; } if (!g_hash_table_contains(key_to_ac, key)) { return; } Autocomplete ac = g_hash_table_lookup(key_to_ac, key); autocomplete_remove_all(ac, items); } void autocompleters_clear(const char* const plugin_name, const char* key) { GHashTable* key_to_ac = g_hash_table_lookup(plugin_to_acs, plugin_name); if (!key_to_ac) { return; } if (!g_hash_table_contains(key_to_ac, key)) { return; } Autocomplete ac = g_hash_table_lookup(key_to_ac, key); autocomplete_clear(ac); } void autocompleters_filepath_add(const char* const plugin_name, const char* prefix) { GHashTable* prefixes = g_hash_table_lookup(plugin_to_filepath_acs, plugin_name); if (prefixes) { g_hash_table_add(prefixes, strdup(prefix)); } else { prefixes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); g_hash_table_add(prefixes, strdup(prefix)); g_hash_table_insert(plugin_to_filepath_acs, strdup(plugin_name), prefixes); } } char* autocompleters_complete(const char* const input, gboolean previous) { char* result = NULL; GList* ac_hashes = g_hash_table_get_values(plugin_to_acs); GList* curr_hash = ac_hashes; while (curr_hash) { GHashTable* key_to_ac = curr_hash->data; GList* keys = g_hash_table_get_keys(key_to_ac); GList* curr = keys; while (curr) { result = autocomplete_param_with_ac(input, curr->data, g_hash_table_lookup(key_to_ac, curr->data), TRUE, previous); if (result) { g_list_free(ac_hashes); g_list_free(keys); return result; } curr = g_list_next(curr); } g_list_free(keys); curr_hash = g_list_next(curr_hash); } g_list_free(ac_hashes); GList* filepath_hashes = g_hash_table_get_values(plugin_to_filepath_acs); curr_hash = filepath_hashes; while (curr_hash) { GHashTable* prefixes_hash = curr_hash->data; GList* prefixes = g_hash_table_get_keys(prefixes_hash); GList* curr_prefix = prefixes; while (curr_prefix) { char* prefix = curr_prefix->data; if (g_str_has_prefix(input, prefix)) { result = cmd_ac_complete_filepath(input, prefix, previous); if (result) { g_list_free(filepath_hashes); g_list_free(prefixes); return result; } } curr_prefix = g_list_next(curr_prefix); } g_list_free(prefixes); curr_hash = g_list_next(curr_hash); } g_list_free(filepath_hashes); return NULL; } void autocompleters_reset(void) { GList* ac_hashes = g_hash_table_get_values(plugin_to_acs); GList* curr_hash = ac_hashes; while (curr_hash) { GList* acs = g_hash_table_get_values(curr_hash->data); GList* curr = acs; while (curr) { autocomplete_reset(curr->data); curr = g_list_next(curr); } g_list_free(acs); curr_hash = g_list_next(curr_hash); } g_list_free(ac_hashes); } void autocompleters_destroy(void) { g_hash_table_destroy(plugin_to_acs); g_hash_table_destroy(plugin_to_filepath_acs); plugin_to_acs = NULL; plugin_to_filepath_acs = NULL; }