starship: hyperlink github PR number
β’ 451 words β’ 3 min β’ updated
Problem statement: the GitHub PR number in my Starship prompt was plain text.
The custom module already asked gh for the PR number and cached it with
bkt:
[custom.github_pr]
command = "bkt --ttl=10m --scope=\"$(git rev-parse --show-toplevel):$(git branch --show-current)\" -- gh pr view --json number --jq '\"#\" + (.number | tostring)' 2>/dev/null"
when = "git rev-parse --is-inside-work-tree 2>/dev/null"
format = " [$output](magenta)"
ignore_timeout = trueAn OSC 8 escape sequence can turn #78 into a terminal hyperlink. I first used
ESC \ to terminate each sequence. The template produced the expected bytes,
but zsh prompt expansion consumed each backslash and left an incomplete escape
sequence:
missing hyperlink sequence; output=b'...\x1b]8;;https://github.com/thiagowfx/.dotfiles/pull/78\x1b#78\x1b]8;;\x1b...'BEL terminates OSC 8 without passing a backslash through zsh:
diff --git starship/.config/starship.toml starship/.config/starship.toml
index 87e83794..739ee62f 100644
--- starship/.config/starship.toml
+++ starship/.config/starship.toml
@@ -54,7 +54,7 @@ format = " [β $output]($style)"
style = "bold yellow"
[custom.github_pr]
-command = "bkt --ttl=10m --scope=\"$(git rev-parse --show-toplevel):$(git branch --show-current)\" -- gh pr view --json number --jq '\"#\" + (.number | tostring)' 2>/dev/null"
+command = "bkt --ttl=10m --scope=\"$(git rev-parse --show-toplevel):$(git branch --show-current)\" -- gh pr view --json number,url --template '{{printf \"\\033]8;;%s\\007#%v\\033]8;;\\007\" .url .number}}' 2>/dev/null"
when = "git rev-parse --is-inside-work-tree 2>/dev/null"
format = " [$output](magenta)"
ignore_timeout = true
I tested the full Starship-to-zsh path against the branch for PR #78:
% tmp=$(mktemp -d)
% git -C "$tmp" init -q
% git -C "$tmp" remote add origin https://github.com/thiagowfx/.dotfiles.git
% git -C "$tmp" switch -q -c renovate/web-tree-sitter-0.x
% (cd "$tmp" && STARSHIP_SHELL=zsh starship prompt) |
zsh -c 'prompt=$(cat); print -nP -- "$prompt"' |
python3 -c 'import sys
out = sys.stdin.buffer.read()
expected = b"\x1b]8;;https://github.com/thiagowfx/.dotfiles/pull/78\x07#78\x1b]8;;\x07"
assert expected in out
print("PASS: zsh-rendered Starship prompt links #78 to PR URL")'
PASS: zsh-rendered Starship prompt links #78 to PR URLCmd + click on the number now opens the PR in Ghostty.
That test covered zsh only. Bash exposed a prompt alignment bug two weeks later. Text from the command line appeared at the right edge and before the prompt.
Starship did not mark the complete OSC 8 sequence as non-printing for Bash:
\[\x1b]8;;https://github.com\]/[redacted]/[redacted]/pull/7163\x07#7163\[\x1b]8;;\x07Only ESC ] 8 ;; https://github.com was inside Readline’s \[ and \]
markers. Bash counted the remaining URL as visible prompt text, so its cursor
position was wrong.
I reverted the hyperlink:
[custom.github_pr]
-command = "bkt --ttl=10m --scope=\"$(git rev-parse --show-toplevel):$(git branch --show-current)\" -- gh pr view --json number,url --template '{{printf \"\\033]8;;%s\\007#%v\\033]8;;\\007\" .url .number}}' 2>/dev/null"
+command = "bkt --ttl=10m --scope=\"$(git rev-parse --show-toplevel):$(git branch --show-current)\" -- gh pr view --json number --jq '\"#\" + (.number | tostring)' 2>/dev/null"
when = "git rev-parse --is-inside-work-tree 2>/dev/null"
format = " [$output](magenta)"
ignore_timeout = true
The PR number is plain text again. The Bash prompt now stays aligned.
π€ Drafted with /bloggify. β
/bloggify,
then reviewed and edited by me.
More agent-assisted posts.