gitg/libgitg-gtk/gitg-gtk-diff-view-request-diff.vala

365 lines
8.6 KiB
Vala
Raw Normal View History

/*
* This file is part of gitg
*
* Copyright (C) 2012 - Jesse van den Kieboom
*
* gitg is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* gitg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with gitg. If not, see <http://www.gnu.org/licenses/>.
*/
namespace GitgGtk
{
class DiffViewRequestDiff : DiffViewRequest
{
private enum DiffType
{
DEFAULT,
DIFF_ONLY,
COMMIT_ONLY,
}
private DiffType d_diff_type;
private Ggit.Diff? d_diff;
private Ggit.Commit? d_commit;
public DiffViewRequestDiff(DiffView? view, WebKit.URISchemeRequest request, Soup.URI uri)
{
base(view, request, uri);
d_mimetype = "application/json";
d_diff_type = DiffType.DEFAULT;
if (has_view)
{
d_commit = d_view.commit;
d_diff = d_view.diff;
}
var format = parameter("format");
switch (format)
{
case "diff_only":
d_diff_type = DiffType.DIFF_ONLY;
break;
case "commit_only":
d_diff_type = DiffType.COMMIT_ONLY;
break;
}
}
private void file_to_json(Json.Builder builder, Ggit.DiffFile file)
{
builder.begin_object();
{
builder.set_member_name("path").add_string_value(file.get_path());
builder.set_member_name("mode").add_int_value(file.get_mode());
builder.set_member_name("size").add_int_value(file.get_size());
builder.set_member_name("flags").add_int_value(file.get_flags());
}
builder.end_object();
}
private void range_to_json(Json.Builder builder, int start, int lines)
{
builder.begin_object();
{
builder.set_member_name("start").add_int_value(start);
builder.set_member_name("lines").add_int_value(lines);
}
builder.end_object();
}
private class DiffState
{
public bool in_file;
public bool in_hunk;
}
private void file_cb(Json.Builder builder,
DiffState state,
Ggit.DiffDelta delta,
float progress)
{
if (state.in_hunk)
{
builder.end_array();
builder.end_object();
state.in_hunk = false;
}
if (state.in_file)
{
builder.end_array();
builder.end_object();
state.in_file = false;
}
builder.begin_object();
builder.set_member_name("file");
builder.begin_object();
{
file_to_json(builder.set_member_name("old"), delta.get_old_file());
file_to_json(builder.set_member_name("new"), delta.get_new_file());
}
builder.end_object();
builder.set_member_name("status").add_int_value(delta.get_status());
builder.set_member_name("similarity").add_int_value(delta.get_similarity());
builder.set_member_name("binary").add_int_value((int64)((delta.get_flags() & Ggit.DiffFlag.NOT_BINARY) == 0));
builder.set_member_name("hunks").begin_array();
state.in_file = true;
}
private void hunk_cb(Json.Builder builder,
DiffState state,
Ggit.DiffDelta delta,
Ggit.DiffRange range,
string header)
{
if (state.in_hunk)
{
builder.end_array();
builder.end_object();
state.in_hunk = false;
}
builder.begin_object();
builder.set_member_name("range");
builder.begin_object();
{
range_to_json(builder.set_member_name("old"),
range.get_old_start(),
range.get_old_lines());
range_to_json(builder.set_member_name("new"),
range.get_new_start(),
range.get_new_lines());
}
builder.end_object();
builder.set_member_name("header").add_string_value(header);
builder.set_member_name("lines");
builder.begin_array();
state.in_hunk = true;
}
private void line_cb(Json.Builder builder,
Ggit.DiffDelta delta,
Ggit.DiffRange range,
Ggit.DiffLineType line_type,
string content)
{
builder.begin_object();
{
builder.set_member_name("type").add_int_value(line_type);
builder.set_member_name("content").add_string_value(content);
}
builder.end_object();
}
private void signature_to_json(Json.Builder builder, Ggit.Signature sig)
{
builder.begin_object();
builder.set_member_name("name");
builder.add_string_value(sig.get_name());
builder.set_member_name("email");
builder.add_string_value(sig.get_email());
2012-07-11 12:04:05 +00:00
builder.set_member_name("email_md5");
builder.add_string_value(Checksum.compute_for_string(ChecksumType.MD5, sig.get_email()));
builder.set_member_name("time");
builder.add_int_value(sig.get_time().to_unix());
builder.end_object();
}
private void commit_to_json(Json.Builder builder, Ggit.Commit commit)
{
builder.begin_object();
builder.set_member_name("id");
builder.add_string_value(commit.get_id().to_string());
builder.set_member_name("subject");
builder.add_string_value(commit.get_subject());
builder.set_member_name("message");
builder.add_string_value(commit.get_message());
builder.set_member_name("committer");
signature_to_json(builder, commit.get_committer());
builder.set_member_name("author");
signature_to_json(builder, commit.get_author());
builder.end_object();
}
private void build_diff(Ggit.Diff? diff, Json.Builder builder, Cancellable? cancellable) throws GLib.Error
{
DiffState state = new DiffState();
builder.set_member_name("diff").begin_array();
int64 numlines = 0;
2013-03-02 13:29:08 +00:00
int64 maxlines = 0;
diff.foreach(
(delta, progress) => {
if (cancellable != null && cancellable.is_cancelled())
{
return 1;
}
file_cb(builder, state, delta, progress);
return 0;
},
(delta, range, header) => {
if (cancellable != null && cancellable.is_cancelled())
{
return 1;
}
2013-03-02 13:29:08 +00:00
var maxold = range.get_old_start() + range.get_old_lines();
var maxnew = range.get_new_start() + range.get_new_lines();
var ml = int64.max(maxold, maxnew);
if (ml > maxlines)
{
maxlines = ml;
}
hunk_cb(builder, state, delta, range, ((string)header).substring(0, header.length));
return 0;
},
(delta, range, line_type, content) => {
if (cancellable != null && cancellable.is_cancelled())
{
return 1;
}
if ((delta.get_flags() & Ggit.DiffFlag.NOT_BINARY) == 0)
{
++numlines;
2013-03-02 13:29:08 +00:00
line_cb(builder, delta, range, line_type, ((string)content).substring(0, content.length));
}
return 0;
}
);
if (cancellable != null && cancellable.is_cancelled())
{
throw new IOError.CANCELLED("Cancelled");
}
if (state.in_hunk)
{
builder.end_array();
builder.end_object();
}
if (state.in_file)
{
builder.end_array();
builder.end_object();
}
builder.end_array();
builder.set_member_name("lines").add_int_value(numlines);
2013-03-02 13:29:08 +00:00
builder.set_member_name("maxlines").add_int_value(maxlines);
}
private void build_commit(Ggit.Diff? diff, Json.Builder builder, Cancellable? cancellable)
{
builder.set_member_name("commit");
commit_to_json(builder, d_commit);
}
private InputStream? run_diff(Ggit.Diff? diff, Cancellable? cancellable) throws GLib.Error
{
if (diff == null)
{
return null;
}
// create memory output stream
var builder = new Json.Builder();
builder.begin_object();
if (d_commit != null && d_diff_type != DiffType.DIFF_ONLY)
{
build_commit(diff, builder, cancellable);
}
if (d_diff_type != DiffType.COMMIT_ONLY)
{
build_diff(diff, builder, cancellable);
}
builder.end_object();
var gen = new Json.Generator();
gen.set_root(builder.get_root());
var stream = new MemoryOutputStream(null, realloc, free);
gen.to_stream(stream, cancellable);
if (cancellable != null && cancellable.is_cancelled())
{
throw new IOError.CANCELLED("Cancelled");
}
stream.close();
uint8[] data = stream.steal_data();
d_size = stream.get_data_size();
data = data[0:d_size];
return new MemoryInputStream.from_data(data, stream.destroy_function);
}
public override InputStream? run_async(Cancellable? cancellable) throws GLib.Error
{
if (!has_view)
{
throw new IOError.NOT_FOUND("Could not find diff view with corresponding id");
}
return run_diff(d_diff, cancellable);
}
}
}
// vi:ts=4