Revision: 2070 http://geany-plugins.svn.sourceforge.net/geany-plugins/?rev=2070&view=re... Author: codebrainz Date: 2011-05-22 22:28:24 +0000 (Sun, 22 May 2011)
Log Message: ----------- Add support for searching manual pages.
Modified Paths: -------------- trunk/geany-plugins/devhelp/src/Makefile.am trunk/geany-plugins/devhelp/src/devhelpplugin.c trunk/geany-plugins/devhelp/src/devhelpplugin.h trunk/geany-plugins/devhelp/src/main-notebook.c
Added Paths: ----------- trunk/geany-plugins/devhelp/src/manpages.c trunk/geany-plugins/devhelp/src/manpages.h
Modified: trunk/geany-plugins/devhelp/src/Makefile.am =================================================================== --- trunk/geany-plugins/devhelp/src/Makefile.am 2011-05-22 00:24:13 UTC (rev 2069) +++ trunk/geany-plugins/devhelp/src/Makefile.am 2011-05-22 22:28:24 UTC (rev 2070) @@ -12,7 +12,8 @@ devhelp_la_SOURCES = \ main-notebook.c \ devhelpplugin.c \ - plugin.c + plugin.c \ + manpages.c
noinst_HEADERS = \ plugin.h \
Modified: trunk/geany-plugins/devhelp/src/devhelpplugin.c =================================================================== --- trunk/geany-plugins/devhelp/src/devhelpplugin.c 2011-05-22 00:24:13 UTC (rev 2069) +++ trunk/geany-plugins/devhelp/src/devhelpplugin.c 2011-05-22 22:28:24 UTC (rev 2070) @@ -36,6 +36,7 @@ #include "main-notebook.h" #include "devhelpplugin.h" #include "plugin.h" +#include "manpages.h"
struct _DevhelpPluginPrivate @@ -51,6 +52,7 @@ * and webkit view */ GtkWidget* doc_notebook; /* Geany's document notebook */ GtkWidget* editor_menu_item; /* Item in the editor's context menu */ + GtkWidget* editor_man_menu_item; /* Manpage search menu item in the editor's context menu */ GtkWidget* editor_menu_sep; /* Separator item above menu item */ gboolean webview_active; /* Tracks whether webview stuff is shown */ gboolean last_main_tab_id; /* These track the last id of the tabs */ @@ -75,8 +77,12 @@ G_DEFINE_TYPE(DevhelpPlugin, devhelp_plugin, G_TYPE_OBJECT)
+static DhBase *dhbase = NULL; + + /* Internal callbacks */ static void on_search_help_activate(GtkMenuItem * menuitem, DevhelpPlugin *self); +static void on_search_help_man_activate(GtkMenuItem * menuitem, DevhelpPlugin *self); static void on_editor_menu_popup(GtkWidget * widget, DevhelpPlugin *self); static void on_link_clicked(GObject * ignored, DhLink * dhlink, DevhelpPlugin *self); static void on_back_button_clicked(GtkToolButton * btn, DevhelpPlugin *self); @@ -106,10 +112,13 @@ gtk_notebook_remove_page(GTK_NOTEBOOK(self->priv->main_notebook), self->priv->webview_tab);
if (!self->priv->in_message_window) + { + g_debug("Destroying main notebook"); main_notebook_destroy(); - + } gtk_widget_destroy(self->priv->editor_menu_sep); gtk_widget_destroy(self->priv->editor_menu_item); + gtk_widget_destroy(self->priv->editor_man_menu_item);
gtk_notebook_set_tab_pos(GTK_NOTEBOOK(geany->main_widgets->sidebar_notebook), self->priv->orig_sb_tab_pos); @@ -117,6 +126,8 @@ if (self->priv->last_uri != NULL) g_free(self->priv->last_uri);
+ devhelp_plugin_remove_manpages_temp_files(); + G_OBJECT_CLASS(devhelp_plugin_parent_class)->finalize(object); }
@@ -144,7 +155,9 @@ GList *keywords; #endif
- self->priv->dhbase = dh_base_new(); + if (dhbase == NULL) + dhbase = dh_base_new(); + self->priv->dhbase = dhbase;
#ifdef HAVE_BOOK_MANAGER /* for newer api */ book_manager = dh_base_get_book_manager(self->priv->dhbase); @@ -174,16 +187,20 @@ p = self->priv;
p->editor_menu_sep = gtk_separator_menu_item_new(); - p->editor_menu_item = gtk_menu_item_new_with_label(_("Search Documentation for Tag")); + p->editor_menu_item = gtk_menu_item_new_with_label(_("Search Devhelp for Tag")); + p->editor_man_menu_item = gtk_menu_item_new_with_label(_("Search manual pages for Tag"));
g_signal_connect(geany->main_widgets->editor_menu, "show", G_CALLBACK(on_editor_menu_popup), self); g_signal_connect(p->editor_menu_item, "activate", G_CALLBACK(on_search_help_activate), self); + g_signal_connect(p->editor_man_menu_item, "activate", G_CALLBACK(on_search_help_man_activate), self);
gtk_menu_shell_append(GTK_MENU_SHELL(geany->main_widgets->editor_menu), p->editor_menu_sep); gtk_menu_shell_append(GTK_MENU_SHELL(geany->main_widgets->editor_menu), p->editor_menu_item); + gtk_menu_shell_append(GTK_MENU_SHELL(geany->main_widgets->editor_menu), p->editor_man_menu_item);
gtk_widget_show(p->editor_menu_sep); gtk_widget_show(p->editor_menu_item); + gtk_widget_show(p->editor_man_menu_item); }
@@ -320,23 +337,58 @@ }
+void devhelp_plugin_search(DevhelpPlugin *self, const gchar *term) +{ + /* todo: fallback on manpages */ + devhelp_plugin_search_books(self, term); +} + + /** * Search for a term in Devhelp and activate/show the plugin's UI stuff. * * @param dhplug Devhelp plugin * @param term The string to search for */ -void devhelp_plugin_search(DevhelpPlugin *self, const gchar *term) +void devhelp_plugin_search_books(DevhelpPlugin *self, const gchar *term) { + g_return_if_fail(self != NULL); g_return_if_fail(term != NULL);
dh_search_set_search_string(DH_SEARCH(self->priv->search), term, NULL); - devhelp_plugin_activate_ui(self, TRUE); + + devhelp_plugin_activate_all_tabs(self); }
/** + * Search for a term in Manual Pages and activate/show the plugin's UI stuff. + * + * @param dhplug Devhelp plugin + * @param term The string to search for + */ +void devhelp_plugin_search_manpages(DevhelpPlugin *self, const gchar *term) +{ + gchar *man_fn; + + g_return_if_fail(self != NULL); + g_return_if_fail(term != NULL); + + man_fn = devhelp_plugin_manpages_search(term, NULL); + + if (man_fn == NULL) + return; + + webkit_web_view_open(WEBKIT_WEB_VIEW(self->priv->webview), man_fn); + + g_free(man_fn); + + devhelp_plugin_activate_all_tabs(self); +} + + +/** * Cleans up a word/tag before searching. * * Replaces non @c GEANY_WORDCHARS in str with spaces and then trims whitespace. @@ -772,10 +824,24 @@ if ((current_tag = devhelp_plugin_get_current_tag()) == NULL) return;
- dh_search_set_search_string(DH_SEARCH(self->priv->search), current_tag, NULL); + devhelp_plugin_search_books(self, current_tag);
- devhelp_plugin_activate_ui(self, TRUE); + g_free(current_tag); +}
+ +/* Called when the editor menu item is selected */ +static void on_search_help_man_activate(GtkMenuItem * menuitem, DevhelpPlugin *self) +{ + gchar *current_tag; + + g_return_if_fail(self != NULL); + + if ((current_tag = devhelp_plugin_get_current_tag()) == NULL) + return; + + devhelp_plugin_search_manpages(self, current_tag); + g_free(current_tag); }
@@ -786,7 +852,7 @@ */ static void on_editor_menu_popup(GtkWidget * widget, DevhelpPlugin *self) { - gchar *label_tag, *curword, *new_label; + gchar *label_tag, *curword, *new_label, *new_man_label;
g_return_if_fail(self != NULL);
@@ -795,18 +861,23 @@ if (curword == NULL) { gtk_widget_set_sensitive(self->priv->editor_menu_item, FALSE); + gtk_widget_set_sensitive(self->priv->editor_man_menu_item, FALSE); return; }
label_tag = g_strndup(curword, DHPLUG_MAX_LABEL_TAG); new_label = g_strdup_printf(_("Search Devhelp for: %s..."), g_strstrip(label_tag)); + new_man_label = g_strdup_printf(_("Search manual pages for: %s..."), label_tag);
gtk_menu_item_set_label(GTK_MENU_ITEM(self->priv->editor_menu_item), new_label); + gtk_menu_item_set_label(GTK_MENU_ITEM(self->priv->editor_man_menu_item), new_man_label);
g_free(new_label); + g_free(new_man_label); g_free(label_tag);
gtk_widget_set_sensitive(self->priv->editor_menu_item, TRUE); + gtk_widget_set_sensitive(self->priv->editor_man_menu_item, TRUE);
g_free(curword); }
Modified: trunk/geany-plugins/devhelp/src/devhelpplugin.h =================================================================== --- trunk/geany-plugins/devhelp/src/devhelpplugin.h 2011-05-22 00:24:13 UTC (rev 2069) +++ trunk/geany-plugins/devhelp/src/devhelpplugin.h 2011-05-22 22:28:24 UTC (rev 2070) @@ -79,7 +79,9 @@ void devhelp_plugin_set_is_in_msgwin (DevhelpPlugin *self, gboolean in_msgwin);
void devhelp_plugin_activate_ui (DevhelpPlugin *self, gboolean show_search_tab); -void devhelp_plugin_search (DevhelpPlugin *self, const gchar *term); +void devhelp_plugin_search (DevhelpPlugin *self, const gchar *term); +void devhelp_plugin_search_books (DevhelpPlugin *self, const gchar *term); +void devhelp_plugin_search_manpages (DevhelpPlugin *self, const gchar *term);
const gchar* devhelp_plugin_get_last_uri (DevhelpPlugin *self); void devhelp_plugin_set_last_uri (DevhelpPlugin *self, const gchar *uri);
Modified: trunk/geany-plugins/devhelp/src/main-notebook.c =================================================================== --- trunk/geany-plugins/devhelp/src/main-notebook.c 2011-05-22 00:24:13 UTC (rev 2069) +++ trunk/geany-plugins/devhelp/src/main-notebook.c 2011-05-22 22:28:24 UTC (rev 2070) @@ -1,24 +1,24 @@ /* * main-notebook.c - Part of the Geany Devhelp Plugin - * + * * Copyright 2010 Matthew Brush mbrush@leftclick.ca - * + * * This program 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. - * + * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ - + #include <gtk/gtk.h> #include "geanyplugin.h" #include "plugin.h" @@ -29,7 +29,7 @@
/** * Checks to see if the main_notebook exists in Geany's UI. - * + * * @return TRUE if the main_notebook exists, FALSE if not. */ gboolean main_notebook_exists(void) @@ -42,7 +42,7 @@ * even exists or if it only contains the code tab (ie. last tab). This * function gets called from main_notebook_destroy() to ensure that you * can't pull the rug out from under another plugin using the notebook. - * + * * @return TRUE if there are no other plugins using the main notebook * and it's safe to destroy or FALSE if it should be left * alone. @@ -63,24 +63,25 @@ * is still using the main_notebook. */ void main_notebook_destroy(void) -{ +{ GtkWidget *main_notebook, *doc_nb_parent, *vbox, *doc_nb; - + if (!main_notebook_needs_destroying()) return; - - main_notebook = ui_lookup_widget(geany->main_widgets->window, - "main_notebook");
+ main_notebook = ui_lookup_widget(geany->main_widgets->window, "main_notebook"); + doc_nb_parent = gtk_widget_get_parent(main_notebook); doc_nb = g_object_get_data(G_OBJECT(main_notebook), "doc_notebook"); - + /* temporarily disable the notebook to prevent a segfault when * on_editor_focus_in() calls editor_check_colorize(). */ gtk_widget_set_sensitive(geany->main_widgets->notebook, FALSE);
vbox = ui_lookup_widget(geany->main_widgets->window, "vbox1"); - if (GTK_IS_WIDGET(doc_nb) && doc_nb->parent != NULL) + + /* fixme */ + if (GTK_IS_WIDGET(doc_nb) && gtk_widget_get_parent(GTK_WIDGET(doc_nb)) == main_notebook) { gtk_widget_ref(doc_nb); gtk_container_remove(GTK_CONTAINER(main_notebook), doc_nb); @@ -88,16 +89,16 @@ gtk_container_add(GTK_CONTAINER(doc_nb_parent), doc_nb); gtk_widget_unref(doc_nb); } - + gtk_widget_set_sensitive(geany->main_widgets->notebook, TRUE); }
/** * Checks to see if the main_notebook already exists and if it does, it - * returns a pointer to it, if not, it creates the main_notebook. This + * returns a pointer to it, if not, it creates the main_notebook. This * function should be called by plugins wishing to use the main_notebook * to ensure that there is no conflict with other plugins. - * + * * @return The main_notebook that already existed or was created. If * there was a problem creating/getting the main_notebook, * NULL is returned. @@ -118,25 +119,25 @@ { gboolean found = FALSE; const gchar *widget_name = gtk_widget_get_name(widget); - + if (widget_name != NULL && g_strcmp0(widget_name, "main_notebook") == 0) found = TRUE; if (GTK_IS_CONTAINER(widget)) { GList *children, *iter; - + children = gtk_container_get_children(GTK_CONTAINER(widget)); - + for (iter=children; !found && iter; iter=g_list_next(iter)) found = holds_main_notebook(iter->data); - + g_list_free(children); } - + return found; }
-/* +/* * Creates the main_notebook if it doesn't already exist and returns a * pointer to it. If it does already exist, the function returns NULL. */ @@ -147,31 +148,32 @@
if (main_notebook_exists()) return NULL; - + doc_nb_box = gtk_vbox_new(FALSE, 0); vbox = ui_lookup_widget(geany->main_widgets->window, "vbox1"); - + main_notebook = gtk_notebook_new(); gtk_widget_set_name(main_notebook, "main_notebook"); - + doc_nb_parent = gtk_widget_get_parent(geany->main_widgets->sidebar_notebook); - + /* sidebar on left */ if (gtk_paned_get_child1(GTK_PANED(doc_nb_parent)) == geany->main_widgets->sidebar_notebook) doc_nb = gtk_paned_get_child2(GTK_PANED(doc_nb_parent)); else /* sidebar on right */ doc_nb = gtk_paned_get_child1(GTK_PANED(doc_nb_parent)); + g_object_set_data(G_OBJECT(main_notebook), "doc_notebook", doc_nb);
- gtk_notebook_append_page(GTK_NOTEBOOK(main_notebook), + gtk_notebook_append_page(GTK_NOTEBOOK(main_notebook), doc_nb_box, gtk_label_new(_("Code"))); - + gtk_widget_ref(doc_nb); gtk_container_remove(GTK_CONTAINER(doc_nb_parent), doc_nb);
gtk_container_add(GTK_CONTAINER(doc_nb_parent), main_notebook); gtk_widget_show_all(main_notebook); - + gtk_container_add(GTK_CONTAINER(doc_nb_box), doc_nb); gtk_widget_unref(doc_nb); gtk_widget_show_all(doc_nb); @@ -181,9 +183,9 @@
/* from ui_utils: ui_hookup_widget() */ g_object_set_data_full( - G_OBJECT(geany->main_widgets->window), + G_OBJECT(geany->main_widgets->window), "main_notebook", - g_object_ref(main_notebook), + g_object_ref(main_notebook), (GDestroyNotify)g_object_unref);
return main_notebook;
Added: trunk/geany-plugins/devhelp/src/manpages.c =================================================================== --- trunk/geany-plugins/devhelp/src/manpages.c (rev 0) +++ trunk/geany-plugins/devhelp/src/manpages.c 2011-05-22 22:28:24 UTC (rev 2070) @@ -0,0 +1,238 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <glib.h> + +#include "manpages.h" + +#define DEVHELP_MANPAGE_NUM_SECTIONS 8 +/* In order of most likely sections */ +static gint sections[DEVHELP_MANPAGE_NUM_SECTIONS] = { 3, 2, 1, 8, 5, 4, 7, 6 }; + +#define DEVHELP_MANPAGE_BUF_SIZE 4096 + +static GList *temp_files = NULL; + + +/* Locates the path to the manpage found for the term and section. */ +static gchar *find_manpage(const gchar *term, const gchar *section) +{ + FILE *fp; + gint i, len, retcode=0; + gchar *cmd, buf[PATH_MAX]; + + g_return_val_if_fail(term != NULL, NULL); + + if (section != NULL) /* user-specified section */ + { + cmd = g_strdup_printf("man --where %s '%s'", section, term); + if ((fp = popen(cmd, "r")) != NULL) + { + g_free(cmd); + + len = fread(buf, sizeof(gchar), PATH_MAX, fp); + retcode = pclose(fp); + } + g_free(cmd); + } + else + { + + /* try in order of most-likely sections */ + for (i = 0; i < DEVHELP_MANPAGE_NUM_SECTIONS; i++) + { + cmd = g_strdup_printf("man --where %d '%s'", sections[i], term); + if ((fp = popen(cmd, "r")) == NULL) + { + g_free(cmd); + continue; + } + + g_free(cmd); + len = fread(buf, sizeof(gchar), PATH_MAX, fp); + retcode = pclose(fp); + + if (retcode != 0) + continue; + else + break; + } + + /* try without section if all else fails */ + if (retcode != 0) + { + cmd = g_strdup_printf("man --where '%s'", term); + if ((fp = popen(cmd, "r")) == NULL) + { + g_free(cmd); + return NULL; + } + + g_free(cmd); + len = fread(buf, sizeof(gchar), PATH_MAX, fp); + retcode = pclose(fp); + } + } + + buf[PATH_MAX - 1] = '\0'; + + if (strlen(buf) == 0 || retcode != 0) + return NULL; + + return g_strstrip(g_strdup(buf)); +} + + +/* Finds the full URI to the manpage for term and section. */ +/* +static gchar *find_manpage_uri(const gchar *term, const gchar *section) +{ + gchar *uri, *fn; + + g_return_val_if_fail(term != NULL, NULL); + + fn = find_manpage(term, section); + if (fn == NULL) + return NULL; + + uri = g_strdup_printf("file://%s", fn); + g_free(fn); + + return uri; +} +*/ + + +/* Read the text output from man2html or NULL. */ +/* +static gchar *devhelp_plugin_man2html(const gchar *filename) +{ + FILE *fp; + gint size = DEVHELP_MANPAGE_BUF_SIZE; + gchar buf[DEVHELP_MANPAGE_BUF_SIZE] = { 0 }; + gchar *text=NULL, *cmd; + + g_return_val_if_fail(filename != NULL, NULL); + + cmd = g_strdup_printf("man2html '%s'", filename); + + fp = popen(cmd, "r"); + g_free(cmd); + if (fp == NULL) + return NULL; + + while(fgets(buf, DEVHELP_MANPAGE_BUF_SIZE-1, fp) != NULL) + { + text = g_realloc(text, size); + strncat(text, buf, DEVHELP_MANPAGE_BUF_SIZE); + size += DEVHELP_MANPAGE_BUF_SIZE; + } + + pclose(fp); + return text; +} +*/ + + +/* Read the text output from man or NULL. */ +static gchar *devhelp_plugin_man(const gchar *filename) +{ + FILE *fp; + gint size = DEVHELP_MANPAGE_BUF_SIZE; + gchar buf[DEVHELP_MANPAGE_BUF_SIZE] = { 0 }; + gchar *text=NULL, *cmd; + + g_return_val_if_fail(filename != NULL, NULL); + + cmd = g_strdup_printf("man "%s"", filename); + + fp = popen(cmd, "r"); + g_free(cmd); + if (fp == NULL) + return NULL; + + while (fgets(buf, DEVHELP_MANPAGE_BUF_SIZE-1, fp) != NULL) + { + text = g_realloc(text, size); + strncat(text, buf, DEVHELP_MANPAGE_BUF_SIZE); + size += DEVHELP_MANPAGE_BUF_SIZE; + } + + pclose(fp); + return g_strstrip(text); +} + + +/* Gets the manpage content as text, writes it to a temp file and returns + * the path to the tempfile */ +gchar *devhelp_plugin_manpages_search(const gchar *term, const gchar *section) +{ + FILE *fp; + gint fd, len; + gchar *man_fn, *tmp_fn, *uri, *text; + const gchar *tmpl = "devhelp_manpage_XXXXXX.txt"; + + man_fn = find_manpage(term, section); + if (man_fn == NULL) + return NULL; + + tmp_fn = NULL; + if ((fd = g_file_open_tmp(tmpl, &tmp_fn, NULL)) == -1) + { + g_free(man_fn); + g_free(tmp_fn); /* is NULL? */ + return NULL; + } + + fp = fdopen(fd, "w"); + fseek(fp, 0, SEEK_SET); + + text = devhelp_plugin_man(man_fn); + if (text == NULL) + { + g_free(man_fn); + g_free(tmp_fn); + fclose(fp); + return NULL; + } + + len = strlen(text); + if (fwrite(text, sizeof(gchar), len, fp) != len) + { + g_free(man_fn); + g_free(tmp_fn); + g_free(text); + fclose(fp); + return NULL; + } + + g_free(man_fn); + g_free(text); + fclose(fp); + + temp_files = g_list_append(temp_files, tmp_fn); + uri = g_strdup_printf("file://%s", tmp_fn); + + return uri; +} + + +void devhelp_plugin_remove_manpages_temp_files(void) +{ + GList *iter; + + if (temp_files == NULL) + return; + + for (iter = temp_files; iter != NULL; iter = iter->next) + { + if (remove(iter->data) == -1) + g_warning("Unable to delete temp file: %s", strerror(errno)); + g_free(iter->data); + } + + g_list_free(temp_files); + + temp_files = NULL; +}
Added: trunk/geany-plugins/devhelp/src/manpages.h =================================================================== --- trunk/geany-plugins/devhelp/src/manpages.h (rev 0) +++ trunk/geany-plugins/devhelp/src/manpages.h 2011-05-22 22:28:24 UTC (rev 2070) @@ -0,0 +1,36 @@ +/* + * manpages.h + * + * Copyright 2011 Matthew Brush mbrush@desktop + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + * + */ + +#ifndef MANPAGES_H +#define MANPAGES_H +#ifdef __cplusplus +extern "C" { +#endif + + +gchar *devhelp_plugin_manpages_search(const gchar *term, const gchar *section); +void devhelp_plugin_remove_manpages_temp_files(void); + +#ifdef __cplusplus +} /* extern "C" */ +#endif +#endif /* MANPAGES_H */
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.