One of the aspects I personally find most compelling about fish shell is its scripting ease. Unlike traditional shells, fish’s scripting language is straightforward, clean, and comes with features that encourage writing and maintaining scripts effortlessly. From its intelligent autosuggestions to the robust error handling, fish shell stands out as a powerful tool in the developer’s toolkit.
With the integration of the Oh My Fish (OMF) framework, users can further extend the shell’s functionality. OMF offers a package management system, allowing users to install new packages, themes, and utilities, thus customizing their shell environment to their liking.
In this post, we will delve into the process of creating and sharing fish packages using Oh My Fish, exploring how this powerful combination can elevate your command-line experience to new heights.
Setting Up Oh My Fish (OMF)
Before we dive into the creation and sharing of packages, it’s essential to have Oh-My-Fish (omf) installed in your fish environment. omf
is a package manager for the Fish shell, offering an extensive ecosystem of themes, packages, and a framework for advanced customization. Follow the installation guide here.
After installation, you can verify that omf
is correctly installed by running:
omf --version
Next step, check your existing repositories:
omf repositories
it should output something like https://github.com/oh-my-fish/packages-main master
Also, check the packages installed - if it’s a fresh installation you won’t have much 😊
omf list
Last but not least, check where all the omf
configuration lives, the environment variable OMF_CONFIG
will point to
the configured directory.
env | grep OMF_CONFIG
Creating a Fish Package
In the world of omf
, what we generally refer to as a package is known as a plugin. These plugins are essentially extensions or add-ons that enhance the functionality of the Fish shell, ranging from simple utility functions to complex integrations with external tools.
Understanding the OMF Directory Structure
Before we move into the practical steps to create a plugin, it’s essential to understand the directory structure that it uses. This knowledge will help you manage and navigate your fish shell environment more effectively. Let’s clarify the roles of two key directories: OMF_CONFIG
and ~/.local/share/omf
.
1. The OMF_CONFIG
Directory
Location and Purpose: Typically found at
~/.config/omf
, this directory is the heart of your user-specific Oh My Fish configuration. It’s where your personalized settings, such as custom themes or packages, reside.User Customization and Flexibility: This is your playground for customization. Whether you’re adding unique plugins or tweaking themes, your changes are encapsulated here, keeping your individual setup neatly organized.
Portability and Backup: Given its nature, the
OMF_CONFIG
directory is perfect for backing up or transferring. Copying this directory allows you to replicate your Oh My Fish setup on another machine seamlessly.
2. The ~/.local/share/omf
Directory
Core Installation: This directory houses the core of your Oh My Fish installation. It includes the package manager and the default sets of packages and themes provided by OMF.
Package Storage: Beyond the package manager, this directory stores the installed packages and themes. Unless overridden by user-specific configurations in
OMF_CONFIG
, the content here forms the base of your Oh My Fish environment.Separation of Concerns: This directory ensures a clear distinction between the OMF base installation (shared and consistent across users) and user-specific configurations (personalized and varied). Such separation is key for a clean and stable setup.
Understanding OMF Plugins
Now that we’ve familiarized ourselves with the foundational directory structure of OMF, it’s time to delve deeper into the anatomy of an OMF plugin.
- Plugin Directory: Each plugin resides in its own directory within the
~/.local/share/omf/pkg/
directory. - Plugin Files: A typical plugin may contain several files, but there are a few key ones:
init.fish
: The initialization script that’s run when the plugin is loaded.uninstall.fish
: (Optional) A script that’s run when the plugin is removed.functions/
: A directory containing Fish functions that the plugin provides.completions/
: A directory containing completion definitions for the commands provided by the plugin.
Steps to Create an OMF Plugin
The name of the directory should match your plugin’s name. The plugin we will build, as an example, is called env_loader
, that automatically loads environment variables from the .env
file when navigating to the directory.
- Creating the plugin:
omf new plugin env_loader
This should result on the following:
create completions/env_loader.fish
create functions/env_loader.fish
create init.fish
create LICENSE
create README.md
create uninstall.fish
The first thing I do is initialize a git repository from it, but you can also copy this folder and move it to your code directory, because we will create a repository for it and install it from the repository.
git init .
git commit -am "inital import"
- Write the
init.sh
script
# reacts to directory changes
function load_env --on-variable PWD
# Call the load_env function from load_env.fish
env_loader
end
# Trigger load_env on shell start
emit load_env
- Write the
env_loader
function on thefunctions/env_loader.fish
file:
function env_loader
set -l env_file "$PWD/.env"
if test -f $env_file
for line in (cat $env_file)
set -gx (string split "=" $line)[1] (string split "=" $line)[2]
end
end
end
Before distributing your plugin, it’s indeed a good practice to thoroughly test it. Sourcing init.fish
and the functions from functions/env_loader.fish
will help you ensure that everything is working as expected.
source init.fish
source functions/env_loader.fish
- Test it!
mkdir tmp; echo "FOO=BAR" > tmp/.env
Navigate into tmp/
and check the loaded environment variable:
cd tmp; env | grep FOO
Finally, commit the final version and make it available on github, for example https://github.com/username/env_loader
.
Sharing Your Package with the Community
Here are two primary ways to share your Fish shell, submitting to the official Oh My Fish registry or creating our own package repository. We will explore the latter.
Initialize a New Repository: Create a new Git repository on GitHub for example and called it
fish-packages
Organize Your Packages: Create a directory inside
fish-packages
calledpackages
. Inside thepackages
directory create a file calledenv_loader
with the following content:
type = plugin
repository = https://github.com/username/env_loader
description = Package provides a way to automatically load environment variables from .env
Should end up with file tree like this:
.
├── README.md
└── packages
└── env_loader
1 directory, 2 files
- Inform Your Users:
Update your
README.md
to include instructions on how users can add your repository as a custom repository to their Oh My Fish installation:
omf repository add <your_repository_url>
List the repositories, notice we have our own repository now:
https://github.com/oh-my-fish/packages-main master
https://github.com/username/fish-packages master
Finally, install the new plugin:
omf update; omf install env_loader
The installation will install the plugin on ~/.local/share/omf/pkg
and will be ready to use!
Conclusion
Dive in, start creating, and become an active participant in the ever-growing ecosystem of the Fish shell and Oh My Fish. Happy scripting!