"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Mark Jamsek <mark@jamsek.com>
Subject:
show base commit markers in tog log view
To:
gameoftrees@openbsd.org
Date:
Fri, 21 Jul 2023 22:54:58 +1000

Download raw body.

Thread
This is a simple change along the same lines of showing reference labels
next to tog log messages insofar as it improves situational awareness,
which can be handy at times.

For example, in the case where you want to fold or drop some commits.
After 'got up -c:head:-N', I often like to confirm I've updated to the
correct commit before invoking histedit. With this, you can open tog and
at a glance confirm that your base commit is indeed the correct one for
the desired histedit operation. Similarly, when your base commit is
something other than the tip, it's nice to know where the base commit is
in relation to the rest when browsing the log view. This can interop
well with the new :base keyword feature.

The change will be immediately obvious upon running tog with the patch
inside a work tree, but to summarise: we show the "[base commit]" label
in the log view headline if the currently selected commit is the work
tree's base commit; and, irrespective of which commit is selected, we
prepend the base commit's summary log message with the '@' symbol. There
is no change to the log view when tog is invoked outside a work tree.


-----------------------------------------------
commit 5a5052fc079f77f45bb7d7339c1e6b5590f37d19 (main)
from: Mark Jamsek <mark@jamsek.dev>
date: Fri Jul 21 11:56:12 2023 UTC
 
 show base commit markers in log view header and msg line
 
 If tog is invoked in a work tree, prefix the base commit log message summary
 line with an '@' symbol. And, if the currently selected commit is the work
 tree's base commit, show "[base commit]" in the log view's headline.
 
 M  regress/tog/log.sh  |  89+  1-
 M  tog/tog.c           |  71+  4-

2 files changed, 160 insertions(+), 5 deletions(-)

diff 9c986b77d3f71b37ff5b5c6b4ec58b495ad8f312 5a5052fc079f77f45bb7d7339c1e6b5590f37d19
commit - 9c986b77d3f71b37ff5b5c6b4ec58b495ad8f312
commit + 5a5052fc079f77f45bb7d7339c1e6b5590f37d19
blob - 2a28c65c9bf9e227cba943ce259438976ac67c02
blob + fecfffb8a93f29610f56212f3fac114308276e7b
--- regress/tog/log.sh
+++ regress/tog/log.sh
@@ -448,7 +448,7 @@ test_log_commit_keywords()
 	commit $(pop_id 5 $ids) [1/5]
 	$ymd $(pop_id 5 $short_ids) flan_hacker  commit 4
 	$ymd $(pop_id 4 $short_ids) flan_hacker  commit 3
-	$ymd $(pop_id 3 $short_ids) flan_hacker  commit 2
+	$ymd $(pop_id 3 $short_ids) flan_hacker @commit 2
 	$ymd $(pop_id 2 $short_ids) flan_hacker  commit 1
 	$ymd $(pop_id 1 $short_ids) flan_hacker  adding the test tree
 
@@ -499,6 +499,93 @@ test_parseargs "$@"
 	test_done "$testroot" "$ret"
 }
 
+test_log_show_base_commit()
+{
+	# make view wide enough to show full headline
+	test_init log_show_base_commit 80 3
+	local repo="$testroot/repo"
+	local id=$(git_show_head "$repo")
+
+	echo "alpha" >> "$repo/alpha"
+	git_commit "$repo" -m "base commit"
+
+	got checkout "$repo" "$testroot/wt" > /dev/null
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		echo "got checkout failed unexpectedly"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	# move into the work tree (test is run in a subshell)
+	cd "$testroot/wt"
+
+	local head_id=$(git_show_head "$repo")
+	local author_time=$(git_show_author_time "$repo")
+	local ymd=$(date -u -r "$author_time" +"%G-%m-%d")
+
+	# check base commit header label is shown when base commit is selected
+	# and base commit marker prefixes base commit log message
+	cat <<-EOF >$TOG_TEST_SCRIPT
+	SCREENDUMP
+	EOF
+
+	cat <<-EOF >$testroot/view.expected
+	commit $head_id [base commit] [1/2] master
+	$ymd flan_hacker @[master] base commit
+	$ymd flan_hacker  adding the test tree
+	EOF
+
+	tog log
+	cmp -s "$testroot/view.expected" "$testroot/view"
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u "$testroot/view.expected" "$testroot/view"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	# check neither marker nor label are drawn when not in a work tree
+	cat <<-EOF >$testroot/view.expected
+	commit $head_id [1/2] master
+	$ymd flan_hacker  [master] base commit
+	$ymd flan_hacker  adding the test tree
+	EOF
+
+	tog log -r "$repo"
+	cmp -s "$testroot/view.expected" "$testroot/view"
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u "$testroot/view.expected" "$testroot/view"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	# check label is not shown when base commit is not selected
+	# but base commit marker still prefixes log message
+	cat <<-EOF >$TOG_TEST_SCRIPT
+	j		select non-base commit
+	SCREENDUMP
+	EOF
+
+	cat <<-EOF >$testroot/view.expected
+	commit $id [2/2]
+	$ymd flan_hacker @[master] base commit
+	$ymd flan_hacker  adding the test tree
+	EOF
+
+	tog log
+	cmp -s "$testroot/view.expected" "$testroot/view"
+	ret=$?
+	if [ $ret -ne 0 ]; then
+		diff -u "$testroot/view.expected" "$testroot/view"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	test_done "$testroot" "$ret"
+}
+
 test_parseargs "$@"
 run_test test_log_hsplit_diff
 run_test test_log_vsplit_diff
