index e5612c197c7320b51ea0303284ab52718ca6d9eb..7bc5daaaeeb440018bcb7642e42af11c66ea63ad 100644 (file)
--- a/tig.c
+++ b/tig.c
#define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
/* Some ASCII-shorthands fitted into the ncurses namespace. */
#define S_ISGITLINK(mode) (((mode) & S_IFMT) == 0160000)
/* Some ASCII-shorthands fitted into the ncurses namespace. */
+#define KEY_CTL(x) ((x) & 0x1f) /* KEY_CTL(A) == ^A == \1 */
#define KEY_TAB '\t'
#define KEY_RETURN '\r'
#define KEY_ESC 27
#define KEY_TAB '\t'
#define KEY_RETURN '\r'
#define KEY_ESC 27
argv[0] = NULL;
}
argv[0] = NULL;
}
+static size_t
+argv_size(const char **argv)
+{
+ int argc = 0;
+
+ while (argv && argv[argc])
+ argc++;
+
+ return argc;
+}
+
DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
static bool
argv_append(const char ***argv, const char *arg)
{
DEFINE_ALLOCATOR(argv_realloc, const char *, SIZEOF_ARG)
static bool
argv_append(const char ***argv, const char *arg)
{
- int argc = 0;
-
- while (*argv && (*argv)[argc])
- argc++;
+ size_t argc = argv_size(*argv);
if (!argv_realloc(argv, argc, 2))
return FALSE;
if (!argv_realloc(argv, argc, 2))
return FALSE;
REQ_(MOVE_LAST_LINE, "Move cursor to last line"), \
\
REQ_GROUP("Scrolling") \
REQ_(MOVE_LAST_LINE, "Move cursor to last line"), \
\
REQ_GROUP("Scrolling") \
+ REQ_(SCROLL_FIRST_COL, "Scroll to the first line columns"), \
REQ_(SCROLL_LEFT, "Scroll two columns left"), \
REQ_(SCROLL_RIGHT, "Scroll two columns right"), \
REQ_(SCROLL_LINE_UP, "Scroll one line up"), \
REQ_(SCROLL_LEFT, "Scroll two columns left"), \
REQ_(SCROLL_RIGHT, "Scroll two columns right"), \
REQ_(SCROLL_LINE_UP, "Scroll one line up"), \
REQ_(OPTIONS, "Open option menu"), \
REQ_(TOGGLE_LINENO, "Toggle line numbers"), \
REQ_(TOGGLE_DATE, "Toggle date display"), \
REQ_(OPTIONS, "Open option menu"), \
REQ_(TOGGLE_LINENO, "Toggle line numbers"), \
REQ_(TOGGLE_DATE, "Toggle date display"), \
- REQ_(TOGGLE_DATE_SHORT, "Toggle short (date-only) dates"), \
REQ_(TOGGLE_AUTHOR, "Toggle author display"), \
REQ_(TOGGLE_REV_GRAPH, "Toggle revision graph visualization"), \
REQ_(TOGGLE_REFS, "Toggle reference display (tags/branches)"), \
REQ_(TOGGLE_AUTHOR, "Toggle author display"), \
REQ_(TOGGLE_REV_GRAPH, "Toggle revision graph visualization"), \
REQ_(TOGGLE_REFS, "Toggle reference display (tags/branches)"), \
static bool opt_line_graphics = TRUE;
static bool opt_rev_graph = FALSE;
static bool opt_show_refs = TRUE;
static bool opt_line_graphics = TRUE;
static bool opt_rev_graph = FALSE;
static bool opt_show_refs = TRUE;
+static bool opt_untracked_dirs_content = TRUE;
static int opt_num_interval = 5;
static double opt_hscroll = 0.50;
static double opt_scale_split_view = 2.0 / 3.0;
static int opt_num_interval = 5;
static double opt_hscroll = 0.50;
static double opt_scale_split_view = 2.0 / 3.0;
{ KEY_TAB, REQ_VIEW_NEXT },
{ KEY_RETURN, REQ_ENTER },
{ KEY_UP, REQ_PREVIOUS },
{ KEY_TAB, REQ_VIEW_NEXT },
{ KEY_RETURN, REQ_ENTER },
{ KEY_UP, REQ_PREVIOUS },
+ { KEY_CTL('P'), REQ_PREVIOUS },
{ KEY_DOWN, REQ_NEXT },
{ KEY_DOWN, REQ_NEXT },
+ { KEY_CTL('N'), REQ_NEXT },
{ 'R', REQ_REFRESH },
{ KEY_F(5), REQ_REFRESH },
{ 'O', REQ_MAXIMIZE },
{ 'R', REQ_REFRESH },
{ KEY_F(5), REQ_REFRESH },
{ 'O', REQ_MAXIMIZE },
{ KEY_HOME, REQ_MOVE_FIRST_LINE },
{ KEY_END, REQ_MOVE_LAST_LINE },
{ KEY_NPAGE, REQ_MOVE_PAGE_DOWN },
{ KEY_HOME, REQ_MOVE_FIRST_LINE },
{ KEY_END, REQ_MOVE_LAST_LINE },
{ KEY_NPAGE, REQ_MOVE_PAGE_DOWN },
+ { KEY_CTL('D'), REQ_MOVE_PAGE_DOWN },
{ ' ', REQ_MOVE_PAGE_DOWN },
{ KEY_PPAGE, REQ_MOVE_PAGE_UP },
{ ' ', REQ_MOVE_PAGE_DOWN },
{ KEY_PPAGE, REQ_MOVE_PAGE_UP },
+ { KEY_CTL('U'), REQ_MOVE_PAGE_UP },
{ 'b', REQ_MOVE_PAGE_UP },
{ '-', REQ_MOVE_PAGE_UP },
/* Scrolling */
{ 'b', REQ_MOVE_PAGE_UP },
{ '-', REQ_MOVE_PAGE_UP },
/* Scrolling */
+ { '|', REQ_SCROLL_FIRST_COL },
{ KEY_LEFT, REQ_SCROLL_LEFT },
{ KEY_RIGHT, REQ_SCROLL_RIGHT },
{ KEY_IC, REQ_SCROLL_LINE_UP },
{ KEY_LEFT, REQ_SCROLL_LEFT },
{ KEY_RIGHT, REQ_SCROLL_RIGHT },
{ KEY_IC, REQ_SCROLL_LINE_UP },
+ { KEY_CTL('Y'), REQ_SCROLL_LINE_UP },
{ KEY_DC, REQ_SCROLL_LINE_DOWN },
{ KEY_DC, REQ_SCROLL_LINE_DOWN },
+ { KEY_CTL('E'), REQ_SCROLL_LINE_DOWN },
{ 'w', REQ_SCROLL_PAGE_UP },
{ 's', REQ_SCROLL_PAGE_DOWN },
{ 'w', REQ_SCROLL_PAGE_UP },
{ 's', REQ_SCROLL_PAGE_DOWN },
{ 'z', REQ_STOP_LOADING },
{ 'v', REQ_SHOW_VERSION },
{ 'r', REQ_SCREEN_REDRAW },
{ 'z', REQ_STOP_LOADING },
{ 'v', REQ_SHOW_VERSION },
{ 'r', REQ_SCREEN_REDRAW },
+ { KEY_CTL('L'), REQ_SCREEN_REDRAW },
{ 'o', REQ_OPTIONS },
{ '.', REQ_TOGGLE_LINENO },
{ 'D', REQ_TOGGLE_DATE },
{ 'o', REQ_OPTIONS },
{ '.', REQ_TOGGLE_LINENO },
{ 'D', REQ_TOGGLE_DATE },
if (!strcasecmp(key_table[i].name, name))
return key_table[i].value;
if (!strcasecmp(key_table[i].name, name))
return key_table[i].value;
+ if (strlen(name) == 2 && name[0] == '^' && isprint(*name))
+ return (int)name[1] & 0x1f;
if (strlen(name) == 1 && isprint(*name))
return (int) *name;
if (strlen(name) == 1 && isprint(*name))
return (int) *name;
-
return ERR;
}
static const char *
get_key_name(int key_value)
{
return ERR;
}
static const char *
get_key_name(int key_value)
{
- static char key_char[] = "'X'";
+ static char key_char[] = "'X'\0";
const char *seq = NULL;
int key;
const char *seq = NULL;
int key;
if (key_table[key].value == key_value)
seq = key_table[key].name;
if (key_table[key].value == key_value)
seq = key_table[key].name;
- if (seq == NULL &&
- key_value < 127 &&
- isprint(key_value)) {
- key_char[1] = (char) key_value;
+ if (seq == NULL && key_value < 0x7f) {
+ char *s = key_char + 1;
+
+ if (key_value >= 0x20) {
+ *s++ = key_value;
+ } else {
+ *s++ = '^';
+ *s++ = 0x40 | (key_value & 0x1f);
+ }
+ *s++ = '\'';
+ *s++ = '\0';
seq = key_char;
}
seq = key_char;
}
if (!strcmp(argv[0], "commit-encoding"))
return parse_string(opt_encoding, argv[2], sizeof(opt_encoding));
if (!strcmp(argv[0], "commit-encoding"))
return parse_string(opt_encoding, argv[2], sizeof(opt_encoding));
+ if (!strcmp(argv[0], "status-untracked-dirs"))
+ return parse_bool(&opt_untracked_dirs_content, argv[2]);
+
config_msg = "Unknown variable name";
return ERR;
}
config_msg = "Unknown variable name";
return ERR;
}
const char *home = getenv("HOME");
const char *tigrc_user = getenv("TIGRC_USER");
const char *tigrc_system = getenv("TIGRC_SYSTEM");
const char *home = getenv("HOME");
const char *tigrc_user = getenv("TIGRC_USER");
const char *tigrc_system = getenv("TIGRC_SYSTEM");
+ const char *tig_diff_opts = getenv("TIG_DIFF_OPTS");
char buf[SIZEOF_STR];
if (!tigrc_system)
char buf[SIZEOF_STR];
if (!tigrc_system)
* that conflict with keybindings. */
add_builtin_run_requests();
* that conflict with keybindings. */
add_builtin_run_requests();
+ if (!opt_diff_args && tig_diff_opts && *tig_diff_opts) {
+ static const char *diff_opts[SIZEOF_ARG] = { NULL };
+ int argc = 0;
+
+ if (!string_format(buf, "%s", tig_diff_opts) ||
+ !argv_from_string(diff_opts, &argc, buf))
+ die("TIG_DIFF_OPTS contains too many arguments");
+ else if (!argv_copy(&opt_diff_args, diff_opts))
+ die("Failed to format TIG_DIFF_OPTS arguments");
+ }
+
return OK;
}
return OK;
}
VIEW_(BLAME, "blame", &blame_ops, TRUE, ref_commit),
VIEW_(BRANCH, "branch", &branch_ops, TRUE, ref_head),
VIEW_(HELP, "help", &help_ops, FALSE, ""),
VIEW_(BLAME, "blame", &blame_ops, TRUE, ref_commit),
VIEW_(BRANCH, "branch", &branch_ops, TRUE, ref_head),
VIEW_(HELP, "help", &help_ops, FALSE, ""),
- VIEW_(PAGER, "pager", &pager_ops, FALSE, "stdin"),
+ VIEW_(PAGER, "pager", &pager_ops, FALSE, ""),
VIEW_(STATUS, "status", &status_ops, TRUE, ""),
VIEW_(STAGE, "stage", &stage_ops, TRUE, ""),
};
VIEW_(STATUS, "status", &status_ops, TRUE, ""),
VIEW_(STAGE, "stage", &stage_ops, TRUE, ""),
};
}
waddnstr(view->win, string, len);
}
waddnstr(view->win, string, len);
- }
- if (trimmed && use_tilde) {
- set_view_attr(view, LINE_DELIMITER);
- waddch(view->win, '~');
- col++;
+
+ if (trimmed && use_tilde) {
+ set_view_attr(view, LINE_DELIMITER);
+ waddch(view->win, '~');
+ col++;
+ }
}
return col;
}
return col;
assert(view_is_displayed(view));
switch (request) {
assert(view_is_displayed(view));
switch (request) {
+ case REQ_SCROLL_FIRST_COL:
+ view->yoffset = 0;
+ redraw_view_from(view, 0);
+ report("");
+ return;
case REQ_SCROLL_LEFT:
if (view->yoffset == 0) {
report("Cannot scroll beyond the first column");
case REQ_SCROLL_LEFT:
if (view->yoffset == 0) {
report("Cannot scroll beyond the first column");
}
static bool
}
static bool
-format_argv(const char ***dst_argv, const char *src_argv[], bool replace)
+format_argv(const char ***dst_argv, const char *src_argv[], bool replace, bool first)
{
char buf[SIZEOF_STR];
int argc;
{
char buf[SIZEOF_STR];
int argc;
const char *arg = src_argv[argc];
size_t bufpos = 0;
const char *arg = src_argv[argc];
size_t bufpos = 0;
- if (!strcmp(arg, "%(file-args)")) {
+ if (!strcmp(arg, "%(fileargs)")) {
if (!argv_append_array(dst_argv, opt_file_args))
break;
continue;
if (!argv_append_array(dst_argv, opt_file_args))
break;
continue;
- } else if (!strcmp(arg, "%(diff-args)")) {
+ } else if (!strcmp(arg, "%(diffargs)")) {
if (!argv_append_array(dst_argv, opt_diff_args))
break;
continue;
if (!argv_append_array(dst_argv, opt_diff_args))
break;
continue;
- } else if (!strcmp(arg, "%(rev-args)")) {
+ } else if (!strcmp(arg, "%(revargs)") ||
+ (first && !strcmp(arg, "%(commit)"))) {
if (!argv_append_array(dst_argv, opt_rev_args))
break;
continue;
if (!argv_append_array(dst_argv, opt_rev_args))
break;
continue;
prepare_io(struct view *view, const char *dir, const char *argv[], bool replace)
{
view->dir = dir;
prepare_io(struct view *view, const char *dir, const char *argv[], bool replace)
{
view->dir = dir;
- return format_argv(&view->argv, argv, replace);
+ return format_argv(&view->argv, argv, replace, !view->parent);
}
static bool
}
static bool
return;
}
return;
}
- if (format_argv(&argv, req->argv, TRUE))
+ if (format_argv(&argv, req->argv, TRUE, FALSE))
open_external_viewer(argv, NULL);
if (argv)
argv_free(argv);
open_external_viewer(argv, NULL);
if (argv)
argv_free(argv);
move_view(view, request);
break;
move_view(view, request);
break;
+ case REQ_SCROLL_FIRST_COL:
case REQ_SCROLL_LEFT:
case REQ_SCROLL_RIGHT:
case REQ_SCROLL_LINE_DOWN:
case REQ_SCROLL_LEFT:
case REQ_SCROLL_RIGHT:
case REQ_SCROLL_LINE_DOWN:
break;
case REQ_VIEW_PAGER:
break;
case REQ_VIEW_PAGER:
+ if (view == NULL) {
+ if (!io_open(&VIEW(REQ_VIEW_PAGER)->io, ""))
+ die("Failed to open stdin");
+ open_view(view, request, OPEN_PREPARED);
+ break;
+ }
+
if (!VIEW(REQ_VIEW_PAGER)->pipe && !VIEW(REQ_VIEW_PAGER)->lines) {
report("No pager content, press %s to run command from prompt",
get_key(view->keymap, REQ_PROMPT));
if (!VIEW(REQ_VIEW_PAGER)->pipe && !VIEW(REQ_VIEW_PAGER)->lines) {
report("No pager content, press %s to run command from prompt",
get_key(view->keymap, REQ_PROMPT));
static const char *diff_argv[SIZEOF_ARG] = {
"git", "show", "--pretty=fuller", "--no-color", "--root",
"--patch-with-stat", "--find-copies-harder", "-C",
static const char *diff_argv[SIZEOF_ARG] = {
"git", "show", "--pretty=fuller", "--no-color", "--root",
"--patch-with-stat", "--find-copies-harder", "-C",
- "%(diff-args)", "%(commit)", "--", "%(file-args)", NULL
+ "%(diffargs)", "%(commit)", "--", "%(fileargs)", NULL
};
};
+static bool
+diff_read(struct view *view, char *data)
+{
+ if (!data) {
+ /* Fall back to retry if no diff will be shown. */
+ if (view->lines == 0 && opt_file_args) {
+ int pos = argv_size(view->argv)
+ - argv_size(opt_file_args) - 1;
+
+ if (pos > 0 && !strcmp(view->argv[pos], "--")) {
+ for (; view->argv[pos]; pos++) {
+ free((void *) view->argv[pos]);
+ view->argv[pos] = NULL;
+ }
+
+ if (view->pipe)
+ io_done(view->pipe);
+ if (io_run(&view->io, IO_RD, view->dir, view->argv))
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ return pager_read(view, data);
+}
+
static struct view_ops diff_ops = {
"line",
diff_argv,
NULL,
static struct view_ops diff_ops = {
"line",
diff_argv,
NULL,
- pager_read,
+ diff_read,
pager_draw,
pager_request,
pager_grep,
pager_draw,
pager_request,
pager_grep,
};
static const char *status_list_other_argv[] = {
};
static const char *status_list_other_argv[] = {
- "git", "ls-files", "-z", "--others", "--exclude-standard", opt_prefix, NULL
+ "git", "ls-files", "-z", "--others", "--exclude-standard", opt_prefix, NULL, NULL,
};
static const char *status_list_no_head_argv[] = {
};
static const char *status_list_no_head_argv[] = {
return FALSE;
}
return FALSE;
}
+ if (!opt_untracked_dirs_content)
+ status_list_other_argv[ARRAY_SIZE(status_list_other_argv) - 2] = "--directory";
+
if (!status_run(view, status_diff_files_argv, 0, LINE_STAT_UNSTAGED) ||
!status_run(view, status_list_other_argv, '?', LINE_STAT_UNTRACKED))
return FALSE;
if (!status_run(view, status_diff_files_argv, 0, LINE_STAT_UNSTAGED) ||
!status_run(view, status_list_other_argv, '?', LINE_STAT_UNTRACKED))
return FALSE;
static const char *main_argv[SIZEOF_ARG] = {
"git", "log", "--no-color", "--pretty=raw", "--parents",
static const char *main_argv[SIZEOF_ARG] = {
"git", "log", "--no-color", "--pretty=raw", "--parents",
- "--topo-order", "%(diff-args)", "%(rev-args)",
- "--", "%(file-args)", NULL
+ "--topo-order", "%(diffargs)", "%(revargs)",
+ "--", "%(fileargs)", NULL
};
static bool
};
static bool
keypad(status_win, TRUE);
wbkgdset(status_win, get_line_attr(LINE_STATUS));
keypad(status_win, TRUE);
wbkgdset(status_win, get_line_attr(LINE_STATUS));
- TABSIZE = opt_tab_size;
+ set_tabsize(opt_tab_size);
term = getenv("XTERM_VERSION") ? NULL : getenv("COLORTERM");
if (term && !strcmp(term, "gnome-terminal")) {
term = getenv("XTERM_VERSION") ? NULL : getenv("COLORTERM");
if (term && !strcmp(term, "gnome-terminal")) {
const char **filter_argv = NULL;
int i;
const char **filter_argv = NULL;
int i;
- if (!isatty(STDIN_FILENO)) {
- io_open(&VIEW(REQ_VIEW_PAGER)->io, "");
+ if (!isatty(STDIN_FILENO))
return REQ_VIEW_PAGER;
return REQ_VIEW_PAGER;
- }
if (argc <= 1)
return REQ_VIEW_MAIN;
if (argc <= 1)
return REQ_VIEW_MAIN;