index 486b0c7444cd29526195bdb7faa61511c3505c42..dc1d2251464c031c7744d22bd9ebac928975c0a4 100644 (file)
--- a/tig.c
+++ b/tig.c
return done_io(&io) || error;
}
-static int read_properties(struct io *io, const char *separators, int (*read)(char *, size_t, char *, size_t));
+static int
+io_load(struct io *io, const char *separators,
+ int (*read_property)(char *, size_t, char *, size_t))
+{
+ char *name;
+ int state = OK;
+
+ if (!start_io(io))
+ return ERR;
+
+ while (state == OK && (name = io_get(io, '\n', TRUE))) {
+ char *value;
+ size_t namelen;
+ size_t valuelen;
+
+ name = chomp_string(name);
+ namelen = strcspn(name, separators);
+
+ if (name[namelen]) {
+ name[namelen] = 0;
+ value = chomp_string(name + namelen + 1);
+ valuelen = strlen(value);
+
+ } else {
+ value = "";
+ valuelen = 0;
+ }
+
+ state = read_property(name, namelen, value, valuelen);
+ }
+
+ if (state != ERR && io_error(io))
+ state = ERR;
+ done_io(io);
+
+ return state;
+}
+
+static int
+run_io_load(const char **argv, const char *separators,
+ int (*read_property)(char *, size_t, char *, size_t))
+{
+ struct io io = {};
+
+ return init_io_rd(&io, argv, NULL, FORMAT_NONE)
+ ? io_load(&io, separators, read_property) : ERR;
+}
+
/*
* User requests
}
if (status == ERR) {
- fprintf(stderr, "Error on line %d, near '%.*s': %s\n",
- config_lineno, (int) optlen, opt, config_msg);
+ warn("Error on line %d, near '%.*s': %s",
+ config_lineno, (int) optlen, opt, config_msg);
config_errors = TRUE;
}
config_lineno = 0;
config_errors = FALSE;
- if (read_properties(&io, " \t", read_option) == ERR ||
+ if (io_load(&io, " \t", read_option) == ERR ||
config_errors == TRUE)
- fprintf(stderr, "Errors while loading %s.\n", path);
+ warn("Errors while loading %s.", path);
}
static int
struct line *curline; /* Line currently being drawn. */
enum line_type curtype; /* Attribute currently used for drawing. */
unsigned long col; /* Column when drawing. */
+ bool has_scrolled; /* View was scrolled. */
/* Loading */
struct io io;
}
-static void
-update_display_cursor(struct view *view)
-{
- /* Move the cursor to the right-most column of the cursor line.
- *
- * XXX: This could turn out to be a bit expensive, but it ensures that
- * the cursor does not jump around. */
- if (view->lines) {
- wmove(view->win, view->lineno - view->offset, view->width - 1);
- wnoutrefresh(view->win);
- }
-}
-
static void
update_view_title(struct view *view)
{
mvwaddnstr(view->title, 0, 0, buf, bufpos);
wclrtoeol(view->title);
- wmove(view->title, 0, view->width - 1);
wnoutrefresh(view->title);
}
redraw_view(view);
update_view_title(view);
}
-
- if (display[current_view])
- update_display_cursor(display[current_view]);
}
static void
wnoutrefresh(view->win);
}
+ view->has_scrolled = TRUE;
report("");
}
if (view->lines == 0) {
time_t secs = time(NULL) - view->start_time;
- if (secs > view->update_secs) {
+ if (secs > 1 && secs > view->update_secs) {
if (view->update_secs == 0)
redraw_view(view);
update_view_title(view);
/* Update the title _after_ the redraw so that if the redraw picks up a
* commit reference in view->ref it'll be available here. */
update_view_title(view);
- update_display_cursor(view);
return TRUE;
}
@@ -6118,6 +6149,10 @@ utf8_length(const char *string, int *width, size_t max_width, int *trimmed, bool
/* Whether or not the curses interface has been initialized. */
static bool cursed = FALSE;
+/* Terminal hacks and workarounds. */
+static bool use_scroll_redrawwin;
+static bool use_scroll_status_wclear;
+
/* The status window is used for polling keystrokes. */
static WINDOW *status_win;
va_start(args, msg);
wmove(status_win, 0, 0);
+ if (view->has_scrolled && use_scroll_status_wclear)
+ wclear(status_win);
if (*msg) {
vwprintw(status_win, msg, args);
status_empty = FALSE;
}
update_view_title(view);
- update_display_cursor(view);
}
/* Controls when nodelay should be in effect when polling user input. */
static void
init_display(void)
{
+ const char *term;
int x, y;
/* Initialize the curses library */
nonl(); /* Tell curses not to do NL->CR/NL on output */
cbreak(); /* Take input chars one at a time, no wait for \n */
noecho(); /* Don't echo input */
- leaveok(stdscr, TRUE);
+ leaveok(stdscr, FALSE);
if (has_colors())
init_colors();
if (opt_line_graphics) {
line_graphics[LINE_GRAPHIC_VLINE] = ACS_VLINE;
}
+
+ term = getenv("XTERM_VERSION") ? NULL : getenv("COLORTERM");
+ if (term && !strcmp(term, "gnome-terminal")) {
+ /* In the gnome-terminal-emulator, the message from
+ * scrolling up one line when impossible followed by
+ * scrolling down one line causes corruption of the
+ * status line. This is fixed by calling wclear. */
+ use_scroll_status_wclear = TRUE;
+ use_scroll_redrawwin = FALSE;
+
+ } else if (term && !strcmp(term, "xrvt-xpm")) {
+ /* No problems with full optimizations in xrvt-(unicode)
+ * and aterm. */
+ use_scroll_status_wclear = use_scroll_redrawwin = FALSE;
+
+ } else {
+ /* When scrolling in (u)xterm the last line in the
+ * scrolling direction will update slowly. */
+ use_scroll_redrawwin = TRUE;
+ use_scroll_status_wclear = FALSE;
+ }
}
static int
-get_input(bool prompting)
+get_input(int prompt_position)
{
struct view *view;
- int i, key;
+ int i, key, cursor_y, cursor_x;
- if (prompting)
+ if (prompt_position)
input_mode = TRUE;
- while (true) {
- foreach_view (view, i)
+ while (TRUE) {
+ foreach_view (view, i) {
update_view(view);
+ if (view_is_displayed(view) && view->has_scrolled &&
+ use_scroll_redrawwin)
+ redrawwin(view->win);
+ view->has_scrolled = FALSE;
+ }
+
+ /* Update the cursor position. */
+ if (prompt_position) {
+ getbegyx(status_win, cursor_y, cursor_x);
+ cursor_x = prompt_position;
+ } else {
+ view = display[current_view];
+ getbegyx(view->win, cursor_y, cursor_x);
+ cursor_x = view->width - 1;
+ cursor_y += view->lineno - view->offset;
+ }
+ setsyx(cursor_y, cursor_x);
/* Refresh, accept single keystroke of input */
doupdate();
getmaxyx(stdscr, height, width);
- /* Resize the status view first so the cursor is
- * placed properly. */
wresize(status_win, 1, width);
mvwin(status_win, height - 1, 0);
wnoutrefresh(status_win);
mvwprintw(status_win, 0, 0, "%s%.*s", prompt, pos, buf);
wclrtoeol(status_win);
- key = get_input(TRUE);
+ key = get_input(pos + 1);
switch (key) {
case KEY_RETURN:
case KEY_ENTER:
* Repository properties
*/
-static int
-git_properties(const char **argv, const char *separators,
- int (*read_property)(char *, size_t, char *, size_t))
-{
- struct io io = {};
-
- if (init_io_rd(&io, argv, NULL, FORMAT_NONE))
- return read_properties(&io, separators, read_property);
- return ERR;
-}
-
static struct ref *refs = NULL;
static size_t refs_alloc = 0;
static size_t refs_size = 0;
while (id_refs_size > 0)
free(id_refs[--id_refs_size]);
- return git_properties(ls_remote_argv, "\t", read_ref);
+ return run_io_load(ls_remote_argv, "\t", read_ref);
}
static int
{
const char *config_list_argv[] = { "git", GIT_CONFIG, "--list", NULL };
- return git_properties(config_list_argv, "=", read_repo_config_option);
+ return run_io_load(config_list_argv, "=", read_repo_config_option);
}
static int
}
}
- return git_properties(rev_parse_argv, "=", read_repo_info);
-}
-
-static int
-read_properties(struct io *io, const char *separators,
- int (*read_property)(char *, size_t, char *, size_t))
-{
- char *name;
- int state = OK;
-
- if (!start_io(io))
- return ERR;
-
- while (state == OK && (name = io_get(io, '\n', TRUE))) {
- char *value;
- size_t namelen;
- size_t valuelen;
-
- name = chomp_string(name);
- namelen = strcspn(name, separators);
-
- if (name[namelen]) {
- name[namelen] = 0;
- value = chomp_string(name + namelen + 1);
- valuelen = strlen(value);
-
- } else {
- value = "";
- valuelen = 0;
- }
-
- state = read_property(name, namelen, value, valuelen);
- }
-
- if (state != ERR && io_error(io))
- state = ERR;
- done_io(io);
-
- return state;
+ return run_io_load(rev_parse_argv, "=", read_repo_info);
}
}
while (view_driver(display[current_view], request)) {
- int key = get_input(FALSE);
+ int key = get_input(0);
view = display[current_view];
request = get_keybinding(view->keymap, key);