index 13c167d3c49f772d12dcd680eda2658c8d5181bb..aec50bca39ff98d3d8358789c6a70f676e2d5bfb 100644 (file)
--- a/tig.c
+++ b/tig.c
#define ENUM_MAP(name, value) { name, STRING_SIZE(name), value }
static bool
-map_enum_do(struct enum_map *map, size_t map_size, int *value, const char *name)
+map_enum_do(const struct enum_map *map, size_t map_size, int *value, const char *name)
{
size_t namelen = strlen(name);
int i;
{
init_io(io, NULL, IO_FD);
io->pipe = *name ? open(name, O_RDONLY) : STDIN_FILENO;
+ if (io->pipe == -1)
+ io->error = errno;
return io->pipe != -1;
}
return io->error;
}
-static bool
+static char *
io_strerror(struct io *io)
{
return strerror(io->error);
const char *help;
};
-static struct request_info req_info[] = {
+static const struct request_info req_info[] = {
#define REQ_GROUP(help) { 0, NULL, 0, (help) },
#define REQ_(req, help) { REQ_##req, (#req), STRING_SIZE(#req), (help) }
REQ_INFO
enum request request;
};
-static struct keybinding default_keybindings[] = {
+static const struct keybinding default_keybindings[] = {
/* View switching */
{ 'm', REQ_VIEW_MAIN },
{ 'd', REQ_VIEW_DIFF },
#undef KEYMAP_
};
-static struct enum_map keymap_table[] = {
+static const struct enum_map keymap_table[] = {
#define KEYMAP_(name) ENUM_MAP(#name, KEYMAP_##name)
KEYMAP_INFO
#undef KEYMAP_
int value;
};
-static struct key key_table[] = {
+static const struct key key_table[] = {
{ "Enter", KEY_RETURN },
{ "Space", ' ' },
{ "Backspace", KEY_BACKSPACE },
buf[pos] = 0;
for (i = 0; i < ARRAY_SIZE(default_keybindings); i++) {
- struct keybinding *keybinding = &default_keybindings[i];
+ const struct keybinding *keybinding = &default_keybindings[i];
if (keybinding->request != request)
continue;
static bool config_errors;
static const char *config_msg;
-static struct enum_map color_map[] = {
+static const struct enum_map color_map[] = {
#define COLOR_MAP(name) ENUM_MAP(#name, COLOR_##name)
COLOR_MAP(DEFAULT),
COLOR_MAP(BLACK),
COLOR_MAP(YELLOW),
};
-static struct enum_map attr_map[] = {
+static const struct enum_map attr_map[] = {
#define ATTR_MAP(name) ENUM_MAP(#name, A_##name)
ATTR_MAP(NORMAL),
ATTR_MAP(BLINK),
info = get_line_info(argv[0]);
if (!info) {
- static struct enum_map obsolete[] = {
+ static const struct enum_map obsolete[] = {
ENUM_MAP("main-delim", LINE_DELIMITER),
ENUM_MAP("main-date", LINE_DATE),
ENUM_MAP("main-author", LINE_AUTHOR),
request = get_request(argv[2]);
if (request == REQ_NONE) {
- static struct enum_map obsolete[] = {
+ static const struct enum_map obsolete[] = {
ENUM_MAP("cherry-pick", REQ_NONE),
ENUM_MAP("screen-resize", REQ_NONE),
ENUM_MAP("tree-parent", REQ_PARENT),
report("%sabling %s", *option ? "En" : "Dis", help);
}
+static void
+maximize_view(struct view *view)
+{
+ memset(display, 0, sizeof(display));
+ current_view = 0;
+ display[current_view] = view;
+ resize_display();
+ redraw_display(FALSE);
+ report("");
+}
+
+
/*
* Navigation
*/
case REQ_MAXIMIZE:
if (displayed_views() == 2)
- open_view(view, VIEW_REQ(view), OPEN_DEFAULT);
+ maximize_view(view);
break;
case REQ_TOGGLE_LINENO:
* followed. */
if (view->parent &&
view->parent->parent != view->parent) {
- memset(display, 0, sizeof(display));
- current_view = 0;
- display[current_view] = view->parent;
+ maximize_view(view->parent);
view->parent = view;
- resize_display();
- redraw_display(FALSE);
- report("");
break;
}
/* Fall-through */
}
static bool
-check_blame_commit(struct blame *blame)
+check_blame_commit(struct blame *blame, bool check_null_id)
{
if (!blame->commit)
report("Commit data not loaded yet");
- else if (!strcmp(blame->commit->id, NULL_ID))
+ else if (check_null_id && !strcmp(blame->commit->id, NULL_ID))
report("No commit exist for the selected line");
else
return TRUE;
switch (request) {
case REQ_VIEW_BLAME:
- if (check_blame_commit(blame)) {
+ if (check_blame_commit(blame, TRUE)) {
string_copy(opt_ref, blame->commit->id);
string_copy(opt_file, blame->commit->filename);
if (blame->lineno)
break;
case REQ_PARENT:
- if (check_blame_commit(blame) &&
+ if (check_blame_commit(blame, TRUE) &&
select_commit_parent(blame->commit->id, opt_ref,
blame->commit->filename)) {
string_copy(opt_file, blame->commit->filename);
break;
case REQ_ENTER:
- if (!blame->commit) {
- report("No commit loaded yet");
+ if (!check_blame_commit(blame, FALSE))
break;
- }
if (view_is_displayed(VIEW(REQ_VIEW_DIFF)) &&
!strcmp(blame->commit->id, VIEW(REQ_VIEW_DIFF)->ref))
return TRUE;
}
+static enum request
+status_load_error(struct view *view, struct view *stage, const char *path)
+{
+ if (displayed_views() == 2 || display[current_view] != view)
+ maximize_view(view);
+ report("Failed to load '%s': %s", path, io_strerror(&stage->io));
+ return REQ_NONE;
+}
+
static enum request
status_enter(struct view *view, struct line *line)
{
};
if (!prepare_update(stage, no_head_diff_argv, opt_cdup, FORMAT_DASH))
- return REQ_QUIT;
+ return status_load_error(view, stage, newpath);
} else {
const char *index_show_argv[] = {
"git", "diff-index", "--root", "--patch-with-stat",
};
if (!prepare_update(stage, index_show_argv, opt_cdup, FORMAT_DASH))
- return REQ_QUIT;
+ return status_load_error(view, stage, newpath);
}
if (status)
};
if (!prepare_update(stage, files_show_argv, opt_cdup, FORMAT_DASH))
- return REQ_QUIT;
+ return status_load_error(view, stage, newpath);
if (status)
info = "Unstaged changes to %s";
else
}
if (!prepare_update_file(stage, newpath))
- return REQ_QUIT;
+ return status_load_error(view, stage, newpath);
info = "Untracked file %s";
break;
/* After returning the status view has been split to
* show the stage view. No further reloading is
* necessary. */
- status_enter(view, line);
- return REQ_NONE;
+ return status_enter(view, line);
case REQ_REFRESH:
/* Simply reload the view. */
load_refs(void)
{
static const char *ls_remote_argv[SIZEOF_ARG] = {
- "git", "ls-remote", ".", NULL
+ "git", "ls-remote", opt_git_dir, NULL
};
static bool init = FALSE;
return run_io_load(ls_remote_argv, "\t", read_ref);
}
+static void
+set_remote_branch(const char *name, const char *value, size_t valuelen)
+{
+ if (!strcmp(name, ".remote")) {
+ string_ncopy(opt_remote, value, valuelen);
+
+ } else if (*opt_remote && !strcmp(name, ".merge")) {
+ size_t from = strlen(opt_remote);
+
+ if (!prefixcmp(value, "refs/heads/"))
+ value += STRING_SIZE("refs/heads/");
+
+ if (!string_format_from(opt_remote, &from, "/%s", value))
+ opt_remote[0] = 0;
+ }
+}
+
static void
set_repo_config_option(char *name, char *value, int (*cmd)(int, const char **))
{
@@ -6695,16 +6727,43 @@ set_repo_config_option(char *name, char *value, int (*cmd)(int, const char **))
warn("Option 'tig.%s': %s", name, config_msg);
}
+static void
+set_work_tree(const char *value)
+{
+ char cwd[SIZEOF_STR];
+
+ if (!getcwd(cwd, sizeof(cwd)))
+ die("Failed to get cwd path: %s", strerror(errno));
+ if (chdir(opt_git_dir) < 0)
+ die("Failed to chdir(%s): %s", strerror(errno));
+ if (!getcwd(opt_git_dir, sizeof(opt_git_dir)))
+ die("Failed to get git path: %s", strerror(errno));
+ if (chdir(cwd) < 0)
+ die("Failed to chdir(%s): %s", cwd, strerror(errno));
+ if (chdir(value) < 0)
+ die("Failed to chdir(%s): %s", value, strerror(errno));
+ if (!getcwd(cwd, sizeof(cwd)))
+ die("Failed to get cwd path: %s", strerror(errno));
+ if (setenv("GIT_WORK_TREE", cwd, TRUE) < 0)
+ die("Failed to set GIT_WORK_TREE to '%s'", cwd);
+ if (setenv("GIT_DIR", opt_git_dir, TRUE) < 0)
+ die("Failed to set GIT_DIR to '%s'", opt_git_dir);
+ opt_is_inside_work_tree = TRUE;
+}
+
static int
read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen)
{
if (!strcmp(name, "i18n.commitencoding"))
string_ncopy(opt_encoding, value, valuelen);
- if (!strcmp(name, "core.editor"))
+ else if (!strcmp(name, "core.editor"))
string_ncopy(opt_editor, value, valuelen);
- if (!prefixcmp(name, "tig.color."))
+ else if (!strcmp(name, "core.worktree"))
+ set_work_tree(value);
+
+ else if (!prefixcmp(name, "tig.color."))
set_repo_config_option(name + 10, value, option_color_command);
else if (!prefixcmp(name, "tig.bind."))
@@ -6713,27 +6772,9 @@ read_repo_config_option(char *name, size_t namelen, char *value, size_t valuelen
else if (!prefixcmp(name, "tig."))
set_repo_config_option(name + 4, value, option_set_command);
- /* branch.<head>.remote */
- if (*opt_head &&
- !strncmp(name, "branch.", 7) &&
- !strncmp(name + 7, opt_head, strlen(opt_head)) &&
- !strcmp(name + 7 + strlen(opt_head), ".remote"))
- string_ncopy(opt_remote, value, valuelen);
-
- if (*opt_head && *opt_remote &&
- !strncmp(name, "branch.", 7) &&
- !strncmp(name + 7, opt_head, strlen(opt_head)) &&
- !strcmp(name + 7 + strlen(opt_head), ".merge")) {
- size_t from = strlen(opt_remote);
-
- if (!prefixcmp(value, "refs/heads/")) {
- value += STRING_SIZE("refs/heads/");
- valuelen -= STRING_SIZE("refs/heads/");
- }
-
- if (!string_format_from(opt_remote, &from, "/%s", value))
- opt_remote[0] = 0;
- }
+ else if (*opt_head && !prefixcmp(name, "branch.") &&
+ !strncmp(name + 7, opt_head, strlen(opt_head)))
+ set_remote_branch(name + 7 + strlen(opt_head), value, valuelen);
return OK;
}