Code

tig-0.14.1
[tig.git] / tig.c
diff --git a/tig.c b/tig.c
index a0d4df405c850d0d205846b9597be79251c966eb..180661a4fcfbc94067a795898df1a6fc6a6e0330 100644 (file)
--- a/tig.c
+++ b/tig.c
@@ -109,7 +109,6 @@ static size_t utf8_length(const char **string, size_t col, int *width, size_t ma
 
 /* The default interval between line numbers. */
 #define NUMBER_INTERVAL        5
-#define SCROLL_INTERVAL        1
 
 #define TAB_SIZE       8
 
@@ -117,6 +116,8 @@ static size_t utf8_length(const char **string, size_t col, int *width, size_t ma
 
 #define NULL_ID                "0000000000000000000000000000000000000000"
 
+#define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
+
 #ifndef GIT_CONFIG
 #define GIT_CONFIG "config"
 #endif
@@ -861,6 +862,7 @@ static bool opt_line_graphics               = TRUE;
 static bool opt_rev_graph              = FALSE;
 static bool opt_show_refs              = TRUE;
 static int opt_num_interval            = NUMBER_INTERVAL;
+static double opt_hscroll              = 0.50;
 static int opt_tab_size                        = TAB_SIZE;
 static int opt_author_cols             = AUTHOR_COLS-1;
 static char opt_path[SIZEOF_STR]       = "";
@@ -1382,6 +1384,27 @@ static const struct enum_map attr_map[] = {
 
 #define set_attribute(attr, name)      map_enum(attr, attr_map, name)
 
+static int parse_step(double *opt, const char *arg)
+{
+       *opt = atoi(arg);
+       if (!strchr(arg, '%'))
+               return OK;
+
+       /* "Shift down" so 100% and 1 does not conflict. */
+       *opt = (*opt - 1) / 100;
+       if (*opt >= 1.0) {
+               *opt = 0.99;
+               config_msg = "Step value larger than 100%";
+               return ERR;
+       }
+       if (*opt < 0.0) {
+               *opt = 1;
+               config_msg = "Invalid step value";
+               return ERR;
+       }
+       return OK;
+}
+
 static int
 parse_int(int *opt, const char *arg, int min, int max)
 {
@@ -1468,7 +1491,7 @@ parse_string(char *opt, const char *arg, size_t optsize)
                }
                arg += 1; arglen -= 2;
        default:
-               string_ncopy_do(opt, optsize, arg, strlen(arg));
+               string_ncopy_do(opt, optsize, arg, arglen);
                return OK;
        }
 }
@@ -1511,6 +1534,9 @@ option_set_command(int argc, const char *argv[])
        if (!strcmp(argv[0], "author-width"))
                return parse_int(&opt_author_cols, argv[2], 0, 1024);
 
+       if (!strcmp(argv[0], "horizontal-scroll"))
+               return parse_step(&opt_hscroll, argv[2]);
+
        if (!strcmp(argv[0], "tab-size"))
                return parse_int(&opt_tab_size, argv[2], 1, 1024);
 
@@ -1745,7 +1771,6 @@ struct view {
        enum line_type curtype; /* Attribute currently used for drawing. */
        unsigned long col;      /* Column when drawing. */
        bool has_scrolled;      /* View was scrolled. */
-       bool can_hscroll;       /* View can be scrolled horizontally. */
 
        /* Loading */
        struct io io;
@@ -1818,7 +1843,7 @@ enum line_graphic {
        LINE_GRAPHIC_VLINE
 };
 
-static int line_graphics[] = {
+static chtype line_graphics[] = {
        /* LINE_GRAPHIC_VLINE: */ '|'
 };
 
@@ -1866,9 +1891,6 @@ draw_chars(struct view *view, enum line_type type, const char *string,
                col++;
        }
 
-       if (view->col + col >= view->width + view->yoffset)
-               view->can_hscroll = TRUE;
-
        return col;
 }
 
@@ -1883,66 +1905,25 @@ draw_space(struct view *view, enum line_type type, int max, int spaces)
        while (spaces > 0) {
                int len = MIN(spaces, sizeof(space) - 1);
 
-               col += draw_chars(view, type, space, spaces, FALSE);
+               col += draw_chars(view, type, space, len, FALSE);
                spaces -= len;
        }
 
        return col;
 }
 
-static bool
-draw_lineno(struct view *view, unsigned int lineno)
-{
-       size_t skip = view->yoffset > view->col ? view->yoffset - view->col : 0;
-       char number[10];
-       int digits3 = view->digits < 3 ? 3 : view->digits;
-       int max_number = MIN(digits3, STRING_SIZE(number));
-       int max = view->width - view->col;
-       int col;
-
-       if (max < max_number)
-               max_number = max;
-
-       lineno += view->offset + 1;
-       if (lineno == 1 || (lineno % opt_num_interval) == 0) {
-               static char fmt[] = "%1ld";
-
-               if (view->digits <= 9)
-                       fmt[1] = '0' + digits3;
-
-               if (!string_format(number, fmt, lineno))
-                       number[0] = 0;
-               col = draw_chars(view, LINE_LINE_NUMBER, number, max_number, TRUE);
-       } else {
-               col = draw_space(view, LINE_LINE_NUMBER, max_number, max_number);
-       }
-
-       if (col < max && skip <= col) {
-               set_view_attr(view, LINE_DEFAULT);
-               waddch(view->win, line_graphics[LINE_GRAPHIC_VLINE]);
-       }
-       col++;
-
-       view->col += col;
-       if (col < max && skip <= col)
-               col = draw_space(view, LINE_DEFAULT, max - col, 1);
-       view->col++;
-
-       return view->width + view->yoffset <= view->col;
-}
-
 static bool
 draw_text(struct view *view, enum line_type type, const char *string, bool trim)
 {
        view->col += draw_chars(view, type, string, view->width + view->yoffset - view->col, trim);
-       return view->width - view->col <= 0;
+       return view->width + view->yoffset <= view->col;
 }
 
 static bool
 draw_graphic(struct view *view, enum line_type type, chtype graphic[], size_t size)
 {
        size_t skip = view->yoffset > view->col ? view->yoffset - view->col : 0;
-       int max = view->width - view->col;
+       int max = view->width + view->yoffset - view->col;
        int i;
 
        if (max < size)
@@ -1959,13 +1940,13 @@ draw_graphic(struct view *view, enum line_type type, chtype graphic[], size_t si
                waddch(view->win, ' ');
        view->col++;
 
-       return view->width - view->col <= 0;
+       return view->width + view->yoffset <= view->col;
 }
 
 static bool
 draw_field(struct view *view, enum line_type type, const char *text, int len, bool trim)
 {
-       int max = MIN(view->width - view->col, len);
+       int max = MIN(view->width + view->yoffset - view->col, len);
        int col;
 
        if (text)
@@ -2021,22 +2002,45 @@ draw_author(struct view *view, const char *author)
 static bool
 draw_mode(struct view *view, mode_t mode)
 {
-       static const char dir_mode[]    = "drwxr-xr-x";
-       static const char link_mode[]   = "lrwxrwxrwx";
-       static const char exe_mode[]    = "-rwxr-xr-x";
-       static const char file_mode[]   = "-rw-r--r--";
        const char *str;
 
        if (S_ISDIR(mode))
-               str = dir_mode;
+               str = "drwxr-xr-x";
        else if (S_ISLNK(mode))
-               str = link_mode;
-       else if (mode & S_IXUSR)
-               str = exe_mode;
+               str = "lrwxrwxrwx";
+       else if (S_ISGITLINK(mode))
+               str = "m---------";
+       else if (S_ISREG(mode) && mode & S_IXUSR)
+               str = "-rwxr-xr-x";
+       else if (S_ISREG(mode))
+               str = "-rw-r--r--";
        else
-               str = file_mode;
+               str = "----------";
 
-       return draw_field(view, LINE_MODE, str, sizeof(file_mode), FALSE);
+       return draw_field(view, LINE_MODE, str, STRING_SIZE("-rw-r--r-- "), FALSE);
+}
+
+static bool
+draw_lineno(struct view *view, unsigned int lineno)
+{
+       char number[10];
+       int digits3 = view->digits < 3 ? 3 : view->digits;
+       int max = MIN(view->width + view->yoffset - view->col, digits3);
+       char *text = NULL;
+
+       lineno += view->offset + 1;
+       if (lineno == 1 || (lineno % opt_num_interval) == 0) {
+               static char fmt[] = "%1ld";
+
+               fmt[1] = '0' + (view->digits <= 9 ? digits3 : 1);
+               if (string_format(number, fmt, lineno))
+                       text = number;
+       }
+       if (text)
+               view->col += draw_chars(view, LINE_LINE_NUMBER, text, max, TRUE);
+       else
+               view->col += draw_space(view, LINE_LINE_NUMBER, max, digits3);
+       return draw_graphic(view, LINE_DEFAULT, &line_graphics[LINE_GRAPHIC_VLINE], 1);
 }
 
 static bool
@@ -2096,9 +2100,6 @@ redraw_view_from(struct view *view, int lineno)
 {
        assert(0 <= lineno && lineno < view->height);
 
-       if (lineno == 0)
-               view->can_hscroll = FALSE;
-
        for (; lineno < view->height; lineno++) {
                if (!draw_view_line(view, lineno))
                        break;
@@ -2283,6 +2284,15 @@ goto_view_line(struct view *view, unsigned long offset, unsigned long lineno)
        return FALSE;
 }
 
+static int
+apply_step(double step, int value)
+{
+       if (step >= 1)
+               return (int) step;
+       value *= step + 0.01;
+       return value ? value : 1;
+}
+
 /* Scrolling backend */
 static void
 do_scroll_view(struct view *view, int lines)
@@ -2344,19 +2354,15 @@ scroll_view(struct view *view, enum request request)
                        report("Cannot scroll beyond the first column");
                        return;
                }
-               if (view->yoffset <= SCROLL_INTERVAL)
+               if (view->yoffset <= apply_step(opt_hscroll, view->width))
                        view->yoffset = 0;
                else
-                       view->yoffset -= SCROLL_INTERVAL;
+                       view->yoffset -= apply_step(opt_hscroll, view->width);
                redraw_view_from(view, 0);
                report("");
                return;
        case REQ_SCROLL_RIGHT:
-               if (!view->can_hscroll) {
-                       report("Cannot scroll beyond the last column");
-                       return;
-               }
-               view->yoffset += SCROLL_INTERVAL;
+               view->yoffset += apply_step(opt_hscroll, view->width);
                redraw_view(view);
                report("");
                return;
@@ -2822,7 +2828,7 @@ update_view(struct view *view)
                return TRUE;
 
        if (!io_can_read(view->pipe)) {
-               if (view->lines == 0) {
+               if (view->lines == 0 && view_is_displayed(view)) {
                        time_t secs = time(NULL) - view->start_time;
 
                        if (secs > 1 && secs > view->update_secs) {
@@ -3095,10 +3101,8 @@ view_driver(struct view *view, enum request request)
 {
        int i;
 
-       if (request == REQ_NONE) {
-               doupdate();
+       if (request == REQ_NONE)
                return TRUE;
-       }
 
        if (request > REQ_NONE) {
                open_run_request(request);
@@ -5102,18 +5106,19 @@ status_update_file(struct status *status, enum line_type type)
                return FALSE;
 
        result = status_update_write(&io, status, type);
-       done_io(&io);
-       return result;
+       return done_io(&io) && result;
 }
 
 static bool
 status_update_files(struct view *view, struct line *line)
 {
+       char buf[sizeof(view->ref)];
        struct io io = {};
        bool result = TRUE;
        struct line *pos = view->line + view->lines;
        int files = 0;
        int file, done;
+       int cursor_y, cursor_x;
 
        if (!status_update_prepare(&io, line->type))
                return FALSE;
@@ -5121,7 +5126,9 @@ status_update_files(struct view *view, struct line *line)
        for (pos = line; pos < view->line + view->lines && pos->data; pos++)
                files++;
 
-       for (file = 0, done = 0; result && file < files; line++, file++) {
+       string_copy(buf, view->ref);
+       getsyx(cursor_y, cursor_x);
+       for (file = 0, done = 5; result && file < files; line++, file++) {
                int almost_done = file * 100 / files;
 
                if (almost_done > done) {
@@ -5129,12 +5136,14 @@ status_update_files(struct view *view, struct line *line)
                        string_format(view->ref, "updating file %u of %u (%d%% done)",
                                      file, files, done);
                        update_view_title(view);
+                       setsyx(cursor_y, cursor_x);
+                       doupdate();
                }
                result = status_update_write(&io, line->data, line->type);
        }
+       string_copy(view->ref, buf);
 
-       done_io(&io);
-       return result;
+       return done_io(&io) && result;
 }
 
 static bool
@@ -6990,6 +6999,7 @@ main(int argc, const char *argv[])
        size_t i;
 
        signal(SIGINT, quit);
+       signal(SIGPIPE, SIG_IGN);
 
        if (setlocale(LC_ALL, "")) {
                char *codeset = nl_langinfo(CODESET);