31
33
#include "support.h"
32
34
#include "plugindata.h"
33
35
#include "document.h"
34
37
#include "filetypes.h"
36
39
#include "project.h"
37
41
#include "pluginmacros.h"
40
PluginFields *plugin_fields;
43
#define project geany->app->project
41
46
GeanyData *geany_data;
44
PLUGIN_VERSION_CHECK(27)
46
PLUGIN_INFO(_("Version Diff"), _("Creates a patch of a file against version control."), VERSION,
47
GeanyFunctions *geany_functions;
50
PLUGIN_VERSION_CHECK(GEANY_API_VERSION)
52
PLUGIN_SET_INFO(_("Version Diff"), _("Creates a patch of a file against version control."), VERSION,
47
53
_("The Geany developer team"))
56
static GtkWidget *main_menu_item = NULL;
52
61
VC_COMMAND_DIFF_FILE,
74
83
static void* CVS_COMMANDS[] = { CVS_CMD_DIFF_FILE, CVS_CMD_DIFF_DIR, CVS_CMD_DIFF_PROJECT };
77
static const gchar* GIT_CMD_DIFF_FILE[] = {"git", "diff", BASE_FILENAME, NULL};
78
static const gchar* GIT_CMD_DIFF_DIR[] = {"git", "diff", NULL};
79
static const gchar* GIT_CMD_DIFF_PROJECT[] = {"git", "diff", NULL};
86
static const gchar* GIT_CMD_DIFF_FILE[] = {"git", "diff", "HEAD", "--", BASE_FILENAME, NULL};
87
static const gchar* GIT_CMD_DIFF_DIR[] = {"git", "diff", "HEAD", NULL};
88
static const gchar* GIT_CMD_DIFF_PROJECT[] = {"git", "diff", "HEAD", NULL};
81
90
static const gchar* GIT_ENV_DIFF_FILE[] = {"PAGER=cat", NULL};
82
91
static const gchar* GIT_ENV_DIFF_DIR[] = {"PAGER=cat", NULL};
114
123
gchar *base_prev = g_strdup(":");
116
125
if (g_file_test(filename, G_FILE_TEST_IS_DIR))
117
base = g_strdup(filename);
126
base = g_strdup(filename);
119
base = g_path_get_dirname(filename);
128
base = g_path_get_dirname(filename);
121
while(strcmp(base, base_prev) != 0)
130
while (strcmp(base, base_prev) != 0)
123
gitdir = g_build_path("/", base, subdir, NULL);
124
ret = g_file_test(gitdir, G_FILE_TEST_IS_DIR);
132
gitdir = g_build_path("/", base, subdir, NULL);
133
ret = g_file_test(gitdir, G_FILE_TEST_IS_DIR);
130
base = g_path_get_dirname(base);
139
base = g_path_get_dirname(base);
155
164
return find_subdir(filename, vc->subdir);
157
166
if (g_file_test(filename, G_FILE_TEST_IS_DIR))
158
base = g_strdup(filename);
167
base = g_strdup(filename);
160
base = g_path_get_dirname(filename);
169
base = g_path_get_dirname(filename);
161
170
dir = g_build_path("/", base, vc->subdir, NULL);
163
172
ret = g_file_test(dir, G_FILE_TEST_IS_DIR);
247
static int find_by_filename(const gchar* filename)
251
for (i = 0; i < doc_array->len; i++)
253
if (doc_list[i].is_valid && doc_list[i].file_name &&
254
strcmp(doc_list[i].file_name, filename) == 0)
261
/* name_prefix should be in UTF-8, and can have a path. */
262
static void show_output(const gchar *std_output, const gchar *name_prefix,
256
/* utf8_name_prefix can have a path. */
257
static void show_output(const gchar *std_output, const gchar *utf8_name_prefix,
263
258
const gchar *force_encoding)
265
260
gchar *text, *detect_enc = NULL;
267
263
GtkNotebook *book;
270
filename = g_path_get_basename(name_prefix);
266
filename = g_path_get_basename(utf8_name_prefix);
271
267
setptr(filename, g_strconcat(filename, ".vc.diff", NULL));
273
269
/* need to convert input text from the encoding of the original file into
274
270
* UTF-8 because internally Geany always needs UTF-8 */
275
271
if (force_encoding)
277
text = p_encoding->convert_to_utf8_from_charset(
273
text = p_encodings->convert_to_utf8_from_charset(
278
274
std_output, (gsize)-1, force_encoding, TRUE);
282
text = p_encoding->convert_to_utf8(std_output, (gsize)-1, &detect_enc);
278
text = p_encodings->convert_to_utf8(std_output, (gsize)-1, &detect_enc);
286
idx = find_by_filename(filename);
282
doc = p_document->find_by_filename(filename);
289
idx = p_document->new_file(filename,
290
geany_data->filetypes[GEANY_FILETYPES_DIFF], text);
285
GeanyFiletype *ft = p_filetypes->lookup_by_name("Diff");
286
doc = p_document->new_file(filename, ft, text);
294
p_sci->set_text(doc_list[idx].sci, text);
295
book = GTK_NOTEBOOK(app->notebook);
296
page = gtk_notebook_page_num(book, GTK_WIDGET(doc_list[idx].sci));
290
p_sci->set_text(doc->editor->sci, text);
291
book = GTK_NOTEBOOK(geany->main_widgets->notebook);
292
page = gtk_notebook_page_num(book, GTK_WIDGET(doc->editor->sci));
297
293
gtk_notebook_set_current_page(book, page);
298
doc_list[idx].changed = FALSE;
299
p_document->set_text_changed(idx);
294
p_document->set_text_changed(doc, FALSE);
302
p_document->set_encoding(idx,
297
p_document->set_encoding(doc,
303
298
force_encoding ? force_encoding : detect_enc);
307
p_ui->set_statusbar(FALSE, _("Could not parse the output of the diff"));
302
p_ui->set_statusbar(FALSE, _("Input conversion of the diff output failed."));
310
305
g_free(detect_enc);
346
341
/* CVS dump stuff to stderr when diff nested dirs */
347
342
if (strcmp(argv[0], "cvs") != 0 && NZV(std_error))
349
p_dialogs->show_msgbox(1,
344
p_dialogs->show_msgbox(1,
350
345
_("%s exited with an error: \n%s."), argv[0], g_strstrip(std_error));
352
347
else if (NZV(std_output))
392
387
/* Make a diff from the current directory */
393
388
static void vcdirectory_activated(GtkMenuItem *menuitem, gpointer gdata)
396
391
gchar *base_name = NULL;
397
392
gchar *locale_filename = NULL;
400
idx = p_document->get_cur_idx();
402
g_return_if_fail(DOC_IDX_VALID(idx) && doc_list[idx].file_name != NULL);
404
if (doc_list[idx].changed)
395
doc = p_document->get_current();
397
g_return_if_fail(doc != NULL && doc->file_name != NULL);
406
p_document->save_file(idx, FALSE);
401
p_document->save_file(doc, FALSE);
409
locale_filename = p_utils->get_locale_from_utf8(doc_list[idx].file_name);
404
locale_filename = p_utils->get_locale_from_utf8(doc->file_name);
410
405
base_name = g_path_get_dirname(locale_filename);
412
407
text = make_diff(base_name, VC_COMMAND_DIFF_DIR);
410
setptr(base_name, p_utils->get_utf8_from_locale(base_name));
415
411
show_output(text, base_name, NULL);
424
420
/* Callback if menu item for the current project was activated */
425
421
static void vcproject_activated(GtkMenuItem *menuitem, gpointer gdata)
428
424
gchar *locale_filename = NULL;
431
idx = p_document->get_cur_idx();
427
doc = p_document->get_current();
433
429
g_return_if_fail(project != NULL && NZV(project->base_path));
435
if (DOC_IDX_VALID(idx) && doc_list[idx].changed && doc_list[idx].file_name != NULL)
431
if (doc != NULL && doc->changed && doc->file_name != NULL)
437
p_document->save_file(idx, FALSE);
433
p_document->save_file(doc, FALSE);
440
436
locale_filename = p_utils->get_locale_from_utf8(project->base_path);
451
447
/* Callback if menu item for a single file was activated */
452
448
static void vcfile_activated(GtkMenuItem *menuitem, gpointer gdata)
455
gchar *locale_filename, *text;
457
idx = p_document->get_cur_idx();
459
g_return_if_fail(DOC_IDX_VALID(idx) && doc_list[idx].file_name != NULL);
461
if (doc_list[idx].changed)
451
gchar *locale_filename, *text;
453
doc = p_document->get_current();
455
g_return_if_fail(doc != NULL && doc->file_name != NULL);
463
p_document->save_file(idx, FALSE);
459
p_document->save_file(doc, FALSE);
466
locale_filename = p_utils->get_locale_from_utf8(doc_list[idx].file_name);
462
locale_filename = p_utils->get_locale_from_utf8(doc->file_name);
468
464
text = make_diff(locale_filename, VC_COMMAND_DIFF_FILE);
471
show_output(text, doc_list[idx].file_name, doc_list[idx].encoding);
467
show_output(text, doc->file_name, doc->encoding);
474
470
g_free(locale_filename);
507
503
tooltips = gtk_tooltips_new();
509
505
menu_vcdiff = gtk_image_menu_item_new_with_mnemonic(_("_Version Diff"));
510
gtk_container_add(GTK_CONTAINER(data->tools_menu), menu_vcdiff);
506
gtk_container_add(GTK_CONTAINER(geany->main_widgets->tools_menu), menu_vcdiff);
512
g_signal_connect((gpointer) menu_vcdiff, "activate",
513
G_CALLBACK(update_menu_items), NULL);
508
g_signal_connect(menu_vcdiff, "activate", G_CALLBACK(update_menu_items), NULL);
515
510
menu_vcdiff_menu = gtk_menu_new ();
516
511
gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_vcdiff), menu_vcdiff_menu);
521
516
gtk_tooltips_set_tip (tooltips, menu_vcdiff_file,
522
517
_("Make a diff from the current active file"), NULL);
524
g_signal_connect((gpointer) menu_vcdiff_file, "activate",
525
G_CALLBACK(vcfile_activated), NULL);
519
g_signal_connect(menu_vcdiff_file, "activate", G_CALLBACK(vcfile_activated), NULL);
528
522
menu_vcdiff_dir = gtk_menu_item_new_with_mnemonic(_("From Current _Directory"));
530
524
gtk_tooltips_set_tip (tooltips, menu_vcdiff_dir,
531
525
_("Make a diff from the directory of the current active file"), NULL);
533
g_signal_connect((gpointer) menu_vcdiff_dir, "activate",
534
G_CALLBACK(vcdirectory_activated), NULL);
527
g_signal_connect(menu_vcdiff_dir, "activate", G_CALLBACK(vcdirectory_activated), NULL);
537
530
menu_vcdiff_project = gtk_menu_item_new_with_mnemonic(_("From Current _Project"));
539
532
gtk_tooltips_set_tip (tooltips, menu_vcdiff_project,
540
533
_("Make a diff from the current project's base path"), NULL);
542
g_signal_connect((gpointer) menu_vcdiff_project, "activate",
543
G_CALLBACK(vcproject_activated), NULL);
535
g_signal_connect(menu_vcdiff_project, "activate", G_CALLBACK(vcproject_activated), NULL);
545
537
gtk_widget_show_all(menu_vcdiff);
547
plugin_fields->menu_item = menu_vcdiff;
548
plugin_fields->flags = PLUGIN_IS_DOCUMENT_SENSITIVE;
539
p_ui->add_document_sensitive(menu_vcdiff);
540
main_menu_item = menu_vcdiff;
552
544
/* Called by Geany before unloading the plugin. */
545
void plugin_cleanup(void)
555
/* remove the menu item added in init() */
556
gtk_widget_destroy(plugin_fields->menu_item);
547
/* remove the menu item added in plugin_init() */
548
gtk_widget_destroy(main_menu_item);