diff --git a/geanyvc/src/geanyvc.c b/geanyvc/src/geanyvc.c index 68af176d8..b2b6ac92f 100644 --- a/geanyvc/src/geanyvc.c +++ b/geanyvc/src/geanyvc.c @@ -84,6 +84,7 @@ static gboolean set_editor_menu_entries; static gboolean set_menubar_entry; static gint commit_dialog_width = 0; static gint commit_dialog_height = 0; +static GSList *commit_message_history = NULL; static gchar *config_file; @@ -155,6 +156,15 @@ enum COUNT_KB }; +enum +{ + COMMIT_MESSAGE_HISTORY_DISPLAY_TEXT = 0, + COMMIT_MESSAGE_HISTORY_FULL_TEXT, + COMMIT_MESSAGE_HISTORY_ACTIVE, + COMMIT_MESSAGE_HISTORY_NUM_COLUMNS +}; +#define COMMIT_MESSAGE_HISTORY_LENGTH 10 + GSList *get_commit_files_null(G_GNUC_UNUSED const gchar * dir) { @@ -1319,6 +1329,90 @@ static void commit_tree_selection_changed_cb(GtkTreeSelection *sel, GtkTextView g_free(path); } +static void commit_message_update_cb(GtkWidget *widget, gpointer user_data) +{ + GtkTreeIter iter; + + if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(widget), &iter)) + { + gchar *commit_message; + GtkTreeModel *model = gtk_combo_box_get_model(GTK_COMBO_BOX(widget)); + gboolean active = FALSE; + + gtk_tree_model_get(model, &iter, + COMMIT_MESSAGE_HISTORY_FULL_TEXT, &commit_message, + COMMIT_MESSAGE_HISTORY_ACTIVE, &active, -1); + + if (active) + { + GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(user_data)); + gtk_text_buffer_set_text(buffer, commit_message, -1); + } + g_free(commit_message); + } +} + +static GtkWidget * +create_commit_message_history_combobox(void) +{ + GtkWidget *combobox; + GtkCellRenderer *renderer; + GtkTreeIter iter; + GtkListStore *store; + GSList *list_item; + GString *display_message_string; + gchar *display_message; + + combobox = gtk_combo_box_new(); + renderer = gtk_cell_renderer_text_new(); + store = gtk_list_store_new( + COMMIT_MESSAGE_HISTORY_NUM_COLUMNS, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_BOOLEAN); + + foreach_slist(list_item, commit_message_history) + { + display_message_string = g_string_new(list_item->data); + /* replace line breaks */ + utils_string_replace_all(display_message_string, "\n", " "); + /* shorten commit message */ + if (display_message_string->len > 80) + { + g_string_truncate(display_message_string, 80); + g_string_append(display_message_string, "..."); + } + display_message = g_string_free(display_message_string, FALSE); + + /* by _prepend() we reverse the list order for display on purpose: + * most recent item should be on top */ + gtk_list_store_prepend(store, &iter); + gtk_list_store_set(store, &iter, + COMMIT_MESSAGE_HISTORY_DISPLAY_TEXT, display_message, + COMMIT_MESSAGE_HISTORY_FULL_TEXT, list_item->data, + COMMIT_MESSAGE_HISTORY_ACTIVE, TRUE, -1); + + g_free(display_message); + } + + gtk_list_store_prepend(store, &iter); + gtk_list_store_set(store, &iter, + COMMIT_MESSAGE_HISTORY_DISPLAY_TEXT, _("Choose a previous commit message"), + COMMIT_MESSAGE_HISTORY_FULL_TEXT, NULL, + COMMIT_MESSAGE_HISTORY_ACTIVE, FALSE, -1); + + gtk_combo_box_set_model(GTK_COMBO_BOX(combobox), GTK_TREE_MODEL(store)); + gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0); + g_object_unref(store); + + gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox), renderer, TRUE); + gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox), renderer, + "text", COMMIT_MESSAGE_HISTORY_DISPLAY_TEXT, + "sensitive", COMMIT_MESSAGE_HISTORY_ACTIVE, NULL); + + return combobox; +} + static gboolean commit_text_line_number_update_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data) { @@ -1363,6 +1457,7 @@ create_commitDialog(void) GtkWidget *bottom_vbox; GtkWidget *commit_text_vbox; GtkWidget *lineColumnLabel; + GtkWidget *commitMessageHistoryComboBox; GtkTreeSelection *sel; gchar *rcstyle = g_strdup_printf("style \"geanyvc-diff-font\"\n" @@ -1476,6 +1571,11 @@ create_commitDialog(void) gtk_box_pack_end(GTK_BOX(commit_text_vbox), lineColumnLabel, FALSE, TRUE, 0); gtk_widget_show(lineColumnLabel); + /* last commit message dropdown */ + commitMessageHistoryComboBox = create_commit_message_history_combobox(); + gtk_box_pack_end(GTK_BOX(commit_text_vbox), commitMessageHistoryComboBox, FALSE, TRUE, 0); + gtk_widget_show(commitMessageHistoryComboBox); + dialog_action_area1 = gtk_dialog_get_action_area(GTK_DIALOG(commitDialog)); gtk_widget_show(dialog_action_area1); gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog_action_area1), GTK_BUTTONBOX_END); @@ -1496,6 +1596,8 @@ create_commitDialog(void) G_CALLBACK(commit_text_line_number_update_cb), lineColumnLabel); g_signal_connect(textCommitMessage, "button-release-event", G_CALLBACK(commit_text_line_number_update_cb), lineColumnLabel); + g_signal_connect(commitMessageHistoryComboBox, "changed", + G_CALLBACK(commit_message_update_cb), textCommitMessage); /* initial setup */ commit_text_line_number_update_cb(textCommitMessage, NULL, lineColumnLabel); @@ -1521,6 +1623,29 @@ create_commitDialog(void) return commitDialog; } +static void +add_commit_message_to_history(const gchar *commit_message) +{ + GSList *list_item = NULL; + gchar *message = g_strdup(commit_message); + + /* add commit message to the history */ + commit_message_history = g_slist_append(commit_message_history, (gpointer)message); + + /* House keeping: keep only a maximum of COMMIT_MESSAGE_HISTORY_LENGTH items and delete the rest + * We remove the first element from the list as often as the list is too long. + * While the loop is not the most efficient way, it should be ok since the list never has + * much more than 10 items */ + while (g_slist_length(commit_message_history) > COMMIT_MESSAGE_HISTORY_LENGTH) + { + list_item = commit_message_history; /* remember the element to delete */ + commit_message_history = list_item->next; /* start the list with the next item */ + /* delete the current item and its data */ + list_item->next = NULL; + g_slist_free_full(list_item, g_free); + } +} + static void vccommit_activated(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer gdata) { @@ -1630,6 +1755,7 @@ vccommit_activated(G_GNUC_UNUSED GtkMenuItem * menuitem, G_GNUC_UNUSED gpointer gtk_text_buffer_get_start_iter(mbuf, &begin); gtk_text_buffer_get_end_iter(mbuf, &end); message = gtk_text_buffer_get_text(mbuf, &begin, &end, FALSE); + add_commit_message_to_history(message); gtk_tree_model_foreach(model, get_commit_files_foreach, &selected_files); if (!EMPTY(message) && selected_files) { @@ -1795,6 +1921,8 @@ widgets; static void save_config(void) { + GSList *list_item = NULL; + gint list_item_count = 0; GKeyFile *config = g_key_file_new(); gchar *config_dir = g_path_get_dirname(config_file); @@ -1827,6 +1955,16 @@ save_config(void) "commit_dialog_height", commit_dialog_height); } + g_key_file_remove_group(config, "CommitMessageHistory", NULL); /* cleanup */ + foreach_slist(list_item, commit_message_history) + { + gchar *key = g_strdup_printf("message_%d", list_item_count); + g_key_file_set_string(config, "CommitMessageHistory", key, list_item->data); + g_free(key); + + list_item_count++; + } + if (!g_file_test(config_dir, G_FILE_TEST_IS_DIR) && utils_mkdir(config_dir, TRUE) != 0) { @@ -2009,6 +2147,8 @@ load_config(void) GError *error = NULL; #endif + gchar **commit_message_history_keys, **ptr; + gchar *commit_message; GKeyFile *config = g_key_file_new(); g_key_file_load_from_file(config, config_file, G_KEY_FILE_NONE, NULL); @@ -2054,6 +2194,18 @@ load_config(void) commit_dialog_height = utils_get_setting_integer(config, "CommitDialog", "commit_dialog_height", 500); + commit_message_history_keys = g_key_file_get_keys(config,"CommitMessageHistory", NULL, NULL); + if (commit_message_history_keys != NULL) + { + foreach_strv(ptr, commit_message_history_keys) + { + commit_message = g_key_file_get_string(config, "CommitMessageHistory", *ptr, NULL); + /* do not free the newly allocated commit_message string as we need it later in the list, + * will be finally freed when cleaning up the commit_message_history list */ + commit_message_history = g_slist_append(commit_message_history, commit_message); + } + g_strfreev(commit_message_history_keys); + } g_key_file_free(config); } @@ -2408,5 +2560,6 @@ plugin_cleanup(void) gtk_widget_destroy(menu_entry); g_slist_free(VC); VC = NULL; + g_slist_free_full(commit_message_history, g_free); g_free(config_file); }