@@ -508,3 +595,4 @@ run_test test_log_commit_keywords
 run_test test_log_hsplit_tree
 run_test test_log_logmsg_widechar
 run_test test_log_commit_keywords
+run_test test_log_show_base_commit
blob - 55201d879df128d62d2a76ec797059af85649fa8
blob + 8c0b33eedc0db80f91741d15a52ecfa711c0d664
--- tog/tog.c
+++ tog/tog.c
@@ -151,6 +151,7 @@ static enum got_diff_algorithm tog_diff_algo = GOT_DIF
 
 static struct got_reflist_head tog_refs = TAILQ_HEAD_INITIALIZER(tog_refs);
 static struct got_reflist_object_id_map *tog_refs_idmap;
+static struct got_object_id *tog_base_commit_id;
 static enum got_diff_algorithm tog_diff_algo = GOT_DIFF_ALGORITHM_MYERS;
 
 static const struct got_error *
@@ -2411,7 +2412,7 @@ draw_commit(struct tog_view *view, struct got_commit_o
 	int author_width, refstr_width, logmsg_width;
 	char *newline, *line = NULL;
 	int col, limit, scrollx, logmsg_x;
-	const int avail = view->ncols;
+	const int avail = view->ncols, marker_column = author_display_cols + 1;
 	struct tm tm;
 	time_t committer_time;
 	struct tog_color *tc;
@@ -2476,7 +2477,12 @@ draw_commit(struct tog_view *view, struct got_commit_o
 	waddwstr(view->window, wauthor);
 	col += author_width;
 	while (col < avail && author_width < author_display_cols + 2) {
-		waddch(view->window, ' ');
+		if (tog_base_commit_id != NULL &&
+		    author_width == marker_column &&
+		    got_object_id_cmp(id, tog_base_commit_id) == 0)
+			waddch(view->window, '@');
+		else
+			waddch(view->window, ' ');
 		col++;
 		author_width++;
 	}
@@ -2777,6 +2783,7 @@ draw_commits(struct tog_view *view)
 	int width;
 	int ncommits, author_cols = 4, refstr_cols;
 	char *id_str = NULL, *header = NULL, *ncommits_str = NULL;
+	const char *base_label = NULL;
 	char *refs_str = NULL;
 	wchar_t *wline;
 	struct tog_color *tc;
@@ -2802,8 +2809,13 @@ draw_commits(struct tog_view *view)
 	if (s->thread_args.commits_needed == 0 && !using_mock_io)
 		halfdelay(10); /* disable fast refresh */
 
+	if (s->selected_entry != NULL && tog_base_commit_id != NULL &&
+	    got_object_id_cmp(s->selected_entry->id, tog_base_commit_id) == 0)
+		base_label = "[base commit] ";
+
 	if (s->thread_args.commits_needed > 0 || s->thread_args.load_all) {
-		if (asprintf(&ncommits_str, " [%d/%d] %s",
+		if (asprintf(&ncommits_str, " %s[%d/%d] %s",
+		    base_label != NULL ? base_label : "",
 		    entry ? entry->idx + 1 : 0, s->commits->ncommits,
 		    (view->searching && !view->search_next_done) ?
 		    "searching..." : "loading...") == -1) {
@@ -2826,7 +2838,8 @@ draw_commits(struct tog_view *view)
 		if (s->limit_view && s->commits->ncommits == 0)
 			limit_str = "no matches found";
 
-		if (asprintf(&ncommits_str, " [%d/%d] %s %s",
+		if (asprintf(&ncommits_str, " %s[%d/%d] %s %s",
+		    base_label != NULL ? base_label : "",
 		    entry ? entry->idx + 1 : 0, s->commits->ncommits,
 		    search_str ? search_str : (refs_str ? refs_str : ""),
 		    limit_str ? limit_str : "") == -1) {
@@ -4518,13 +4531,24 @@ cmd_log(int argc, char *argv[])
 	    in_repo_path, log_branches);
 	if (error)
 		goto done;
+
 	if (worktree) {
+		tog_base_commit_id = got_object_id_dup(
+		    got_worktree_get_base_commit_id(worktree));
+		if (tog_base_commit_id == NULL) {
+			error = got_error_from_errno( "got_object_id_dup");
+			goto done;
+		}
+
 		/* Release work tree lock. */
 		got_worktree_close(worktree);
 		worktree = NULL;
 	}
+
 	error = view_loop(view);
+
 done:
+	free(tog_base_commit_id);
 	free(keyword_idstr);
 	free(in_repo_path);
 	free(repo_path);
@@ -6046,8 +6070,20 @@ cmd_diff(int argc, char *argv[])
 	    ignore_whitespace, force_text_diff, NULL,  repo);
 	if (error)
 		goto done;
+
+	if (worktree) {
+		tog_base_commit_id = got_object_id_dup(
+		    got_worktree_get_base_commit_id(worktree));
+		if (tog_base_commit_id == NULL) {
+			error = got_error_from_errno( "got_object_id_dup");
+			goto done;
+		}
+	}
+
 	error = view_loop(view);
+
 done:
+	free(tog_base_commit_id);
 	free(keyword_idstr1);
 	free(keyword_idstr2);
 	free(label1);
@@ -7194,13 +7230,24 @@ cmd_blame(int argc, char *argv[])
 		view_close(view);
 		goto done;
 	}
+
 	if (worktree) {
+		tog_base_commit_id = got_object_id_dup(
+		    got_worktree_get_base_commit_id(worktree));
+		if (tog_base_commit_id == NULL) {
+			error = got_error_from_errno( "got_object_id_dup");
+			goto done;
+		}
+
 		/* Release work tree lock. */
 		got_worktree_close(worktree);
 		worktree = NULL;
 	}
+
 	error = view_loop(view);
+
 done:
+	free(tog_base_commit_id);
 	free(repo_path);
 	free(in_repo_path);
 	free(link_target);
@@ -8183,12 +8230,22 @@ cmd_tree(int argc, char *argv[])
 	}
 
 	if (worktree) {
+		tog_base_commit_id = got_object_id_dup(
+		    got_worktree_get_base_commit_id(worktree));
+		if (tog_base_commit_id == NULL) {
+			error = got_error_from_errno( "got_object_id_dup");
+			goto done;
+		}
+
 		/* Release work tree lock. */
 		got_worktree_close(worktree);
 		worktree = NULL;
 	}
+
 	error = view_loop(view);
+
 done:
+	free(tog_base_commit_id);
 	free(keyword_idstr);
 	free(repo_path);
 	free(cwd);
@@ -9032,12 +9089,22 @@ cmd_ref(int argc, char *argv[])
 		goto done;
 
 	if (worktree) {
+		tog_base_commit_id = got_object_id_dup(
+		    got_worktree_get_base_commit_id(worktree));
+		if (tog_base_commit_id == NULL) {
+			error = got_error_from_errno( "got_object_id_dup");
+			goto done;
+		}
+
 		/* Release work tree lock. */
 		got_worktree_close(worktree);
 		worktree = NULL;
 	}
+
 	error = view_loop(view);
+
 done:
+	free(tog_base_commit_id);
 	free(repo_path);
 	free(cwd);
 	if (repo) {


-- 
Mark Jamsek <https://bsdbox.org>
GPG: F2FF 13DE 6A06 C471 CA80  E6E2 2930 DC66 86EE CF68