[gitg] Implemented selection discard
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg] Implemented selection discard
- Date: Tue, 1 Jul 2014 13:14:31 +0000 (UTC)
commit e815ebc78f6009ed96cf0614db74b154c3fade1d
Author: Jesse van den Kieboom <jessevdk gnome org>
Date: Tue Jul 1 15:13:28 2014 +0200
Implemented selection discard
gitg/commit/gitg-commit-paned.vala | 8 ++
gitg/commit/gitg-commit.vala | 77 ++++++++++++++++++++
gitg/resources/ui/gitg-commit-paned.ui | 11 +++
libgitg/gitg-stage.vala | 125 +++++++++++++++++++++++++++++---
4 files changed, 211 insertions(+), 10 deletions(-)
---
diff --git a/gitg/commit/gitg-commit-paned.vala b/gitg/commit/gitg-commit-paned.vala
index 0af1e71..3ae26bc 100644
--- a/gitg/commit/gitg-commit-paned.vala
+++ b/gitg/commit/gitg-commit-paned.vala
@@ -38,6 +38,9 @@ class Paned : Gtk.Paned
[GtkChild (name = "button_stage")]
private Gtk.Button d_button_stage;
+ [GtkChild (name = "button_discard")]
+ private Gtk.Button d_button_discard;
+
public Gitg.Sidebar sidebar
{
get { return d_tree_view_files; }
@@ -63,6 +66,11 @@ class Paned : Gtk.Paned
get { return d_button_stage; }
}
+ public Gtk.Button button_discard
+ {
+ get { return d_button_discard; }
+ }
+
construct
{
var state_settings = new Settings("org.gnome.gitg.state.commit");
diff --git a/gitg/commit/gitg-commit.vala b/gitg/commit/gitg-commit.vala
index a6d2308..eeb079a 100644
--- a/gitg/commit/gitg-commit.vala
+++ b/gitg/commit/gitg-commit.vala
@@ -148,6 +148,7 @@ namespace GitgCommit
d_main.diff_view.staged = false;
d_main.button_stage.label = _("_Stage selection");
+ d_main.button_discard.visible = true;
d_main.diff_view.diff = d;
}
@@ -232,6 +233,7 @@ namespace GitgCommit
d_main.diff_view.staged = true;
d_main.button_stage.label = _("_Unstage selection");
+ d_main.button_discard.visible = false;
d_main.diff_view.diff = d;
}
@@ -826,6 +828,72 @@ namespace GitgCommit
}
}
+ private async void discard_selection() throws Error
+ {
+ var selection = yield d_main.diff_view.get_selection();
+ var stage = application.repository.stage;
+
+ foreach (var pset in selection)
+ {
+ yield stage.revert_patch(pset);
+ }
+ }
+
+ private void on_discard_clicked()
+ {
+ var primary = _("Discard changes");
+ var secondary = _("Are you sure you want to permanently discard the selected changes
in the file `%s'?").printf(d_current_file.path);
+
+ var q = new GitgExt.UserQuery();
+
+ q.title = primary;
+ q.message = secondary;
+ q.message_type = Gtk.MessageType.QUESTION;
+
+ q.responses = new GitgExt.UserQueryResponse[] {
+ new GitgExt.UserQueryResponse(_("Discard"), Gtk.ResponseType.OK),
+ new GitgExt.UserQueryResponse(_("_Cancel"), Gtk.ResponseType.CANCEL)
+ };
+
+ q.default_response = Gtk.ResponseType.OK;
+
+ q.response.connect((w, r) => {
+ if (r == Gtk.ResponseType.OK)
+ {
+ return do_discard_selection(q);
+ }
+
+ return true;
+ });
+
+ application.user_query(q);
+ }
+
+ private bool do_discard_selection(GitgExt.UserQuery q)
+ {
+ application.busy = true;
+
+ discard_selection.begin((obj, res) => {
+ try
+ {
+ discard_selection.end(res);
+ }
+ catch (Error e)
+ {
+ application.show_infobar(_("Failed to discard selection"),
+ e.message,
+ Gtk.MessageType.ERROR);
+ }
+
+ q.quit();
+ application.busy = false;
+
+ reload();
+ });
+
+ return false;
+ }
+
private void on_stage_clicked()
{
var staging = d_main.diff_view.unstaged;
@@ -944,12 +1012,21 @@ namespace GitgCommit
on_stage_clicked();
});
+ d_main.button_discard.clicked.connect(() => {
+ on_discard_clicked();
+ });
+
d_main.sidebar.populate_popup.connect(do_populate_menu);
d_main.diff_view.bind_property("has-selection",
d_main.button_stage,
"sensitive",
BindingFlags.DEFAULT);
+
+ d_main.diff_view.bind_property("has-selection",
+ d_main.button_discard,
+ "sensitive",
+ BindingFlags.DEFAULT);
}
}
}
diff --git a/gitg/resources/ui/gitg-commit-paned.ui b/gitg/resources/ui/gitg-commit-paned.ui
index 5b0c94e..fb8efef 100644
--- a/gitg/resources/ui/gitg-commit-paned.ui
+++ b/gitg/resources/ui/gitg-commit-paned.ui
@@ -94,6 +94,17 @@
<property name="pack-type">end</property>
</packing>
</child>
+ <child>
+ <object class="GtkButton" id="button_discard">
+ <property name="visible">True</property>
+ <property name="use_underline">True</property>
+ <property name="label" translatable="yes">D_iscard selection</property>
+ <property name="sensitive">False</property>
+ </object>
+ <packing>
+ <property name="pack-type">end</property>
+ </packing>
+ </child>
</object>
</child>
</object>
diff --git a/libgitg/gitg-stage.vala b/libgitg/gitg-stage.vala
index 39d2a0a..d8b9a41 100644
--- a/libgitg/gitg-stage.vala
+++ b/libgitg/gitg-stage.vala
@@ -552,6 +552,100 @@ public class Stage : Object
}
/**
+ * Revert a patch in the working directory.
+ *
+ * @param patch the patch to revert.
+ *
+ * Revert a provided patch from the working directory. The patch should
+ * contain changes of the file in the current working directory to the contents
+ * of the index (i.e. as obtained from diff_workdir)
+ */
+ public async void revert_patch(PatchSet patch) throws Error
+ {
+ // new file is the current file in the working directory
+ var workdirf = d_repository.get_workdir().resolve_relative_path(patch.filename);
+ var workdirf_stream = yield workdirf.read_async();
+
+ yield thread_index((index) => {
+ var entries = index.get_entries();
+ var entry = entries.get_by_path(workdirf, 0);
+
+ if (entry == null)
+ {
+ throw new StageError.INDEX_ENTRY_NOT_FOUND(patch.filename);
+ }
+
+ var index_blob = d_repository.lookup<Ggit.Blob>(entry.get_id());
+ unowned uchar[] index_content = index_blob.get_raw_content();
+
+ var index_stream = new MemoryInputStream.from_bytes(new Bytes(index_content));
+ var reversed = patch.reversed();
+
+ FileIOStream? out_stream = null;
+ File ?outf = null;
+
+ try
+ {
+ outf = File.new_tmp(null, out out_stream);
+
+ apply_patch_stream(workdirf_stream,
+ index_stream,
+ out_stream.output_stream,
+ reversed);
+ }
+ catch (Error e)
+ {
+ workdirf_stream.close();
+ index_stream.close();
+
+ if (outf != null)
+ {
+ try
+ {
+ outf.delete();
+ } catch {}
+ }
+
+ throw e;
+ }
+
+ workdirf_stream.close();
+ index_stream.close();
+
+ if (out_stream != null)
+ {
+ out_stream.close();
+ }
+
+ // Move outf to workdirf
+ try
+ {
+ var repl = workdirf.replace(null,
+ false,
+ FileCreateFlags.NONE);
+
+ repl.splice(outf.read(),
+ OutputStreamSpliceFlags.CLOSE_SOURCE |
+ OutputStreamSpliceFlags.CLOSE_TARGET);
+ }
+ catch (Error e)
+ {
+ try
+ {
+ outf.delete();
+ } catch {}
+
+ throw e;
+ }
+
+ try
+ {
+ outf.delete();
+ } catch {}
+ });
+ }
+
+ /**
* Delete a file from the index.
*
* @param file the file to delete.
@@ -628,10 +722,30 @@ public class Stage : Object
pos += length;
}
- private void apply_patch(Ggit.Index index, InputStream old_stream, InputStream new_stream, PatchSet
patch) throws Error
+ private void apply_patch(Ggit.Index index,
+ InputStream old_stream,
+ InputStream new_stream,
+ PatchSet patch) throws Error
{
var patched_stream = d_repository.create_blob();
+ apply_patch_stream(old_stream, new_stream, patched_stream, patch);
+
+ patched_stream.close();
+ var new_id = patched_stream.get_id();
+
+ var new_entry = d_repository.create_index_entry_for_path(patch.filename,
+ new_id);
+
+ index.add(new_entry);
+ index.write();
+ }
+
+ private void apply_patch_stream(InputStream old_stream,
+ InputStream new_stream,
+ OutputStream patched_stream,
+ PatchSet patch) throws Error
+ {
size_t old_ptr = 0;
size_t new_ptr = 0;
@@ -665,15 +779,6 @@ public class Stage : Object
// Copy remaining part of old
patched_stream.splice(old_stream, OutputStreamSpliceFlags.NONE);
- patched_stream.close();
-
- var new_id = patched_stream.get_id();
-
- var new_entry = d_repository.create_index_entry_for_path(patch.filename,
- new_id);
-
- index.add(new_entry);
- index.write();
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]