🐟 Fish Functions
This page is automatically generated from the shell configuration files.
arch-find
function arch-find
set -l clone_dir "$HOME/aur"
mkdir -p "$clone_dir"; and cd "$clone_dir"; or return
set -l selection (
begin
pacman -Ssq $argv
auracle search -q $argv
end | sort -u | \
fzf --height 40% --reverse --border \
--prompt="Arch > " \
--preview 'pacman -Si {} 2>/dev/null || auracle info {} 2>/dev/null' \
--bind 'alt-p:change-preview(auracle show {} 2>/dev/null || echo -e "\n [!] PKGBUILD preview is only available for AUR packages via auracle.\n Official packages require fetching from the Arch Gitlab.")' \
--bind 'alt-i:change-preview(pacman -Si {} 2>/dev/null || auracle info {} 2>/dev/null)' \
--bind 'ctrl-space:toggle-preview'
)
if test -n "$selection"
if pacman -Si "$selection" >/dev/null 2>&1
echo ":: Official package detected: $selection"
# Directly install it to the system
sudo pacman -S "$selection"
set_color green; echo "[+] Official package installed."; set_color normal
else
echo ":: AUR package detected: $selection"
# Clone it so it retains the .git history
git clone "https://aur.archlinux.org/$selection.git"
# Only change directories and prompt for build if it's an AUR package
cd "$selection"; or return
echo ":: Entered "(pwd)
set_color green; echo "[+] Source ready. Run 'mkp' to build."; set_color normal
end
end
end
aur-find
# Search and Clone from AUR
function aur-find
cd "$HOME/aur"; or return
set -l selection (auracle search -q $argv | \
fzf --height 40% --reverse --border \
--prompt="AUR > " \
--preview 'auracle info {}' \
--bind 'alt-p:change-preview(auracle show {})' \
--bind 'alt-i:change-preview(auracle info {})' \
--bind 'ctrl-space:toggle-preview')
if test -n "$selection"
auracle clone "$selection"
cd "$selection"; or return
echo ":: Entered "(pwd)
set_color green; echo "[+] Source ready. Run 'mkp' to build."; set_color normal
end
end
aur-refresh
# Refresh all local AUR clones
function aur-refresh
for d in ~/aur/*/
if test -d "$d/.git"
echo "Refreshing "(basename $d)"..."
git -C $d reset --hard HEAD
git -C $d clean -dfx
end
end
end
build_package
# Intelligent Build/Install Decider
function build_package
set -l pkg $argv[1]
if pacman -Si "$pkg" >/dev/null 2>&1
set_color yellow; echo "[!] $pkg exists in the official repositories."; set_color normal
echo -n "Install via pacman instead? (Y/n): "
read -l choice
if not string match -qi "n" "$choice"
sudo pacman -S "$pkg" --needed
return
end
end
set_color blue; echo ":: Checking AUR for $pkg..."; set_color normal
if auracle info "$pkg" >/dev/null 2>&1
mkdir -p ~/aur; and cd ~/aur; or return
if test -d "$pkg"
echo ":: Directory exists, syncing..."
cd "$pkg"; and auracle sync
else
auracle clone "$pkg"; and cd "$pkg"
end
set_color green; echo "[+] Source ready. Run 'mkp' to build."; set_color normal
else
set_color red; echo "[!] Error: $pkg not found in official repos or AUR."; set_color normal
return 1
end
end
check_cookies
function check_cookies --wraps='sqlite3'
# Define the base profiles path
set -l profiles_dir $HOME/.local/share/qutebrowser/profiles
# Check if the directory exists and has subdirectories
if not test -d $profiles_dir
echo "Profiles directory not found: $profiles_dir"
return 1
end
# Loop through each profile directory found
for profile_path in $profiles_dir/*
if test -d $profile_path
# Extract just the profile name from the path
set -l profile_name (basename $profile_path)
set -l cookie_db "$profile_path/data/webengine/Cookies"
# Only attempt to read if the Cookie database actually exists for this profile
if test -f $cookie_db
echo "--- Profile: $profile_name ---"
sqlite3 $cookie_db "SELECT DISTINCT host_key FROM cookies;" | sed 's/^\.//' | sort -u
echo "" # Blank line for cleaner spacing
else
echo "--- Profile: $profile_name (No Cookie DB found) ---"
echo ""
end
end
end
end
cleanempty
function cleanempty --wraps='find . -type d -empty -delete' --description 'Delete empty directories except ~/Public'
set -l public_dir (realpath ~/Public)
find . -type d -empty -not -path "$public_dir" -delete $argv
end
fish_mode_prompt
function fish_mode_prompt --description 'Displays the current mode'
# To reuse the mode indicator use this function instead
fish_default_mode_prompt
end
fish_prompt
function fish_prompt --description 'Write out the prompt'
set -l last_status $status
set -l normal (set_color --reset)
set -l status_color (set_color brgreen)
set -l cwd_color (set_color $fish_color_cwd)
set -l vcs_color (set_color brpurple)
set -l prompt_status ""
# Since we display the prompt on a new line allow the directory names to be longer.
set -q fish_prompt_pwd_dir_length
or set -lx fish_prompt_pwd_dir_length 0
# Color the prompt differently when we're root
set -l suffix '❯'
if functions -q fish_is_root_user; and fish_is_root_user
if set -q fish_color_cwd_root
set cwd_color (set_color $fish_color_cwd_root)
end
set suffix '#'
end
# Color the prompt in red on error
if test $last_status -ne 0
set status_color (set_color $fish_color_error)
set prompt_status $status_color "[" $last_status "]" $normal
end
echo -s (prompt_login) ' ' $cwd_color (prompt_pwd) $vcs_color (fish_vcs_prompt) $normal ' ' $prompt_status
echo -n -s $status_color $suffix ' ' $normal
end
fish_user_key_bindings
function fish_user_key_bindings
bind \es 'prepend_commandline_history_with_sudo'
end
gc
function gc
git clone https://aur.archlinux.org/$argv.git
end
getflac
function getflac
cd ~/Music/Various\ Artists/Singles/
yt-dlp -x --audio-format flac -o "%(title)s.%(ext)s" $argv
end
getmp3
function getmp3
cd ~/Music/Various\ Artists/Singles/
yt-dlp -x --audio-format mp3 -o "%(title)s.%(ext)s" $argv
end
getogg
function getogg
cd ~/Music/Various\ Artists/Singles/
yt-dlp -x --audio-format vorbis -o "%(title)s.%(ext)s" $argv
end
get_series
function get_series
set -l ap_path (type -P atomicparsley)
if test -n "$ap_path"
cd ~/Downloads
get_iplayer --pid-recursive --atomicparsley $ap_path
else
set_color red; echo "Error: atomicparsley not found!"; set_color normal
end
end
ghostwriter
function ghostwriter --description 'Launch Ghostwriter with the sidebar rooted in the current directory and bypass breaking NVIDIA Vulkan layers'
set -l config_file "$HOME/.config/kde.org/ghostwriter.conf"
# Update the sidebar root folder to the current working directory
if test -f $config_file
sed -i "s|^folderPath=.*|folderPath=$PWD|" $config_file
end
# Run the application with your existing NVIDIA Vulkan workaround
env VK_DRIVER_FILES="" /usr/bin/ghostwriter $argv
end
ld
# Dynamic date filter function replacing the broken 'ld' alias
function ld
ls -altrh --time-style=+%D | grep (date +%D)
end
menu_refresh
function menu_refresh --wraps='update-desktop-database ~/.local/share/applications/' --description 'alias menu_refresh=update-desktop-database ~/.local/share/applications/'
update-desktop-database ~/.local/share/applications/ $argv
end
mkp
# Build and Archive (Secure Chroot Version)
function mkp
# 1. Print recent Git commit history right on the terminal screen
if test -d .git
echo -e "\nRecent package changes:"
git log -n 3 --oneline --graph
echo "------------------------------------------"
end
# 2. Locate the PKGBUILD dynamically (handles nested repository structures)
set -l pkgbuild_path "PKGBUILD"
if not test -f "PKGBUILD"
set -l found (find . -maxdepth 2 -name PKGBUILD)
if test -n "$found[1]"
set pkgbuild_path "$found[1]"
cd (dirname "$pkgbuild_path")
set pkgbuild_path "PKGBUILD"
else
echo "==> ERROR: No PKGBUILD found in this repository structure!"
return 1
end
end
# 3. Collect files to audit in Kate tabs relative to the correct directory
set -l files_to_open "$pkgbuild_path"
if test -f ".SRCINFO"
set files_to_open $files_to_open ".SRCINFO"
end
for f in *.install
if test -f "$f"
set files_to_open $files_to_open "$f"
end
end
# Launch Kate and block the script until closed
kate $files_to_open --block
# 4. Ask if you want to proceed with the build (Default: Yes)
echo "------------------------------------------"
read -l -P "Do all files and history look safe? Proceed with build? (Y/n): " proceed
# If you explicitly type 'n' or 'N', abort. Otherwise, proceed.
if string match -qi "n" "$proceed"
echo "Aborting build."
return 1
end
echo "Proceeding with isolated container build..."
echo "------------------------------------------"
# 5. Build the package safely inside a clean chroot
extra-x86_64-build
if test $status -eq 0; and count *.pkg.tar.zst >/dev/null
# Automatically install the newly built isolated package onto your host machine
echo "Installing the compiled package..."
sudo pacman -U *.pkg.tar.zst
echo "------------------------------------------"
read -l -P "Move package to ~/aur/Packages? (y/N): " choice
if string match -qi "y" "$choice"
mkdir -p ~/aur/Packages
mv -v *.pkg.tar.zst ~/aur/Packages/
end
end
end
pksudo
function pksudo --description 'Run graphical commands as root under Wayland'
pkexec env WAYLAND_DISPLAY=$WAYLAND_DISPLAY XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR $argv
end
prepend_commandline_history_with_sudo
function prepend_commandline_history_with_sudo
# Get the current command line buffer
set -l cl (commandline)
# If it's not empty and doesn't already start with sudo, prepend it
if test -n "$cl"; and not string match -q "sudo *" "$cl"
commandline -r "sudo $cl"
end
end
restore_file
function restore_file
# Check if the current directory is a symlink, and get the real physical path
set -l real_pwd (pwd -P)
# Run the git checkout from the main branch using the true path
git -C $real_pwd checkout main -- $argv
end
sync_quickmarks
function sync_quickmarks --description 'Sync web edits safely, qutebrowser bookmarks, and rebuild startpage'
set -l b_file /home/simon/.local/share/qutebrowser/profiles/main/config/bookmarks/urls
set -l q_file /home/simon/.local/share/qutebrowser/profiles/main/config/quickmarks
# Web space paths
set -l q_web_copy /home/simon/public_html/quickmarks.txt
set -l script_path /home/simon/bin/parse_quickmarks.py
set -l php_output /home/simon/public_html/bookmarks.php
# 1. CHECK FOR LOCAL CHANGES BEFORE OVERWRITING:
if test -s $b_file
echo "New standard bookmarks detected. Preserving master quickmarks."
else if test -s $q_web_copy; and test $q_web_copy -nt $q_file
# FIX: Only apply web changes if the web file is actually newer than your local file
echo "Web edits detected. Applying web layout changes cleanly."
cp $q_web_copy $q_file
else
echo "Local quickmarks are up-to-date or newer than web copy. Preserving local modifications."
end
# 2. PROCESS NEW BOOKMARKS: If you added anything new via qutebrowser :bookmark-add
if test -s $b_file
set -l awk_script '
NR == FNR {
match($0, /https?:\/\/[^ ]+$/)
if (RSTART > 0) {
url = substr($0, RSTART, RLENGTH)
seen[url] = 1
}
next
}
{
url = $1
$1 = ""
full_line = substr($0, 2)
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", url)
gsub(/^[ \t\r\n]+|[ \t\r\n]+$/, "", full_line)
if (!seen[url]) {
if (full_line ~ /^[A-Za-z0-9_ \/]+ \| /) {
print full_line " " url
} else {
print "Unsorted | " full_line " " url
}
seen[url] = 1
}
}
'
awk $awk_script $q_file $b_file 2>/dev/null >> $q_file
echo "Sync complete! New standard browser bookmarks merged."
echo -n "" > $b_file
end
# 3. MIRROR MASTER BACK TO WEB SPACE
cp $q_file $q_web_copy
chmod 666 $q_web_copy
# 4. REBUILD STARTPAGE
if test -f $script_path
python3 $script_path $q_web_copy > $php_output
echo "Startpage successfully rebuilt at $php_output!"
else
echo "Warning: parse_quickmarks.py not found at $script_path."
end
end
update_bookmarks
function update_bookmarks --description 'Interactive workflow to import, edit via web UI, and rebuild bookmarks.php'
# Define primary application paths
set -l sync_cmd sync_quickmarks
set -l editor_url "http://localhost/~simon/edit_quickmarks.php"
set -l q_file /home/simon/.local/share/qutebrowser/profiles/main/config/quickmarks
set -l q_web_copy /home/simon/public_html/quickmarks.txt
set -l script_path /home/simon/bin/parse_quickmarks.py
set -l php_output /home/simon/public_html/bookmarks.php
echo (set_color yellow)"====== Step 1: Importing Fresh Bookmarks & Quickmarks ======"(set_color normal)
if not eval $sync_cmd
echo (set_color red)"Error: sync_quickmarks execution failed. Aborting pipeline."(set_color normal)
return 1
end
echo \n(set_color yellow)"====== Step 2: Opening Interactive Web UI Editor ======"(set_color normal)
echo "Launching editor environment in a new qutebrowser tab..."
qutebrowser --qt-flag disable-gpu --qt-flag disable-vulkan --qt-flag disable-software-rasterizer --basedir /home/simon/.local/share/qutebrowser/profiles/main "$editor_url" 2>/dev/null &
echo \n(set_color cyan)"[ACTION REQUIRED]"(set_color normal) "Go to qutebrowser, reorganize items/categories, and hit 'Save Changes'."
echo "Once your updates are successfully written via the webpage, return here to this terminal pane."
read -P "Press [ENTER] here in the terminal ONLY after saving your changes online... " confirm
echo \n(set_color yellow)"====== Step 3: Processing Data & Compiling Production Output ======"(set_color normal)
if test -s $q_web_copy
echo "Compiling final optimized layout via python script..."
python3 $script_path $q_web_copy > $php_output
if test $status -eq 0
# CRITICAL FIX: Explicitly commit changes back from web disk down to main configuration profiles
cp $q_web_copy $q_file
echo (set_color green)"\nSuccess! All categories and links alphabetized. Production startpage rebuilt at: $php_output"(set_color normal)
else
echo (set_color red)"Error: The Python compilation step failed."(set_color normal)
end
else
echo (set_color red)"Error: Working dataset ($q_web_copy) is missing or empty. Cannot compile."(set_color normal)
end
end
validate
function validate
if test -f ~/.config/fish/config.fish
fish --no-execute ~/.config/fish/config.fish
if test $status -eq 0
set_color green; echo "[✓] config.fish syntax looks great!"; set_color normal
end
else
set_color red; echo "[!] Could not locate config.fish"; set_color normal
end
end
wikigen
function wikigen
set -l DOCS_DIR "$HOME/Documents/Git/arch-docs"
set -l TARGET_FILE "$DOCS_DIR/docs/index.md"
set -l HEADER "$DOCS_DIR/header.md"
set -l FOOTER "$DOCS_DIR/footer.md"
if not test -f $HEADER; or not test -f $FOOTER
echo "Error: Base templates (header.md or footer.md) missing from $DOCS_DIR"
return 1
end
echo "Gathering the 5 most recent updates by creation date..."
set -l recent_items
# 1. Use find + stat to grab the Birth Epoch (%W), a custom delimiter (|||), and the filepath (%n)
# 2. Sort numerically in reverse and pull the top 5
set -l lines (find "$DOCS_DIR/docs/" -type f -name "*.md" -not -name "index.md" -exec stat --format="%W|||%n" {} + | sort -nr | head -n 10)
for line in $lines
# Split the string safely by our custom delimiter
set -l parts (string split "|||" $line)
set -l birth_epoch $parts[1]
set -l file $parts[2]
# Explicit fallback if birth time isn't stored properly (0 or -)
if test -z "$birth_epoch"; or test "$birth_epoch" = "0"; or test "$birth_epoch" = "-"
set birth_epoch (stat --format="%Y" "$file")
end
# Convert the Birth Epoch cleanly to YYYY-MM-DD
set -l show_date (date -d "@$birth_epoch" +%Y-%m-%d)
set -l title (string replace -r '^#\s+' '' (grep -m 1 '^# ' "$file"))
if test -z "$title"
set title (string replace -r '[-_]' ' ' (basename "$file" .md))
end
set -l rel_path (string replace "$DOCS_DIR/docs/" "" "$file")
set recent_items $recent_items "* **$show_date**: [$title]($rel_path)"
end
# --- THE COMPILATION PIPELINE ---
cat $HEADER > $TARGET_FILE
echo "" >> $TARGET_FILE
echo "### :material-note-text-outline: Recent Posts/Updates" >> $TARGET_FILE
if test (count $recent_items) -eq 0
echo "* No content found." >> $TARGET_FILE
else
for item in $recent_items
echo $item >> $TARGET_FILE
end
end
echo "" >> $TARGET_FILE
cat $FOOTER >> $TARGET_FILE
echo "[*] Homepage freshly assembled with the 5 latest updates."
end
wikisync
function wikisync
set -l DOCS_DIR "$HOME/Documents/Git/arch-docs"
set -l TARGET_FILE "$DOCS_DIR/docs/index.md"
# --- AUTOMATIC CODE DOCS GENERATION ---
# Stripped the .sh suffix if you updated your PKGBUILD, or kept standard path
if test -x ~/bin/generate_functions_md
echo "Updating code documentation for Fish functions..."
~/bin/generate_functions_md
else if test -x ~/bin/generate_functions_md.sh
echo "Updating code documentation for Fish functions..."
~/bin/generate_functions_md.sh
else
echo "[!] Warning: Functions doc generator script not found or not executable."
end
# 1. Compile the homepage from our safe external files
if not wikigen
echo "[!] Compilation failed. Aborting sync."
return 1
end
# 2. Generate full date variables natively for the timestamp footer
set -l DAY (date +"%-d")
set -l MONTH_YEAR (date +"%B %Y")
switch $DAY
case 1 21 31
set SUFFIX "st"
case 2 22
set SUFFIX "nd"
case 3 23
set SUFFIX "rd"
case '*'
set SUFFIX "th"
end
set -l NEW_DATE "$DAY$SUFFIX $MONTH_YEAR"
# 3. Update ONLY the date timestamp line at the bottom of the freshly generated index.md
if test -f $TARGET_FILE
sed -i "s/\*Last updated:.*\*/\*Last updated: $NEW_DATE\*/" $TARGET_FILE
echo "Updated date to $NEW_DATE in index.md"
end
# 4. Automatically compress PNG assets
if test -d "$DOCS_DIR/docs/assets"
if command -v optipng >/dev/null
echo "Optimizing PNG assets..."
find "$DOCS_DIR/docs/assets/" -name "*.png" -exec optipng -o2 -quiet {} +
end
end
# 5. Complete build and deploy steps for Codeberg Pages
echo "Building and deploying wiki updates to Codeberg..."
cd $DOCS_DIR
# Compile the site static assets locally
if mkdocs build
# Deploy statically built assets to Codeberg's 'pages' branch instead of GitHub's 'gh-pages'
mkdocs gh-deploy --remote-branch pages
else
echo "[!] MkDocs build failed. Deployment aborted."
return 1
end
end
yt
function yt
set url $argv[1]
cd ~/Downloads
# Check if this is an algorithmic YouTube Mix (list starts with RD)
if string match -q "*list=RD*" $url
# Strip out the list and index parameters so yt-dlp only sees the single video
set url (string replace -r '&list=RD[^&]*' '' $url)
set url (string replace -r '&index=[0-9]*' '' $url)
notify-send "yt-dlp" "YouTube Mix detected! Defusing playlist, downloading single video." -i dialog-warning -t 4000
else
notify-send "yt-dlp" "Downloading playlist/video..." -i video-x-generic -t 3000
end
# Run the download
if yt-dlp -f 'bestvideo+bestaudio' --merge-output-format mp4 $url
notify-send "yt-dlp" "Download completed successfully!" -i dialog-information -t 3000
else
notify-send "yt-dlp" "Download failed." -i dialog-error -t 4000
end
end