Skip to content

Commit

Permalink
Unify jumping to line IDs using a git-rev-parse-able expression
Browse files Browse the repository at this point in the history
This allows to create keybindings to go to the 2nd parent and jumping to
a commit by branch name.
  • Loading branch information
jonas committed Aug 5, 2016
1 parent 1e6da9d commit 97771e1
Show file tree
Hide file tree
Showing 11 changed files with 87 additions and 74 deletions.
2 changes: 2 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ Improvements:
- Compact relative date display mode. (GH #331)
- Add date column option controlling whether to show local date.
- Move to parent commit in the main view. (GH #388)
- Add `:goto <rev>` prompt command to go to a `git-rev-parse`d revision, e.g.
`:goto some/branch` or `:goto %(commit)^2`.
- Respect the XDG standard for configuration files. (GH #513)
- Support for custom `strftime(3)` date formats, e.g.:

Expand Down
4 changes: 4 additions & 0 deletions doc/manual.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,10 @@ Prompt
|:<x> |Execute the corresponding key binding, e.g. `:q`.
|:!<command> |Execute a system command in a pager, e.g. `:!git log -p`.
|:<action> |Execute a Tig command, e.g. `:edit`.
|:goto <rev> |Jump to a specific revision, e.g. `:goto %(commit)^2`
to goto the current commit's 2nd parent or
`:goto some/branch` to goto the commit denoting the
branch `some/branch`.
|:save-display <file> |Save current display to `<file>`.
|:save-options <file> |Save current options to `<file>`.
|:script <file> |Execute commands from `<file>`.
Expand Down
4 changes: 2 additions & 2 deletions include/tig/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,8 @@ ssize_t io_read(struct io *io, void *buf, size_t bufsize);
bool io_get(struct io *io, struct buffer *buf, int c, bool can_read);
bool io_write(struct io *io, const void *buf, size_t bufsize);
bool io_printf(struct io *io, const char *fmt, ...) PRINTF_LIKE(2, 3);
bool io_read_buf(struct io *io, char buf[], size_t bufsize);
bool io_run_buf(const char **argv, char buf[], size_t bufsize);
bool io_read_buf(struct io *io, char buf[], size_t bufsize, bool allow_empty);
bool io_run_buf(const char **argv, char buf[], size_t bufsize, bool allow_empty);
enum status_code io_load(struct io *io, const char *separators,
io_read_fn read_property, void *data);
enum status_code io_load_span(struct io *io, const char *separators,
Expand Down
1 change: 1 addition & 0 deletions include/tig/view.h
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ void select_view_line(struct view *view, unsigned long lineno);
void do_scroll_view(struct view *view, int lines);
void scroll_view(struct view *view, enum request request);
void move_view(struct view *view, enum request request);
void goto_id(struct view *view, const char *expression, bool from_start, bool save_search);

/*
* View history
Expand Down
2 changes: 1 addition & 1 deletion src/blob.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ blob_open(struct view *view, enum open_flags flags)
};

if (!string_format(blob_spec, "%s:%s", commit, view->env->file) ||
!io_run_buf(rev_parse_argv, view->env->blob, sizeof(view->env->blob))) {
!io_run_buf(rev_parse_argv, view->env->blob, sizeof(view->env->blob), false)) {
report("Failed to resolve blob from file name");
return false;
}
Expand Down
12 changes: 6 additions & 6 deletions src/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ get_path_encoding(const char *path, struct encoding *default_encoding)

/* <path>: encoding: <encoding> */

if (!*path || !io_run_buf(check_attr_argv, buf, sizeof(buf))
if (!*path || !io_run_buf(check_attr_argv, buf, sizeof(buf), false)
|| !(encoding = strstr(buf, ENCODING_SEP)))
return default_encoding;

Expand All @@ -121,7 +121,7 @@ get_path_encoding(const char *path, struct encoding *default_encoding)
"file", "-I", "--", path, NULL
};

if (!*path || !io_run_buf(file_argv, buf, sizeof(buf))
if (!*path || !io_run_buf(file_argv, buf, sizeof(buf), false)
|| !(encoding = strstr(buf, CHARSET_SEP)))
return default_encoding;

Expand Down Expand Up @@ -532,7 +532,7 @@ io_printf(struct io *io, const char *fmt, ...)
}

bool
io_read_buf(struct io *io, char buf[], size_t bufsize)
io_read_buf(struct io *io, char buf[], size_t bufsize, bool allow_empty)
{
struct buffer result = {0};

Expand All @@ -541,15 +541,15 @@ io_read_buf(struct io *io, char buf[], size_t bufsize)
string_ncopy_do(buf, bufsize, result.data, strlen(result.data));
}

return io_done(io) && result.data;
return io_done(io) && (result.data || allow_empty);
}

bool
io_run_buf(const char **argv, char buf[], size_t bufsize)
io_run_buf(const char **argv, char buf[], size_t bufsize, bool allow_empty)
{
struct io io;

return io_run(&io, IO_RD, NULL, NULL, argv) && io_read_buf(&io, buf, bufsize);
return io_run(&io, IO_RD, NULL, NULL, argv) && io_read_buf(&io, buf, bufsize, allow_empty);
}

bool
Expand Down
39 changes: 1 addition & 38 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -500,43 +500,6 @@ main_read(struct view *view, struct buffer *buf, bool force_stop)
return true;
}

static void
main_move_to_parent(struct view *view)
{
struct line *line = &view->line[view->pos.lineno];
struct commit *commit = line->data;

/* Handle staged and unstaged commit lines. */
if (string_rev_is_null(commit->id)) {
line++;

} else {
const char *rev_list_parents_argv[] = {
"git", "log", "--no-color", "-n1", "--pretty=format:%P",
commit->id, NULL
};
char parents[SIZEOF_STR] = "";

if (!io_run_buf(rev_list_parents_argv, parents, sizeof(parents))) {
report("Failed to read commit parent(s)");
return;
}

/* Find a commit line matching the first parent commit ID. */
for (line++; view_has_line(view, line); line++) {
commit = line->data;

if (!strncasecmp(commit->id, parents, strlen(commit->id)))
break;
}
}

if (view_has_line(view, line)) {
select_view_line(view, line - view->line);
report_clear();
}
}

enum request
main_request(struct view *view, enum request request, struct line *line)
{
Expand Down Expand Up @@ -570,7 +533,7 @@ main_request(struct view *view, enum request request, struct line *line)
break;

case REQ_PARENT:
main_move_to_parent(view);
goto_id(view, "%(commit)^", true, false);
break;

default:
Expand Down
31 changes: 9 additions & 22 deletions src/prompt.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ readline_action_generator(const char *text, int state)
"bind",
"set",
"toggle",
"goto",
"save-display",
"save-options",
"exec",
Expand Down Expand Up @@ -753,28 +754,7 @@ run_prompt_command(struct view *view, const char *argv[])
report("Unable to parse '%s' as a line number", cmd);
}
} else if (iscommit(cmd)) {
int lineno;

if (!(view->ops->column_bits & view_column_bit(ID))) {
report("Jumping to commits is not supported by the %s view", view->name);
return REQ_NONE;
}

for (lineno = 0; lineno < view->lines; lineno++) {
struct view_column_data column_data = {0};
struct line *line = &view->line[lineno];

if (view->ops->get_column_data(view, line, &column_data) &&
column_data.id &&
!strncasecmp(column_data.id, cmd, cmdlen)) {
string_ncopy(view->env->search, cmd, cmdlen);
select_view_line(view, lineno);
report_clear();
return REQ_NONE;
}
}

report("Unable to find commit '%s'", view->env->search);
goto_id(view, cmd, true, true);
return REQ_NONE;

} else if (cmdlen > 1 && (cmd[0] == '/' || cmd[0] == '?')) {
Expand Down Expand Up @@ -812,6 +792,13 @@ run_prompt_command(struct view *view, const char *argv[])
open_pager_view(view, OPEN_PREPARED | OPEN_WITH_STDERR);
}

} else if (!strcmp(cmd, "goto")) {
if (!argv[1] || !strlen(argv[1]))
report("goto requires an argument");
else
goto_id(view, argv[1], true, true);
return REQ_NONE;

} else if (!strcmp(cmd, "save-display")) {
const char *path = argv[1] ? argv[1] : "tig-display.txt";

Expand Down
2 changes: 1 addition & 1 deletion src/status.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ status_update_onbranch(void)
struct io io;

if (io_open(&io, "%s/%s", repo.git_dir, paths[i][1]) &&
io_read_buf(&io, buf, sizeof(buf))) {
io_read_buf(&io, buf, sizeof(buf), false)) {
head = buf;
if (!prefixcmp(head, "refs/heads/"))
head += STRING_SIZE("refs/heads/");
Expand Down
55 changes: 55 additions & 0 deletions src/view.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,61 @@ select_view_line(struct view *view, unsigned long lineno)
}
}

