X-Git-Url: https://git.distorted.org.uk/~mdw/tig/blobdiff_plain/9295982a3492d52bc85a6b7b12817ca3d6fbe007..b1744cbe9a54bc7b62b1c5316b6e73ab95cfea12:/tig.c diff --git a/tig.c b/tig.c index fcbf93c..73aa991 100644 --- a/tig.c +++ b/tig.c @@ -42,6 +42,9 @@ #include #include +/* ncurses(3): Must be defined to have extended wide-character functions. */ +#define _XOPEN_SOURCE_EXTENDED + #include #if __GNUC__ >= 3 @@ -55,7 +58,7 @@ static void warn(const char *msg, ...); static void report(const char *msg, ...); static int read_properties(FILE *pipe, const char *separators, int (*read)(char *, size_t, char *, size_t)); static void set_nonblocking_input(bool loading); -static size_t utf8_length(const char *string, size_t max_width, int *coloffset, int *trimmed); +static size_t utf8_length(const char *string, size_t max_width, int *trimmed, bool reserve); #define ABS(x) ((x) >= 0 ? (x) : -(x)) #define MIN(x, y) ((x) < (y) ? (x) : (y)) @@ -107,7 +110,7 @@ static size_t utf8_length(const char *string, size_t max_width, int *coloffset, "git ls-remote $(git rev-parse --git-dir) 2>/dev/null" #define TIG_DIFF_CMD \ - "git show --no-color --root --patch-with-stat --find-copies-harder -C %s 2>/dev/null" + "git show --pretty=fuller --no-color --root --patch-with-stat --find-copies-harder -C %s 2>/dev/null" #define TIG_LOG_CMD \ "git log --no-color --cc --stat -n100 %s 2>/dev/null" @@ -1453,6 +1456,40 @@ static struct view views[] = { #define view_is_displayed(view) \ (view == display[0] || view == display[1]) +static int +draw_text(struct view *view, const char *string, int max_len, int col, + bool use_tilde, int tilde_attr) +{ + int len = 0; + int trimmed = FALSE; + + if (max_len <= 0) + return 0; + + if (opt_utf8) { + len = utf8_length(string, max_len, &trimmed, use_tilde); + } else { + len = strlen(string); + if (len > max_len) { + if (use_tilde) { + max_len -= 1; + } + len = max_len; + trimmed = TRUE; + } + } + + waddnstr(view->win, string, len); + if (trimmed && use_tilde) { + if (tilde_attr != -1) + wattrset(view->win, tilde_attr); + waddch(view->win, '~'); + len++; + } + + return len; +} + static bool draw_view_line(struct view *view, unsigned int lineno) { @@ -2590,7 +2627,6 @@ pager_draw(struct view *view, struct line *line, unsigned int lineno, bool selec { char *text = line->data; enum line_type type = line->type; - int textlen = strlen(text); int attr; wmove(view->win, lineno, 0); @@ -2643,13 +2679,9 @@ pager_draw(struct view *view, struct line *line, unsigned int lineno, bool selec } } else { - int col = 0, pos = 0; + int tilde_attr = get_line_attr(LINE_MAIN_DELIM); - for (; pos < textlen && col < view->width; pos++, col++) - if (text[pos] == '\t') - col += TABSIZE - (col % TABSIZE) - 1; - - waddnstr(view->win, text, pos); + draw_text(view, text, view->width, 0, TRUE, tilde_attr); } return TRUE; @@ -3324,7 +3356,7 @@ error_out: /* Don't show unmerged entries in the staged section. */ #define STATUS_DIFF_INDEX_CMD "git diff-index -z --diff-filter=ACDMRTXB --cached -M HEAD" -#define STATUS_DIFF_FILES_CMD "git update-index -q --refresh && git diff-files -z" +#define STATUS_DIFF_FILES_CMD "git diff-files -z" #define STATUS_LIST_OTHER_CMD \ "git ls-files -z --others --exclude-per-directory=.gitignore" @@ -3368,6 +3400,8 @@ status_open(struct view *view) return FALSE; } + system("git update-index -q --refresh"); + if (!status_run(view, STATUS_DIFF_INDEX_CMD, TRUE, LINE_STAT_STAGED) || !status_run(view, STATUS_DIFF_FILES_CMD, TRUE, LINE_STAT_UNSTAGED) || !status_run(view, cmd, FALSE, LINE_STAT_UNTRACKED)) @@ -3387,12 +3421,14 @@ static bool status_draw(struct view *view, struct line *line, unsigned int lineno, bool selected) { struct status *status = line->data; + int tilde_attr = get_line_attr(LINE_MAIN_DELIM); wmove(view->win, lineno, 0); if (selected) { wattrset(view->win, get_line_attr(LINE_CURSOR)); wchgat(view->win, -1, 0, LINE_CURSOR, NULL); + tilde_attr = -1; } else if (!status && line->type != LINE_STAT_NONE) { wattrset(view->win, get_line_attr(LINE_STAT_SECTION)); @@ -3426,7 +3462,7 @@ status_draw(struct view *view, struct line *line, unsigned int lineno, bool sele return FALSE; } - waddstr(view->win, text); + draw_text(view, text, view->width, 0, TRUE, tilde_attr); return TRUE; } @@ -3434,8 +3470,10 @@ status_draw(struct view *view, struct line *line, unsigned int lineno, bool sele if (!selected) wattrset(view->win, A_NORMAL); wmove(view->win, lineno, 4); - waddstr(view->win, status->new.name); + if (view->width < 5) + return TRUE; + draw_text(view, status->new.name, view->width - 5, 5, TRUE, tilde_attr); return TRUE; } @@ -4117,67 +4155,75 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select enum line_type type; int col = 0; size_t timelen; - size_t authorlen; - int trimmed = 1; + int tilde_attr; + int space; if (!*commit->author) return FALSE; + space = view->width; wmove(view->win, lineno, col); if (selected) { type = LINE_CURSOR; wattrset(view->win, get_line_attr(type)); wchgat(view->win, -1, 0, type, NULL); - + tilde_attr = -1; } else { type = LINE_MAIN_COMMIT; wattrset(view->win, get_line_attr(LINE_MAIN_DATE)); + tilde_attr = get_line_attr(LINE_MAIN_DELIM); } - timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time); - waddnstr(view->win, buf, timelen); - waddstr(view->win, " "); + { + int n; - col += DATE_COLS; - wmove(view->win, lineno, col); - if (type != LINE_CURSOR) - wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR)); + timelen = strftime(buf, sizeof(buf), DATE_FORMAT, &commit->time); + n = draw_text( + view, buf, view->width - col, col, FALSE, tilde_attr); + draw_text( + view, " ", view->width - col - n, col + n, FALSE, + tilde_attr); - if (opt_utf8) { - authorlen = utf8_length(commit->author, AUTHOR_COLS - 2, &col, &trimmed); - } else { - authorlen = strlen(commit->author); - if (authorlen > AUTHOR_COLS - 2) { - authorlen = AUTHOR_COLS - 2; - trimmed = 1; - } + col += DATE_COLS; + wmove(view->win, lineno, col); + if (col >= view->width) + return TRUE; } + if (type != LINE_CURSOR) + wattrset(view->win, get_line_attr(LINE_MAIN_AUTHOR)); - if (trimmed) { - waddnstr(view->win, commit->author, authorlen); - if (type != LINE_CURSOR) - wattrset(view->win, get_line_attr(LINE_MAIN_DELIM)); - waddch(view->win, '~'); - } else { - waddstr(view->win, commit->author); + { + int max_len; + + max_len = view->width - col; + if (max_len > AUTHOR_COLS - 1) + max_len = AUTHOR_COLS - 1; + draw_text( + view, commit->author, max_len, col, TRUE, tilde_attr); + col += AUTHOR_COLS; + if (col >= view->width) + return TRUE; } - col += AUTHOR_COLS; - if (opt_rev_graph && commit->graph_size) { + size_t graph_size = view->width - col; size_t i; if (type != LINE_CURSOR) wattrset(view->win, get_line_attr(LINE_MAIN_REVGRAPH)); wmove(view->win, lineno, col); + if (graph_size > commit->graph_size) + graph_size = commit->graph_size; /* Using waddch() instead of waddnstr() ensures that * they'll be rendered correctly for the cursor line. */ - for (i = 0; i < commit->graph_size; i++) + for (i = 0; i < graph_size; i++) waddch(view->win, commit->graph[i]); - waddch(view->win, ' '); col += commit->graph_size + 1; + if (col >= view->width) + return TRUE; + waddch(view->win, ' '); } if (type != LINE_CURSOR) wattrset(view->win, A_NORMAL); @@ -4196,27 +4242,31 @@ main_draw(struct view *view, struct line *line, unsigned int lineno, bool select wattrset(view->win, get_line_attr(LINE_MAIN_REMOTE)); else wattrset(view->win, get_line_attr(LINE_MAIN_REF)); - waddstr(view->win, "["); - waddstr(view->win, commit->refs[i]->name); - waddstr(view->win, "]"); + + col += draw_text( + view, "[", view->width - col, col, TRUE, + tilde_attr); + col += draw_text( + view, commit->refs[i]->name, view->width - col, + col, TRUE, tilde_attr); + col += draw_text( + view, "]", view->width - col, col, TRUE, + tilde_attr); if (type != LINE_CURSOR) wattrset(view->win, A_NORMAL); - waddstr(view->win, " "); - col += strlen(commit->refs[i]->name) + STRING_SIZE("[] "); + col += draw_text( + view, " ", view->width - col, col, TRUE, + tilde_attr); + if (col >= view->width) + return TRUE; } while (commit->refs[i++]->next); } if (type != LINE_CURSOR) wattrset(view->win, get_line_attr(type)); - { - int titlelen = strlen(commit->title); - - if (col + titlelen > view->width) - titlelen = view->width - col; - - waddnstr(view->win, commit->title, titlelen); - } + col += draw_text( + view, commit->title, view->width - col, col, TRUE, tilde_attr); return TRUE; } @@ -4431,6 +4481,9 @@ unicode_width(unsigned long c) || (c >= 0x30000 && c <= 0x3fffd))) return 2; + if (c == '\t') + return opt_tab_size; + return 1; } @@ -4498,19 +4551,16 @@ utf8_to_unicode(const char *string, size_t length) /* Calculates how much of string can be shown within the given maximum width * and sets trimmed parameter to non-zero value if all of string could not be - * shown. - * - * Additionally, adds to coloffset how many many columns to move to align with - * the expected position. Takes into account how multi-byte and double-width - * characters will effect the cursor position. + * shown. If the reserve flag is TRUE, it will reserve at least one + * trailing character, which can be useful when drawing a delimiter. * * Returns the number of bytes to output from string to satisfy max_width. */ static size_t -utf8_length(const char *string, size_t max_width, int *coloffset, int *trimmed) +utf8_length(const char *string, size_t max_width, int *trimmed, bool reserve) { const char *start = string; const char *end = strchr(string, '\0'); - size_t mbwidth = 0; + unsigned char last_bytes = 0; size_t width = 0; *trimmed = 0; @@ -4536,27 +4586,16 @@ utf8_length(const char *string, size_t max_width, int *coloffset, int *trimmed) width += ucwidth; if (width > max_width) { *trimmed = 1; + if (reserve && width - ucwidth == max_width) { + string -= last_bytes; + } break; } - /* The column offset collects the differences between the - * number of bytes encoding a character and the number of - * columns will be used for rendering said character. - * - * So if some character A is encoded in 2 bytes, but will be - * represented on the screen using only 1 byte this will and up - * adding 1 to the multi-byte column offset. - * - * Assumes that no double-width character can be encoding in - * less than two bytes. */ - if (bytes > ucwidth) - mbwidth += bytes - ucwidth; - string += bytes; + last_bytes = bytes; } - *coloffset += mbwidth; - return string - start; }