Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support delta along with ANSI support #1140

Closed
wants to merge 19 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"editor.tabSize": 8,
"editor.insertSpaces": false,
"files.associations": {
"*.h": "c"
}
}
This conversation was marked as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,7 @@ TIG_OBJS = \
src/grep.o \
src/ui.o \
src/apps.o \
src/ansi.o \
$(GRAPH_OBJS) \
$(COMPAT_OBJS)

Expand Down
2 changes: 1 addition & 1 deletion doc/tigrc.5.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ The following variables can be set:
to false. When set to true then 'diff-highlight' is used, else the option
value is used as the path. When this option is in effect, highlighted
regions are governed by `color diff-add-highlight` and
`color diff-del-highlight`.
`color diff-del-highlight`. git-delta is also supported.

'ignore-space' (mixed) [no|all|some|at-eol|<bool>]::

Expand Down
34 changes: 34 additions & 0 deletions include/tig/ansi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/* Copyright (c) 2006-2015 Jonas Fonseca <[email protected]>
*
* This program 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.
*
* This program 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.
*/

#ifndef TIG_ANSI_H
#define TIG_ANSI_H

#include "tig/line.h"
#include "tig/tig.h"
#include "tig/view.h"

struct ansi_status {
short fg;
short bg;
unsigned int attr;
};

void split_ansi(const char *string, int *ansi_num, char **ansi_ptrs);
void draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs);
void draw_ansi_line(struct view *view, char *text, int len);
void wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status);

#endif

/* vim: set ts=8 sw=8 noexpandtab: */
2 changes: 2 additions & 0 deletions include/tig/line.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "tig/tig.h"
struct ref;

extern short color_pairs_map[256][256];

/*
* Line-oriented content detection.
*/
Expand Down
181 changes: 181 additions & 0 deletions src/ansi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/* Copyright (c) 2006-2015 Jonas Fonseca <[email protected]>
*
* This program 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.
*
* This program 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.
*/

#include "tig/ansi.h"
#include "tig/draw.h"
#include "tig/line.h"
#include "tig/tig.h"
#include "tig/view.h"

void
split_ansi(const char *string, int *ansi_num, char **ansi_ptrs) {
char *head_of_ansi = "\033[";
int current_ansi_idx = 0;
char *next_ansi_ptr = strstr(string + current_ansi_idx, head_of_ansi);

if (next_ansi_ptr == NULL)
return;
while (next_ansi_ptr != NULL) {
if (strcmp(string, next_ansi_ptr) == 0) {
next_ansi_ptr = strstr(string + current_ansi_idx + strlen(head_of_ansi), head_of_ansi);
continue;
}
int current_ansi_length = strlen(string + current_ansi_idx) - strlen(next_ansi_ptr);
strncpy(ansi_ptrs[*ansi_num], string + current_ansi_idx, current_ansi_length);
ansi_ptrs[*ansi_num][current_ansi_length] = '\0';
*ansi_num += 1;
current_ansi_idx += current_ansi_length / sizeof(char);
next_ansi_ptr = strstr(string + current_ansi_idx + strlen(head_of_ansi), head_of_ansi);
}

strcpy(ansi_ptrs[*ansi_num], string + current_ansi_idx);
*ansi_num += 1;
}

