1/* 2 * This file is part of gitg 3 * 4 * Copyright (C) 2015 - Jesse van den Kieboom 5 * 6 * gitg is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * gitg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with gitg. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20class Gitg.DiffViewLinesRenderer : Gtk.SourceGutterRendererText 21{ 22 public enum Style 23 { 24 OLD, 25 NEW, 26 SYMBOL 27 } 28 29 private int d_num_digits; 30 private string d_num_digits_fill; 31 32 private ulong d_view_style_updated_id; 33 34 private struct HunkInfo 35 { 36 int start; 37 int end; 38 int hunk_line; 39 Ggit.DiffHunk hunk; 40 string[] line_infos; 41 } 42 43 private Gee.ArrayList<HunkInfo?> d_hunks_list; 44 45 public Style style 46 { 47 get; construct set; 48 } 49 50 private int d_maxlines; 51 52 public int maxlines 53 { 54 get { return d_maxlines; } 55 set 56 { 57 if (value > d_maxlines) 58 { 59 d_maxlines = value; 60 61 calculate_num_digits(); 62 recalculate_size(); 63 } 64 } 65 } 66 67 public DiffViewLinesRenderer(Style style) 68 { 69 Object(style: style); 70 } 71 72 construct 73 { 74 d_hunks_list = new Gee.ArrayList<HunkInfo?>(); 75 76 set_alignment(1.0f, 0.5f); 77 calculate_num_digits(); 78 } 79 80 protected Gtk.TextBuffer buffer 81 { 82 get { return get_view().buffer; } 83 } 84 85 protected override void query_data(Gtk.TextIter start, Gtk.TextIter end, Gtk.SourceGutterRendererState state) 86 { 87 var line = start.get_line(); 88 bool is_hunk = false; 89 HunkInfo? info = null; 90 91 foreach (var i in d_hunks_list) 92 { 93 if (line == i.hunk_line) 94 { 95 is_hunk = true; 96 break; 97 } 98 else if (line >= i.start && line <= i.end) 99 { 100 info = i; 101 break; 102 } 103 } 104 105 if (info == null || (line - info.start) >= info.line_infos.length) 106 { 107 if (is_hunk && style != Style.SYMBOL) 108 { 109 set_text("...", -1); 110 } 111 else 112 { 113 set_text("", -1); 114 } 115 } 116 else 117 { 118 set_text(info.line_infos[start.get_line() - info.start], -1); 119 } 120 } 121 122 private void on_view_style_updated() 123 { 124 recalculate_size(); 125 } 126 127 protected override void change_view(Gtk.TextView? old_view) 128 { 129 if (old_view != null) 130 { 131 old_view.disconnect(d_view_style_updated_id); 132 d_view_style_updated_id = 0; 133 } 134 135 var view = get_view(); 136 137 if (view != null) 138 { 139 d_view_style_updated_id = view.style_updated.connect(on_view_style_updated); 140 recalculate_size(); 141 } 142 143 base.change_view(old_view); 144 } 145 146 private void recalculate_size() 147 { 148 int size = 0; 149 int height = 0; 150 151 measure(@"$d_num_digits_fill", out size, out height); 152 set_size(size); 153 } 154 155 private void calculate_num_digits() 156 { 157 int num_digits; 158 159 if (style == Style.OLD || style == Style.NEW) 160 { 161 num_digits = 3; 162 163 foreach (var info in d_hunks_list) 164 { 165 var oldn = info.hunk.get_old_start() + info.hunk.get_old_lines(); 166 var newn = info.hunk.get_new_start() + info.hunk.get_new_lines(); 167 168 var num = int.max(int.max(oldn, newn), d_maxlines); 169 170 var hunk_digits = 0; 171 while (num > 0) 172 { 173 ++hunk_digits; 174 num /= 10; 175 } 176 177 num_digits = int.max(num_digits, hunk_digits); 178 } 179 } 180 else 181 { 182 num_digits = 1; 183 } 184 185 d_num_digits = num_digits; 186 d_num_digits_fill = string.nfill(num_digits, ' '); 187 } 188 189 private string[] precalculate_line_strings(Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines) 190 { 191 var oldn = hunk.get_old_start(); 192 var newn = hunk.get_new_start(); 193 194 var lns = lines; 195 196 var line_infos = new string[lns.size]; 197 198 for (var i = 0; i < lns.size; i++) 199 { 200 var line = lns[i]; 201 var origin = line.get_origin(); 202 203 string ltext = ""; 204 205 switch (style) 206 { 207 case Style.NEW: 208 if (origin == Ggit.DiffLineType.CONTEXT || origin == Ggit.DiffLineType.ADDITION) 209 { 210 ltext = "%*d".printf(d_num_digits, newn); 211 newn++; 212 } 213 break; 214 case Style.OLD: 215 if (origin == Ggit.DiffLineType.CONTEXT || origin == Ggit.DiffLineType.DELETION) 216 { 217 ltext = "%*d".printf(d_num_digits, oldn); 218 oldn++; 219 } 220 break; 221 case Style.SYMBOL: 222 if (origin == Ggit.DiffLineType.ADDITION) 223 { 224 ltext = "+"; 225 } 226 else if (origin == Ggit.DiffLineType.DELETION) 227 { 228 ltext = "-"; 229 } 230 break; 231 } 232 233 line_infos[i] = ltext; 234 } 235 236 return line_infos; 237 } 238 239 public void add_hunk(int buffer_line_start, int buffer_line_end, Ggit.DiffHunk hunk, Gee.ArrayList<Ggit.DiffLine> lines) 240 { 241 HunkInfo info = HunkInfo(); 242 243 calculate_num_digits(); 244 245 info.start = buffer_line_start; 246 info.end = buffer_line_end; 247 info.hunk_line = buffer_line_start - 1; 248 info.hunk = hunk; 249 info.line_infos = precalculate_line_strings(hunk, lines); 250 251 d_hunks_list.add(info); 252 253 recalculate_size(); 254 } 255} 256 257// ex:ts=4 noet 258