index 4990de5f5961311d3b20b4680c82ebadedf10b44..aec50bca39ff98d3d8358789c6a70f676e2d5bfb 100644 (file)
--- a/tig.c
+++ b/tig.c
#define string_add(dst, from, src) \
string_ncopy_do(dst + (from), sizeof(dst) - (from), src, sizeof(src))
-static size_t
-string_expand_length(const char *line, int tabsize)
-{
- size_t size, pos;
-
- for (pos = 0; line[pos]; pos++) {
- if (line[pos] == '\t' && tabsize > 0)
- size += tabsize - (size % tabsize);
- else
- size++;
- }
- return size;
-}
-
static void
string_expand(char *dst, size_t dstlen, const char *src, int tabsize)
{
#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);
}
static bool
-run_io_buf(const char **argv, char buf[], size_t bufsize)
+io_read_buf(struct io *io, char buf[], size_t bufsize)
{
- struct io io = {};
bool error;
- if (!run_io_rd(&io, argv, FORMAT_NONE))
- return FALSE;
+ io->buf = io->bufpos = buf;
+ io->bufalloc = bufsize;
+ error = !io_get(io, '\n', TRUE) && io_error(io);
+ io->buf = NULL;
+
+ return done_io(io) || error;
+}
- io.buf = io.bufpos = buf;
- io.bufalloc = bufsize;
- error = !io_get(&io, '\n', TRUE) && io_error(&io);
- io.buf = NULL;
+static bool
+run_io_buf(const char **argv, char buf[], size_t bufsize)
+{
+ struct io io = {};
- return done_io(&io) || error;
+ return run_io_rd(&io, argv, FORMAT_NONE) && io_read_buf(&io, buf, bufsize);
}
static int
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;
* User config file handling.
*/
-static struct enum_map color_map[] = {
+static int config_lineno;
+static bool config_errors;
+static const char *config_msg;
+
+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),
ATTR_MAP(UNDERLINE),
};
-#define set_color(color, name) map_enum(color, color_map, name)
#define set_attribute(attr, name) map_enum(attr, attr_map, name)
-static int config_lineno;
-static bool config_errors;
-static const char *config_msg;
+static int
+parse_int(int *opt, const char *arg, int min, int max)
+{
+ int value = atoi(arg);
+
+ if (min <= value && value <= max) {
+ *opt = value;
+ return OK;
+ }
+
+ config_msg = "Integer value out of bound";
+ return ERR;
+}
+
+static bool
+set_color(int *color, const char *name)
+{
+ if (map_enum(color, color_map, name))
+ return TRUE;
+ if (!prefixcmp(name, "color"))
+ return parse_int(color, name + 5, 0, 255) == OK;
+ return FALSE;
+}
/* Wants: object fgcolor bgcolor [attribute] */
static int
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),
return OK;
}
-static int
-parse_int(int *opt, const char *arg, int min, int max)
-{
- int value = atoi(arg);
-
- if (min <= value && value <= max)
- *opt = value;
- return OK;
-}
-
static int
parse_string(char *opt, const char *arg, size_t optsize)
{
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),
add_builtin_run_requests();
- if (!tigrc_system) {
- if (!string_format(buf, "%s/tigrc", SYSCONFDIR))
- return ERR;
- tigrc_system = buf;
- }
+ if (!tigrc_system)
+ tigrc_system = SYSCONFDIR "/tigrc";
load_option_file(tigrc_system);
if (!tigrc_user) {
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
*/
+static bool
+goto_view_line(struct view *view, unsigned long offset, unsigned long lineno)
+{
+ if (lineno >= view->lines)
+ lineno = view->lines > 0 ? view->lines - 1 : 0;
+
+ if (offset > lineno || offset + view->height <= lineno) {
+ unsigned long half = view->height / 2;
+
+ if (lineno > half)
+ offset = lineno - half;
+ else
+ offset = 0;
+ }
+
+ if (offset != view->offset || lineno != view->lineno) {
+ view->offset = offset;
+ view->lineno = lineno;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/* Scrolling backend */
static void
do_scroll_view(struct view *view, int lines)
static void
select_view_line(struct view *view, unsigned long lineno)
{
- if (lineno - view->offset >= view->height) {
- view->offset = lineno;
- view->lineno = lineno;
- if (view_is_displayed(view))
- redraw_view(view);
+ unsigned long old_lineno = view->lineno;
+ unsigned long old_offset = view->offset;
- } else {
- unsigned long old_lineno = view->lineno - view->offset;
-
- view->lineno = lineno;
+ if (goto_view_line(view, view->offset, lineno)) {
if (view_is_displayed(view)) {
- draw_view_line(view, old_lineno);
- draw_view_line(view, view->lineno - view->offset);
- wnoutrefresh(view->win);
+ if (old_offset != view->offset) {
+ redraw_view(view);
+ } else {
+ draw_view_line(view, old_lineno - view->offset);
+ draw_view_line(view, view->lineno - view->offset);
+ wnoutrefresh(view->win);
+ }
} else {
view->ops->select(view, &view->line[view->lineno]);
}
return FALSE;
}
- if (view->p_lineno >= view->lines) {
- view->p_lineno = view->lines > 0 ? view->lines - 1 : 0;
- if (view->p_offset >= view->p_lineno) {
- unsigned long half = view->height / 2;
-
- if (view->p_lineno > half)
- view->p_offset = view->p_lineno - half;
- else
- view->p_offset = 0;
- }
- }
-
- if (view_is_displayed(view) &&
- view->offset != view->p_offset &&
- view->lineno != view->p_lineno)
+ if (goto_view_line(view, view->p_offset, view->p_lineno) &&
+ view_is_displayed(view))
werase(view->win);
- view->offset = view->p_offset;
view->yoffset = view->p_yoffset;
- view->lineno = view->p_lineno;
view->p_restore = FALSE;
return TRUE;
OPEN_DEFAULT = 0, /* Use default view switching. */
OPEN_SPLIT = 1, /* Split current view. */
OPEN_RELOAD = 4, /* Reload view even if it is the current. */
- OPEN_NOMAXIMIZE = 8, /* Do not maximize the current view. */
OPEN_REFRESH = 16, /* Refresh view using previous command. */
OPEN_PREPARED = 32, /* Open already prepared command. */
};
{
bool split = !!(flags & OPEN_SPLIT);
bool reload = !!(flags & (OPEN_RELOAD | OPEN_REFRESH | OPEN_PREPARED));
- bool nomaximize = !!(flags & (OPEN_NOMAXIMIZE | OPEN_REFRESH));
+ bool nomaximize = !!(flags & OPEN_REFRESH);
struct view *view = VIEW(request);
int nviews = displayed_views();
struct view *base_view = display[0];
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 */
* View backend utilities
*/
+static void
+parse_timezone(time_t *time, const char *zone)
+{
+ long tz;
+
+ tz = ('0' - zone[1]) * 60 * 60 * 10;
+ tz += ('0' - zone[2]) * 60 * 60;
+ tz += ('0' - zone[3]) * 60;
+ tz += ('0' - zone[4]);
+
+ if (zone[0] == '-')
+ tz = -tz;
+
+ *time -= tz;
+}
+
/* Parse author lines where the name may be empty:
* author <email@address.tld> 1138474660 +0100
*/
@@ -3336,20 +3367,8 @@ parse_author_line(char *ident, char *author, size_t authorsize, struct tm *tm)
char *zone = strchr(secs, ' ');
time_t time = (time_t) atol(secs);
- if (zone && strlen(zone) == STRING_SIZE(" +0700")) {
- long tz;
-
- zone++;
- tz = ('0' - zone[1]) * 60 * 60 * 10;
- tz += ('0' - zone[2]) * 60 * 60;
- tz += ('0' - zone[3]) * 60;
- tz += ('0' - zone[4]) * 60;
-
- if (zone[0] == '-')
- tz = -tz;
-
- time -= tz;
- }
+ if (zone && strlen(zone) == STRING_SIZE(" +0700"))
+ parse_timezone(&time, zone + 1);
gmtime_r(&time, tm);
}
}
static bool
-select_commit_parent(const char *id, char rev[SIZEOF_REV])
+select_commit_parent(const char *id, char rev[SIZEOF_REV], const char *path)
{
char buf[SIZEOF_STR * 4];
const char *revlist_argv[] = {
- "git", "rev-list", "-1", "--parents", id, NULL
+ "git", "rev-list", "-1", "--parents", id, "--", path, NULL
};
int parents;
return FALSE;
} else if (parents == 0) {
- report("The selected commit has no parents");
+ if (path)
+ report("Path '%s' does not exist in the parent", path);
+ else
+ report("The selected commit has no parents");
return FALSE;
}
struct blame {
struct blame_commit *commit;
+ unsigned long lineno;
char text[1];
};
{
struct blame_commit *commit;
struct blame *blame;
- const char *pos = text + SIZEOF_REV - 1;
+ const char *pos = text + SIZEOF_REV - 2;
+ size_t orig_lineno = 0;
size_t lineno;
size_t group;
- if (strlen(text) <= SIZEOF_REV || *pos != ' ')
+ if (strlen(text) <= SIZEOF_REV || pos[1] != ' ')
return NULL;
- if (!parse_number(&pos, &lineno, 1, view->lines) ||
+ if (!parse_number(&pos, &orig_lineno, 1, 9999999) ||
+ !parse_number(&pos, &lineno, 1, view->lines) ||
!parse_number(&pos, &group, 1, view->lines - lineno + 1))
return NULL;
blame = line->data;
blame->commit = commit;
+ blame->lineno = orig_lineno + group - 1;
line->dirty = 1;
}
return FALSE;
} else {
- size_t linelen = string_expand_length(line, opt_tab_size);
+ size_t linelen = strlen(line);
struct blame *blame = malloc(sizeof(*blame) + linelen);
if (!blame)
return FALSE;
blame->commit = NULL;
- string_expand(blame->text, linelen + 1, line, opt_tab_size);
+ strncpy(blame->text, line, linelen);
+ blame->text[linelen] = 0;
return add_line_data(view, blame, LINE_BLAME_ID) != NULL;
}
}
author_time = (time_t) atol(line);
} else if (match_blame_header("author-tz ", &line)) {
- long tz;
-
- tz = ('0' - line[1]) * 60 * 60 * 10;
- tz += ('0' - line[2]) * 60 * 60;
- tz += ('0' - line[3]) * 60;
- tz += ('0' - line[4]) * 60;
-
- if (line[0] == '-')
- tz = -tz;
-
- author_time -= tz;
+ parse_timezone(&author_time, line);
gmtime_r(&author_time, &commit->time);
} else if (match_blame_header("summary ", &line)) {
struct blame *blame = line->data;
struct tm *time = NULL;
const char *id = NULL, *author = NULL;
+ char text[SIZEOF_STR];
if (blame->commit && *blame->commit->filename) {
id = blame->commit->id;
if (draw_lineno(view, lineno))
return TRUE;
- draw_text(view, LINE_DEFAULT, blame->text, TRUE);
+ string_expand(text, sizeof(text), blame->text, opt_tab_size);
+ draw_text(view, LINE_DEFAULT, text, TRUE);
return TRUE;
}
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;
return FALSE;
}
+static void
+setup_blame_parent_line(struct view *view, struct blame *blame)
+{
+ const char *diff_tree_argv[] = {
+ "git", "diff-tree", "-U0", blame->commit->id,
+ "--", blame->commit->filename, NULL
+ };
+ struct io io = {};
+ int parent_lineno = -1;
+ int blamed_lineno = -1;
+ char *line;
+
+ if (!run_io(&io, diff_tree_argv, NULL, IO_RD))
+ return;
+
+ while ((line = io_get(&io, '\n', TRUE))) {
+ if (*line == '@') {
+ char *pos = strchr(line, '+');
+
+ parent_lineno = atoi(line + 4);
+ if (pos)
+ blamed_lineno = atoi(pos + 1);
+
+ } else if (*line == '+' && parent_lineno != -1) {
+ if (blame->lineno == blamed_lineno - 1 &&
+ !strcmp(blame->text, line + 1)) {
+ view->lineno = parent_lineno ? parent_lineno - 1 : 0;
+ break;
+ }
+ blamed_lineno++;
+ }
+ }
+
+ done_io(&io);
+}
+
static enum request
blame_request(struct view *view, enum request request, struct line *line)
{
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)
+ view->lineno = blame->lineno;
open_view(view, REQ_VIEW_BLAME, OPEN_REFRESH);
}
break;
case REQ_PARENT:
- if (check_blame_commit(blame) &&
- select_commit_parent(blame->commit->id, opt_ref))
+ if (check_blame_commit(blame, TRUE) &&
+ select_commit_parent(blame->commit->id, opt_ref,
+ blame->commit->filename)) {
+ string_copy(opt_file, blame->commit->filename);
+ setup_blame_parent_line(view, blame);
open_view(view, REQ_VIEW_BLAME, OPEN_REFRESH);
+ }
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))
view->p_restore = FALSE;
}
+static void
+status_update_onbranch(void)
+{
+ static const char *paths[][2] = {
+ { "rebase-apply/rebasing", "Rebasing" },
+ { "rebase-apply/applying", "Applying mailbox" },
+ { "rebase-apply/", "Rebasing mailbox" },
+ { "rebase-merge/interactive", "Interactive rebase" },
+ { "rebase-merge/", "Rebase merge" },
+ { "MERGE_HEAD", "Merging" },
+ { "BISECT_LOG", "Bisecting" },
+ { "HEAD", "On branch" },
+ };
+ char buf[SIZEOF_STR];
+ struct stat stat;
+ int i;
+
+ if (is_initial_commit()) {
+ string_copy(status_onbranch, "Initial commit");
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(paths); i++) {
+ char *head = opt_head;
+
+ if (!string_format(buf, "%s/%s", opt_git_dir, paths[i][0]) ||
+ lstat(buf, &stat) < 0)
+ continue;
+
+ if (!*opt_head) {
+ struct io io = {};
+
+ if (string_format(buf, "%s/rebase-merge/head-name", opt_git_dir) &&
+ io_open(&io, buf) &&
+ io_read_buf(&io, buf, sizeof(buf))) {
+ head = chomp_string(buf);
+ if (!prefixcmp(head, "refs/heads/"))
+ head += STRING_SIZE("refs/heads/");
+ }
+ }
+
+ if (!string_format(status_onbranch, "%s %s", paths[i][1], head))
+ string_copy(status_onbranch, opt_head);
+ return;
+ }
+
+ string_copy(status_onbranch, "Not currently on any branch");
+}
+
/* First parse staged info using git-diff-index(1), then parse unstaged
* info using git-diff-files(1), and finally untracked files using
* git-ls-files(1). */
reset_view(view);
add_line_data(view, NULL, LINE_STAT_HEAD);
- if (is_initial_commit())
- string_copy(status_onbranch, "Initial commit");
- else if (!*opt_head)
- string_copy(status_onbranch, "Not currently on any branch");
- else if (!string_format(status_onbranch, "On branch %s", opt_head))
- return FALSE;
+ status_update_onbranch();
run_io_bg(update_index_argv);
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. */
}
VIEW(REQ_VIEW_STATUS)->p_restore = TRUE;
- open_view(view, REQ_VIEW_STATUS, OPEN_RELOAD | OPEN_NOMAXIMIZE);
+ open_view(view, REQ_VIEW_STATUS, OPEN_REFRESH);
/* Check whether the staged entry still exists, and close the
* stage view if it doesn't. */
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 **))
{
@@ -6598,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."))
@@ -6616,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;
}
{
char *cmd = read_prompt(":");
- if (cmd) {
+ if (cmd && isdigit(*cmd)) {
+ int lineno = view->lineno + 1;
+
+ if (parse_int(&lineno, cmd, 1, view->lines + 1) == OK) {
+ select_view_line(view, lineno - 1);
+ report("");
+ } else {
+ report("Unable to parse '%s' as a line number", cmd);
+ }
+
+ } else if (cmd) {
struct view *next = VIEW(REQ_VIEW_PAGER);
const char *argv[SIZEOF_ARG] = { "git" };
int argc = 1;