void
draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs) {
static struct ansi_status cur_ansi_status;
cur_ansi_status.fg = COLOR_WHITE;
cur_ansi_status.bg = COLOR_BLACK;
cur_ansi_status.attr = A_NORMAL;

for (int i = 0; i < *ansi_num; i++) {
int len = strlen(ansi_ptrs[i]);
char text[len + 1];
strcpy(text, ansi_ptrs[i]);

if (i == 0 && text[0] != '\033') {
waddnstr(view->win, text, len);
continue;
}
// delta won't add moving ansi codes which are
// A, B, C, D, E, F, G, H, f, S, T.
// J, K exists for filling lines with a color, but ncurses can't do.
if ((text[3] == 'J') || (text[3] == 'K'))
continue;

char *ansi_end_ptr = strchr(text, 'm');
int after_ansi_len = strlen(ansi_end_ptr);
int ansi_code_len = len - after_ansi_len - 2;
char *ansi_code = malloc(sizeof(char) * (ansi_code_len + 1));
strncpy(ansi_code, text + 2, ansi_code_len);
ansi_code[ansi_code_len] = '\0';
ansi_end_ptr += 1;

if (strchr(ansi_code, ';') == NULL) {
if (strcmp(ansi_code, "0") == 0)
cur_ansi_status.attr = A_NORMAL;
if (strcmp(ansi_code, "1") == 0)
cur_ansi_status.attr = A_BOLD;
if (strcmp(ansi_code, "2") == 0)
cur_ansi_status.attr = A_DIM;
if (strcmp(ansi_code, "3") == 0)
cur_ansi_status.attr = A_ITALIC;
if (strcmp(ansi_code, "4") == 0)
cur_ansi_status.attr = A_UNDERLINE;
if (strcmp(ansi_code, "5") == 0)
cur_ansi_status.attr = A_BLINK;
if (strcmp(ansi_code, "6") == 0)
cur_ansi_status.attr = A_BLINK; // This is supposed to be faster than normal blink, but ncurses doesn't have any way to achieve.
if (strcmp(ansi_code, "7") == 0)
cur_ansi_status.attr = A_REVERSE;
if (strcmp(ansi_code, "8") == 0)
cur_ansi_status.attr = A_INVIS;
if (strcmp(ansi_code, "9") == 0)
// This is supposed to be strikethrough, but ncurses doesn't have any way to achieve.
if (strcmp(ansi_code, "30") == 0)
cur_ansi_status.fg = COLOR_BLACK;
if (strcmp(ansi_code, "31") == 0)
cur_ansi_status.fg = COLOR_RED;
if (strcmp(ansi_code, "32") == 0)
cur_ansi_status.fg = COLOR_GREEN;
if (strcmp(ansi_code, "33") == 0)
cur_ansi_status.fg = COLOR_YELLOW;
if (strcmp(ansi_code, "34") == 0)
cur_ansi_status.fg = COLOR_BLUE;
if (strcmp(ansi_code, "35") == 0)
cur_ansi_status.fg = COLOR_MAGENTA;
if (strcmp(ansi_code, "36") == 0)
cur_ansi_status.fg = COLOR_CYAN;
if (strcmp(ansi_code, "37") == 0)
cur_ansi_status.fg = COLOR_WHITE;
if (strcmp(ansi_code, "40") == 0)
cur_ansi_status.bg = COLOR_BLACK;
if (strcmp(ansi_code, "41") == 0)
cur_ansi_status.bg = COLOR_RED;
if (strcmp(ansi_code, "42") == 0)
cur_ansi_status.bg = COLOR_GREEN;
if (strcmp(ansi_code, "43") == 0)
cur_ansi_status.bg = COLOR_YELLOW;
if (strcmp(ansi_code, "44") == 0)
cur_ansi_status.bg = COLOR_BLUE;
if (strcmp(ansi_code, "45") == 0)
cur_ansi_status.bg = COLOR_MAGENTA;
if (strcmp(ansi_code, "46") == 0)
cur_ansi_status.bg = COLOR_CYAN;
if (strcmp(ansi_code, "47") == 0)
cur_ansi_status.bg = COLOR_WHITE;
} else {
char *token = malloc(sizeof(char) * (ansi_code_len + 1));
strcpy(token, ansi_code);
char *ansi_code_part = strtok(token, ";");

while (ansi_code_part != NULL) {
char *color_method_mark = strtok(NULL, ";");
if (strcmp(color_method_mark, "5") == 0) {
char *c256 = strtok(NULL, ";");
if (strcmp(ansi_code_part, "38") == 0)
cur_ansi_status.fg = atoi(c256);
if (strcmp(ansi_code_part, "48") == 0)
cur_ansi_status.bg = atoi(c256);
}
// WONTFIX: You can't init_color with numerous RGB code in ncurses.
// I decided to force delta users to use "true-color = never" when using tig,
// so the process never comes to this condition.
// I leave the code for someone who wants to implements in the future.
// if (strcmp(color_method_mark, "2") == 0) {
// char *r = strtok(NULL, ";");
// char *g = strtok(NULL, ";");
// char *b = strtok(NULL, ";");
// }
ansi_code_part = strtok(NULL, ";");
}

free(token);
token = NULL;
}

wattrset_by_ansi_status(view, &cur_ansi_status);
draw_ansi_line(view, ansi_end_ptr, after_ansi_len);
free(ansi_code);
ansi_code = NULL;
}
}

void
draw_ansi_line(struct view *view, char *text, int len) {
if (len > 1)
waddnstr(view->win, text, len);
}

void
wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status) {
if (cur_ansi_status->fg > 15 && cur_ansi_status->fg % 2 == 1)
cur_ansi_status->fg -= 1;
if (cur_ansi_status->bg > 15 && cur_ansi_status->bg % 2 == 1)
cur_ansi_status->bg -= 1;
short id = color_pairs_map[cur_ansi_status->fg][cur_ansi_status->bg];
wattr_set(view->win, cur_ansi_status->attr, id, NULL);
}

