keeping config.fish clean

Posted on:October 20, 2023

Here are some rules/recommendations, tips & ticks for creating a more digustable and maintainable config.fish file.

Table of contents

Open Table of contents

Intro

As a long term user of the fish-shell, I’ve recently started trying to keep my config.fish file more maintainable. Your fish/config.fish, fish/{functions,completions}/*.fish files are autoloaded when the shell is started up. An important thing to consider is that functions included in the config.fish file are treated the exact same as files in the functions directory. What I have recently started doing to create a more modular config.fish, is exporting funciton calls into the functions directory.

Normal config.fish

Here is an example of a valid config.fish:

# global variables
set -gx EDITOR 'nvim'
set -gx VISUAL 'nvim'
set -gx CWD $HOME
# ...

# abbr
abbr -a -g gw 'git worktree'
abbr -a -g gwa 'git worktree add'
abbr -a -g ga 'git add .'
abbr -a -g gc 'git commit '
# ...

# aliases
alias vim='nvim'
alias vi='nvim'
# ...


# theming
set -gx fish_pager_color_prefix '#815bf5' --bold
set -gx fish_pager_color_completion '#685abc'
set -gx fish_pager_color_secondary_prefix '#685abc'
set -gx fish_pager_color_secondary_completion '#685abc'
set -gx fish_pager_color_secondary_descrition '#685abc'
set -gx fish_pager_color_selected_prefix white
set -gx fish_pager_color_selected_completion white
set -gx fish_pager_color_selected_description white
# ...

# keybinds
function fish_user_keybinds
    bind \cr 'ranger; commandline -f repaint'
    bind -k nul 'complete'
    # ...
end

# variable handlers
function _save_dir --on-variable PWD
    status --is-command-substitution;and return
    set -gx CWD $PWD
end

Cleaner layout for config.fish

As I’ve become more comfortable with the fish-shell, I’ve found it much more maintainable to move these blocks into the functions the directory, and just call them in config.fish. Especially while using the fish-lsp, I can now individually test syntax errors/behavior of blocks, without running into huge errors when a new shell is spawned.

# variables
set_global_vars

# abbr
set_global_abbr

# aliases
set_global_aliases

# theming
set_global_theme

# ---------
# functions

# keybinds
fish_user_keybinds

# variable handlers
_save_dir

In the above example, each respective block is moved into a function inside my ~/.config/fish/functions/ directory. Then, the function is called in my config.fish, significantly shortening my overall config’s length.

While I personally don’t do this everywhere inside my config, I think this approach is much more readable than having huge blocks of similiarly grouped commands. The fish-lsp allows for hovering function definitions, and jumping to definitions.

In my own experience, calling functions inside my config has pushed my understanding of the fish-shell to a much more confident level. It has made testing out features I want to add to my enviornment much easier, and I highly recommened designing your config in the manor I described if you are using it across various machines.

More advanced usage

Fish shell provides the variable $fish_function_path, which provides a list of paths to search for functions in. If you want to seperate the functions autoloaded in your config, from scripts you use normally, you can append directories to this list variable.

Alternatively, you could also make the functions in your config private. In fish-shell the naming convention of functions that begin with leading underscores is typically how this is achieved. Although, it is important to mention these functions are not actual private, and behave the same as normal functions (i.e. you can still call _my_private_function from the commandline).

Summary

Move your functions and groupings in your config.fish to an autoloaded directory in the $fish_function_path list.