neocgit

a more 'modern' version of cgit
Log | Files | Refs | Submodules | README | LICENSE | git clone https://git.ne02ptzero.me/git/neocgit

ui-refs.c (5732B)


      1 /* ui-refs.c: browse symbolic refs
      2  *
      3  * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
      4  *
      5  * Licensed under GNU General Public License v2
      6  *   (see COPYING for full license text)
      7  */
      8 
      9 #include "cgit.h"
     10 #include "ui-refs.h"
     11 #include "html.h"
     12 #include "ui-shared.h"
     13 
     14 static inline int cmp_age(int age1, int age2)
     15 {
     16 	/* age1 and age2 are assumed to be non-negative */
     17 	return age2 - age1;
     18 }
     19 
     20 static int cmp_ref_name(const void *a, const void *b)
     21 {
     22 	struct refinfo *r1 = *(struct refinfo **)a;
     23 	struct refinfo *r2 = *(struct refinfo **)b;
     24 
     25 	return strcmp(r1->refname, r2->refname);
     26 }
     27 
     28 static int cmp_branch_age(const void *a, const void *b)
     29 {
     30 	struct refinfo *r1 = *(struct refinfo **)a;
     31 	struct refinfo *r2 = *(struct refinfo **)b;
     32 
     33 	return cmp_age(r1->commit->committer_date, r2->commit->committer_date);
     34 }
     35 
     36 static int get_ref_age(struct refinfo *ref)
     37 {
     38 	if (!ref->object)
     39 		return 0;
     40 	switch (ref->object->type) {
     41 	case OBJ_TAG:
     42 		return ref->tag ? ref->tag->tagger_date : 0;
     43 	case OBJ_COMMIT:
     44 		return ref->commit ? ref->commit->committer_date : 0;
     45 	}
     46 	return 0;
     47 }
     48 
     49 static int cmp_tag_age(const void *a, const void *b)
     50 {
     51 	struct refinfo *r1 = *(struct refinfo **)a;
     52 	struct refinfo *r2 = *(struct refinfo **)b;
     53 
     54 	return cmp_age(get_ref_age(r1), get_ref_age(r2));
     55 }
     56 
     57 static int print_branch(struct refinfo *ref)
     58 {
     59 	struct commitinfo *info = ref->commit;
     60 	char *name = (char *)ref->refname;
     61 
     62 	if (!info)
     63 		return 1;
     64 	html("<tr><td>");
     65 	cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL,
     66 		      ctx.qry.showmsg, 0);
     67 	html("</td><td>");
     68 
     69 	if (ref->object->type == OBJ_COMMIT) {
     70 		cgit_commit_link(info->subject, NULL, NULL, name, NULL, NULL);
     71 		html("</td><td>");
     72 		cgit_open_filter(ctx.repo->email_filter, info->author_email, "refs");
     73 		html_txt(info->author);
     74 		cgit_close_filter(ctx.repo->email_filter);
     75 		html("</td><td colspan='2'>");
     76 		cgit_print_age(info->committer_date, info->committer_tz, -1);
     77 	} else {
     78 		html("</td><td></td><td>");
     79 		cgit_object_link(ref->object);
     80 	}
     81 	html("</td></tr>\n");
     82 	return 0;
     83 }
     84 
     85 static void print_tag_header(void)
     86 {
     87 	html("<tr class='nohover'><th class='left'>Tag</th>"
     88 	     "<th class='left'>Download</th>"
     89 	     "<th class='left'>Author</th>"
     90 	     "<th class='left' colspan='2'>Age</th></tr>\n");
     91 }
     92 
     93 static int print_tag(struct refinfo *ref)
     94 {
     95 	struct tag *tag = NULL;
     96 	struct taginfo *info = NULL;
     97 	char *name = (char *)ref->refname;
     98 	struct object *obj = ref->object;
     99 
    100 	if (obj->type == OBJ_TAG) {
    101 		tag = (struct tag *)obj;
    102 		obj = tag->tagged;
    103 		info = ref->tag;
    104 		if (!info)
    105 			return 1;
    106 	}
    107 
    108 	html("<tr><td>");
    109 	cgit_tag_link(name, NULL, NULL, name);
    110 	html("</td><td>");
    111 	if (ctx.repo->snapshots && (obj->type == OBJ_COMMIT))
    112 		cgit_print_snapshot_links(ctx.repo, name, "&nbsp;&nbsp;");
    113 	else
    114 		cgit_object_link(obj);
    115 	html("</td><td>");
    116 	if (info) {
    117 		if (info->tagger) {
    118 			cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "refs");
    119 			html_txt(info->tagger);
    120 			cgit_close_filter(ctx.repo->email_filter);
    121 		}
    122 	} else if (ref->object->type == OBJ_COMMIT) {
    123 		cgit_open_filter(ctx.repo->email_filter, ref->commit->author_email, "refs");
    124 		html_txt(ref->commit->author);
    125 		cgit_close_filter(ctx.repo->email_filter);
    126 	}
    127 	html("</td><td colspan='2'>");
    128 	if (info) {
    129 		if (info->tagger_date > 0)
    130 			cgit_print_age(info->tagger_date, info->tagger_tz, -1);
    131 	} else if (ref->object->type == OBJ_COMMIT) {
    132 		cgit_print_age(ref->commit->commit->date, 0, -1);
    133 	}
    134 	html("</td></tr>\n");
    135 
    136 	return 0;
    137 }
    138 
    139 static void print_refs_link(char *path)
    140 {
    141 	html("<tr class='nohover'><td colspan='5'>");
    142 	cgit_refs_link("[...]", NULL, NULL, ctx.qry.head, NULL, path);
    143 	html("</td></tr>");
    144 }
    145 
    146 int cgit_count_branches(void)
    147 {
    148     struct reflist      list = { 0 };
    149 
    150     for_each_branch_ref(cgit_refs_cb, &list);
    151     return list.count;
    152 }
    153 
    154 void cgit_print_branches(int maxcount)
    155 {
    156 	struct reflist list;
    157 	int i;
    158 
    159 	html("<tr class='nohover'><th class='left'>Branch</th>"
    160 	     "<th class='left'>Commit message</th>"
    161 	     "<th class='left'>Author</th>"
    162 	     "<th class='left' colspan='2'>Age</th></tr>\n");
    163 
    164 	list.refs = NULL;
    165 	list.alloc = list.count = 0;
    166 	for_each_branch_ref(cgit_refs_cb, &list);
    167 	if (ctx.repo->enable_remote_branches)
    168 		for_each_remote_ref(cgit_refs_cb, &list);
    169 
    170 	if (maxcount == 0 || maxcount > list.count)
    171 		maxcount = list.count;
    172 
    173 	qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age);
    174 	if (ctx.repo->branch_sort == 0)
    175 		qsort(list.refs, maxcount, sizeof(*list.refs), cmp_ref_name);
    176 
    177 	for (i = 0; i < maxcount; i++)
    178 		print_branch(list.refs[i]);
    179 
    180 	if (maxcount < list.count)
    181 		print_refs_link("heads");
    182 
    183 	cgit_free_reflist_inner(&list);
    184 }
    185 
    186 void cgit_print_tags(int maxcount)
    187 {
    188 	struct reflist list;
    189 	int i;
    190 
    191 	list.refs = NULL;
    192 	list.alloc = list.count = 0;
    193 	for_each_tag_ref(cgit_refs_cb, &list);
    194 	if (list.count == 0)
    195 		return;
    196 	qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age);
    197 	if (!maxcount)
    198 		maxcount = list.count;
    199 	else if (maxcount > list.count)
    200 		maxcount = list.count;
    201 	print_tag_header();
    202 	for (i = 0; i < maxcount; i++)
    203 		print_tag(list.refs[i]);
    204 
    205 	if (maxcount < list.count)
    206 		print_refs_link("tags");
    207 
    208 	cgit_free_reflist_inner(&list);
    209 }
    210 
    211 int cgit_count_tags(void)
    212 {
    213     struct reflist      list = { 0 };
    214 
    215     for_each_tag_ref(cgit_refs_cb, &list);
    216     return list.count;
    217 }
    218 
    219 void cgit_print_refs(void)
    220 {
    221 	cgit_print_layout_start();
    222 	html("<table class='list nowrap'>");
    223 
    224 	if (ctx.qry.path && starts_with(ctx.qry.path, "heads"))
    225 		cgit_print_branches(0);
    226 	else if (ctx.qry.path && starts_with(ctx.qry.path, "tags"))
    227 		cgit_print_tags(0);
    228 	else {
    229 		cgit_print_branches(0);
    230 		html("<tr class='nohover'><td colspan='5'>&nbsp;</td></tr>");
    231 		cgit_print_tags(0);
    232 	}
    233 	html("</table>");
    234 	cgit_print_layout_end();
    235 }