From 4862289c88c76dec60b91133a3d2002053c45462 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 17 Aug 2021 09:11:06 +0900 Subject: [PATCH 01/20] Add vscode setting based on the vim setting --- .vscode/settings.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..555d1a3dd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "editor.tabSize": 8, + "editor.insertSpaces": false, + "files.associations": { + "*.h": "c" + } +} From 93233fef54b0097649028057912b5009a79258b6 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 17 Aug 2021 09:13:17 +0900 Subject: [PATCH 02/20] Support delta with parsing its ansi code --- Makefile | 1 + include/tig/ansi.h | 34 +++++++++ include/tig/line.h | 2 + src/ansi.c | 182 +++++++++++++++++++++++++++++++++++++++++++++ src/draw.c | 23 +++++- src/line.c | 16 ++++ src/string.c | 2 +- 7 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 include/tig/ansi.h create mode 100644 src/ansi.c diff --git a/Makefile b/Makefile index 20cbb7e45..9c1e15d7d 100644 --- a/Makefile +++ b/Makefile @@ -360,6 +360,7 @@ TIG_OBJS = \ src/grep.o \ src/ui.o \ src/apps.o \ + src/ansi.o \ $(GRAPH_OBJS) \ $(COMPAT_OBJS) diff --git a/include/tig/ansi.h b/include/tig/ansi.h new file mode 100644 index 000000000..1be6e432e --- /dev/null +++ b/include/tig/ansi.h @@ -0,0 +1,34 @@ +/* Copyright (c) 2006-2015 Jonas Fonseca + * + * 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: */ diff --git a/include/tig/line.h b/include/tig/line.h index ad3118d61..e38710046 100644 --- a/include/tig/line.h +++ b/include/tig/line.h @@ -17,6 +17,8 @@ #include "tig/tig.h" struct ref; +extern short color_pairs_map[256][256]; + /* * Line-oriented content detection. */ diff --git a/src/ansi.c b/src/ansi.c new file mode 100644 index 000000000..e5c4467c9 --- /dev/null +++ b/src/ansi.c @@ -0,0 +1,182 @@ +/* Copyright (c) 2006-2015 Jonas Fonseca + * + * 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 *needle = "\033["; + int current_ansi_idx = 0; + char *next_ansi_ptr = strstr(string + current_ansi_idx, needle); + + 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(needle), needle); + 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(needle), needle); + } + + 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]; + wattrset(view->win, COLOR_PAIR(id)|cur_ansi_status->attr); +} + +/* vim: set ts=8 sw=8 noexpandtab: */ diff --git a/src/draw.c b/src/draw.c index b764294b6..c1b65dc22 100644 --- a/src/draw.c +++ b/src/draw.c @@ -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" @@ -78,9 +79,25 @@ draw_chars(struct view *view, enum line_type type, const char *string, int lengt len = utf8_length(&string, length, skip, &col, max_width, &trimmed, use_tilde, opt_tab_size); 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 : "~"); diff --git a/src/line.c b/src/line.c index a5f3936df..cfca4877f 100644 --- a/src/line.c +++ b/src/line.c @@ -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) @@ -240,6 +242,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); + 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: */ diff --git a/src/string.c b/src/string.c index 6146d8aee..14995c9d2 100644 --- a/src/string.c +++ b/src/string.c @@ -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]; From 4e653e9c23dc2fb39ca6cb42d8b74967151de51e Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 17 Aug 2021 09:13:57 +0900 Subject: [PATCH 03/20] Restrict delta from enabling true-color --- src/apps.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/apps.c b/src/apps.c index a8afc0ade..9a5063c15 100644 --- a/src/apps.c +++ b/src/apps.c @@ -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 */ From 256dea03a1c3cffee439e71916f534d80a97d3b7 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 17 Aug 2021 09:14:20 +0900 Subject: [PATCH 04/20] Note about delta is supported --- doc/tigrc.5.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tigrc.5.adoc b/doc/tigrc.5.adoc index 865d3784a..158ef647c 100644 --- a/doc/tigrc.5.adoc +++ b/doc/tigrc.5.adoc @@ -280,7 +280,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|]:: From da8ec39da53d77582025f38c5b8645bf7d3be8b8 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 17 Aug 2021 16:40:56 +0900 Subject: [PATCH 05/20] Fix wording for parsing ansi --- src/ansi.c | 13 ++++++------- src/line.c | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/ansi.c b/src/ansi.c index e5c4467c9..0272f9f01 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -19,15 +19,15 @@ void split_ansi(const char *string, int *ansi_num, char **ansi_ptrs) { - char *needle = "\033["; + char *head_of_ansi = "\033["; int current_ansi_idx = 0; - char *next_ansi_ptr = strstr(string + current_ansi_idx, needle); + 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(needle), needle); + 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); @@ -35,7 +35,7 @@ split_ansi(const char *string, int *ansi_num, char **ansi_ptrs) { 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(needle), needle); + next_ansi_ptr = strstr(string + current_ansi_idx + strlen(head_of_ansi), head_of_ansi); } strcpy(ansi_ptrs[*ansi_num], string + current_ansi_idx); @@ -49,8 +49,7 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs) { cur_ansi_status.bg = COLOR_BLACK; cur_ansi_status.attr = A_NORMAL; - for (int i = 0; i < *ansi_num; i++) - { + for (int i = 0; i < *ansi_num; i++) { int len = strlen(ansi_ptrs[i]); char text[len + 1]; strcpy(text, ansi_ptrs[i]); @@ -131,7 +130,7 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs) { strcpy(token, ansi_code); char *ansi_code_part = strtok(token, ";"); - while(ansi_code_part != NULL) { + while (ansi_code_part != NULL) { char *color_method_mark = strtok(NULL, ";"); if (strcmp(color_method_mark, "5") == 0) { char *c256 = strtok(NULL, ";"); diff --git a/src/line.c b/src/line.c index cfca4877f..4db230678 100644 --- a/src/line.c +++ b/src/line.c @@ -247,12 +247,12 @@ init_colors(void) // 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); + 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); + init_extended_pair(++cnt, fg, bg); color_pairs_map[fg][bg] = cnt; } } From a63053936a3fef651abb27f111db3e3a519299eb Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 17 Aug 2021 19:10:15 +0900 Subject: [PATCH 06/20] Change wattrset to wattr_set for accepting short id number --- src/ansi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansi.c b/src/ansi.c index 0272f9f01..77d737841 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -175,7 +175,7 @@ wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status) 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]; - wattrset(view->win, COLOR_PAIR(id)|cur_ansi_status->attr); + wattr_set(view->win, cur_ansi_status->attr, id, NULL); } /* vim: set ts=8 sw=8 noexpandtab: */ From bc2f50672e97baafb169cfc327cf265a096fed12 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Fri, 20 Aug 2021 05:33:41 +0900 Subject: [PATCH 07/20] Keep LINE_CURSOR pair while line is selected --- src/ansi.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/ansi.c b/src/ansi.c index 77d737841..2cf42143f 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -67,10 +67,16 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs) { char *ansi_end_ptr = strchr(text, 'm'); int after_ansi_len = strlen(ansi_end_ptr); int ansi_code_len = len - after_ansi_len - 2; + ansi_end_ptr += 1; + + if (view->curline->selected) { + draw_ansi_line(view, ansi_end_ptr, after_ansi_len); + continue; + } + 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) From a5a28e67db3f937149c085997c7428d82e31a932 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Fri, 20 Aug 2021 05:43:31 +0900 Subject: [PATCH 08/20] Fix comment about init_extended_pair --- src/ansi.c | 2 ++ src/line.c | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ansi.c b/src/ansi.c index 2cf42143f..b07f5c9fd 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -176,6 +176,8 @@ draw_ansi_line(struct view *view, char *text, int len) { void wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status) { + // Because init_extended_pair can't accept more than 32768 pairs, + // we skip the colors with color codes odd numbered and greater than 15 currently. 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) diff --git a/src/line.c b/src/line.c index 4db230678..3d3407a99 100644 --- a/src/line.c +++ b/src/line.c @@ -243,10 +243,8 @@ init_colors(void) } } - // 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. + // Because init_extended_pair can't accept more than 32768 pairs, + // we skip the colors with color codes odd numbered and greater than 15 currently. short cnt = COLOR_ID(LINE_NONE) + 1; for (short bg = 0; bg < 256; bg++) { for (short fg = 0; fg < 256; fg++) { From 69e40ce74ea4cb7bc648f78f6c62d8bc5dbb2778 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Mon, 7 Feb 2022 19:04:19 +0900 Subject: [PATCH 09/20] Add pager handling when drawing anci codes --- include/tig/ansi.h | 4 +-- src/ansi.c | 37 +++++++++++++++------ src/draw.c | 80 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/include/tig/ansi.h b/include/tig/ansi.h index 1be6e432e..8d061faad 100644 --- a/include/tig/ansi.h +++ b/include/tig/ansi.h @@ -25,8 +25,8 @@ struct ansi_status { }; 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 draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, size_t skip); +void draw_ansi_line(struct view *view, char *ansi_end_ptr, int after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display); void wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status); #endif diff --git a/src/ansi.c b/src/ansi.c index b07f5c9fd..78ce94821 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -16,6 +16,7 @@ #include "tig/line.h" #include "tig/tig.h" #include "tig/view.h" +#include "compat/utf8proc.h" void split_ansi(const char *string, int *ansi_num, char **ansi_ptrs) { @@ -43,13 +44,17 @@ split_ansi(const char *string, int *ansi_num, char **ansi_ptrs) { } void -draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs) { +draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, size_t skip) { 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; + int cur_width = 0; for (int i = 0; i < *ansi_num; i++) { + if (cur_width >= view->width) + break; + int len = strlen(ansi_ptrs[i]); char text[len + 1]; strcpy(text, ansi_ptrs[i]); @@ -69,15 +74,21 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs) { int ansi_code_len = len - after_ansi_len - 2; ansi_end_ptr += 1; + int widths_of_display = utf8_width_of(ansi_end_ptr, after_ansi_len, after_ansi_len); + if (skip > widths_of_display) { + skip -= widths_of_display; + continue; + } + if (view->curline->selected) { - draw_ansi_line(view, ansi_end_ptr, after_ansi_len); + draw_ansi_line(view, ansi_end_ptr, after_ansi_len, &skip, &cur_width, &widths_of_display); + cur_width += widths_of_display; continue; } char *ansi_code = malloc(sizeof(char) * (ansi_code_len + 1)); strncpy(ansi_code, text + 2, ansi_code_len); ansi_code[ansi_code_len] = '\0'; - if (strchr(ansi_code, ';') == NULL) { if (strcmp(ansi_code, "0") == 0) cur_ansi_status.attr = A_NORMAL; @@ -156,22 +167,30 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs) { // } 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); + + draw_ansi_line(view, ansi_end_ptr, after_ansi_len, &skip, &cur_width, &widths_of_display); + cur_width += widths_of_display; + 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); +draw_ansi_line(struct view *view, char *ansi_end_ptr, int after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display) { + while (*skip > 0) { + utf8proc_int32_t unicode; + int bytes_to_skip = utf8proc_iterate((const utf8proc_uint8_t *) ansi_end_ptr, strlen(ansi_end_ptr), &unicode); + ansi_end_ptr += bytes_to_skip; + after_ansi_len -= bytes_to_skip; + *skip -= 1; + *widths_of_display -= 1; + } + waddnstr(view->win, ansi_end_ptr, after_ansi_len); } void diff --git a/src/draw.c b/src/draw.c index c1b65dc22..c81d4e638 100644 --- a/src/draw.c +++ b/src/draw.c @@ -79,25 +79,59 @@ draw_chars(struct view *view, enum line_type type, const char *string, int lengt len = utf8_length(&string, length, skip, &col, max_width, &trimmed, use_tilde, opt_tab_size); set_view_attr(view, type); - 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 (len > 0) + waddnstr(view->win, string, len); + + if (trimmed && use_tilde) { + set_view_attr(view, LINE_DELIMITER); + waddstr(view->win, opt_truncation_delimiter ? opt_truncation_delimiter : "~"); + col++; + } + + view->col += col; + return VIEW_MAX_LEN(view) <= 0; +} + +static bool +draw_chars_with_ansi(struct view *view, enum line_type type, const char *string, int length, + int max_width, bool use_tilde) +{ + int len = 0; + int col = 0; + int trimmed = false; + size_t skip = view->pos.col > view->col ? view->pos.col - view->col : 0; + + if (max_width <= 0) + return VIEW_MAX_LEN(view) <= 0; + + if (opt_iconv_out != ICONV_NONE) { + string = encoding_iconv(opt_iconv_out, string, len); + if (!string) + return VIEW_MAX_LEN(view) <= 0; + } + + set_view_attr(view, type); + + 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, max_width, skip); + else { + len = utf8_length(&string, length, skip, &col, view->width, &trimmed, use_tilde, opt_tab_size); + 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 : "~"); @@ -138,8 +172,14 @@ draw_text_expanded(struct view *view, enum line_type type, const char *string, i size_t pos = string_expand(text, sizeof(text), string, length, opt_tab_size); size_t col = view->col; - if (draw_chars(view, type, text, -1, max_width, use_tilde)) - return true; + if (opt_diff_highlight && *opt_diff_highlight && strcmp(opt_diff_highlight, "delta") == 0) { + if (draw_chars_with_ansi(view, type, text, -1, max_width, use_tilde)) + return true; + } else { + if (draw_chars(view, type, text, -1, max_width, use_tilde)) + return true; + } + string += pos; length -= pos; max_width -= view->col - col; From 16694489460d0aceb39914c3e625a808fe6dc358 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Mon, 7 Feb 2022 19:06:56 +0900 Subject: [PATCH 10/20] Handle oversized string out of maxwidth while string contains ansi codes --- src/ansi.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ansi.c b/src/ansi.c index 78ce94821..0935a34cf 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -190,7 +190,20 @@ draw_ansi_line(struct view *view, char *ansi_end_ptr, int after_ansi_len, size_t *skip -= 1; *widths_of_display -= 1; } - waddnstr(view->win, ansi_end_ptr, after_ansi_len); + + if (*cur_width + *widths_of_display > view->width) { + int left_widths = view->width - *cur_width; + while (left_widths > 0) { + utf8proc_int32_t unicode; + int bytes_to_display = utf8proc_iterate((const utf8proc_uint8_t *) ansi_end_ptr, strlen(ansi_end_ptr), &unicode); + waddnstr(view->win, ansi_end_ptr, bytes_to_display); + ansi_end_ptr += bytes_to_display; + after_ansi_len -= bytes_to_display; + left_widths -= 1; + } + } else { + waddnstr(view->win, ansi_end_ptr, after_ansi_len); + } } void From 47baf22e5c7d7e5a4247843f22a0ad203b397d05 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Mon, 7 Feb 2022 20:58:38 +0900 Subject: [PATCH 11/20] Apply Light theme option --- src/ansi.c | 8 ++++---- src/line.c | 8 ++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/ansi.c b/src/ansi.c index 0935a34cf..908927326 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -46,8 +46,8 @@ split_ansi(const char *string, int *ansi_num, char **ansi_ptrs) { void draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, size_t skip) { static struct ansi_status cur_ansi_status; - cur_ansi_status.fg = COLOR_WHITE; - cur_ansi_status.bg = COLOR_BLACK; + cur_ansi_status.fg = 256; + cur_ansi_status.bg = 256; cur_ansi_status.attr = A_NORMAL; int cur_width = 0; @@ -210,9 +210,9 @@ void wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status) { // Because init_extended_pair can't accept more than 32768 pairs, // we skip the colors with color codes odd numbered and greater than 15 currently. - if (cur_ansi_status->fg > 15 && cur_ansi_status->fg % 2 == 1) + if (cur_ansi_status->fg < 256 && 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) + if (cur_ansi_status->bg < 256 && 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); diff --git a/src/line.c b/src/line.c index 3d3407a99..48a93dce1 100644 --- a/src/line.c +++ b/src/line.c @@ -254,6 +254,14 @@ init_colors(void) color_pairs_map[fg][bg] = cnt; } } + for (short bg = 0; bg < 256; bg++) { + init_extended_pair(++cnt, COLOR_DEFAULT, bg); + color_pairs_map[256][bg] = cnt; + } + for (short fg = 0; fg < 256; fg++) { + init_extended_pair(++cnt, fg, COLOR_DEFAULT); + color_pairs_map[fg][256] = cnt; + } } /* vim: set ts=8 sw=8 noexpandtab: */ From b318ee91e13f455e96a1a20aad9cd1c6305542b6 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Mon, 7 Feb 2022 23:22:57 +0900 Subject: [PATCH 12/20] Add test for supporting delta --- test/diff/diff-highlight-with-delta-test | 52 ++++++++++++++++++++++++ test/tools/libtest.sh | 13 +++++- 2 files changed, 64 insertions(+), 1 deletion(-) create mode 100755 test/diff/diff-highlight-with-delta-test diff --git a/test/diff/diff-highlight-with-delta-test b/test/diff/diff-highlight-with-delta-test new file mode 100755 index 000000000..658956690 --- /dev/null +++ b/test/diff/diff-highlight-with-delta-test @@ -0,0 +1,52 @@ +#!/bin/sh + +. libtest.sh +. libgit.sh + +test_require delta + +export PATH="$(dirname -- "$delta_path"):$PATH" + +tigrc < +AuthorDate: Sat Mar 1 15:59:02 2014 -0500 +Commit: Jonas Fonseca +CommitDate: Sat Mar 1 15:59:02 2014 -0500 + + Add type parameter for js.Dynamic +--- + common/src/main/scala/org/scalajs/benchmark/Benchmark.scala | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + + +common/src/main/scala/org/scalajs/benchmark/Benchmark.scala +──────────────────────────────────────────────────────────────────────────────── + +───────────────────────┐ +15: object Benchmark { │ +───────────────────────┘ + val benchmarks = js.Array[Benchmark]() + val benchmarkApps = js.Array[BenchmarkApp]() + + val global = js.Dynamic.global.asInstanceOf[js.Dictionary] + val global = js.Dynamic.global.asInstanceOf[js.Dictionary[js.Any]] + global("runScalaJSBenchmarks") = runBenchmarks _ + global("initScalaJSBenchmarkApps") = initBenchmarkApps _ + + + +[diff] a1dcf1aaa11470978db1d5d8bcf9e16201eb70ff - line 1 of 26 100% +EOF diff --git a/test/tools/libtest.sh b/test/tools/libtest.sh index ceb85a337..eab7b5fd8 100644 --- a/test/tools/libtest.sh +++ b/test/tools/libtest.sh @@ -440,7 +440,12 @@ show_test_results() fi # Replace CR used by Git progress messages - tr '\r' '\n' < .test-result + kernel="$(uname -s 2>/dev/null || printf 'unknown\n')" + case "$kernel" in + Darwin) LC_ALL=C tr '\r' '\n' < .test-result ;; + *) tr '\r' '\n' < .test-result ;; + esac + elif [ -n "$verbose" ]; then count="$(grep -c '^ *\[OK\]' < .test-result || true)" printf 'Passed %d assertions\n' "$count" @@ -548,6 +553,12 @@ test_require() test_skip "The test requires diff-highlight, usually found in share/git-core-contrib" fi ;; + delta) + delta_path="/usr/local/bin/delta" + if [ ! -e "$delta_path" ]; then + test_skip "The test requires git-delta, https://dandavison.github.io/delta/installation.html" + fi + ;; readline) if ! has_readline; then test_skip "The test requires a tig compiled with readline" From 087c51c89869054e9623339814ad9958e2f89b41 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 8 Feb 2022 11:08:15 +0900 Subject: [PATCH 13/20] Refactor codes for delta support --- include/tig/line.h | 2 +- src/ansi.c | 4 ++-- src/draw.c | 2 +- src/line.c | 4 +++- test/tools/libtest.sh | 10 +++++----- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/tig/line.h b/include/tig/line.h index e38710046..83941a942 100644 --- a/include/tig/line.h +++ b/include/tig/line.h @@ -17,7 +17,7 @@ #include "tig/tig.h" struct ref; -extern short color_pairs_map[256][256]; +extern short color_pairs_map[257][257]; /* * Line-oriented content detection. diff --git a/src/ansi.c b/src/ansi.c index 908927326..96563359f 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -82,7 +82,6 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz if (view->curline->selected) { draw_ansi_line(view, ansi_end_ptr, after_ansi_len, &skip, &cur_width, &widths_of_display); - cur_width += widths_of_display; continue; } @@ -173,7 +172,6 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz wattrset_by_ansi_status(view, &cur_ansi_status); draw_ansi_line(view, ansi_end_ptr, after_ansi_len, &skip, &cur_width, &widths_of_display); - cur_width += widths_of_display; free(ansi_code); ansi_code = NULL; @@ -204,6 +202,8 @@ draw_ansi_line(struct view *view, char *ansi_end_ptr, int after_ansi_len, size_t } else { waddnstr(view->win, ansi_end_ptr, after_ansi_len); } + + *cur_width += *widths_of_display; } void diff --git a/src/draw.c b/src/draw.c index c81d4e638..7567db917 100644 --- a/src/draw.c +++ b/src/draw.c @@ -172,7 +172,7 @@ draw_text_expanded(struct view *view, enum line_type type, const char *string, i size_t pos = string_expand(text, sizeof(text), string, length, opt_tab_size); size_t col = view->col; - if (opt_diff_highlight && *opt_diff_highlight && strcmp(opt_diff_highlight, "delta") == 0) { + if (opt_diff_highlight && *opt_diff_highlight && strcmp(opt_diff_highlight, "delta") == 0 && strstr(string, "\033[") != NULL) { if (draw_chars_with_ansi(view, type, text, -1, max_width, use_tilde)) return true; } else { diff --git a/src/line.c b/src/line.c index 48a93dce1..19446d50c 100644 --- a/src/line.c +++ b/src/line.c @@ -23,7 +23,7 @@ static size_t line_rules; static struct line_info **color_pair; static size_t color_pairs; -short color_pairs_map[256][256]; +short color_pairs_map[257][257]; DEFINE_ALLOCATOR(realloc_line_rule, struct line_rule, 8) DEFINE_ALLOCATOR(realloc_color_pair, struct line_info *, 8) @@ -262,6 +262,8 @@ init_colors(void) init_extended_pair(++cnt, fg, COLOR_DEFAULT); color_pairs_map[fg][256] = cnt; } + init_extended_pair(++cnt, COLOR_DEFAULT, COLOR_DEFAULT); + color_pairs_map[256][256] = cnt; } /* vim: set ts=8 sw=8 noexpandtab: */ diff --git a/test/tools/libtest.sh b/test/tools/libtest.sh index eab7b5fd8..391177fd8 100644 --- a/test/tools/libtest.sh +++ b/test/tools/libtest.sh @@ -440,11 +440,11 @@ show_test_results() fi # Replace CR used by Git progress messages - kernel="$(uname -s 2>/dev/null || printf 'unknown\n')" - case "$kernel" in - Darwin) LC_ALL=C tr '\r' '\n' < .test-result ;; - *) tr '\r' '\n' < .test-result ;; - esac + kernel="$(uname -s 2>/dev/null || printf 'unknown\n')" + case "$kernel" in + Darwin) LC_ALL=C tr '\r' '\n' < .test-result ;; + *) tr '\r' '\n' < .test-result ;; + esac elif [ -n "$verbose" ]; then count="$(grep -c '^ *\[OK\]' < .test-result || true)" From dc89bcce0785589e4eb2c3fabc357d3506399dbd Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 8 Feb 2022 11:15:04 +0900 Subject: [PATCH 14/20] Avoid the edge case at entering drawing ansi but it's actually not ansi --- src/draw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw.c b/src/draw.c index 7567db917..8dcf44284 100644 --- a/src/draw.c +++ b/src/draw.c @@ -125,7 +125,7 @@ draw_chars_with_ansi(struct view *view, enum line_type type, const char *string, if (ansi_num > 0) draw_ansi(view, &ansi_num, ansi_ptrs, max_width, skip); else { - len = utf8_length(&string, length, skip, &col, view->width, &trimmed, use_tilde, opt_tab_size); + len = utf8_length(&string, length, skip, &col, max_width, &trimmed, use_tilde, opt_tab_size); waddnstr(view->win, string, len); } From 2e81666838b113e380516c2d21c9dc6da4b5f19e Mon Sep 17 00:00:00 2001 From: ulwlu Date: Fri, 11 Feb 2022 00:11:17 +0900 Subject: [PATCH 15/20] Refactor draw_ansi_line by removing unnecessary strlen --- include/tig/ansi.h | 2 +- src/ansi.c | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/tig/ansi.h b/include/tig/ansi.h index 8d061faad..eb2e71f26 100644 --- a/include/tig/ansi.h +++ b/include/tig/ansi.h @@ -26,7 +26,7 @@ struct ansi_status { void split_ansi(const char *string, int *ansi_num, char **ansi_ptrs); void draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, size_t skip); -void draw_ansi_line(struct view *view, char *ansi_end_ptr, int after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display); +void draw_ansi_line(struct view *view, char *ansi_end_ptr, int *after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display); void wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status); #endif diff --git a/src/ansi.c b/src/ansi.c index 96563359f..2580440c2 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -81,7 +81,7 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz } if (view->curline->selected) { - draw_ansi_line(view, ansi_end_ptr, after_ansi_len, &skip, &cur_width, &widths_of_display); + draw_ansi_line(view, ansi_end_ptr, &after_ansi_len, &skip, &cur_width, &widths_of_display); continue; } @@ -171,7 +171,7 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz } wattrset_by_ansi_status(view, &cur_ansi_status); - draw_ansi_line(view, ansi_end_ptr, after_ansi_len, &skip, &cur_width, &widths_of_display); + draw_ansi_line(view, ansi_end_ptr, &after_ansi_len, &skip, &cur_width, &widths_of_display); free(ansi_code); ansi_code = NULL; @@ -179,12 +179,12 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz } void -draw_ansi_line(struct view *view, char *ansi_end_ptr, int after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display) { +draw_ansi_line(struct view *view, char *ansi_end_ptr, int *after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display) { while (*skip > 0) { utf8proc_int32_t unicode; - int bytes_to_skip = utf8proc_iterate((const utf8proc_uint8_t *) ansi_end_ptr, strlen(ansi_end_ptr), &unicode); + int bytes_to_skip = utf8proc_iterate((const utf8proc_uint8_t *) ansi_end_ptr, *after_ansi_len, &unicode); ansi_end_ptr += bytes_to_skip; - after_ansi_len -= bytes_to_skip; + *after_ansi_len -= bytes_to_skip; *skip -= 1; *widths_of_display -= 1; } @@ -193,14 +193,14 @@ draw_ansi_line(struct view *view, char *ansi_end_ptr, int after_ansi_len, size_t int left_widths = view->width - *cur_width; while (left_widths > 0) { utf8proc_int32_t unicode; - int bytes_to_display = utf8proc_iterate((const utf8proc_uint8_t *) ansi_end_ptr, strlen(ansi_end_ptr), &unicode); + int bytes_to_display = utf8proc_iterate((const utf8proc_uint8_t *) ansi_end_ptr, *after_ansi_len, &unicode); waddnstr(view->win, ansi_end_ptr, bytes_to_display); ansi_end_ptr += bytes_to_display; - after_ansi_len -= bytes_to_display; + *after_ansi_len -= bytes_to_display; left_widths -= 1; } } else { - waddnstr(view->win, ansi_end_ptr, after_ansi_len); + waddnstr(view->win, ansi_end_ptr, *after_ansi_len); } *cur_width += *widths_of_display; From 4180ab3492780e6f9a0a35fe1d267f9a9aefac6a Mon Sep 17 00:00:00 2001 From: ulwlu Date: Sat, 12 Feb 2022 21:01:28 +0900 Subject: [PATCH 16/20] Remove the vscode settings from delta support pull request --- .vscode/settings.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 555d1a3dd..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "editor.tabSize": 8, - "editor.insertSpaces": false, - "files.associations": { - "*.h": "c" - } -} From 851abb5d4ed5a216cb5d1523fe50a4c63547dd9c Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 22 Feb 2022 23:25:09 +0900 Subject: [PATCH 17/20] Handle a consecutive ansi which has more than two attributes --- include/tig/ansi.h | 1 + src/ansi.c | 122 +++++++++++++++++++++++++-------------------- 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/include/tig/ansi.h b/include/tig/ansi.h index eb2e71f26..695e0cec1 100644 --- a/include/tig/ansi.h +++ b/include/tig/ansi.h @@ -28,6 +28,7 @@ void split_ansi(const char *string, int *ansi_num, char **ansi_ptrs); void draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, size_t skip); void draw_ansi_line(struct view *view, char *ansi_end_ptr, int *after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display); void wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status); +short convert_ansi_into_256_color(char *save_ptr); #endif diff --git a/src/ansi.c b/src/ansi.c index 2580440c2..cc857e6c3 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -85,92 +85,81 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz continue; } + // ncurses can't handle multiple attribute such as BOLD & UNDERLINE. + // If input-ansi has "\033[1;4" we'll give priority to the latter one. + char *saveptr; char *ansi_code = malloc(sizeof(char) * (ansi_code_len + 1)); strncpy(ansi_code, text + 2, ansi_code_len); ansi_code[ansi_code_len] = '\0'; - if (strchr(ansi_code, ';') == NULL) { - if (strcmp(ansi_code, "0") == 0) + char *ansi_code_part = strtok_r(ansi_code, ";", &saveptr); + while (ansi_code_part != NULL) { + if (strcmp(ansi_code_part, "0") == 0) { + cur_ansi_status.fg = 256; + cur_ansi_status.bg = 256; cur_ansi_status.attr = A_NORMAL; - if (strcmp(ansi_code, "1") == 0) + } + if (strcmp(ansi_code_part, "1") == 0) cur_ansi_status.attr = A_BOLD; - if (strcmp(ansi_code, "2") == 0) + if (strcmp(ansi_code_part, "2") == 0) cur_ansi_status.attr = A_DIM; - if (strcmp(ansi_code, "3") == 0) + if (strcmp(ansi_code_part, "3") == 0) cur_ansi_status.attr = A_ITALIC; - if (strcmp(ansi_code, "4") == 0) + if (strcmp(ansi_code_part, "4") == 0) cur_ansi_status.attr = A_UNDERLINE; - if (strcmp(ansi_code, "5") == 0) + if (strcmp(ansi_code_part, "5") == 0) cur_ansi_status.attr = A_BLINK; - if (strcmp(ansi_code, "6") == 0) + if (strcmp(ansi_code_part, "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) + if (strcmp(ansi_code_part, "7") == 0) cur_ansi_status.attr = A_REVERSE; - if (strcmp(ansi_code, "8") == 0) + if (strcmp(ansi_code_part, "8") == 0) cur_ansi_status.attr = A_INVIS; - if (strcmp(ansi_code, "9") == 0) + if (strcmp(ansi_code_part, "9") == 0) // This is supposed to be strikethrough, but ncurses doesn't have any way to achieve. - if (strcmp(ansi_code, "30") == 0) + if (strcmp(ansi_code_part, "30") == 0) cur_ansi_status.fg = COLOR_BLACK; - if (strcmp(ansi_code, "31") == 0) + if (strcmp(ansi_code_part, "31") == 0) cur_ansi_status.fg = COLOR_RED; - if (strcmp(ansi_code, "32") == 0) + if (strcmp(ansi_code_part, "32") == 0) cur_ansi_status.fg = COLOR_GREEN; - if (strcmp(ansi_code, "33") == 0) + if (strcmp(ansi_code_part, "33") == 0) cur_ansi_status.fg = COLOR_YELLOW; - if (strcmp(ansi_code, "34") == 0) + if (strcmp(ansi_code_part, "34") == 0) cur_ansi_status.fg = COLOR_BLUE; - if (strcmp(ansi_code, "35") == 0) + if (strcmp(ansi_code_part, "35") == 0) cur_ansi_status.fg = COLOR_MAGENTA; - if (strcmp(ansi_code, "36") == 0) + if (strcmp(ansi_code_part, "36") == 0) cur_ansi_status.fg = COLOR_CYAN; - if (strcmp(ansi_code, "37") == 0) + if (strcmp(ansi_code_part, "37") == 0) cur_ansi_status.fg = COLOR_WHITE; - if (strcmp(ansi_code, "40") == 0) + if (strcmp(ansi_code_part, "38") == 0) { + short c256 = convert_ansi_into_256_color(saveptr); + if (c256 != -1) + cur_ansi_status.fg = c256; + } + if (strcmp(ansi_code_part, "40") == 0) cur_ansi_status.bg = COLOR_BLACK; - if (strcmp(ansi_code, "41") == 0) + if (strcmp(ansi_code_part, "41") == 0) cur_ansi_status.bg = COLOR_RED; - if (strcmp(ansi_code, "42") == 0) + if (strcmp(ansi_code_part, "42") == 0) cur_ansi_status.bg = COLOR_GREEN; - if (strcmp(ansi_code, "43") == 0) + if (strcmp(ansi_code_part, "43") == 0) cur_ansi_status.bg = COLOR_YELLOW; - if (strcmp(ansi_code, "44") == 0) + if (strcmp(ansi_code_part, "44") == 0) cur_ansi_status.bg = COLOR_BLUE; - if (strcmp(ansi_code, "45") == 0) + if (strcmp(ansi_code_part, "45") == 0) cur_ansi_status.bg = COLOR_MAGENTA; - if (strcmp(ansi_code, "46") == 0) + if (strcmp(ansi_code_part, "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, ";"); + if (strcmp(ansi_code_part, "48") == 0) { + short c256 = convert_ansi_into_256_color(saveptr); + if (c256 != -1) + cur_ansi_status.bg = c256; } - free(token); - token = NULL; + + ansi_code_part = strtok_r(NULL, ";", &saveptr); } wattrset_by_ansi_status(view, &cur_ansi_status); - draw_ansi_line(view, ansi_end_ptr, &after_ansi_len, &skip, &cur_width, &widths_of_display); free(ansi_code); @@ -218,4 +207,27 @@ wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status) wattr_set(view->win, cur_ansi_status->attr, id, NULL); } +short +convert_ansi_into_256_color(char *save_ptr) { + char *color_method_mark = strtok_r(NULL, ";", &save_ptr); + short c256 = -1; + if (strcmp(color_method_mark, "5") == 0) { + char *color_code = strtok_r(NULL, ";", &save_ptr); + c256 = atoi(color_code); + } + + // 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, ";"); + // } + // Do some process to convert those color infos for ncurses. + + return c256; +} + /* vim: set ts=8 sw=8 noexpandtab: */ From dc7addb136673b64d296c0645b2ae1e63e9821fb Mon Sep 17 00:00:00 2001 From: ulwlu Date: Wed, 23 Feb 2022 01:42:03 +0900 Subject: [PATCH 18/20] Fix ansi converter by passing char pointer by reference --- include/tig/ansi.h | 2 +- src/ansi.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/tig/ansi.h b/include/tig/ansi.h index 695e0cec1..36bcc6f87 100644 --- a/include/tig/ansi.h +++ b/include/tig/ansi.h @@ -28,7 +28,7 @@ void split_ansi(const char *string, int *ansi_num, char **ansi_ptrs); void draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, size_t skip); void draw_ansi_line(struct view *view, char *ansi_end_ptr, int *after_ansi_len, size_t *skip, int *cur_width, int *widths_of_display); void wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status); -short convert_ansi_into_256_color(char *save_ptr); +short convert_ansi_into_256_color(char **save_ptr); #endif diff --git a/src/ansi.c b/src/ansi.c index cc857e6c3..430e4511c 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -133,7 +133,7 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz if (strcmp(ansi_code_part, "37") == 0) cur_ansi_status.fg = COLOR_WHITE; if (strcmp(ansi_code_part, "38") == 0) { - short c256 = convert_ansi_into_256_color(saveptr); + short c256 = convert_ansi_into_256_color(&saveptr); if (c256 != -1) cur_ansi_status.fg = c256; } @@ -152,7 +152,7 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz if (strcmp(ansi_code_part, "46") == 0) cur_ansi_status.bg = COLOR_CYAN; if (strcmp(ansi_code_part, "48") == 0) { - short c256 = convert_ansi_into_256_color(saveptr); + short c256 = convert_ansi_into_256_color(&saveptr); if (c256 != -1) cur_ansi_status.bg = c256; } @@ -208,11 +208,11 @@ wattrset_by_ansi_status(struct view *view, struct ansi_status* cur_ansi_status) } short -convert_ansi_into_256_color(char *save_ptr) { - char *color_method_mark = strtok_r(NULL, ";", &save_ptr); +convert_ansi_into_256_color(char **save_ptr) { + char *color_method_mark = strtok_r(NULL, ";", save_ptr); short c256 = -1; if (strcmp(color_method_mark, "5") == 0) { - char *color_code = strtok_r(NULL, ";", &save_ptr); + char *color_code = strtok_r(NULL, ";", save_ptr); c256 = atoi(color_code); } From d0f5df28702240c72b84a24e7535c09f2223f7c1 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Wed, 23 Feb 2022 01:42:55 +0900 Subject: [PATCH 19/20] Bring back the process of ansi 47 code --- src/ansi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ansi.c b/src/ansi.c index 430e4511c..f310791cd 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -151,6 +151,8 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz cur_ansi_status.bg = COLOR_MAGENTA; if (strcmp(ansi_code_part, "46") == 0) cur_ansi_status.bg = COLOR_CYAN; + if (strcmp(ansi_code_part, "47") == 0) + cur_ansi_status.bg = COLOR_WHITE; if (strcmp(ansi_code_part, "48") == 0) { short c256 = convert_ansi_into_256_color(&saveptr); if (c256 != -1) From d2b29cd2d424ccdd78ef080bd6b8e184847ce909 Mon Sep 17 00:00:00 2001 From: ulwlu Date: Tue, 16 Aug 2022 23:37:52 +0200 Subject: [PATCH 20/20] Rework after review --- doc/tigrc.5.adoc | 2 +- include/tig/line.h | 2 ++ src/ansi.c | 12 +++++------- src/draw.c | 12 ++++++++++-- src/line.c | 4 ++++ 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/doc/tigrc.5.adoc b/doc/tigrc.5.adoc index 158ef647c..865d3784a 100644 --- a/doc/tigrc.5.adoc +++ b/doc/tigrc.5.adoc @@ -280,7 +280,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`. git-delta is also supported. + `color diff-del-highlight`. 'ignore-space' (mixed) [no|all|some|at-eol|]:: diff --git a/include/tig/line.h b/include/tig/line.h index 83941a942..fd5bad174 100644 --- a/include/tig/line.h +++ b/include/tig/line.h @@ -17,7 +17,9 @@ #include "tig/tig.h" struct ref; +#if defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH >= 20180127 extern short color_pairs_map[257][257]; +#endif /* * Line-oriented content detection. diff --git a/src/ansi.c b/src/ansi.c index f310791cd..1aa17d8cb 100644 --- a/src/ansi.c +++ b/src/ansi.c @@ -63,9 +63,8 @@ draw_ansi(struct view *view, int *ansi_num, char **ansi_ptrs, int max_width, siz 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. + + // ncurses can't handle J and K of ANSI code behavior. if ((text[3] == 'J') || (text[3] == 'K')) continue; @@ -219,15 +218,14 @@ convert_ansi_into_256_color(char **save_ptr) { } // 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. + // Therefore, \e[(3 or 4)8;2;r;g;bm syntax is disabled currently. + // The below code is left for when it is someday implemented. // if (strcmp(color_method_mark, "2") == 0) { // char *r = strtok(NULL, ";"); // char *g = strtok(NULL, ";"); // char *b = strtok(NULL, ";"); // } - // Do some process to convert those color infos for ncurses. + // Return a color pair ID that matches this rgb combination. return c256; } diff --git a/src/draw.c b/src/draw.c index 8dcf44284..b6f8eeb2d 100644 --- a/src/draw.c +++ b/src/draw.c @@ -13,11 +13,14 @@ #include "tig/tig.h" #include "tig/graph.h" -#include "tig/ansi.h" #include "tig/draw.h" #include "tig/options.h" #include "compat/hashtab.h" +#if defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH >= 20180127 +#include "tig/ansi.h" +#endif + static const enum line_type palette_colors[] = { LINE_PALETTE_0, LINE_PALETTE_1, @@ -172,13 +175,18 @@ draw_text_expanded(struct view *view, enum line_type type, const char *string, i size_t pos = string_expand(text, sizeof(text), string, length, opt_tab_size); size_t col = view->col; - if (opt_diff_highlight && *opt_diff_highlight && strcmp(opt_diff_highlight, "delta") == 0 && strstr(string, "\033[") != NULL) { +#if defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH >= 20180127 + if (strstr(string, "\033[") != NULL) { if (draw_chars_with_ansi(view, type, text, -1, max_width, use_tilde)) return true; } else { if (draw_chars(view, type, text, -1, max_width, use_tilde)) return true; } +#else + if (draw_chars(view, type, text, -1, max_width, use_tilde)) + return true; +#endif string += pos; length -= pos; diff --git a/src/line.c b/src/line.c index 19446d50c..3cd8c3b27 100644 --- a/src/line.c +++ b/src/line.c @@ -23,7 +23,9 @@ static size_t line_rules; static struct line_info **color_pair; static size_t color_pairs; +#if defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH >= 20180127 short color_pairs_map[257][257]; +#endif DEFINE_ALLOCATOR(realloc_line_rule, struct line_rule, 8) DEFINE_ALLOCATOR(realloc_color_pair, struct line_info *, 8) @@ -243,6 +245,7 @@ init_colors(void) } } +#if defined(NCURSES_VERSION_PATCH) && NCURSES_VERSION_PATCH >= 20180127 // Because init_extended_pair can't accept more than 32768 pairs, // we skip the colors with color codes odd numbered and greater than 15 currently. short cnt = COLOR_ID(LINE_NONE) + 1; @@ -264,6 +267,7 @@ init_colors(void) } init_extended_pair(++cnt, COLOR_DEFAULT, COLOR_DEFAULT); color_pairs_map[256][256] = cnt; +#endif } /* vim: set ts=8 sw=8 noexpandtab: */