Skip to content

Commit

Permalink
Added word-diff=plain colorizing support
Browse files Browse the repository at this point in the history
Added ADD and DEL colors for {+added+} and [-removed-] blocks of git word-diff=plain

Since git does not escape the delimiters and splits them by line, this code would sometimes end up with an incorrect highlighting.

The solution scans DEFAULT lines of the diff chunk and and adds colored cells. Since git (unlike wdiff) does not use multi-line word-diff, it works.
  • Loading branch information
dvalter committed Nov 11, 2019
1 parent 6642c11 commit 4028a49
Showing 1 changed file with 77 additions and 1 deletion.
78 changes: 77 additions & 1 deletion src/diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,79 @@ diff_common_add_diff_stat(struct view *view, const char *text, size_t offset)
return NULL;
}

static bool
diff_common_read_diff_wdiff_group(struct diff_stat_context *context)
{
const char *sep_add = strstr(context->text, "{+");
const char *sep_del = strstr(context->text, "[-");

if (sep_add == NULL && sep_del == NULL)
return false;

const char * sep;
enum line_type next_type;
const char* end_delimiter;

if (sep_del == NULL || (sep_add != NULL && sep_add < sep_del)) {
sep = sep_add;
next_type = LINE_DIFF_ADD;
end_delimiter = "+}";
} else {
sep = sep_del;
next_type = LINE_DIFF_DEL;
end_delimiter = "-]";
}

diff_common_add_cell(context, sep - context->text, false);

context->type = next_type;
context->text = sep;

// workaround for a single }/] change
const char* end_sep = strstr(context->text + sizeof("{+") - 1, end_delimiter);

size_t len;
if (end_sep == NULL) {
// diff is not terminated
len = strlen(context->text);
} else {
// separators are included in the add/del highlight
len = end_sep - context->text + sizeof("+}") - 1;
}

diff_common_add_cell(context, len, false);

if (end_sep == NULL) {
context->text += len;
} else {
context->text = end_sep + sizeof("+}") - 1;
}
context->type = LINE_DEFAULT;

return true;
}

static struct line *
diff_common_read_diff_wdiff(struct view *view, const char *text)
{
struct diff_stat_context context = { text, LINE_DEFAULT };


/* Detect remaining part of a word diff line:
*
* added {+new +} text
* removed[- something -] from the file
* replaced [-some-]{+same+} text
* there could be [-one-] diff part{+s+} in the {+any +} line
*/

while (diff_common_read_diff_wdiff_group(&context));

diff_common_add_cell(&context, strlen(context.text), false);

return diff_common_add_line(view, text, LINE_DEFAULT, &context);
}

static bool
diff_common_highlight(struct view *view, const char *text, enum line_type type)
{
Expand Down Expand Up @@ -270,7 +343,10 @@ diff_common_read(struct view *view, const char *data, struct diff_state *state)
return line != NULL;
}

if (type == LINE_DIFF_HEADER) {
if (state->reading_diff_chunk && type == LINE_DEFAULT) {
if (diff_common_read_diff_wdiff(view, data))
return true;
} else if (type == LINE_DIFF_HEADER) {
state->after_diff = true;
state->reading_diff_chunk = false;

Expand Down

0 comments on commit 4028a49

Please sign in to comment.