/* vim: set ts=8 sw=8 noexpandtab: */
10 changes: 8 additions & 2 deletions src/apps.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,14 @@ struct app_external
&& app_diff_highlight_path_search(dhlt_path, sizeof(dhlt_path), query)
&& *dhlt_path) {
if (suffixcmp(dhlt_path, strlen(dhlt_path), "/diff-highlight.perl")) {
dhlt_app.argv[0] = dhlt_path;
dhlt_app.argv[1] = NULL;
if (strcmp(strrchr(dhlt_path, '/'), "/delta") == 0) {
dhlt_app.argv[0] = dhlt_path;
dhlt_app.argv[1] = "--true-color=never";
dhlt_app.argv[2] = NULL;
} else {
dhlt_app.argv[0] = dhlt_path;
dhlt_app.argv[1] = NULL;
}
} else if (path_search(perl_path, sizeof(perl_path), "perl", getenv("PATH"), X_OK)) {
/* if the package manager failed to "make install" within the contrib dir, rescue via */
/* perl -MDiffHighlight -I/path/containing /path/containing/diff-highlight.perl */
Expand Down
23 changes: 20 additions & 3 deletions src/draw.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "tig/tig.h"
#include "tig/graph.h"
#include "tig/ansi.h"
#include "tig/draw.h"
#include "tig/options.h"
#include "compat/hashtab.h"
Expand Down Expand Up @@ -74,9 +75,25 @@ draw_chars(struct view *view, enum line_type type, const char *string, int lengt
}

set_view_attr(view, type);
if (len > 0)
waddnstr(view->win, string, len);

if (len > 0) {
int ansi_num = 0;
int len_with_ansi = strlen(string);
int max_num = (len_with_ansi / 4) + 1;
int max_len = (len_with_ansi - 4) + 1;
char **ansi_ptrs = (char **)malloc(sizeof(char *) * max_num);
char *ansi_ptrs_for_free = (char *)malloc(sizeof(char) * max_num * max_len);
for (int i = 0; i < max_num; i++)
ansi_ptrs[i] = ansi_ptrs_for_free + i * max_len;
split_ansi(string, &ansi_num, ansi_ptrs);

if (ansi_num > 0)
draw_ansi(view, &ansi_num, ansi_ptrs);
else
waddnstr(view->win, string, len);

free(ansi_ptrs_for_free);
free(ansi_ptrs);
}
if (trimmed && use_tilde) {
set_view_attr(view, LINE_DELIMITER);
waddstr(view->win, opt_truncation_delimiter ? opt_truncation_delimiter : "~");
Expand Down
16 changes: 16 additions & 0 deletions src/line.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ static size_t line_rules;
static struct line_info **color_pair;
static size_t color_pairs;

short color_pairs_map[256][256];

DEFINE_ALLOCATOR(realloc_line_rule, struct line_rule, 8)
DEFINE_ALLOCATOR(realloc_color_pair, struct line_info *, 8)

Expand Down Expand Up @@ -232,6 +234,20 @@ init_colors(void)
init_line_info_color_pair(info, type, default_bg, default_fg);
}
}

// TODO: init_extended_pair must be able to accept more than 256 here
// if we compiled with --ext-colors, but it doesn't work.
// https://github.com/mirror/ncurses/blob/56a81c7e79f73d397cc8074401d039f59c34cad5/ncurses/base/lib_color.c#L382-L391
// Currently we skip the odd number upper than 15.
short cnt = COLOR_ID(LINE_NONE) + 1;
for (short bg = 0; bg < 256; bg++) {
for (short fg = 0; fg < 256; fg++) {
if ((fg > 15 && fg % 2 == 1) || (bg > 15 && bg % 2 == 1))
continue;
init_extended_pair(++cnt, fg, bg);
color_pairs_map[fg][bg] = cnt;
}
}
}

/* vim: set ts=8 sw=8 noexpandtab: */
2 changes: 1 addition & 1 deletion src/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ string_expand(char *dst, size_t dstlen, const char *src, int srclen, int tabsize
expanded = dstlen - size - 1;
memcpy(dst + size, " ", expanded);
size += expanded;
} else if (isspace(c) || iscntrl(c)) {
} else if ((isspace(c) || iscntrl(c)) && !(c == '\033' && src[pos+1] == '[')) {
dst[size++] = ' ';
} else {
dst[size++] = src[pos];
Expand Down