Skip to main content

fish_functions/fish_prompt.fish

1###############################################################################
2# My fish prompt
3#
4# This has been inspired by various examples from other people, not all
5# of whom I kept notes of.
6###############################################################################
9function print_current_directory
10 set_color green
11 if string match -q "$TMPDIR*" (pwd); and test -n "$TMPDIR"
12 set remaining (string replace -r "^$TMPDIR" "" (pwd))
13 printf (echo -n "\$TMPDIR/$remaining")
14 else
15 printf (echo -n (prompt_pwd))
16 end
17 set_color normal
18end
21# Print information about the current Git branch, if I'm in a Git repo.
23# At one point I had similar functions for getting SVN and Mercurial information,
24# but at time of writing (Apr 2022), it's been 5+ years since I used a non-Git VCS.
25# It's not worth maintaining those alternatives or running them against every
26# shell prompt.
27function print_git_information
28 which git 2>&1 >/dev/null
30 set is_bare (git rev-parse --is-bare-repository 2> /dev/null)
31 if string match --quiet "true*" $is_bare
32 return
33 end
35 set branch (git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
36 if [ -n "$branch" ]
37 set_color normal
38 printf " on git:"
40 if test (basename "$branch") = main
41 set_color cyan
42 else
43 set_color purple
44 end
46 printf "$branch"
48 # Print an asterisk to indicate uncommitted changes, if there are any
49 # Try git update-index --really-refresh?
50 if ! git diff-index --quiet HEAD --
51 printf "*"
52 end
54 set_color normal
55 end
56end
59# Print information about the current virtualenv, if one is enabled.
61# The VIRTUAL_ENV_DISABLE_PROMPT command disables the auto-prepending of the
62# venv into my prompt by the virtualenv itself; see
63# https://stackoverflow.com/a/63029769/1558022
64set -x VIRTUAL_ENV_DISABLE_PROMPT 1
66function print_venv_information
67 if test -n "$VIRTUAL_ENV"
69 # If the virtualenv has ceased to exist since the last prompt,
70 # then it can't possibly be activated, so deactivate and don't
71 # print it in the prompt.
72 if test ! -d "$VIRTUAL_ENV"
73 deactivate
74 return
75 end
77 set_color normal
78 printf " using "
80 if test (basename "$VIRTUAL_ENV") = ".venv"
81 set_color cyan
82 else
83 set_color purple
84 end
86 printf (basename "$VIRTUAL_ENV")
87 set_color normal
88 end
89end
92# If I'm running over SSH, prepend the name of the remote host to
93# the context line.
94function print_ssh_information
95 if set -q SSH_CLIENT
96 printf "("
97 set_color purple
98 printf (echo -n (hostname))
99 set_color normal
100 printf ") "
101 end
102end
105# Allow me to prevent certain dangerous commands from ever
106# appearing in autocomplete.
108# See https://alexwlchan.net/2023/forgetful-fish/
109# See https://github.com/fish-shell/fish-shell/issues/10066
110function forget_dangerous_history_commands
111 set last_typed_command (history --max 1)
113 if [ "$last_typed_command" = "git push origin (gcb) --force" ]
114 history delete --exact --case-sensitive "$last_typed_command"
115 history save
116 end
117end
120function fish_prompt --description 'Write out the prompt'
121 # forget_dangerous_history_commands
123 # Put a newline between new prompts for cleanliness, but not on the first run.
124 #
125 # This means the first prompt of a new session is right at the top of
126 # the terminal window, not with a newline above it.
127 #
128 # If we're in an SSH session, we always insert a newline, even on the first
129 # command -- to separate from the client session. I avoid getting the
130 # 'Last login' message with `touch ~/.hushlogin`
131 if set -q SSH_CLIENT
132 echo ''
133 else
134 if test \( -f "/tmp/$TERM_SESSION_ID" -o -f "/tmp/$XDG_SESSION_ID" \)
135 echo ''
136 end
138 touch "/tmp/$TERM_SESSION_ID" 2>/dev/null
139 touch "/tmp/$XDG_SESSION_ID" 2>/dev/null
140 end
142 # Print some context about where I'm running this command.
143 #
144 # If I'm in my home directory, the context isn't very interesting (it's where
145 # new shells open, and it's not in Git), so skip the context line to reduce
146 # visual noise.
147 if [ (prompt_pwd) = "~" ]
148 if set -q SSH_CLIENT
149 print_ssh_information
150 echo ''
151 end
152 echo '$ '
153 return
154 end
156 print_ssh_information
157 print_current_directory
158 print_git_information
159 print_venv_information
161 # Print the shell prompt.
162 #
163 # I have a different prompt for when I'm running as root; admittedly this
164 # is extremely rare if I'm also using fish, but if I am I want a visual cue
165 # that this terminal is unusual.
166 #
167 # I print the prompt on a separate line to the context information so it's
168 # always in the same place: as I'm typing commands, I get the full width of
169 # the terminal to use, rather than a variable amount based on the context line.
170 set_color normal
171 if [ "$USER" = root ]
172 echo '' & echo '# '
173 else
174 echo '' & echo '$ '
175 end
176end