mirror of
https://github.com/prdlk/dotfiles.git
synced 2026-11-03 03:37:36 +00:00
config(fish): add fish completions for cli tools
This commit is contained in:
1 parent
b1fb6ee6fb
commit
7db95c2076
48 files changed
+2241
No files matched your search
@@ -0,0 +1,20 @@
|
||||
function _nvm_index_update
|
||||
test ! -d $nvm_data && command mkdir -p $nvm_data
|
||||
|
||||
set --local index $nvm_data/.index
|
||||
|
||||
if not command curl -q --location --silent $nvm_mirror/index.tab >$index.temp
|
||||
command rm -f $index.temp
|
||||
echo "nvm: Can't update index, host unavailable: \"$nvm_mirror\"" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
command awk -v OFS=\t '
|
||||
/v0.9.12/ { exit } # Unsupported
|
||||
NR > 1 {
|
||||
print $1 (NR == 2 ? " latest" : $10 != "-" ? " lts/" tolower($10) : "")
|
||||
}
|
||||
' $index.temp >$index
|
||||
|
||||
command rm -f $index.temp
|
||||
end
|
||||
@@ -0,0 +1,14 @@
|
||||
function _nvm_list
|
||||
set --local versions $nvm_data/*
|
||||
|
||||
set --query versions[1] &&
|
||||
string match --entire --regex -- (
|
||||
string replace --all -- $nvm_data/ "" $versions |
|
||||
string match --regex -- "v\d.+" |
|
||||
string escape --style=regex |
|
||||
string join "|"
|
||||
) <$nvm_data/.index
|
||||
|
||||
command --all node |
|
||||
string match --quiet --invert --regex -- "^$nvm_data" && echo system
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
function _nvm_version_activate --argument-names ver
|
||||
set --global --export nvm_current_version $ver
|
||||
set --prepend PATH $nvm_data/$ver/bin
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
function _nvm_version_deactivate --argument-names ver
|
||||
test "$nvm_current_version" = "$ver" && set --erase nvm_current_version
|
||||
set --local index (contains --index -- $nvm_data/$ver/bin $PATH) &&
|
||||
set --erase PATH[$index]
|
||||
end
|
||||
@@ -0,0 +1,13 @@
|
||||
function ai --description 'Choose and launch an AI CLI via gum'
|
||||
set -l choice (gum choose --header 'AI CLI' claude opencode codex hermes fractal)
|
||||
test -n "$choice"; or return # cancelled (Esc / Ctrl-C) → bail out
|
||||
|
||||
switch $choice
|
||||
case claude
|
||||
claude --dangerously-skip-permissions
|
||||
case '*'
|
||||
# labels match the binary names, so just run it
|
||||
# add a dedicated `case` here if another tool needs flags
|
||||
$choice
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
function c
|
||||
if test -z "$argv[1]"
|
||||
clear
|
||||
else
|
||||
cd $argv[1]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
function c2p --description "Code2Prompt with fuzzy-search template"
|
||||
fd --type f --extension hbs . $HOME/.config/code2prompt | fzf | xargs code2prompt --template
|
||||
end
|
||||
@@ -0,0 +1,20 @@
|
||||
function cd --description 'cd with zoxide fallback, else builtin cd'
|
||||
if test (count $argv) -eq 0
|
||||
builtin cd $HOME
|
||||
else if test "$argv[1]" = '-'
|
||||
builtin cd -
|
||||
else if builtin cd $argv[1] 2>/dev/null
|
||||
# exact path resolved, nothing else to do
|
||||
else if type -q zoxide
|
||||
set -l target (zoxide query -- $argv[1] 2>/dev/null)
|
||||
if test -n "$target"
|
||||
builtin cd $target
|
||||
else
|
||||
builtin cd $argv[1] # let builtin cd surface the real error
|
||||
end
|
||||
else
|
||||
builtin cd $argv[1]
|
||||
end
|
||||
|
||||
type -q zoxide; and zoxide add $PWD
|
||||
end
|
||||
@@ -0,0 +1,11 @@
|
||||
function clear --wraps clear --description 'clear screen + kitty scrollback, prompt pinned to the bottom'
|
||||
if not status is-interactive
|
||||
command clear $argv
|
||||
return
|
||||
end
|
||||
# kitty doesn't clear scrollback with plain `clear`; 3J drops it.
|
||||
printf '\033[2J\033[3J\033[1;1H'
|
||||
# Re-pin only when the bottom prompt is enabled (FISH_BOTTOM_PROMPT=0
|
||||
# keeps the default top prompt).
|
||||
test "$FISH_BOTTOM_PROMPT" = 1; and tput cup $LINES 0
|
||||
end
|
||||
@@ -0,0 +1,4 @@
|
||||
function clip-last --description 'Re-run last command, copy output to clipboard'
|
||||
eval $history[1] | wl-copy
|
||||
notify-send -a fish "Clipboard" "Command output copied to clipboard"
|
||||
end
|
||||
@@ -0,0 +1,43 @@
|
||||
function cp-appid --description "Fuzzy-pick a desktop app ID and copy to clipboard"
|
||||
set -l search_dirs \
|
||||
/usr/share/applications \
|
||||
/usr/local/share/applications \
|
||||
$HOME/.local/share/applications \
|
||||
/var/lib/flatpak/exports/share/applications \
|
||||
$HOME/.local/share/flatpak/exports/share/applications \
|
||||
/var/lib/snapd/desktop/applications
|
||||
|
||||
set -l existing_dirs
|
||||
for d in $search_dirs
|
||||
test -d $d; and set -a existing_dirs $d
|
||||
end
|
||||
|
||||
test (count $existing_dirs) -eq 0
|
||||
and echo "No application directories found." >&2
|
||||
and return 1
|
||||
|
||||
set -l chosen (
|
||||
fd --type f --extension desktop . $existing_dirs \
|
||||
| while read -l f
|
||||
set -l app_id (basename $f .desktop)
|
||||
set -l name (rg -m1 '^Name=' $f | string replace 'Name=' '')
|
||||
test -z "$name"; and set name $app_id
|
||||
echo "$name\t$app_id"
|
||||
end \
|
||||
| sort -u -t\t -k1 \
|
||||
| fzf \
|
||||
--delimiter='\t' \
|
||||
--with-nth=1,2 \
|
||||
--prompt="App ID › " \
|
||||
--height=50% \
|
||||
--layout=reverse \
|
||||
--border=rounded \
|
||||
--info=inline
|
||||
)
|
||||
|
||||
test -z "$chosen"; and return 0
|
||||
|
||||
set -l app_id (string split '\t' $chosen)[2]
|
||||
echo -n $app_id | wl-copy
|
||||
echo "Copied: $app_id"
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
function extract_agents -d "Copy all AGENTS.md files to a target directory while preserving structure"
|
||||
set -l out_dir $argv[1]
|
||||
|
||||
# Validate input
|
||||
if test -z "$out_dir"
|
||||
echo "Error: Output directory required."
|
||||
echo "Usage: extract_agents <absolute_or_relative_output_path>"
|
||||
return 1
|
||||
end
|
||||
|
||||
# Ensure output directory exists
|
||||
mkdir -p $out_dir
|
||||
|
||||
# Find and copy preserving relative paths
|
||||
fd -t f -g "AGENTS.md" -x cp --parents "{}" $out_dir
|
||||
|
||||
echo "Extraction complete. Check $out_dir."
|
||||
end
|
||||
@@ -0,0 +1,40 @@
|
||||
function fab -d "Fuzzy find and execute a Fabric pattern"
|
||||
set -l json_file ~/.config/fabric/pattern_explainations.json
|
||||
|
||||
if not test -f $json_file
|
||||
set_color red; echo "Error: $json_file not found."; set_color normal
|
||||
return 1
|
||||
end
|
||||
|
||||
# 1. Safely capture piped input (if any) to a temp file
|
||||
# This preserves all formatting, newlines, and avoids variable escaping issues
|
||||
set -l temp_input (mktemp)
|
||||
if not isatty stdin
|
||||
cat > $temp_input
|
||||
end
|
||||
|
||||
# 2. Parse JSON to TSV -> fzf (Name in list, Description in preview) -> Extract Name
|
||||
set -l selection (jq -r '.[] | "\(.name)\t\(.description)"' $json_file | \
|
||||
fzf --delimiter '\t' \
|
||||
--with-nth 1 \
|
||||
--preview 'echo {2}' \
|
||||
--preview-window 'right:60%:wrap' \
|
||||
--prompt 'Pattern > ' \
|
||||
--info inline \
|
||||
--bind 'ctrl-/:toggle-preview')
|
||||
|
||||
# 3. Execute with or without the piped data
|
||||
if test -n "$selection"
|
||||
set -l pattern (string split -f 1 \t "$selection")
|
||||
|
||||
# If our temp file has data (-s), pipe it. Otherwise, run bare.
|
||||
if test -s $temp_input
|
||||
cat $temp_input | fabric --pattern "$pattern"
|
||||
else
|
||||
fabric --pattern "$pattern"
|
||||
end
|
||||
end
|
||||
|
||||
# 4. Clean up
|
||||
rm -f $temp_input
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
function fish_title
|
||||
# Show a short hostname over SSH, otherwise just the current directory.
|
||||
if set -q SSH_TTY
|
||||
echo (prompt_hostname | string sub -l 10):(prompt_pwd)
|
||||
else
|
||||
prompt_pwd
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,24 @@
|
||||
function fish_user_key_bindings
|
||||
# Keys owned by kitty.conf never reach fish and are NOT bound here:
|
||||
# ctrl-g → lazygit overlay, ctrl-a → omp hsplit, ctrl-y → yazi vsplit,
|
||||
# ctrl-h/j/k/l → vim-aware split nav (pass_keys.py).
|
||||
bind ctrl-e nvim repaint
|
||||
bind ctrl-b purple repaint
|
||||
bind ctrl-y clip-last
|
||||
|
||||
bind ctrl-o 'gho; commandline -f repaint'
|
||||
bind ctrl-p 'pj; commandline -f repaint'
|
||||
bind ctrl-a 'omp; commandline -f repaint'
|
||||
# bind \ca 'launch_omp_livediff_overlay; commandline -f repaint'
|
||||
|
||||
# ctrl-f: pick file(s) with television and open in nvim.
|
||||
bind ctrl-f 'yy; commandline -f repaint'
|
||||
bind ctrl-g 'lazygit; commandline -f repaint'
|
||||
|
||||
# ctrl-c routes through the clear wrapper (kitty scrollback + prompt
|
||||
# pinned to the bottom) AND wipes any text typed on the command line.
|
||||
bind ctrl-c 'commandline -r ""; clear; commandline -f repaint'
|
||||
|
||||
# ctrl-q mirrors ctrl-d's preset (`exit`) — quit the shell.
|
||||
bind ctrl-q exit
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
function gdc --description "Discard all git changes with gum confirmation"
|
||||
if gum confirm "Discard all uncommitted changes? This is irreversible."
|
||||
git reset --hard HEAD
|
||||
git clean -fd
|
||||
echo "Changes wiped."
|
||||
else
|
||||
echo "Operation aborted."
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,18 @@
|
||||
function ghg -a repo
|
||||
# ghq natively understands https://, ssh://, git@host:…, and host/user/repo
|
||||
ghq get $repo; or return
|
||||
|
||||
# Reduce the input to ghq's on-disk shape: <host>/<user>/<repo>
|
||||
set -l rel (string replace -r '^\w+://' '' -- $repo) # strip scheme (https://, ssh://, git://)
|
||||
set rel (string replace -r '^[^@/]+@' '' -- $rel) # strip user@ (git@github.com:…)
|
||||
set rel (string replace ':' '/' -- $rel) # scp host:path → host/path
|
||||
set rel (string replace -r '\.git$' '' -- $rel) # strip trailing .git
|
||||
|
||||
# bare "user/repo" with no host → default to github.com
|
||||
string match -q '*.*/*' -- $rel; or set rel github.com/$rel
|
||||
|
||||
set -l dir (ghq root)/$rel
|
||||
cd $dir; or return
|
||||
zoxide add $dir
|
||||
clear; and onefetch
|
||||
end
|
||||
@@ -0,0 +1,29 @@
|
||||
function ghn -a repo
|
||||
if test -z "$repo"
|
||||
echo "usage: ghn <repo-name>" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l host (gum choose "prad.codes" "github.com")
|
||||
or return 1
|
||||
|
||||
if test "$host" = prad.codes
|
||||
set -l owner (tea organizations list -o simple | string trim | gum choose)
|
||||
or return 1
|
||||
|
||||
tea repos create --name $repo --owner $owner --private
|
||||
or return 1
|
||||
|
||||
ghq get https://prad.codes/$owner/$repo
|
||||
and cd (ghq root)/prad.codes/$owner/$repo
|
||||
else
|
||||
set -l owner (gum choose "prdlk" "wltbs")
|
||||
or return 1
|
||||
|
||||
gh repo create $owner/$repo --private
|
||||
or return 1
|
||||
|
||||
ghq get github.com/$owner/$repo
|
||||
and cd (ghq root)/github.com/$owner/$repo
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,23 @@
|
||||
function gho
|
||||
set -l vaults ~/Documents/Obsidian/Personal ~/Documents/Obsidian/Walletbase ~/Documents/Obsidian/Research
|
||||
|
||||
set -l selection (ghq list | fzf --prompt="repo: " --tiebreak=end \
|
||||
--bind "tab:transform:if test \"\$FZF_PROMPT\" = 'repo: '
|
||||
echo 'change-prompt(vault: )+reload(printf %s\n $vaults)'
|
||||
else
|
||||
echo 'change-prompt(repo: )+reload(ghq list)'
|
||||
end")
|
||||
or return
|
||||
|
||||
# Vault entries are absolute paths; ghq entries are host/user/repo
|
||||
if string match -q '/*' -- $selection
|
||||
cd $selection
|
||||
else
|
||||
cd (ghq root)/$selection
|
||||
end
|
||||
|
||||
clear
|
||||
if test -d .git
|
||||
onefetch
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,22 @@
|
||||
function git-summary --description "Aggregate all AGENTS.md files in the current git repo via code2prompt"
|
||||
# Resolve the repo root so it works from any subdirectory
|
||||
set -l repo_root (git rev-parse --show-toplevel 2>/dev/null)
|
||||
if test -z "$repo_root"
|
||||
echo "git-summary: not inside a git repository" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
set -l template ~/.config/code2prompt/agents-md.hbs
|
||||
if not test -f $template
|
||||
echo "git-summary: template not found at $template" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
# Pass through any extra flags (e.g. --output-file, --tokens)
|
||||
code2prompt $repo_root \
|
||||
--include "AGENTS.md" \
|
||||
--include "**/AGENTS.md" \
|
||||
--template $template \
|
||||
$argv
|
||||
end
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
function launch_omp_livediff_overlay --description "Overlay omp on the current kitty window with a livediff split beside it"
|
||||
# kitty appends -PID to config-file listen_on sockets, so a hardcoded
|
||||
# --to unix:@kitty-local never matches. kitty @ resolves the real
|
||||
# address from $KITTY_LISTEN_ON on its own.
|
||||
if not set -q KITTY_LISTEN_ON
|
||||
echo "launch_omp_livediff_overlay: no kitty remote-control socket (KITTY_LISTEN_ON unset)" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
# omp overlays the current window; capture its window id
|
||||
set -l wid (kitty @ launch --type=overlay-main --cwd=current omp)
|
||||
or return
|
||||
|
||||
# livediff side by side in the same tab; keep focus on omp
|
||||
kitty @ launch --match id:$wid --location=vsplit --keep-focus --cwd=current livediff
|
||||
end
|
||||
@@ -0,0 +1,16 @@
|
||||
function lc-elir -d "fzf-pick LeetCode solution files and run /leetcode-eli5 on each via omp"
|
||||
set -l root (count $argv > /dev/null; and echo $argv[1]; or echo .)
|
||||
# Match only numbered problem files: 1365.some-slug.js anywhere in the tree
|
||||
set -l files (fd --type f '^\d+\..+\.(js|ts)$' $root \
|
||||
| fzf --multi \
|
||||
--prompt='eli5> ' \
|
||||
--delimiter=/ \
|
||||
--with-nth=-3.. \
|
||||
--preview 'bat --color=always --line-range=:40 {}' \
|
||||
--preview-window=right:60%)
|
||||
test -z "$files"; and return 1
|
||||
for f in $files
|
||||
echo "── /leetcode-eli5 $f"
|
||||
omp -p "/leetcode-eli5 $f"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
function mdcp -a url
|
||||
if test -z "$url"
|
||||
echo "usage: mdcp <url>" >&2
|
||||
return 1
|
||||
end
|
||||
curl.md $url | wl-copy
|
||||
wl-paste | mdfried
|
||||
end
|
||||
@@ -0,0 +1,10 @@
|
||||
# ~/.config/fish/functions/mdv.fish
|
||||
function mdp -d "Interactive Markdown selector and previewer"
|
||||
# Find markdown files up to 3 directories deep
|
||||
set -l file (fd --type f --extension md --max-depth 3 | fzf --preview 'mdfried {}' --preview-window=right:60%:wrap)
|
||||
|
||||
# Execute mdfried on the selected file if one was chosen
|
||||
if test -n "$file"
|
||||
mdfried "$file"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,237 @@
|
||||
function nvm --description "Node version manager"
|
||||
for silent in --silent -s
|
||||
if set --local index (contains --index -- $silent $argv)
|
||||
set --erase argv[$index] && break
|
||||
end
|
||||
set --erase silent
|
||||
end
|
||||
|
||||
set --local cmd $argv[1]
|
||||
set --local ver $argv[2]
|
||||
|
||||
if set --query silent && ! set --query cmd[1]
|
||||
echo "nvm: Version number not specified (see nvm -h for usage)" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
if ! set --query ver[1] && contains -- "$cmd" install use
|
||||
for file in .nvmrc .node-version
|
||||
set file (_nvm_find_up $PWD $file) && read ver <$file && break
|
||||
end
|
||||
|
||||
if ! set --query ver[1]
|
||||
echo "nvm: Invalid version or missing \".nvmrc\" file" >&2
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
set --local their_version $ver
|
||||
|
||||
switch "$cmd"
|
||||
case -v --version
|
||||
echo "nvm, version 2.2.18"
|
||||
case "" -h --help
|
||||
echo "Usage: nvm install <version> Download and activate the specified Node version"
|
||||
echo " nvm install Install the version specified in the nearest .nvmrc file"
|
||||
echo " nvm use <version> Activate the specified Node version in the current shell"
|
||||
echo " nvm use Activate the version specified in the nearest .nvmrc file"
|
||||
echo " nvm list List installed Node versions"
|
||||
echo " nvm list-remote List available Node versions to install"
|
||||
echo " nvm list-remote <regex> List Node versions matching a given regex pattern"
|
||||
echo " nvm current Print the currently-active Node version"
|
||||
echo " nvm uninstall <version> Uninstall the specified Node version"
|
||||
echo "Options:"
|
||||
echo " -s, --silent Suppress standard output"
|
||||
echo " -v, --version Print the version of nvm"
|
||||
echo " -h, --help Print this help message"
|
||||
echo "Variables:"
|
||||
echo " nvm_arch Override architecture, e.g. x64-musl"
|
||||
echo " nvm_mirror Use a mirror for downloading Node binaries"
|
||||
echo " nvm_default_version Set the default version for new shells"
|
||||
echo " nvm_default_packages Install a list of packages every time a Node version is installed"
|
||||
echo " nvm_data Set a custom directory for storing nvm data"
|
||||
echo "Examples:"
|
||||
echo " nvm install latest Install the latest version of Node"
|
||||
echo " nvm use 14.15.1 Use Node version 14.15.1"
|
||||
echo " nvm use system Activate the system's Node version"
|
||||
|
||||
case install
|
||||
_nvm_index_update
|
||||
|
||||
string match --entire --regex -- (_nvm_version_match $ver) <$nvm_data/.index | read ver alias
|
||||
|
||||
if ! set --query ver[1]
|
||||
echo "nvm: Invalid version number or alias: \"$their_version\"" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
if test ! -e $nvm_data/$ver
|
||||
set --local os (command uname -s | string lower)
|
||||
set --local ext tar.gz
|
||||
set --local arch (command uname -m)
|
||||
set --local tarcmd tar
|
||||
|
||||
switch $os
|
||||
case aix
|
||||
set arch ppc64
|
||||
case sunos
|
||||
case linux
|
||||
case darwin
|
||||
case {msys_nt,mingw\*_nt}\*
|
||||
set os win
|
||||
set ext zip
|
||||
set tarcmd bsdtar
|
||||
case \*
|
||||
echo "nvm: Unsupported operating system: \"$os\"" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
switch $arch
|
||||
case i\*86
|
||||
set arch x86
|
||||
case x86_64
|
||||
set arch x64
|
||||
case arm64
|
||||
string match --regex --quiet "v(?<major>\d+)" $ver
|
||||
if test "$os" = darwin -a $major -lt 16
|
||||
set arch x64
|
||||
end
|
||||
case armv6 armv6l
|
||||
set arch armv6l
|
||||
case armv7 armv7l
|
||||
set arch armv7l
|
||||
case armv8 armv8l aarch64
|
||||
set arch arm64
|
||||
end
|
||||
|
||||
set --query nvm_arch && set arch $nvm_arch
|
||||
|
||||
set --local dir "node-$ver-$os-$arch"
|
||||
set --local url $nvm_mirror/$ver/$dir.$ext
|
||||
|
||||
command mkdir -p $nvm_data/$ver
|
||||
|
||||
if ! set --query silent
|
||||
echo -e "Installing Node \x1b[1m$ver\x1b[22m $alias"
|
||||
echo -e "Fetching \x1b[4m$url\x1b[24m\x1b[7m"
|
||||
end
|
||||
|
||||
if ! command curl -q $silent --progress-bar --location $url |
|
||||
command $tarcmd --extract --gzip --directory $nvm_data/$ver 2>/dev/null
|
||||
command rm -rf $nvm_data/$ver
|
||||
echo -e "\033[F\33[2K\x1b[0mnvm: Invalid mirror or host unavailable: \"$url\"" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
set --query silent || echo -en "\033[F\33[2K\x1b[0m"
|
||||
|
||||
if test "$os" = win
|
||||
command mv $nvm_data/$ver/$dir $nvm_data/$ver/bin
|
||||
else
|
||||
command mv $nvm_data/$ver/$dir/* $nvm_data/$ver
|
||||
command rm -rf $nvm_data/$ver/$dir
|
||||
end
|
||||
end
|
||||
|
||||
if test $ver != "$nvm_current_version"
|
||||
set --query nvm_current_version && _nvm_version_deactivate $nvm_current_version
|
||||
_nvm_version_activate $ver
|
||||
|
||||
set --query nvm_default_packages[1] && npm install --global $silent $nvm_default_packages
|
||||
end
|
||||
|
||||
set --query silent || printf "Now using Node %s (npm %s) %s\n" (_nvm_node_info)
|
||||
case use
|
||||
test $ver = default && set ver $nvm_default_version
|
||||
_nvm_list | string match --entire --regex -- (_nvm_version_match $ver) | read ver __
|
||||
|
||||
if ! set --query ver[1]
|
||||
echo "nvm: Can't use Node \"$their_version\", version must be installed first" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
if test $ver != "$nvm_current_version"
|
||||
set --query nvm_current_version && _nvm_version_deactivate $nvm_current_version
|
||||
test $ver != system && _nvm_version_activate $ver
|
||||
end
|
||||
|
||||
set --query silent || printf "Now using Node %s (npm %s) %s\n" (_nvm_node_info)
|
||||
case uninstall
|
||||
if test -z "$ver"
|
||||
echo "nvm: Not enough arguments for command: \"$cmd\"" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
test $ver = default && test ! -z "$nvm_default_version" && set ver $nvm_default_version
|
||||
|
||||
_nvm_list | string match --entire --regex -- (_nvm_version_match $ver) | read ver __
|
||||
|
||||
if ! set -q ver[1]
|
||||
echo "nvm: Node version not installed or invalid: \"$their_version\"" >&2
|
||||
return 1
|
||||
end
|
||||
|
||||
set --query silent || printf "Uninstalling Node %s %s\n" $ver (string replace ~ \~ "$nvm_data/$ver/bin/node")
|
||||
|
||||
_nvm_version_deactivate $ver
|
||||
|
||||
command rm -rf $nvm_data/$ver
|
||||
case current
|
||||
_nvm_current
|
||||
case ls list
|
||||
_nvm_list | _nvm_list_format (_nvm_current) $argv[2]
|
||||
case lsr {ls,list}-remote
|
||||
_nvm_index_update || return
|
||||
_nvm_list | command awk '
|
||||
FILENAME == "-" && (is_local[$1] = FNR == NR) { next } {
|
||||
print $0 (is_local[$1] ? " ✓" : "")
|
||||
}
|
||||
' - $nvm_data/.index | _nvm_list_format (_nvm_current) $argv[2]
|
||||
case \*
|
||||
echo "nvm: Unknown command or option: \"$cmd\" (see nvm -h for usage)" >&2
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
function _nvm_find_up --argument-names path file
|
||||
test -e "$path/$file" && echo $path/$file || begin
|
||||
test ! -z "$path" || return
|
||||
_nvm_find_up (string replace --regex -- '/[^/]*$' "" $path) $file
|
||||
end
|
||||
end
|
||||
|
||||
function _nvm_version_match --argument-names ver
|
||||
string replace --regex -- '^v?(\d+|\d+\.\d+)$' 'v$1.' $ver |
|
||||
string replace --filter --regex -- '^v?(\d+)' 'v$1' |
|
||||
string escape --style=regex || string lower '\b'$ver'(?:/\w+)?$'
|
||||
end
|
||||
|
||||
function _nvm_list_format --argument-names current regex
|
||||
command awk -v current="$current" -v regex="$regex" '
|
||||
$0 ~ regex {
|
||||
aliases[versions[i++] = $1] = $2 " " $3
|
||||
pad = (n = length($1)) > pad ? n : pad
|
||||
}
|
||||
END {
|
||||
if (!i) exit 1
|
||||
while (i--)
|
||||
printf((current == versions[i] ? " ▶ " : " ") "%"pad"s %s\n",
|
||||
versions[i], aliases[versions[i]])
|
||||
}
|
||||
'
|
||||
end
|
||||
|
||||
function _nvm_current
|
||||
command --search --quiet node || return
|
||||
set --query nvm_current_version && echo $nvm_current_version || echo system
|
||||
end
|
||||
|
||||
function _nvm_node_info
|
||||
set --local npm_path (string replace bin/npm-cli.js "" (realpath (command --search npm)))
|
||||
test -f $npm_path/package.json || set --local npm_version_default (command npm --version)
|
||||
command node --eval "
|
||||
console.log(process.version)
|
||||
console.log('$npm_version_default' ? '$npm_version_default': require('$npm_path/package.json').version)
|
||||
console.log(process.execPath)
|
||||
" | string replace -- ~ \~
|
||||
end
|
||||
@@ -0,0 +1,86 @@
|
||||
function pj --description "fzf package.json script runner with auto-detected package manager"
|
||||
# ── Locate nearest package.json (walk up) ──────────────────────────
|
||||
set -l dir (pwd)
|
||||
set -l pkg ""
|
||||
while true
|
||||
if test -f "$dir/package.json"
|
||||
set pkg "$dir/package.json"
|
||||
break
|
||||
end
|
||||
test "$dir" = / && break
|
||||
set dir (path dirname $dir)
|
||||
end
|
||||
|
||||
if test -z "$pkg"
|
||||
echo "pj: no package.json found in this tree" >&2
|
||||
return 1
|
||||
end
|
||||
set -l root (path dirname $pkg)
|
||||
|
||||
# ── Detect package manager ─────────────────────────────────────────
|
||||
# Priority: packageManager field (corepack) → lockfiles (walking up
|
||||
# past $root to catch monorepo-root locks) → npm fallback
|
||||
set -l pm (jq -r '.packageManager // empty' $pkg | string split '@')[1]
|
||||
|
||||
if test -z "$pm"
|
||||
set -l d $root
|
||||
while test -z "$pm"
|
||||
if test -f "$d/bun.lockb" -o -f "$d/bun.lock"
|
||||
set pm bun
|
||||
else if test -f "$d/pnpm-lock.yaml"
|
||||
set pm pnpm
|
||||
else if test -f "$d/yarn.lock"
|
||||
set pm yarn
|
||||
else if test -f "$d/package-lock.json"
|
||||
set pm npm
|
||||
end
|
||||
test "$d" = / && break
|
||||
set d (path dirname $d)
|
||||
end
|
||||
test -z "$pm" && set pm npm
|
||||
end
|
||||
|
||||
# ── Pick a script ──────────────────────────────────────────────────
|
||||
set -l script (jq -r '.scripts // {} | keys[]' $pkg | fzf \
|
||||
--prompt="$pm run ❯ " \
|
||||
--header="$root" \
|
||||
--height=40% --layout=reverse --border \
|
||||
--preview="jq -r --arg s {} '.scripts[\$s]' $pkg" \
|
||||
--preview-window=up:2:wrap)
|
||||
|
||||
test -z "$script" && return 0
|
||||
|
||||
# ── Run (npm needs `--` to forward extra args) ────────────────────
|
||||
set -l extra $argv
|
||||
if test "$pm" = npm -a (count $extra) -gt 0
|
||||
set extra -- $extra
|
||||
end
|
||||
|
||||
# Wrap long-running server scripts in openlogs (live log tail for agents).
|
||||
# Matches dev/start/serve and namespaced variants like dev:web, start:api.
|
||||
set -l wrapper
|
||||
if string match -qr '^(dev|start|serve|watch)(:.*)?$' -- $script
|
||||
# Resolve the binary: PATH → mise resolution → mise installs glob
|
||||
set -l ol (command -s openlogs)
|
||||
if test -z "$ol"; and command -sq mise
|
||||
set ol (mise which openlogs 2>/dev/null)
|
||||
end
|
||||
if test -z "$ol"
|
||||
set ol ~/.local/share/mise/installs/node/*/bin/openlogs
|
||||
set ol $ol[1]
|
||||
end
|
||||
|
||||
if test -n "$ol" -a -x "$ol"
|
||||
set wrapper $ol
|
||||
else
|
||||
echo "pj: openlogs not found, running unwrapped" >&2
|
||||
end
|
||||
end
|
||||
if test -n "$wrapper"
|
||||
echo "→ $wrapper $pm run $script $argv" >&2
|
||||
$wrapper $pm run $script $extra
|
||||
else
|
||||
echo "→ $pm run $script $argv" >&2
|
||||
$pm run $script $extra
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,8 @@
|
||||
function yy
|
||||
set tmp (mktemp -t "yazi-cwd.XXXXXX")
|
||||
command yazi $argv --cwd-file="$tmp"
|
||||
if read -z cwd < "$tmp"; and [ "$cwd" != "$PWD" ]; and test -d "$cwd"
|
||||
builtin cd -- "$cwd"
|
||||
end
|
||||
rm -f -- "$tmp"
|
||||
end
|
||||
Reference in new issue
Block a user