diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Keep a detached head in the branch switcher
Diffstat (limited to '')
-rw-r--r--source/ui-shared.c41
-rwxr-xr-xtests/t0103-log.sh20
2 files changed, 61 insertions, 0 deletions
diff --git a/source/ui-shared.c b/source/ui-shared.c
index cd822a0..85712bf 100644
--- a/source/ui-shared.c
+++ b/source/ui-shared.c
@@ -408,6 +408,45 @@ struct branch_option_data {
const char *selected;
};
+/*
+ * Whether the head the request follows is one of the branches the switcher
+ * lists, remote ones included when those are shown. A head that is not, a
+ * raw commit id or a tag, would otherwise leave the select resting on the
+ * first branch, and submitting the form would quietly move the visitor there.
+ */
+static int head_is_listed_branch(void)
+{
+ struct ref_store *refs = get_main_ref_store(the_repository);
+ struct strbuf ref = STRBUF_INIT;
+ int found;
+
+ strbuf_addf(&ref, "refs/heads/%s", ctx.qry.head);
+ found = refs_ref_exists(refs, ref.buf);
+ if (!found && ctx.repo->enable_remote_branches) {
+ strbuf_reset(&ref);
+ strbuf_addf(&ref, "refs/remotes/%s", ctx.qry.head);
+ found = refs_ref_exists(refs, ref.buf);
+ }
+ strbuf_release(&ref);
+ return found;
+}
+
+static void print_detached_head_option(void)
+{
+ const char *head = ctx.qry.head;
+ struct object_id oid;
+ struct strbuf label = STRBUF_INIT;
+
+ // A head that is a full id reads better cut to the length the pinned
+ // entry uses.
+ if (strlen(head) == the_hash_algo->hexsz && !get_oid_hex(head, &oid))
+ strbuf_addf(&label, "%.*s (detached)", SHORT_HASH_LEN, head);
+ else
+ strbuf_addf(&label, "%s (detached)", head);
+ html_option(head, label.buf, head);
+ strbuf_release(&label);
+}
+
static int print_branch_option(const struct reference *ref, void *data)
{
struct branch_option_data *opt = data;
@@ -478,6 +517,8 @@ static void print_header(void)
html_option(hex, cgit_fmt("%.*s (detached)",
SHORT_HASH_LEN, hex), hex);
+ } else if (!head_is_listed_branch()) {
+ print_detached_head_option();
}
refs_for_each_branch_ref(get_main_ref_store(the_repository),
print_branch_option, &opt);
diff --git a/tests/t0103-log.sh b/tests/t0103-log.sh
index 41b9769..dfb5176 100755
--- a/tests/t0103-log.sh
+++ b/tests/t0103-log.sh
@@ -17,6 +17,26 @@ test_expect_success 'generate bar/log' 'cgit_url "bar/log" >tmp'
test_expect_success 'find commit 1' 'grep "commit 1" tmp'
test_expect_success 'find commit 50' 'grep "commit 50" tmp'
+# The switch button submits the select as h, so whatever head the request
+# follows has to sit in the list selected, or submitting would quietly move
+# the visitor to the first branch.
+test_expect_success 'a detached head stays selected in the switcher' '
+ sha=$(git -C repos/foo rev-parse master~1) &&
+ cgit_url "foo/log&h=$sha" >tmp &&
+ grep "option value=.$sha. selected" tmp
+'
+test_expect_success 'a tag head stays selected in the switcher' '
+ git -C repos/foo tag t-switch master~1 &&
+ cgit_url "foo/log&h=t-switch" >tmp &&
+ grep "option value=.t-switch. selected>t-switch (detached)" tmp &&
+ git -C repos/foo tag -d t-switch
+'
+test_expect_success 'a branch head keeps its plain option' '
+ cgit_url "foo/log&h=master" >tmp &&
+ grep "option value=.master. selected>master<" tmp &&
+ ! grep "detached" tmp
+'
+
test_expect_success 'generate "with%20space/log?qt=grep&q=commit+1"' '
cgit_url "with+space/log&qt=grep&q=commit+1" >tmp
'