void
goto_id(struct view *view, const char *expr, bool from_start, bool save_search)
{
struct view_column_data column_data = {0};
char id[SIZEOF_STR] = "";
size_t idlen;
struct line *line = &view->line[view->pos.lineno];

if (!(view->ops->column_bits & view_column_bit(ID))) {
report("Jumping to ID is not supported by the %s view", view->name);
return;
} else {
char *rev = argv_format_arg(view->env, expr);
const char *rev_parse_argv[] = {
"git", "rev-parse", "--revs-only", rev, NULL
};
bool ok = rev && io_run_buf(rev_parse_argv, id, sizeof(id), true);

free(rev);
if (!ok) {
report("Failed to parse expression '%s'", expr);
return;
}
}

if (!id[0]) {
if (view->ops->get_column_data(view, line, &column_data)
&& column_data.id && string_rev_is_null(column_data.id)) {
select_view_line(view, view->pos.lineno + 1);
report_clear();
} else {
report("Expression '%s' is not a meaningful revision", expr);
}
return;
}

line = from_start ? view->line : &view->line[view->pos.lineno];

for (idlen = strlen(id); view_has_line(view, line); line++) {
struct view_column_data column_data = {0};

if (view->ops->get_column_data(view, line, &column_data) &&
column_data.id &&
!strncasecmp(column_data.id, id, idlen)) {
if (save_search)
string_ncopy(view->env->search, id, idlen);
select_view_line(view, line - view->line);
report_clear();
return;
}
}

report("Unable to find commit '%s'", view->env->search);
}

/*
* View history
*/
Expand Down
9 changes: 5 additions & 4 deletions test/main/move-to-parent-test → test/main/goto-test
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,18 @@
export LINES=10

steps '
:3
:save-display unstaged-changes.screen
:parent
:save-display commit-3.screen
:goto conflict-branch
:save-display commit-1.screen
:parent
:save-display commit-2.screen
:parent
:save-display commit-5.screen
:parent
:save-display commit-5-still.screen
:3
:save-display unstaged-changes.screen
:parent
:save-display commit-3.screen
'

tigrc <<EOF
Expand Down

0 comments on commit 97771e1

Please sign in to comment.