Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: Jiří Techet techet@gmail.com Date: Mon, 22 May 2017 13:06:08 UTC Commit: caca891c519ff58766d5c5cc4b12bd3a3b4fa95d https://github.com/geany/geany-plugins/commit/caca891c519ff58766d5c5cc4b12bd...
Log Message: ----------- git-changebar: Add the possibility to undo hunk at cursor position
The patch adds a new keybinding action for undoing hunks. When cursor is placed at a line with a diff and the keybinding is invoked, the corresponding hunk is undone.
To get the previous contents at the given position, a temporary Scintilla instance is used into which the previous state of the document is loaded and the corresponding text from the previous state of the document is extracted. This temporary Scintilla object is then destroyed.
Modified Paths: -------------- git-changebar/src/gcb-plugin.c
Modified: git-changebar/src/gcb-plugin.c 136 lines changed, 136 insertions(+), 0 deletions(-) =================================================================== @@ -80,6 +80,7 @@ enum { enum { KB_GOTO_PREV_HUNK, KB_GOTO_NEXT_HUNK, + KB_UNDO_HUNK, KB_COUNT };
@@ -117,6 +118,16 @@ struct GotoNextHunkData { gint next_line; };
+typedef struct UndoHunkData UndoHunkData; +struct UndoHunkData { + guint doc_id; + gint line; + gboolean found; + gint old_start; + gint old_lines; + gint new_start; + gint new_lines; +};
static void on_git_repo_changed (GFileMonitor *monitor, GFile *file, @@ -1086,6 +1097,129 @@ on_kb_goto_next_hunk (guint kb) } }
+static void +insert_buf_range (GeanyDocument *doc, + const git_buf *old_contents, + gint pos, + gint old_start, + gint old_lines) +{ + ScintillaObject *old_sci = editor_create_widget (doc->editor); + gchar *old_buf = old_contents->ptr; + gsize old_buf_len = old_contents->size; + gboolean free_buf = FALSE; + gint old_pos_start; + gint old_pos_end; + gchar *old_range; + + /* convert the buffer to UTF-8 if necessary */ + if (encoding_needs_coversion (doc->encoding)) { + free_buf = convert_encoding_inplace (&old_buf, &old_buf_len, free_buf, + "UTF-8", doc->encoding, NULL); + } + + scintilla_send_message (old_sci, SCI_ADDTEXT, old_buf_len, (glong) old_buf); + + old_pos_start = sci_get_position_from_line (old_sci, old_start); + old_pos_end = sci_get_position_from_line (old_sci, old_start + old_lines); + old_range = sci_get_contents_range (old_sci, old_pos_start, old_pos_end); + + sci_insert_text (doc->editor->sci, pos, old_range); + + g_free (old_range); + + if (free_buf) { + g_free (old_buf); + } + + g_object_ref_sink (old_sci); + g_object_unref (old_sci); +} + +static int +undo_hunk_diff_hunk_cb (const git_diff_delta *delta, + const git_diff_hunk *hunk, + void *udata) +{ + UndoHunkData *data = udata; + + if (data->line >= hunk->new_start && + data->line < hunk->new_start + MAX (1, hunk->new_lines)) { + data->old_start = hunk->old_start; + data->old_lines = hunk->old_lines; + data->new_start = hunk->new_start; + data->new_lines = hunk->new_lines; + data->found = TRUE; + return 1; + } + + return 0; +} + +static void +undo_hunk_cb (const gchar *path, + git_buf *contents, + gpointer udata) +{ + UndoHunkData *data = udata; + GeanyDocument *doc = document_get_current (); + + if (doc && doc->id == data->doc_id && contents) { + diff_buf_to_doc (contents, doc, undo_hunk_diff_hunk_cb, data); + + if (data->found) { + ScintillaObject *sci = doc->editor->sci; + + sci_start_undo_action (sci); + + if (data->new_lines > 0) { + gint pos = sci_get_position_from_line (sci, data->new_start - 1); + sci_set_target_start (sci, pos); + pos = sci_get_position_from_line (sci, data->new_start + data->new_lines - 1); + sci_set_target_end (sci, pos); + sci_replace_target (sci, "", FALSE); + } + + if (data->old_lines > 0) { + gint line = sci_get_current_line (sci); + gint pos; + + if (data->new_lines == 0) { + line++; /* marker for deleted hunk is on previous line */ + } + pos = sci_get_position_from_line (sci, line); + + insert_buf_range (doc, contents, pos, + data->old_start - 1, + data->old_lines); + } + + sci_scroll_caret (sci); + + sci_end_undo_action (sci); + } + } + + g_slice_free1 (sizeof *data, data); +} + +static void +on_kb_undo_hunk (guint kb) +{ + GeanyDocument *doc = document_get_current (); + + if (doc) { + UndoHunkData *data = g_slice_alloc (sizeof *data); + + data->doc_id = doc->id; + data->line = sci_get_current_line (doc->editor->sci) + 1; + data->found = FALSE; + + get_cached_blob_contents_async (doc->real_path, doc->id, FALSE, + undo_hunk_cb, data); + } +} + /* --- configuration loading and saving --- */
static void @@ -1272,6 +1406,8 @@ plugin_init (GeanyData *data) "goto-prev-hunk", _("Go to the previous hunk"), NULL); keybindings_set_item (kb_group, KB_GOTO_NEXT_HUNK, on_kb_goto_next_hunk, 0, 0, "goto-next-hunk", _("Go to the next hunk"), NULL); + keybindings_set_item (kb_group, KB_UNDO_HUNK, on_kb_undo_hunk, 0, 0, + "undo-hunk", _("Undo hunk at the cursor position"), NULL);
plugin_signal_connect (geany_plugin, NULL, "editor-notify", TRUE, G_CALLBACK (on_editor_notify), NULL);
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).