[geany/geany-plugins] caca89: git-changebar: Add the possibility to undo hunk at cursor position

Jiří Techet git-noreply at xxxxx
Sat Aug 19 13:46:16 UTC 2017


Branch:      refs/heads/master
Author:      Jiří Techet <techet at gmail.com>
Committer:   Jiří Techet <techet at gmail.com>
Date:        Mon, 22 May 2017 13:06:08 UTC
Commit:      caca891c519ff58766d5c5cc4b12bd3a3b4fa95d
             https://github.com/geany/geany-plugins/commit/caca891c519ff58766d5c5cc4b12bd3a3b4fa95d

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).


More information about the Plugins-Commits mailing list