From 14c6bb06b3a0678fbfacf54581ff678f103ce61c Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Sat, 20 May 2023 22:49:31 +0200 Subject: [PATCH] Allow to go to stage view without Enter After selecting unstaged or staged changes in main or status view and pressing "c" to go to stage view, we fail with this error No stage content, press s to open the status view and choose file We can work around this by pressing Enter before "c". This extra key press is really not necessary because the intent is clear. Let's make view-stage (and view-diff) go to the stage view straight away. Note: "d" already worked this way but only in the main view, I'm not sure why. The implementation needs to differentiate between "stat headers" like "Changes to be committed" and status lines that actually contain a file. For stat headers we show all files so we must be careful not to include a file filter. For untracked files, we show a blob so there is no natural way of showing all untracked files. Keep the above behavior for the untracked stat header. --- include/tig/stage.h | 2 +- include/tig/view.h | 1 + src/main.c | 4 ++- src/stage.c | 50 +++++++++++++++++++++++++----------- src/status.c | 6 +++-- src/tig.c | 4 +-- test/stage/default-test | 57 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 103 insertions(+), 21 deletions(-) diff --git a/include/tig/stage.h b/include/tig/stage.h index e3f2f2aba..cee372d63 100644 --- a/include/tig/stage.h +++ b/include/tig/stage.h @@ -20,7 +20,7 @@ struct status; extern struct view stage_view; -void open_stage_view(struct view *prev, struct status *status, enum line_type type, enum open_flags flags); +void open_stage_view(struct view *prev, struct status *status, enum open_flags flags); #endif /* vim: set ts=8 sw=8 noexpandtab: */ diff --git a/include/tig/view.h b/include/tig/view.h index 794530c1c..6821ae529 100644 --- a/include/tig/view.h +++ b/include/tig/view.h @@ -49,6 +49,7 @@ struct line { unsigned int no_commit_refs:1; unsigned int graph_indent:1; unsigned int search_result:1; + unsigned int stat_header:1; void *data; /* User data */ }; diff --git a/src/main.c b/src/main.c index 2401295be..73d10a698 100644 --- a/src/main.c +++ b/src/main.c @@ -92,6 +92,8 @@ main_add_commit(struct view *view, enum line_type type, struct commit *template, line = add_line_alloc(view, &commit, type, titlelen, custom); if (!line) return NULL; + if (custom) + line->stat_header = 1; *commit = *template; strcpy(commit->title, title); @@ -561,7 +563,7 @@ main_request(struct view *view, enum request request, struct line *line) if (line->type == LINE_STAT_UNSTAGED || line->type == LINE_STAT_STAGED) - open_stage_view(view, NULL, line->type, flags); + open_stage_view(view, NULL, flags); else if (line->type == LINE_STAT_UNTRACKED) open_status_view(view, true, flags); else diff --git a/src/stage.c b/src/stage.c index 6fbc6125c..67a0ac528 100644 --- a/src/stage.c +++ b/src/stage.c @@ -38,16 +38,8 @@ typedef enum } update_t; void -open_stage_view(struct view *prev, struct status *status, enum line_type type, enum open_flags flags) +open_stage_view(struct view *prev, struct status *status, enum open_flags flags) { - if (type) { - stage_line_type = type; - if (status) - stage_status = *status; - else - memset(&stage_status, 0, sizeof(stage_status)); - } - open_view(prev, &stage_view, flags); } @@ -700,9 +692,37 @@ stage_select(struct view *view, struct line *line) diff_common_select(view, line, changes_msg); } +static void select_stage_status(struct view *prev) +{ + struct line *line = &prev->line[prev->pos.lineno]; + if (!line) + return; + stage_line_type = 0; + switch (line->type) { + case LINE_STAT_STAGED: + case LINE_STAT_UNSTAGED: + if (!line->stat_header && !line->data) + return; + break; + case LINE_STAT_UNTRACKED: + if (line->stat_header) + return; + break; + default: + return; + } + stage_line_type = line->type; + if (line->data && !line->stat_header) { + struct status *status = line->data; + stage_status = *status; + } else + memset(&stage_status, 0, sizeof(stage_status)); +} + static enum status_code stage_open(struct view *view, enum open_flags flags) { + enum line_type line_type = (select_stage_status(view->prev), stage_line_type); const char *no_head_diff_argv[] = { GIT_DIFF_STAGED_INITIAL(encoding_arg, diff_context_arg(), ignore_space_arg(), stage_status.new.name) @@ -727,13 +747,13 @@ stage_open(struct view *view, enum open_flags flags) struct stage_state *state = view->private; enum status_code code; - if (!stage_line_type) + if (!line_type) return error("No stage content, press %s to open the status view and choose file", get_view_key(view, REQ_VIEW_STATUS)); view->encoding = NULL; - switch (stage_line_type) { + switch (line_type) { case LINE_STAT_STAGED: watch_register(&view->watch, WATCH_INDEX_STAGED); if (is_initial_commit()) { @@ -758,18 +778,18 @@ stage_open(struct view *view, enum open_flags flags) break; default: - die("line type %d not handled in switch", stage_line_type); + die("line type %d not handled in switch", line_type); } - if (!status_stage_info(view->ref, stage_line_type, &stage_status)) + if (!status_stage_info(view->ref, line_type, &stage_status)) return error("Failed to open staged view"); - if (stage_line_type != LINE_STAT_UNTRACKED) + if (line_type != LINE_STAT_UNTRACKED) diff_save_line(view, &state->diff, flags); view->vid[0] = 0; code = begin_update(view, repo.exec_dir, argv, flags); - if (code == SUCCESS && stage_line_type != LINE_STAT_UNTRACKED) { + if (code == SUCCESS && line_type != LINE_STAT_UNTRACKED) { struct stage_state *state = view->private; return diff_init_highlight(view, &state->diff); diff --git a/src/status.c b/src/status.c index 0855dc34e..a5fcd5cbf 100644 --- a/src/status.c +++ b/src/status.c @@ -94,13 +94,14 @@ status_run(struct view *view, const char *argv[], char status, enum line_type ty const char **status_argv = NULL; bool ok = argv_format(view->env, &status_argv, argv, 0) && io_run(&io, IO_RD, repo.exec_dir, NULL, status_argv); + size_t header_offset; argv_free(status_argv); free(status_argv); if (!ok) return false; - add_line_nodata(view, type); + header_offset = add_line_nodata(view, type) - view->line; while (io_get(&io, &buf, 0, true)) { struct line *line; @@ -171,6 +172,7 @@ status_run(struct view *view, const char *argv[], char status, enum line_type ty watch_apply(&view->watch, WATCH_INDEX_UNTRACKED_NO); } } else { + view->line[header_offset].stat_header = 1; if (type == LINE_STAT_STAGED) { watch_apply(&view->watch, WATCH_INDEX_STAGED_YES); no_files_staged = false; @@ -498,7 +500,7 @@ status_enter(struct view *view, struct line *line) return REQ_NONE; } - open_stage_view(view, status, line->type, flags); + open_stage_view(view, status, flags); return REQ_NONE; } diff --git a/src/tig.c b/src/tig.c index c8e6786cc..5d40121b3 100644 --- a/src/tig.c +++ b/src/tig.c @@ -180,7 +180,7 @@ view_driver(struct view *view, enum request request) break; case REQ_VIEW_DIFF: if (view && string_rev_is_null(view->env->commit)) - open_stage_view(view, NULL, 0, OPEN_DEFAULT); + open_stage_view(view, NULL, OPEN_DEFAULT); else open_diff_view(view, OPEN_DEFAULT); break; @@ -209,7 +209,7 @@ view_driver(struct view *view, enum request request) open_status_view(view, false, OPEN_DEFAULT); break; case REQ_VIEW_STAGE: - open_stage_view(view, NULL, 0, OPEN_DEFAULT); + open_stage_view(view, NULL, OPEN_DEFAULT); break; case REQ_VIEW_PAGER: open_pager_view(view, OPEN_DEFAULT); diff --git a/test/stage/default-test b/test/stage/default-test index cbf6db492..bb1060695 100755 --- a/test/stage/default-test +++ b/test/stage/default-test @@ -8,6 +8,35 @@ export LINES=20 steps ' :save-display status.screen + :2 + :view-stage + :save-display staged-changes-shortcut.screen + :view-close + + :5 + :view-stage + :save-display unstaged-changes-shortcut.screen + :view-close + + :view-main + + :1 + :view-stage + :save-display unstaged-changes-shortcut-from-main.screen + :view-close + + :2 + :view-stage + :save-display staged-changes-shortcut-from-main.screen + :view-close + + :view-close + + :4 + :view-stage + :save-display staged-changes-for-a-shortcut.screen + :view-close + :2 :enter :maximize @@ -39,6 +68,7 @@ steps ' :4 :status-update :save-display unstaged-changes-staged-all.screen + ' in_work_dir create_dirty_workdir @@ -68,6 +98,33 @@ Untracked files: [status] Nothing to update 100% EOF +assert_equals 'staged-changes.screen' < 'staged-changes-shortcut.screen' +assert_equals 'unstaged-changes.screen' < 'unstaged-changes-shortcut.screen' +assert_equals 'staged-changes.screen' < 'staged-changes-shortcut-from-main.screen' +assert_equals 'unstaged-changes.screen' < 'unstaged-changes-shortcut-from-main.screen' + +assert_equals 'staged-changes-for-a-shortcut.screen' <' to jump to file diff - line 1 of 23 78% +EOF + assert_equals 'staged-changes.screen' <