Index: plugins/Makefile.am =================================================================== --- plugins/Makefile.am (revision 2011) +++ plugins/Makefile.am (working copy) @@ -11,6 +11,7 @@ htmlchars_la_LDFLAGS = -module -avoid-version export_la_LDFLAGS = -module -avoid-version svndiff_la_LDFLAGS = -module -avoid-version +gitdiff_la_LDFLAGS = -module -avoid-version filebrowser_la_LDFLAGS = -module -avoid-version if PLUGINS @@ -21,6 +22,7 @@ htmlchars.la \ export.la \ svndiff.la \ + gitdiff.la \ filebrowser.la # Plugins not to be installed @@ -32,6 +34,7 @@ htmlchars_la_SOURCES = htmlchars.c export_la_SOURCES = export.c svndiff_la_SOURCES = svndiff.c +gitdiff_la_SOURCES = gitdiff.c filebrowser_la_SOURCES = filebrowser.c demoplugin_la_LIBADD = $(GTK_LIBS) @@ -39,6 +42,7 @@ htmlchars_la_LIBADD = $(GTK_LIBS) export_la_LIBADD = $(GTK_LIBS) svndiff_la_LIBADD = $(GTK_LIBS) +gitdiff_la_LIBADD = $(GTK_LIBS) filebrowser_la_LIBADD = $(GTK_LIBS) endif # PLUGINS Index: plugins/gitdiff.c =================================================================== --- plugins/gitdiff.c (revision 0) +++ plugins/gitdiff.c (revision 0) @@ -0,0 +1,207 @@ +/* + * gitdiff.c - this file is part of Geany, a fast and lightweight IDE + * + * Copyright 2007 Frank Lanitz + * Copyright 2007 Enrico Tröger + * Copyright 2007 Nick Treleaven + * Copyright 2007 Yura Siamashka + * + * 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 2 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. + */ + +/* GITdiff plugin */ +/* This small plugin uses git to generate a diff against the current + * version inside git tree.*/ + +#include "geany.h" +#include "support.h" +#include "plugindata.h" +#include "document.h" +#include "filetypes.h" +#include "utils.h" +#include "project.h" +#include "pluginmacros.h" + +PluginFields *plugin_fields; +GeanyData *geany_data; + +VERSION_CHECK(27) + +PLUGIN_INFO(_("gitdiff"), _("Plugin to create a patch of a file against git"), VERSION) + + +static int find_by_filename(const gchar* filename) +{ + gint i; + for (i = 0; i < doc_array->len; i++) + { + if ( DOC_IDX_VALID(i) && doc_list[i].file_name && + strcmp(doc_list[i].file_name, filename) == 0) + return i; + } + return -1; +} + +/* name_prefix should be in UTF-8, and can have a path. */ +static void show_output(const gchar *std_output, const gchar *force_encoding) +{ + gchar *text, *detect_enc = NULL; + gint idx, page; + GtkNotebook *book; + gchar *filename = "*GIT-DIFF*"; + + // need to convert input text from the encoding of the original file into + // UTF-8 because internally Geany always needs UTF-8 + if (force_encoding) + { + text = geany_data->encoding->convert_to_utf8_from_charset( + std_output, -1, force_encoding, TRUE); + } + else + { + text = geany_data->encoding->convert_to_utf8(std_output, -1, &detect_enc); + } + if (text) + { + idx = find_by_filename(filename); + if ( idx == -1) + { + idx = geany_data->document->new_file(filename, + geany_data->filetypes[GEANY_FILETYPES_DIFF], text); + } + else + { + geany_data->sci->set_text(doc_list[idx].sci, text); + book = GTK_NOTEBOOK(app->notebook); + page = gtk_notebook_page_num(book, GTK_WIDGET(doc_list[idx].sci)); + gtk_notebook_set_current_page(book, page); + doc_list[idx].changed = FALSE; + documents->set_text_changed(idx); + } + + geany_data->document->set_encoding(idx, + force_encoding ? force_encoding : detect_enc); + } + else + { + ui->set_statusbar(FALSE, _("Could not parse the output of git diff")); + } + g_free(text); + g_free(detect_enc); +} + + +static gchar *make_diff(const gchar *dir) +{ + gchar *std_output = NULL; + gchar *std_error = NULL; + gint exit_code; + gchar *command, *text = NULL; + gchar *argv[] = {"git", "diff", NULL}; + gchar *env[] = {"PAGER=cat", NULL}; + + if (g_spawn_sync(dir, argv, env, G_SPAWN_SEARCH_PATH, NULL, NULL, &std_output, &std_error, &exit_code, NULL)) + { + if (! exit_code) + { + if (NZV(std_output)) + { + text = std_output; + } + else + { + ui->set_statusbar(FALSE, _("No changes were made.")); + } + } + else + { // GIT returns some error + dialogs->show_msgbox(1, + _("GIT exited with an error: \n%s."), g_strstrip(std_error)); + } + } + else + { + ui->set_statusbar(FALSE, + _("Something went really wrong. Is there any git-binary in your path?")); + } + g_free(std_error); + return text; +} + +/* Callback if menu item for a single file was activated */ +static void gitdiff_activated(GtkMenuItem *menuitem, gpointer gdata) +{ + gint idx; + gchar *text; + gchar *dir; + + idx = documents->get_cur_idx(); + + if ( !(DOC_IDX_VALID(idx) && doc_list[idx].file_name != NULL && + g_file_test(doc_list[idx].file_name, G_FILE_TEST_EXISTS))) + return; + + if (doc_list[idx].changed) + { + documents->save_file(idx, FALSE); + } + dir = g_path_get_dirname(doc_list[idx].file_name); + + text = make_diff(dir); + if (text) + show_output(text, doc_list[idx].encoding); + g_free(text); + g_free(dir); +} + +static gboolean have_git = FALSE; + +/* Called by Geany to initialize the plugin */ +void init(GeanyData *data) +{ + GtkWidget *gitdiff_item; + GtkTooltips *tooltips = NULL; + gchar *tmp; + + tmp = g_find_program_in_path("git"); + if (!tmp) + return; + + have_git = TRUE; + g_free(tmp); + + tooltips = gtk_tooltips_new(); + + // Add an item to the Tools menu + gitdiff_item = gtk_menu_item_new_with_mnemonic(_("_GITdiff")); + gtk_widget_show(gitdiff_item); + gtk_container_add(GTK_CONTAINER(geany_data->tools_menu), gitdiff_item); + g_signal_connect(G_OBJECT(gitdiff_item), "activate", G_CALLBACK(gitdiff_activated), NULL); + + gtk_tooltips_set_tip (tooltips, gitdiff_item, + _("Make a diff from the repositary of the directory of the current active file"), NULL); + + // keep a pointer to the menu item, so we can remove it when the plugin is unloaded + plugin_fields->menu_item = gitdiff_item; +} + + +/* Called by Geany before unloading the plugin. */ +void cleanup() +{ + // remove the menu item added in init() + if (have_git) + gtk_widget_destroy(plugin_fields->menu_item); +}