Skip to content

🐟 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
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