diff options
Diffstat (limited to '')
| -rw-r--r-- | cgit.css | 10 | ||||
| -rw-r--r-- | ui-ssdiff.c | 145 | 
2 files changed, 130 insertions, 25 deletions
| @@ -627,6 +627,11 @@ table.ssdiff td.add_dark {  	min-width: 50%;  } +table.ssdiff span.add { +	background: #cfc; +	font-weight: bold; +} +  table.ssdiff td.del {  	color: black;  	background: #fcc; @@ -639,6 +644,11 @@ table.ssdiff td.del_dark {  	min-width: 50%;  } +table.ssdiff span.del { +	background: #fcc; +	font-weight: bold; +} +  table.ssdiff td.changed {  	color: black;  	background: #ffc; diff --git a/ui-ssdiff.c b/ui-ssdiff.c index 5673642..408e620 100644 --- a/ui-ssdiff.c +++ b/ui-ssdiff.c @@ -15,6 +15,52 @@ struct deferred_lines {  static struct deferred_lines *deferred_old, *deferred_old_last;  static struct deferred_lines *deferred_new, *deferred_new_last; +static char *longest_common_subsequence(char *A, char *B) +{ +	int i, j, ri; +	int m = strlen(A); +	int n = strlen(B); +	int L[m + 1][n + 1]; +	int tmp1, tmp2; +	int lcs_length; +	char *result; + +	for (i = m; i >= 0; i--) { +		for (j = n; j >= 0; j--) { +			if (A[i] == '\0' || B[j] == '\0') { +				L[i][j] = 0; +			} else if (A[i] == B[j]) { +				L[i][j] = 1 + L[i + 1][j + 1]; +			} else { +				tmp1 = L[i + 1][j]; +				tmp2 = L[i][j + 1]; +				L[i][j] = (tmp1 > tmp2 ? tmp1 : tmp2); +			} +		} +	} + +	lcs_length = L[0][0]; +	result = xmalloc(lcs_length + 2); +	memset(result, 0, sizeof(*result) * (lcs_length + 2)); + +	ri = 0; +	i = 0; +	j = 0; +	while (i < m && j < n) { +		if (A[i] == B[j]) { +			result[ri] = A[i]; +			ri += 1; +			i += 1; +			j += 1; +		} else if (L[i + 1][j] >= L[i][j + 1]) { +			i += 1; +		} else { +			j += 1; +		} +	} +	return result; +} +  static int line_from_hunk(char *line, char type)  {  	char *buf1, *buf2; @@ -73,6 +119,17 @@ static char *replace_tabs(char *line)  	return result;  } +static int calc_deferred_lines(struct deferred_lines *start) +{ +	struct deferred_lines *item = start; +	int result = 0; +	while (item) { +		result += 1; +		item = item->next; +	} +	return result; +} +  static void deferred_old_add(char *line, int line_no)  {  	struct deferred_lines *item = xmalloc(sizeof(struct deferred_lines)); @@ -101,9 +158,45 @@ static void deferred_new_add(char *line, int line_no)  	}  } -static void print_ssdiff_line(char *class, int old_line_no, char *old_line, -			      int new_line_no, char *new_line) +static void print_part_with_lcs(char *class, char *line, char *lcs) +{ +	int line_len = strlen(line); +	int i, j; +	char c[2] = " "; +	int same = 1; + +	j = 0; +	for (i = 0; i < line_len; i++) { +		c[0] = line[i]; +		if (same) { +			if (line[i] == lcs[j]) +				j += 1; +			else { +				same = 0; +				htmlf("<span class='%s'>", class); +			} +		} else if (line[i] == lcs[j]) { +			same = 1; +			htmlf("</span>"); +			j += 1; +		} +		html_txt(c); +	} +} + +static void print_ssdiff_line(char *class, +			      int old_line_no, +			      char *old_line, +			      int new_line_no, +			      char *new_line, int individual_chars)  { +	char *lcs = NULL; +	if (old_line) +		old_line = replace_tabs(old_line + 1); +	if (new_line) +		new_line = replace_tabs(new_line + 1); +	if (individual_chars && old_line && new_line) +		lcs = longest_common_subsequence(old_line, new_line);  	html("<tr>");  	if (old_line_no > 0)  		htmlf("<td class='lineno'>%d</td><td class='%s'>", @@ -112,15 +205,14 @@ static void print_ssdiff_line(char *class, int old_line_no, char *old_line,  		htmlf("<td class='lineno'></td><td class='%s'>", class);  	else  		htmlf("<td class='lineno'></td><td class='%s_dark'>", class); -  	if (old_line) { -		old_line = replace_tabs(old_line + 1); -		html_txt(old_line); -		free(old_line); +		if (lcs) +			print_part_with_lcs("del", old_line, lcs); +		else +			html_txt(old_line);  	}  	html("</td>"); -  	if (new_line_no > 0)  		htmlf("<td class='lineno'>%d</td><td class='%s'>",  		      new_line_no, class); @@ -128,24 +220,29 @@ static void print_ssdiff_line(char *class, int old_line_no, char *old_line,  		htmlf("<td class='lineno'></td><td class='%s'>", class);  	else  		htmlf("<td class='lineno'></td><td class='%s_dark'>", class); -  	if (new_line) { -		new_line = replace_tabs(new_line + 1); -		html_txt(new_line); -		free(new_line); +		if (lcs) +			print_part_with_lcs("add", new_line, lcs); +		else +			html_txt(new_line);  	}  	html("</td></tr>"); +	if (lcs) +		free(lcs); +	if (new_line) +		free(new_line); +	if (old_line) +		free(old_line);  }  static void print_deferred_old_lines()  {  	struct deferred_lines *iter_old, *tmp; -  	iter_old = deferred_old;  	while (iter_old) {  		print_ssdiff_line("del", iter_old->line_no, -				  iter_old->line, -1, NULL); +				  iter_old->line, -1, NULL, 0);  		tmp = iter_old->next;  		free(iter_old);  		iter_old = tmp; @@ -155,11 +252,10 @@ static void print_deferred_old_lines()  static void print_deferred_new_lines()  {  	struct deferred_lines *iter_new, *tmp; -  	iter_new = deferred_new;  	while (iter_new) { -		print_ssdiff_line("add", -1, NULL, iter_new->line_no, -				  iter_new->line); +		print_ssdiff_line("add", -1, NULL, +				  iter_new->line_no, iter_new->line, 0);  		tmp = iter_new->next;  		free(iter_new);  		iter_new = tmp; @@ -169,6 +265,9 @@ static void print_deferred_new_lines()  static void print_deferred_changed_lines()  {  	struct deferred_lines *iter_old, *iter_new, *tmp; +	int n_old_lines = calc_deferred_lines(deferred_old); +	int n_new_lines = calc_deferred_lines(deferred_new); +	int individual_chars = (n_old_lines == n_new_lines ? 1 : 0);  	iter_old = deferred_old;  	iter_new = deferred_new; @@ -176,14 +275,14 @@ static void print_deferred_changed_lines()  		if (iter_old && iter_new)  			print_ssdiff_line("changed", iter_old->line_no,  					  iter_old->line, -					  iter_new->line_no, iter_new->line); +					  iter_new->line_no, iter_new->line, +					  individual_chars);  		else if (iter_old)  			print_ssdiff_line("changed", iter_old->line_no, -					  iter_old->line, -1, NULL); +					  iter_old->line, -1, NULL, 0);  		else if (iter_new)  			print_ssdiff_line("changed", -1, NULL, -					  iter_new->line_no, iter_new->line); - +					  iter_new->line_no, iter_new->line, 0);  		if (iter_old) {  			tmp = iter_old->next;  			free(iter_old); @@ -202,14 +301,12 @@ void cgit_ssdiff_print_deferred_lines()  {  	if (!deferred_old && !deferred_new)  		return; -  	if (deferred_old && !deferred_new)  		print_deferred_old_lines();  	else if (!deferred_old && deferred_new)  		print_deferred_new_lines();  	else  		print_deferred_changed_lines(); -  	deferred_old = deferred_old_last = NULL;  	deferred_new = deferred_new_last = NULL;  } @@ -220,9 +317,7 @@ void cgit_ssdiff_print_deferred_lines()  void cgit_ssdiff_line_cb(char *line, int len)  {  	char c = line[len - 1]; -  	line[len - 1] = '\0'; -  	if (line[0] == '@') {  		current_old_line = line_from_hunk(line, '-');  		current_new_line = line_from_hunk(line, '+'); @@ -232,7 +327,7 @@ void cgit_ssdiff_line_cb(char *line, int len)  		if (deferred_old || deferred_new)  			cgit_ssdiff_print_deferred_lines();  		print_ssdiff_line("ctx", current_old_line, line, -				  current_new_line, line); +				  current_new_line, line, 0);  		current_old_line += 1;  		current_new_line += 1;  	} else if (line[0] == '+') { | 
