1# -----------------------------------------------------------------------------
2# Fishshell Samples
3#  |- Theme / bobthefish
4#  |- Function / funced
5#  |- Configuration / config.fish
6# -----------------------------------------------------------------------------
7
8# name: bobthefish
9#
10# bobthefish is a Powerline-style, Git-aware fish theme optimized for awesome.
11#
12# You will probably need a Powerline-patched font for this to work:
13#
14#     https://powerline.readthedocs.org/en/latest/fontpatching.html
15#
16# I recommend picking one of these:
17#
18#     https://github.com/Lokaltog/powerline-fonts
19#
20# You can override some default options in your config.fish:
21#
22#     set -g theme_display_user yes
23#     set -g default_user your_normal_user
24
25set -g __bobthefish_current_bg NONE
26
27# Powerline glyphs
28set __bobthefish_branch_glyph            \uE0A0
29set __bobthefish_ln_glyph                \uE0A1
30set __bobthefish_padlock_glyph           \uE0A2
31set __bobthefish_right_black_arrow_glyph \uE0B0
32set __bobthefish_right_arrow_glyph       \uE0B1
33set __bobthefish_left_black_arrow_glyph  \uE0B2
34set __bobthefish_left_arrow_glyph        \uE0B3
35
36# Additional glyphs
37set __bobthefish_detached_glyph          \u27A6
38set __bobthefish_nonzero_exit_glyph      '! '
39set __bobthefish_superuser_glyph         '$ '
40set __bobthefish_bg_job_glyph            '% '
41set __bobthefish_hg_glyph                \u263F
42
43# Python glyphs
44set __bobthefish_superscript_glyph       \u00B9 \u00B2 \u00B3
45set __bobthefish_virtualenv_glyph        \u25F0
46set __bobthefish_pypy_glyph              \u1D56
47
48# Colors
49set __bobthefish_lt_green   addc10
50set __bobthefish_med_green  189303
51set __bobthefish_dk_green   0c4801
52
53set __bobthefish_lt_red     C99
54set __bobthefish_med_red    ce000f
55set __bobthefish_dk_red     600
56
57set __bobthefish_slate_blue 255e87
58
59set __bobthefish_lt_orange  f6b117
60set __bobthefish_dk_orange  3a2a03
61
62set __bobthefish_dk_grey    333
63set __bobthefish_med_grey   999
64set __bobthefish_lt_grey    ccc
65
66set __bobthefish_dk_brown   4d2600
67set __bobthefish_med_brown  803F00
68set __bobthefish_lt_brown   BF5E00
69
70set __bobthefish_dk_blue    1E2933
71set __bobthefish_med_blue   275379
72set __bobthefish_lt_blue    326D9E
73
74# ===========================
75# Helper methods
76# ===========================
77
78function __bobthefish_in_git -d 'Check whether pwd is inside a git repo'
79  command which git > /dev/null 2>&1; and command git rev-parse --is-inside-work-tree >/dev/null 2>&1
80end
81
82function __bobthefish_in_hg -d 'Check whether pwd is inside a hg repo'
83  command which hg > /dev/null 2>&1; and command hg stat > /dev/null 2>&1
84end
85
86function __bobthefish_git_branch -d 'Get the current git branch (or commitish)'
87  set -l ref (command git symbolic-ref HEAD 2> /dev/null)
88  if [ $status -gt 0 ]
89    set -l branch (command git show-ref --head -s --abbrev |head -n1 2> /dev/null)
90    set ref "$__bobthefish_detached_glyph $branch"
91  end
92  echo $ref | sed  "s-refs/heads/-$__bobthefish_branch_glyph -"
93end
94
95function __bobthefish_hg_branch -d 'Get the current hg branch'
96  set -l branch (hg branch ^/dev/null)
97  set -l book " @ "(hg book | grep \* | cut -d\  -f3)
98  echo "$__bobthefish_branch_glyph $branch$book"
99end
100
101function __bobthefish_pretty_parent -d 'Print a parent directory, shortened to fit the prompt'
102  echo -n (dirname $argv[1]) | sed -e 's|/private||' -e "s|^$HOME|~|" -e 's-/\(\.\{0,1\}[^/]\)\([^/]*\)-/\1-g' -e 's|/$||'
103end
104
105function __bobthefish_git_project_dir -d 'Print the current git project base directory'
106  command git rev-parse --show-toplevel 2>/dev/null
107end
108
109function __bobthefish_hg_project_dir -d 'Print the current hg project base directory'
110  command hg root 2>/dev/null
111end
112
113function __bobthefish_project_pwd -d 'Print the working directory relative to project root'
114  echo "$PWD" | sed -e "s*$argv[1]**g" -e 's*^/**'
115end
116
117
118# ===========================
119# Segment functions
120# ===========================
121
122function __bobthefish_start_segment -d 'Start a prompt segment'
123  set_color -b $argv[1]
124  set_color $argv[2]
125  if [ "$__bobthefish_current_bg" = 'NONE' ]
126    # If there's no background, just start one
127    echo -n ' '
128  else
129    # If there's already a background...
130    if [ "$argv[1]" = "$__bobthefish_current_bg" ]
131      # and it's the same color, draw a separator
132      echo -n "$__bobthefish_right_arrow_glyph "
133    else
134      # otherwise, draw the end of the previous segment and the start of the next
135      set_color $__bobthefish_current_bg
136      echo -n "$__bobthefish_right_black_arrow_glyph "
137      set_color $argv[2]
138    end
139  end
140  set __bobthefish_current_bg $argv[1]
141end
142
143function __bobthefish_path_segment -d 'Display a shortened form of a directory'
144  if test -w "$argv[1]"
145    __bobthefish_start_segment $__bobthefish_dk_grey $__bobthefish_med_grey
146  else
147    __bobthefish_start_segment $__bobthefish_dk_red $__bobthefish_lt_red
148  end
149
150  set -l directory
151  set -l parent
152
153  switch "$argv[1]"
154    case /
155      set directory '/'
156    case "$HOME"
157      set directory '~'
158    case '*'
159      set parent    (__bobthefish_pretty_parent "$argv[1]")
160      set parent    "$parent/"
161      set directory (basename "$argv[1]")
162  end
163
164  test "$parent"; and echo -n -s "$parent"
165  set_color fff --bold
166  echo -n "$directory "
167  set_color normal
168end
169
170function __bobthefish_finish_segments -d 'Close open prompt segments'
171  if [ -n $__bobthefish_current_bg -a $__bobthefish_current_bg != 'NONE' ]
172    set_color -b normal
173    set_color $__bobthefish_current_bg
174    echo -n "$__bobthefish_right_black_arrow_glyph "
175    set_color normal
176  end
177  set -g __bobthefish_current_bg NONE
178end
179
180
181# ===========================
182# Theme components
183# ===========================
184
185function __bobthefish_prompt_status -d 'Display symbols for a non zero exit status, root and background jobs'
186  set -l nonzero
187  set -l superuser
188  set -l bg_jobs
189
190  # Last exit was nonzero
191  if [ $status -ne 0 ]
192    set nonzero $__bobthefish_nonzero_exit_glyph
193  end
194
195  # if superuser (uid == 0)
196  set -l uid (id -u $USER)
197  if [ $uid -eq 0 ]
198    set superuser $__bobthefish_superuser_glyph
199  end
200
201  # Jobs display
202  if [ (jobs -l | wc -l) -gt 0 ]
203    set bg_jobs $__bobthefish_bg_job_glyph
204  end
205
206  set -l status_flags "$nonzero$superuser$bg_jobs"
207
208  if test "$nonzero" -o "$superuser" -o "$bg_jobs"
209    __bobthefish_start_segment fff 000
210    if [ "$nonzero" ]
211      set_color $__bobthefish_med_red --bold
212      echo -n $__bobthefish_nonzero_exit_glyph
213    end
214
215    if [ "$superuser" ]
216      set_color $__bobthefish_med_green --bold
217      echo -n $__bobthefish_superuser_glyph
218    end
219
220    if [ "$bg_jobs" ]
221      set_color $__bobthefish_slate_blue --bold
222      echo -n $__bobthefish_bg_job_glyph
223    end
224
225    set_color normal
226  end
227end
228
229function __bobthefish_prompt_user -d 'Display actual user if different from $default_user'
230  if [ "$theme_display_user" = 'yes' ]
231    if [ "$USER" != "$default_user" -o -n "$SSH_CLIENT" ]
232      __bobthefish_start_segment $__bobthefish_lt_grey $__bobthefish_slate_blue
233      echo -n -s (whoami) '@' (hostname | cut -d . -f 1) ' '
234    end
235  end
236end
237
238function __bobthefish_prompt_hg -d 'Display the actual hg state'
239  set -l dirty   (command hg stat; or echo -n '*')
240
241  set -l flags "$dirty"
242  test "$flags"; and set flags ""
243
244  set -l flag_bg $__bobthefish_lt_green
245  set -l flag_fg $__bobthefish_dk_green
246  if test "$dirty"
247    set flag_bg $__bobthefish_med_red
248    set flag_fg fff
249  end
250
251  __bobthefish_path_segment (__bobthefish_hg_project_dir)
252
253  __bobthefish_start_segment $flag_bg $flag_fg
254  echo -n -s $__bobthefish_hg_glyph ' '
255
256  __bobthefish_start_segment $flag_bg $flag_fg
257  set_color $flag_fg --bold
258  echo -n -s (__bobthefish_hg_branch) $flags ' '
259  set_color normal
260
261  set -l project_pwd  (__bobthefish_project_pwd (__bobthefish_hg_project_dir))
262  if test "$project_pwd"
263    if test -w "$PWD"
264      __bobthefish_start_segment 333 999
265    else
266      __bobthefish_start_segment $__bobthefish_med_red $__bobthefish_lt_red
267    end
268
269    echo -n -s $project_pwd ' '
270  end
271end
272
273# TODO: clean up the fugly $ahead business
274function __bobthefish_prompt_git -d 'Display the actual git state'
275  set -l dirty   (command git diff --no-ext-diff --quiet --exit-code; or echo -n '*')
276  set -l staged  (command git diff --cached --no-ext-diff --quiet --exit-code; or echo -n '~')
277  set -l stashed (command git rev-parse --verify refs/stash > /dev/null 2>&1; and echo -n '$')
278  set -l ahead   (command git branch -v 2> /dev/null | grep -Eo '^\* [^ ]* *[^ ]* *\[[^]]*\]' | grep -Eo '\[[^]]*\]$' | awk 'ORS="";/ahead/ {print "+"} /behind/ {print "-"}' | sed -e 's/+-/±/')
279
280  set -l new (command git ls-files --other --exclude-standard);
281  test "$new"; and set new '…'
282
283  set -l flags   "$dirty$staged$stashed$ahead$new"
284  test "$flags"; and set flags " $flags"
285
286  set -l flag_bg $__bobthefish_lt_green
287  set -l flag_fg $__bobthefish_dk_green
288  if test "$dirty" -o "$staged"
289    set flag_bg $__bobthefish_med_red
290    set flag_fg fff
291  else
292    if test "$stashed"
293      set flag_bg $__bobthefish_lt_orange
294      set flag_fg $__bobthefish_dk_orange
295    end
296  end
297
298  __bobthefish_path_segment (__bobthefish_git_project_dir)
299
300  __bobthefish_start_segment $flag_bg $flag_fg
301  set_color $flag_fg --bold
302  echo -n -s (__bobthefish_git_branch) $flags ' '
303  set_color normal
304
305  set -l project_pwd  (__bobthefish_project_pwd (__bobthefish_git_project_dir))
306  if test "$project_pwd"
307    if test -w "$PWD"
308      __bobthefish_start_segment 333 999
309    else
310      __bobthefish_start_segment $__bobthefish_med_red $__bobthefish_lt_red
311    end
312
313    echo -n -s $project_pwd ' '
314  end
315end
316
317function __bobthefish_prompt_dir -d 'Display a shortened form of the current directory'
318  __bobthefish_path_segment "$PWD"
319end
320
321function __bobthefish_in_virtualfish_virtualenv
322  set -q VIRTUAL_ENV
323end
324
325function __bobthefish_virtualenv_python_version -d 'Get current python version'
326  switch (readlink (which python))
327    case python2
328      echo $__bobthefish_superscript_glyph[2]
329    case python3
330      echo $__bobthefish_superscript_glyph[3]
331    case pypy
332      echo $__bobthefish_pypy_glyph
333    end
334end
335
336function __bobthefish_virtualenv -d 'Get the current virtualenv'
337  echo $__bobthefish_virtualenv_glyph(__bobthefish_virtualenv_python_version) (basename "$VIRTUAL_ENV")
338end
339
340function __bobthefish_prompt_virtualfish -d "Display activated virtual environment (only for virtualfish, virtualenv's activate.fish changes prompt by itself)"
341  set flag_bg $__bobthefish_lt_blue
342  set flag_fg $__bobthefish_dk_blue
343  __bobthefish_start_segment $flag_bg $flag_fg
344  set_color $flag_fg --bold
345  echo -n -s (__bobthefish_virtualenv) $flags ' '
346  set_color normal
347end
348
349
350# ===========================
351# Apply theme
352# ===========================
353
354function fish_prompt -d 'bobthefish, a fish theme optimized for awesome'
355  __bobthefish_prompt_status
356  __bobthefish_prompt_user
357  if __bobthefish_in_virtualfish_virtualenv
358    __bobthefish_prompt_virtualfish
359  end
360  if __bobthefish_in_git       # TODO: do this right.
361    __bobthefish_prompt_git    # if something is in both git and hg, check the length of
362  else if __bobthefish_in_hg   # __bobthefish_git_project_dir vs __bobthefish_hg_project_dir
363    __bobthefish_prompt_hg     # and pick the longer of the two.
364  else
365    __bobthefish_prompt_dir
366  end
367  __bobthefish_finish_segments
368end
369
370# -----------------------------------------------------------------------------
371# funced - edit a function interactively
372#
373# Synopsis
374#
375#   funced [OPTIONS] NAME
376#
377# Description
378#
379#   funced provides an interface to edit the definition of the function NAME.
380# -----------------------------------------------------------------------------
381
382function funced --description 'Edit function definition'
383    set -l editor $EDITOR
384    set -l interactive
385    set -l funcname
386    while set -q argv[1]
387        switch $argv[1]
388            case -h --help
389                __fish_print_help funced
390                return 0
391
392            case -e --editor
393                set editor $argv[2]
394                set -e argv[2]
395
396            case -i --interactive
397                set interactive 1
398
399            case --
400                set funcname $funcname $argv[2]
401                set -e argv[2]
402
403            case '-*'
404                set_color red
405                printf (_ "%s: Unknown option %s\n") funced $argv[1]
406                set_color normal
407                return 1
408
409            case '*' '.*'
410                set funcname $funcname $argv[1]
411        end
412        set -e argv[1]
413    end
414
415    if begin; set -q funcname[2]; or not test "$funcname[1]"; end
416        set_color red
417        _ "funced: You must specify one function name
418"
419        set_color normal
420        return 1
421    end
422
423    set -l init
424    switch $funcname
425        case '-*'
426        set init function -- $funcname\n\nend
427        case '*'
428        set init function $funcname\n\nend
429    end
430
431    # Break editor up to get its first command (i.e. discard flags)
432    if test -n "$editor"
433        set -l editor_cmd
434        eval set editor_cmd $editor
435        if not type -f "$editor_cmd[1]" >/dev/null
436            _ "funced: The value for \$EDITOR '$editor' could not be used because the command '$editor_cmd[1]' could not be found
437    "
438            set editor fish
439        end
440    end
441
442    # If no editor is specified, use fish
443    if test -z "$editor"
444        set editor fish
445    end
446
447    if begin; set -q interactive[1]; or test "$editor" = fish; end
448        set -l IFS
449        if functions -q -- $funcname
450            # Shadow IFS here to avoid array splitting in command substitution
451            set init (functions -- $funcname | fish_indent --no-indent)
452        end
453
454        set -l prompt 'printf "%s%s%s> " (set_color green) '$funcname' (set_color normal)'
455        # Unshadow IFS since the fish_title breaks otherwise
456        set -e IFS
457        if read -p $prompt -c "$init" -s cmd
458            # Shadow IFS _again_ to avoid array splitting in command substitution
459            set -l IFS
460            eval (echo -n $cmd | fish_indent)
461        end
462        return 0
463    end
464
465    set -q TMPDIR; or set -l TMPDIR /tmp
466    set -l tmpname (printf "$TMPDIR/fish_funced_%d_%d.fish" %self (random))
467    while test -f $tmpname
468        set tmpname (printf "$TMPDIR/fish_funced_%d_%d.fish" %self (random))
469    end
470
471    if functions -q -- $funcname
472        functions -- $funcname > $tmpname
473    else
474        echo $init > $tmpname
475    end
476    if eval $editor $tmpname
477        . $tmpname
478    end
479    set -l stat $status
480    rm -f $tmpname >/dev/null
481    return $stat
482end
483
484# -----------------------------------------------------------------------------
485# Main file for fish command completions. This file contains various
486# common helper functions for the command completions. All actual
487# completions are located in the completions subdirectory.
488## -----------------------------------------------------------------------------
489
490#
491# Set default field separators
492#
493
494set -g IFS \n\ \t
495
496#
497# Set default search paths for completions and shellscript functions
498# unless they already exist
499#
500
501set -l configdir ~/.config
502
503if set -q XDG_CONFIG_HOME
504  set configdir $XDG_CONFIG_HOME
505end
506
507# __fish_datadir, __fish_sysconfdir, __fish_help_dir, __fish_bin_dir
508# are expected to have been set up by read_init from fish.cpp
509
510# Set up function and completion paths. Make sure that the fish
511# default functions/completions are included in the respective path.
512
513if not set -q fish_function_path
514  set fish_function_path $configdir/fish/functions    $__fish_sysconfdir/functions    $__fish_datadir/functions
515end
516
517if not contains $__fish_datadir/functions $fish_function_path
518  set fish_function_path[-1] $__fish_datadir/functions
519end
520
521if not set -q fish_complete_path
522  set fish_complete_path $configdir/fish/completions  $__fish_sysconfdir/completions  $__fish_datadir/completions
523end
524
525if not contains $__fish_datadir/completions $fish_complete_path
526  set fish_complete_path[-1] $__fish_datadir/completions
527end
528
529#
530# This is a Solaris-specific test to modify the PATH so that
531# Posix-conformant tools are used by default. It is separate from the
532# other PATH code because this directory needs to be prepended, not
533# appended, since it contains POSIX-compliant replacements for various
534# system utilities.
535#
536
537if test -d /usr/xpg4/bin
538  if not contains /usr/xpg4/bin $PATH
539    set PATH /usr/xpg4/bin $PATH
540  end
541end
542
543#
544# Add a few common directories to path, if they exists. Note that pure
545# console programs like makedep sometimes live in /usr/X11R6/bin, so we
546# want this even for text-only terminals.
547#
548
549set -l path_list /bin /usr/bin /usr/X11R6/bin /usr/local/bin $__fish_bin_dir
550
551# Root should also have the sbin directories in the path
552switch $USER
553  case root
554  set path_list $path_list /sbin /usr/sbin /usr/local/sbin
555end
556
557for i in $path_list
558  if not contains $i $PATH
559    if test -d $i
560      set PATH $PATH $i
561    end
562  end
563end
564
565#
566# Launch debugger on SIGTRAP
567#
568function fish_sigtrap_handler --on-signal TRAP --no-scope-shadowing --description "Signal handler for the TRAP signal. Lanches a debug prompt."
569  breakpoint
570end
571
572#
573# Whenever a prompt is displayed, make sure that interactive
574# mode-specific initializations have been performed.
575# This handler removes itself after it is first called.
576#
577function __fish_on_interactive --on-event fish_prompt
578  __fish_config_interactive
579  functions -e __fish_on_interactive
580end
581