[gitg/wip/patch-stage: 10/11] Make stage selection behavior part of diff view widget
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gitg/wip/patch-stage: 10/11] Make stage selection behavior part of diff view widget
- Date: Tue, 31 Dec 2013 14:20:11 +0000 (UTC)
commit e5091246142c6c006b161d553ddec0980b223c04
Author: Jesse van den Kieboom <jessevdk gmail com>
Date: Tue Dec 31 15:17:20 2013 +0100
Make stage selection behavior part of diff view widget
libgitg/Makefile.am | 6 +-
libgitg/gitg-diff-view.vala | 159 ++++++++++++++++++++++++++-
libgitg/gitg-js-utils.c | 39 +++++++
libgitg/gitg-js-utils.h | 10 ++
libgitg/resources/diff-view-html-builder.js | 26 +----
libgitg/resources/diff-view.css | 34 ------
libgitg/resources/diff-view.html | 1 -
libgitg/resources/diff-view.js | 147 +++++++++++++++++++++++--
vapi/gitg-js-utils.vapi | 6 +
9 files changed, 358 insertions(+), 70 deletions(-)
---
diff --git a/libgitg/Makefile.am b/libgitg/Makefile.am
index 6036b72..8a767b7 100644
--- a/libgitg/Makefile.am
+++ b/libgitg/Makefile.am
@@ -25,6 +25,7 @@ AM_VALAFLAGS = \
--pkg gee-0.8 \
--pkg json-glib-1.0 \
--pkg gio-unix-2.0 \
+ --pkg gitg-js-utils \
$(GITG_VALAFLAGS) \
--vapidir $(top_srcdir)/vapi \
--header libgitg.h \
@@ -60,10 +61,8 @@ VALA_FILES = \
gitg-diff-view-request-resource.vala \
gitg-diff-view-request-patch.vala \
gitg-diff-view-request-diff.vala \
- gitg-diff-view-request-stage.vala \
gitg-repository-list-box.vala \
gitg-when-mapped.vala \
- gitg-patch-set.vala \
gitg-progress-bin.vala \
gitg-stage.vala \
gitg-stage-status-enumerator.vala \
@@ -79,10 +78,11 @@ libgitg_1_0_la_CFLAGS = \
libgitg_1_0_la_SOURCES = \
gitg-resources.c \
+ gitg-js-utils.c \
$(VALA_FILES)
headerdir = $(prefix)/include/libgitg-1.0/libgitg
-header_HEADERS = libgitg.h
+header_HEADERS = libgitg.h gitg-js-utils.h
vapidir = $(prefix)/share/vala/vapi
vapi_DATA = libgitg-1.0.vapi
diff --git a/libgitg/gitg-diff-view.vala b/libgitg/gitg-diff-view.vala
index f08aace..d270083 100644
--- a/libgitg/gitg-diff-view.vala
+++ b/libgitg/gitg-diff-view.vala
@@ -21,9 +21,73 @@ namespace Gitg
{
public class DiffView : WebKit.WebView
{
+ public class PatchSet
+ {
+ public enum Type
+ {
+ ADD = 'a',
+ REMOVE = 'r'
+ }
+
+ public struct Patch
+ {
+ Type type;
+ size_t old_offset;
+ size_t new_offset;
+ size_t length;
+
+ public string to_string()
+ {
+ var tp = type == Type.ADD ? "add" : "remove";
+ return @"$tp[old_offset: $old_offset, new_offset: $new_offset,
length: $length]";
+ }
+ }
+
+ public string filename;
+ public Patch[] patches;
+
+ public string to_string()
+ {
+ var ps = new string[patches.length];
+
+ for (var i = 0; i < patches.length; i++)
+ {
+ ps[i] = patches[i].to_string();
+ }
+
+ var p = string.joinv(", ", ps);
+ return @"$filename: $p";
+ }
+ }
+
+ private class DiffViewRequestInternal : DiffViewRequest
+ {
+ public DiffViewRequestInternal(DiffView? view, WebKit.URISchemeRequest request,
Soup.URI uri)
+ {
+ base(view, request, uri);
+ }
+
+ protected override InputStream? run_async(Cancellable? cancellable) throws Error
+ {
+ Idle.add(() => {
+ switch (parameter("action"))
+ {
+ case "selection-changed":
+ d_view.update_has_selection(parameter("value") ==
"yes");
+ break;
+ }
+
+ return false;
+ });
+
+ return null;
+ }
+ }
+
private Ggit.Diff? d_diff;
private Commit? d_commit;
private Settings d_fontsettings;
+ private bool d_has_selection;
private static Gee.HashMap<string, DiffView> s_diff_map;
private static uint64 s_diff_id;
@@ -32,6 +96,12 @@ namespace Gitg
public File? custom_js { get; construct; }
public Ggit.DiffOptions? options { get; construct set; }
+ [Notify]
+ public bool has_selection
+ {
+ get { return d_has_selection; }
+ }
+
private Cancellable d_cancellable;
private bool d_loaded;
private ulong d_diffid;
@@ -141,6 +211,8 @@ namespace Gitg
return new DiffViewRequestDiff(view, request, uri);
case "patch":
return new DiffViewRequestPatch(view, request, uri);
+ case "internal":
+ return new DiffViewRequestInternal(view, request, uri);
}
return null;
@@ -150,6 +222,11 @@ namespace Gitg
{
var req = parse_request(request);
+ if (req == null)
+ {
+ return;
+ }
+
if (req.view != null)
{
req.view.request(req);
@@ -262,6 +339,8 @@ namespace Gitg
d_cancellable = new Cancellable();
+ d_loaded = false;
+
load_changed.connect((v, ev) => {
if (ev == WebKit.LoadEvent.FINISHED)
{
@@ -275,8 +354,6 @@ namespace Gitg
uri += "&settings=" + Soup.URI.encode(json_settings(), null);
- d_loaded = false;
-
load_uri(uri);
}
@@ -327,6 +404,84 @@ namespace Gitg
});
}
}
+
+ public void update_has_selection(bool hs)
+ {
+ if (d_has_selection != hs)
+ {
+ d_has_selection = hs;
+ notify_property("has-selection");
+ }
+ }
+
+ private PatchSet parse_patchset(Json.Node node)
+ {
+ PatchSet ret = new PatchSet();
+
+ var elems = node.get_array();
+ ret.filename = elems.get_element(0).get_string();
+
+ var ps = elems.get_element(1).get_array();
+
+ var l = ps.get_length();
+ ret.patches = new PatchSet.Patch[l];
+
+ for (uint i = 0; i < l; i++)
+ {
+ var p = ps.get_element(i).get_array();
+
+ ret.patches[i] = PatchSet.Patch() {
+ type = (PatchSet.Type)p.get_element(0).get_int(),
+ old_offset = (size_t)p.get_element(1).get_int(),
+ new_offset = (size_t)p.get_element(2).get_int(),
+ length = (size_t)p.get_element(3).get_int()
+ };
+ }
+
+ return ret;
+ }
+
+ public async PatchSet[] get_selection()
+ {
+ WebKit.JavascriptResult jsret;
+
+ try
+ {
+ jsret = yield run_javascript("get_selection();", d_cancellable);
+ }
+ catch (Error e)
+ {
+ stderr.printf("Error running get_selection(): %s\n", e.message);
+ return new PatchSet[] {};
+ }
+
+ var json = GitgJsUtils.get_json(jsret);
+ var parser = new Json.Parser();
+
+ try
+ {
+ parser.load_from_data(json, -1);
+ }
+ catch (Error e)
+ {
+ stderr.printf("Error parsing json: %s\n", e.message);
+ return new PatchSet[] {};
+ }
+
+ var root = parser.get_root();
+
+ var elems = root.get_array();
+ var l = elems.get_length();
+
+ var ret = new PatchSet[l];
+
+ for (uint i = 0; i < l; i++)
+ {
+ ret[i] = parse_patchset(elems.get_element(i));
+ }
+
+ return ret;
+ }
}
}
diff --git a/libgitg/gitg-js-utils.c b/libgitg/gitg-js-utils.c
new file mode 100644
index 0000000..8e6123a
--- /dev/null
+++ b/libgitg/gitg-js-utils.c
@@ -0,0 +1,39 @@
+#include "gitg-js-utils.h"
+
+#include <JavaScriptCore/JavaScript.h>
+
+gchar *
+gitg_js_utils_get_json (WebKitJavascriptResult *js_result)
+{
+ JSValueRef value;
+ JSStringRef json;
+ size_t size;
+ gchar *ret;
+
+ value = webkit_javascript_result_get_value (js_result);
+
+ json = JSValueCreateJSONString(webkit_javascript_result_get_global_context (js_result),
+ value,
+ 0,
+ NULL);
+
+ size = JSStringGetMaximumUTF8CStringSize (json);
+ ret = g_new0 (gchar, size);
+
+ JSStringGetUTF8CString (json, ret, size);
+ JSStringRelease (json);
+
+ return ret;
+}
+
+gboolean
+gitg_js_utils_check (WebKitJavascriptResult *js_result)
+{
+ JSValueRef value;
+
+ value = webkit_javascript_result_get_value (js_result);
+
+ return JSValueToBoolean (webkit_javascript_result_get_global_context (js_result),
+ value);
+}
+
diff --git a/libgitg/gitg-js-utils.h b/libgitg/gitg-js-utils.h
new file mode 100644
index 0000000..4e5e65f
--- /dev/null
+++ b/libgitg/gitg-js-utils.h
@@ -0,0 +1,10 @@
+#ifndef __GITG_JS_UTILS_H__
+#define __GITG_JS_UTILS_H__
+
+#include <webkit2/webkit2.h>
+
+gchar *gitg_js_utils_get_json (WebKitJavascriptResult *js_result);
+gboolean gitg_js_utils_check (WebKitJavascriptResult *js_result);
+
+#endif /* __GITG_JS_UTILS_H__ */
+
diff --git a/libgitg/resources/diff-view-html-builder.js b/libgitg/resources/diff-view-html-builder.js
index f4f3158..83f1a87 100644
--- a/libgitg/resources/diff-view-html-builder.js
+++ b/libgitg/resources/diff-view-html-builder.js
@@ -138,7 +138,7 @@ function diff_file(file, lnstate, data)
'FILE_PATH': file_path,
'FILE_BODY': file_body,
'FILE_STATS': file_stats,
- 'FILE_STAGE': lnstate.stagebutton,
+ 'FILE_FILENAME': file_path,
'FILE_CLASSES': file_classes
};
@@ -164,7 +164,7 @@ function diff_files(files, lines, maxlines, data)
'FILE_PATH',
'FILE_BODY',
'FILE_STATS',
- 'FILE_STAGE'
+ 'FILE_FILENAME',
'FILE_CLASSES'
];
@@ -172,7 +172,8 @@ function diff_files(files, lines, maxlines, data)
for (var r in repl)
{
- replacements[repl[r]] = new RegExp('<!-- \\$\\{' + repl[r] + '\\} -->', 'g');
+ var varspec = '\\$\\{' + repl[r] + '\\}';
+ replacements[repl[r]] = new RegExp('<!-- ' + varspec + ' -->|' + varspec, 'g');
}
var lnstate = {
@@ -182,28 +183,9 @@ function diff_files(files, lines, maxlines, data)
processed: 0,
nexttick: 0,
tickfreq: 0.01,
- stagebutton: '',
replacements: replacements,
};
- if (data.settings.staged || data.settings.unstaged)
- {
- var cls;
- var nm;
-
- if (data.settings.staged)
- {
- cls = 'unstage';
- nm = data.settings.strings.unstage;
- }
- else
- {
- cls = 'stage';
- nm = data.settings.strings.stage;
- }
-
- lnstate.stagebutton = '<span class="' + cls + '">' + nm + '</span>';
- }
// special empty background filler
f += diff_file({hunks: [null]}, lnstate, data);
diff --git a/libgitg/resources/diff-view.css b/libgitg/resources/diff-view.css
index 04e2d09..2104742 100644
--- a/libgitg/resources/diff-view.css
+++ b/libgitg/resources/diff-view.css
@@ -235,40 +235,6 @@ div.loading {
font-family: sans-serif;
}
-span.stage, span.unstage {
- border-radius: 3px;
- padding: 2px 5px 2px 5px;
- cursor: pointer;
- display: inline-block;
- vertical-align: middle;
- text-align: center;
- border: 1px solid #999;
- box-shadow: inset 1px 1px 1px 0px #fff;
- color: #333;
-}
-
-span.stage {
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ddffdd), color-stop(1,
#99dd99));
- text-shadow: 1px 1px #99ff99;
- border: 1px solid #6a6;
-}
-
-span.stage:hover {
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ddffdd), color-stop(1,
#bbddbb));
- border: 1px solid #6c6;
-}
-
-span.unstage {
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ffdddd), color-stop(1,
#dd9999));
- text-shadow: 1px 1px #ff9999;
- border: 1px solid #a66;
-}
-
-span.unstage:hover {
- background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ffdddd), color-stop(1,
#ddbbbb));
- border: 1px solid #c66;
-}
-
span.hunk_stats, span.file_path {
display: inline-block;
vertical-align: middle;
diff --git a/libgitg/resources/diff-view.html b/libgitg/resources/diff-view.html
index 91cb5cd..d8bd96f 100644
--- a/libgitg/resources/diff-view.html
+++ b/libgitg/resources/diff-view.html
@@ -31,7 +31,6 @@
<tr class="file_header">
<td colspan="3">
<span class="expander">-</span>
- <!-- ${FILE_STAGE} -->
<!-- ${FILE_STATS} -->
<span class="file_path"><!-- ${FILE_PATH} --></span>
</td>
diff --git a/libgitg/resources/diff-view.js b/libgitg/resources/diff-view.js
index 7b5b2e1..364e986 100644
--- a/libgitg/resources/diff-view.js
+++ b/libgitg/resources/diff-view.js
@@ -144,23 +144,150 @@ function expand_collapse()
expander.closest('tbody').toggleClass("collapsed");
}
+function next_element(elem)
+{
+ elem = elem.nextSibling;
+
+ while (elem != null && elem.nodeType != Node.ELEMENT_NODE)
+ {
+ elem = elem.nextSibling;
+ }
+
+ return elem;
+}
+
+function has_class(e, cls)
+{
+ return e.classList.contains(cls);
+}
+
+var has_selection = false;
+
+function update_has_selection()
+{
+ var selection = document.querySelectorAll('tr.added.selected, tr.removed.selected');
+ var hs = (selection.length != 0);
+
+ if (hs != has_selection)
+ {
+ has_selection = hs;
+
+ var v = has_selection ? "yes" : "no";
+
+ xhr_get('internal', {action: 'selection-changed', value: v});
+ }
+}
+
+function prepare_patchset(filediv)
+{
+ var elem = filediv.querySelector('tr.file_header');
+
+ elem = next_element(elem);
+
+ var patches = [];
+
+ var doffset = 0;
+
+ var a = "a".charCodeAt(0);
+ var r = "r".charCodeAt(0);
+
+ while (elem != null)
+ {
+ var e = elem;
+ elem = next_element(elem);
+
+ var added = has_class(e, 'added');
+ var removed = has_class(e, 'removed');
+
+ if (!added && !removed)
+ {
+ continue;
+ }
+
+ var selected = has_class(e, 'selected');
+ var offset = parseInt(e.getAttribute('data-offset'));
+ var length = parseInt(e.getAttribute('data-length'));
+
+ if (selected)
+ {
+ // [sign, old_offset, new_offset, length]
+ patches.push([added ? a : r, offset + doffset, offset, length]);
+
+ doffset += added ? -length : length;
+ }
+ else
+ {
+ doffset += added ? -length : length;
+ }
+ }
+
+ var filename = filediv.getAttribute('data-filename');
+ return [filename, patches];
+}
+
+function get_selection()
+{
+ var files = document.querySelectorAll('#diff_content div.file');
+ var ret = [];
+
+ for (var i = 0; i < files.length; i++)
+ {
+ ret.push(prepare_patchset(files[i]));
+ }
+
+ return ret;
+}
function stage_unstage_hunk()
{
- var addrm = $(this).nextUntil('tr.file_header, tr.hunk_header').filter('tr.added, tr.removed');
+ var elem = next_element(this);
- var unsel = $.grep(addrm, function(e) { return !$(e).hasClass('selected'); });
- addrm.removeClass('selected');
+ var hasunsel = false;
+ var lines = [];
- if (unsel.length != 0)
+ while (elem != null && !(has_class(elem, 'file_header') || has_class(elem, 'hunk_header')))
{
- addrm.addClass('selected');
+ if ((has_class(elem, 'added') || has_class(elem, 'removed')))
+ {
+ lines.push(elem);
+
+ if (!has_class(elem, 'selected'))
+ {
+ hasunsel = true;
+ }
+ }
+
+ elem = next_element(elem);
}
+
+ for (var i = 0; i < lines.length; i++)
+ {
+ if (hasunsel)
+ {
+ lines[i].classList.add('selected');
+ }
+ else
+ {
+ lines[i].classList.remove('selected');
+ }
+ }
+
+ update_has_selection();
}
function stage_unstage_line()
{
- $(this).toggleClass("selected");
+ if (has_class(this, 'selected'))
+ {
+ this.classList.remove('selected');
+ }
+ else
+ {
+ this.classList.add('selected');
+ }
+
+ update_has_selection();
+}
function xhr_get(action, data, onload)
{
@@ -255,8 +382,12 @@ function update_diff(id, lsettings)
content.html(event.data.diff_html);
$(".expander").click(expand_collapse);
- $("tr.hunk_header").click(stage_unstage_hunk);
- $("tr.added, tr.removed").click(stage_unstage_line);
+
+ if (settings.staged || settings.unstaged)
+ {
+ $("tr.hunk_header").click(stage_unstage_hunk);
+ $("tr.added, tr.removed").click(stage_unstage_line);
+ }
}
}
diff --git a/vapi/gitg-js-utils.vapi b/vapi/gitg-js-utils.vapi
new file mode 100644
index 0000000..d97d563
--- /dev/null
+++ b/vapi/gitg-js-utils.vapi
@@ -0,0 +1,6 @@
+[CCode(cprefix = "GitgJsUtils", lower_case_cprefix = "gitg_js_utils_", cheader_filename =
"libgitg/gitg-js-utils.h")]
+namespace GitgJsUtils
+{
+ public string get_json(WebKit.JavascriptResult result);
+ public bool check(WebKit.JavascriptResult result);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]