Created
April 12, 2014 01:21
-
-
Save b4n/10513496 to your computer and use it in GitHub Desktop.
Internal Mnemonics Checker -- Checks Geany's internal mnemonics for conflicts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2014 Colomban Wendling <[email protected]> | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
/* a plugin to check Geany's internal mnemonic conflicts */ | |
#include "geanyplugin.h" | |
#include <string.h> | |
GeanyPlugin *geany_plugin; | |
GeanyData *geany_data; | |
GeanyFunctions *geany_functions; | |
PLUGIN_VERSION_CHECK (GEANY_API_VERSION) | |
PLUGIN_SET_INFO (_("Internal Mnemonics Checker"), | |
_("Checks Geany's internal mnemonics for conflicts."), | |
"0.1", | |
"Colomban Wendling <[email protected]>") | |
static gunichar | |
get_mnemonic (const gchar *str) | |
{ | |
const gchar *p = strchr (str, '_'); | |
gunichar ch = g_utf8_get_char (p + 1); | |
return g_unichar_tolower (ch); | |
} | |
static gint | |
sort_by_mnemonics (gconstpointer a, | |
gconstpointer b) | |
{ | |
return get_mnemonic (a) - get_mnemonic (b); | |
} | |
static guint | |
check_mnemonics (GtkContainer *container, | |
const gchar *parent) | |
{ | |
GList *children = gtk_container_get_children (container); | |
GList *mnemonics = NULL; | |
guint n_errors = 0; | |
guint total_errors = 0; | |
GList *node; | |
gunichar ch; | |
for (node = children; node; node = node->next) { | |
const gchar *name = NULL; | |
gpointer widget = node->data; | |
/* for some reason, code below breaks separator items, WTF? | |
* so skip them altogether, they are not interesting anyway */ | |
if (GTK_IS_SEPARATOR_MENU_ITEM (widget)) { | |
continue; | |
} | |
if (GTK_IS_MENU_ITEM (widget)) { | |
name = gtk_menu_item_get_label (widget); | |
} | |
if (! name) { | |
name = G_OBJECT_TYPE_NAME (widget); | |
} | |
if (GTK_IS_MENU_ITEM (widget) && | |
gtk_menu_item_get_use_underline (widget)) { | |
GtkStockItem item; | |
const gchar *str = gtk_menu_item_get_label (widget); | |
if (GTK_IS_IMAGE_MENU_ITEM (widget) && | |
gtk_image_menu_item_get_use_stock (widget) && | |
gtk_stock_lookup (str, &item)) { | |
str = item.label; | |
} | |
if (str) { | |
const gchar *p = strchr (str, '_'); | |
if (! p) { | |
g_debug (_("Item \"%s\"::\"%s\" uses mnemonic but don't have one"), | |
parent, str); | |
} else if (! p[1]) { | |
g_warning (_("Item \"%s\"::\"%s\" mnemonic is at the end!"), | |
parent, str); | |
} else { | |
mnemonics = g_list_insert_sorted (mnemonics, (gchar *) str, | |
sort_by_mnemonics); | |
} | |
} | |
} | |
if (GTK_IS_MENU_ITEM (widget)) { | |
GtkWidget *submenu = gtk_menu_item_get_submenu (widget); | |
if (submenu) { | |
widget = submenu; | |
} | |
} | |
if (GTK_IS_CONTAINER (widget)) { | |
total_errors += check_mnemonics (widget, name); | |
} | |
} | |
ch = 0; | |
for (node = mnemonics; node; node = node->next) { | |
gunichar mn = get_mnemonic (node->data); | |
if (ch != mn && node->next && get_mnemonic (node->next->data) == mn) { | |
gchar str[7]; | |
str[g_unichar_to_utf8 (mn, str)] = 0; | |
if (n_errors == 0) { | |
g_debug (_("Conflicting mnemonics inside \"%s\":"), parent); | |
} | |
g_debug (" * %s", str); | |
g_debug (" * %s", (gchar *) node->data); | |
n_errors++; | |
} else if (ch == mn) { | |
g_debug (" * %s", (gchar *) node->data); | |
n_errors++; | |
} | |
ch = mn; | |
} | |
if (n_errors > 0) { | |
g_debug (" + %s", _("this menu already uses the following mnemonics:")); | |
ch = 0; | |
for (node = mnemonics; node; node = node->next) { | |
gunichar mn = get_mnemonic (node->data); | |
if (ch != mn) { | |
gchar str[7]; | |
str[g_unichar_to_utf8 (mn, str)] = 0; | |
g_debug(" * %s", (gchar *) str); | |
} | |
ch = mn; | |
} | |
} | |
g_list_free (mnemonics); | |
g_list_free (children); | |
return total_errors + n_errors; | |
} | |
static gboolean | |
on_idle_check_mnemoics (gpointer dummy) | |
{ | |
guint errors = 0; | |
errors += check_mnemonics (GTK_CONTAINER (geany_data->main_widgets->window), | |
_("<Main Window>")); | |
errors += check_mnemonics (GTK_CONTAINER (geany_data->main_widgets->editor_menu), | |
_("<Editor Menu>")); | |
g_debug (_("Total count of mnemonic conflicts: %u"), errors); | |
return FALSE; | |
} | |
void | |
plugin_init (GeanyData *data) | |
{ | |
plugin_idle_add (geany_plugin, on_idle_check_mnemoics, NULL); | |
} | |
void | |
plugin_cleanup (void) | |
{ | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PLUGIN := internal-mnemonics-check | |
VPATH ?= . | |
# requires https://github.com/b4n/geany-plugin.mk | |
include $(VPATH)/geany-plugin.mk |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment