From 5a70fba83b4e1845cacb745ccd04fbbf3f1dd064 Mon Sep 17 00:00:00 2001 From: Azalea <22280294+hykilpikonna@users.noreply.github.com> Date: Wed, 6 May 2026 12:56:55 -0400 Subject: [PATCH] [+] Fish (#7) --- fish/includes/aliases.fish | 138 +++++++++++++++++++ fish/includes/config-sync.fish | 62 +++++++++ fish/includes/core.fish | 39 ++++++ fish/includes/docker-nix.fish | 22 +++ fish/includes/final.fish | 14 ++ fish/includes/functions.fish | 125 +++++++++++++++++ fish/includes/git.fish | 152 +++++++++++++++++++++ fish/includes/modern.fish | 19 +++ fish/includes/platform.fish | 73 ++++++++++ fish/includes/prompt.fish | 241 +++++++++++++++++++++++++++++++++ fish/includes/session.fish | 63 +++++++++ fish/rc.fish | 28 ++++ install-fish | 71 ++++++++++ scripts/bin/compress-7zst | 11 +- scripts/bin/video.py | 136 ------------------- scripts/includes/archlinux.sh | 20 +-- scripts/includes/docker.sh | 18 +-- scripts/includes/later/git.zsh | 99 +++++++++++++- scripts/includes/media.sh | 21 --- scripts/includes/nix.sh | 35 ----- scripts/zshrc.sh | 106 +++++++++------ 21 files changed, 1217 insertions(+), 276 deletions(-) create mode 100644 fish/includes/aliases.fish create mode 100644 fish/includes/config-sync.fish create mode 100644 fish/includes/core.fish create mode 100644 fish/includes/docker-nix.fish create mode 100644 fish/includes/final.fish create mode 100644 fish/includes/functions.fish create mode 100644 fish/includes/git.fish create mode 100644 fish/includes/modern.fish create mode 100644 fish/includes/platform.fish create mode 100644 fish/includes/prompt.fish create mode 100644 fish/includes/session.fish create mode 100644 fish/rc.fish create mode 100755 install-fish delete mode 100755 scripts/bin/video.py delete mode 100644 scripts/includes/media.sh delete mode 100644 scripts/includes/nix.sh diff --git a/fish/includes/aliases.fish b/fish/includes/aliases.fish new file mode 100644 index 0000000..9134fbe --- /dev/null +++ b/fish/includes/aliases.fish @@ -0,0 +1,138 @@ +# 好用的简写 +if has xdg-open + alias open xdg-open +end + +alias ll 'ls -l' +alias l ll +alias llg 'll --git --git-repos' +alias lla 'ls -la' +alias grep 'grep --color=auto' +alias rm 'rm -ir' +alias mkdirs 'mkdir -p' + +alias ip 'ip -c -h -p' +alias ipa 'ip -br a' + +function ports --description 'Show listening ports' + if has ss + ss -tulpn + else + netstat -tulpn | grep LISTEN + end +end + +function suports --description 'Show listening ports with root privileges when needed' + if has ss + __fishrc_as_root ss -tulpn + else + __fishrc_as_root netstat -tulpn | grep LISTEN + end +end + +function findtxt --description 'Search for text under /' + if test (count $argv) -eq 0 + echo 'Usage: findtxt ' + return 1 + end + + set -l pattern (string join ' ' -- $argv) + if has rg + rg -n --no-messages -- "$pattern" / + else + grep -IHrnws -s -e "$pattern" / + end +end + +alias clr reset +alias please sudo + +if test "$IS_SANDBOX" = 1 + alias codex 'codex --dangerously-bypass-approvals-and-sandbox' + alias claude 'claude --dangerously-skip-permissions' +end + +alias du 'du -h' + +alias ffmpeg 'ffmpeg -hide_banner' +alias ffprobe 'ffprobe -hide_banner' + +function ts --description 'Run tailscale with root privileges when needed' + __fishrc_as_root tailscale $argv +end +alias ts-install 'curl -fsSL https://tailscale.com/install.sh | sh' + +alias visucode 'env EDITOR="code --wait" sudoedit' +alias cpu-temp s-tui + +function gpu-temp --description 'Watch GPU temperatures with gpustat' + while sleep 1 + clear + gpustat + end +end + +function ipv4 --description 'Show public IPv4 from Cloudflare trace' + curl https://1.0.0.1/cdn-cgi/trace -4 | grep ip +end + +function ipv6 --description 'Show public IPv6 from Cloudflare trace' + curl 'https://[2606:4700:4700::1111]/cdn-cgi/trace' -6 | grep ip +end + +function compress-json --description 'Zstd-compress JSON files below the current directory' + find . -name '*.json' -print0 | parallel --jobs 80% -0 zstd -z -19 -v -f --rm '{}' +end + +function dotclean --description 'Remove macOS metadata files below the current directory' + find . \( -name '.DS_Store' -o -name '._*' \) -delete -print +end + +alias clean-empty-dir 'find . -type d -empty -delete -print' + +function mkfs.fat32 --description 'Format FAT32 with root privileges when needed' + __fishrc_as_root mkfs.fat -F 32 $argv +end + +# Rsync aliases by 依云, for synching (keep hard links, ACL, atime, xattr, etc) +# Deletes files in destination that are not in source +alias xcp "rsync -aviHAXKhS --one-file-system --partial --info=progress2 --atimes --open-noatime --delete --exclude='*~' --exclude=__pycache__" +alias xcpz 'xcp --compress-choice=zstd --compress-level=3 --checksum-choice=xxh3' +alias xmv 'xcp --remove-source-files' +alias xmvz 'xcpz --remove-source-files' + +# Rsync aliases by Azalea, for file transfer (do not keep hard links, ACL, atime, etc.) +# Will not delete files in destination that are not in source +alias rcp "rsync -avihS --partial --info=progress2 --exclude='*~' --exclude=__pycache__" +alias rcpz 'rcp --compress --compress-level=3 --checksum-choice=xxh3' +alias rmv 'rcp --remove-source-files' +alias rmvz 'rcpz --remove-source-files' + +alias tmuxs 'tmux new-session -s' +alias tmuxr 'tmux attach-session -t' +alias tmuxl 'tmux list-sessions' + +alias catt 'echo 🐱' +alias old-update-ssh-keys 'curl -L https://github.com/Hykilpikonna.keys > ~/.ssh/authorized_keys' +alias colors "color '&000&111&222&333&444&555&666&777&888&999&aaa&bbb&ccc&ddd&eee&fff'" +alias tar-kill-progress 'watch -n 60 killall tar -SIGUSR1' + +alias valgrin 'valgrind --leak-check=full --show-leak-kinds=all --leak-resolution=med --track-origins=yes --vgdb=no' + +# Automatic sudo aliases. +if test (id -u) -ne 0 + alias sctl 'sudo systemctl' + alias sctlu 'systemctl --user' + alias jctl 'sudo journalctl' + alias jctlu 'journalctl --user-unit' + alias ufw 'sudo ufw' + alias nginx 'sudo nginx' + alias certbot 'sudo certbot' + alias apt 'sudo apt' + alias dpkg 'sudo dpkg' +else + alias sctl systemctl + alias sctlu 'systemctl --user' + alias jctl journalctl + alias jctlu 'journalctl --user-unit' +end diff --git a/fish/includes/config-sync.fish b/fish/includes/config-sync.fish new file mode 100644 index 0000000..5b982e0 --- /dev/null +++ b/fish/includes/config-sync.fish @@ -0,0 +1,62 @@ +# Config sync, matching the zsh setup for Linux-relevant files. +set -g __fishrc_config_prefix '&7[&3fishrc&7]' + +function __fishrc_check_config --description 'Ensure a config path is a symlink to this repo' + set -l file $argv[1] + set -l sync $argv[2] + + if test -z "$file"; or test -z "$sync" + return 1 + end + + if not test -L "$file" + if has color + color "$__fishrc_config_prefix &c$file is not a symlink, creating symlink" + else + echo "$file is not a symlink, creating symlink" + end + + if test -f "$file"; or test -d "$file" + echo "> Original file $file exists." + echo '> Diff:' + diff "$file" "$sync" + set -l bak "$file.bak" + echo "> Moving $file to $bak..." + mv "$file" "$bak" + end + + echo "> Creating symlink from $sync to $file..." + mkdir -p (dirname "$file") + ln -sf "$sync" "$file" + + if has color + color "$__fishrc_config_prefix &aDone!" + end + end +end + +function __fishrc_check_inject --description 'Append a config line if it is missing' + set -l file $argv[1] + set -l config $argv[2] + grep -Fxq "$config" "$file"; or begin + echo "$config" >>"$file" + has color; and color "$__fishrc_config_prefix &aLines injected for $file" + end +end + +set -gx CFGSYNC "$ZSHRC_ROOT/config-sync" +if status is-interactive + __fishrc_check_config "$HOME/.ssh/config" "$CFGSYNC/ssh-config" + __fishrc_check_config "$HOME/.ssh/rc" "$CFGSYNC/ssh-rc" + chmod +x "$CFGSYNC/ssh-rc" + __fishrc_check_config "$HOME/.nanorc" "$CFGSYNC/nanorc" + __fishrc_check_config "$HOME/.condarc" "$CFGSYNC/.condarc" + __fishrc_check_config "$HOME/.java/.userPrefs/com/cburch/logisim/prefs.xml" "$CFGSYNC/.java/.userPrefs/com/cburch/logisim/prefs.xml" + __fishrc_check_config "$HOME/.config/micro" "$CFGSYNC/.config/micro" + __fishrc_check_config "$HOME/.config/mako" "$CFGSYNC/.config/mako" + __fishrc_check_config "$HOME/.config/kitty" "$CFGSYNC/.config/kitty" + __fishrc_check_config "$HOME/.config/tmux" "$CFGSYNC/.config/tmux" + __fishrc_check_config "$HOME/.ipython/profile_default/startup/ipython_init.py" "$CFGSYNC/ipython_init.py" + __fishrc_check_config "$HOME/.local/share/fcitx5/rime" "$CFGSYNC/.config/ibus/rime" + __fishrc_check_config "$HOME/.local/share/fcitx5/themes" "$CFGSYNC/.config/fcitx5/themes" +end diff --git a/fish/includes/core.fish b/fish/includes/core.fish new file mode 100644 index 0000000..2d72cf6 --- /dev/null +++ b/fish/includes/core.fish @@ -0,0 +1,39 @@ +set -gx LANG en_US.UTF-8 +set -gx LC_ALL en_US.UTF-8 + +function has --description 'Return success if a command exists' + test (count $argv) -gt 0; and command -sq -- $argv[1] +end + +function __fishrc_as_root --description 'Run a command through sudo only when not root' + if test (id -u) -eq 0 + command $argv + else + sudo $argv + end +end + +function __fishrc_prepend_path --description 'Prepend directories to PATH if they exist' + for dir in $argv + if test -d "$dir" + if type -q fish_add_path + fish_add_path -g -p "$dir" + else if not contains -- "$dir" $PATH + set -gx PATH "$dir" $PATH + end + end + end +end + +__fishrc_prepend_path \ + "$SCR/bin" \ + "$HOME/.local/bin" \ + "$HOME/.cargo/bin" + +if test (uname -s) = Linux; and test (uname -m) = x86_64 + __fishrc_prepend_path "$SCR/bin/linux-x64" +end + +if not contains -- . $PATH + set -gx PATH $PATH . +end diff --git a/fish/includes/docker-nix.fish b/fish/includes/docker-nix.fish new file mode 100644 index 0000000..9f8ee19 --- /dev/null +++ b/fish/includes/docker-nix.fish @@ -0,0 +1,22 @@ +# Docker setup. +if has docker-compose + alias dc docker-compose +else + alias dc 'docker compose' +end + +if test (id -u) -ne 0 + alias docker 'sudo docker' + alias docker-compose 'sudo docker-compose' +end +alias docker-ip "docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}'" +alias dockers "docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'" + +function docker-compose-path --description 'Show docker compose working directory for a container' + if test (count $argv) -eq 0 + echo 'Usage: docker-compose-path ' + return 1 + end + + docker inspect "$argv[1]" | grep 'com.docker.compose.project.working_dir' +end diff --git a/fish/includes/final.fish b/fish/includes/final.fish new file mode 100644 index 0000000..b34b4fd --- /dev/null +++ b/fish/includes/final.fish @@ -0,0 +1,14 @@ +if has thefuck + thefuck --alias | source +end + +# Reuse the existing zsh updater if zsh is installed. It runs in the background +# and preserves the repository's current update semantics without duplicating it. +if status is-interactive; and has zsh; and not set -q FISHRC_UPDATE_DISABLED + set -l __fishrc_update_path (string join : "$SCR/bin" $PATH) + env SCR="$SCR" ZSHRC_UPDATE_ASYNC_CHILD=1 PATH="$__fishrc_update_path" zsh -f "$SCR/includes/init/update.sh" >/dev/null 2>&1 & +end + +if test -f "$HOME/extra.rc.fish" + source "$HOME/extra.rc.fish" +end diff --git a/fish/includes/functions.fish b/fish/includes/functions.fish new file mode 100644 index 0000000..6b43248 --- /dev/null +++ b/fish/includes/functions.fish @@ -0,0 +1,125 @@ +function mkcd --description 'Create a directory and cd into it' + if test (count $argv) -eq 0 + echo 'Usage: mkcd ' + return 1 + end + + mkdir -p "$argv[1]"; and cd "$argv[1]" +end + +function set-java --description 'Set JAVA_HOME and PATH to an installed JDK version' + if test (count $argv) -eq 0 + echo 'Usage: set-java ' + return 1 + end + + set -l java_home + if test -d /usr/lib/jvm + set java_home (find /usr/lib/jvm -maxdepth 1 -type d -name "*$argv[1]*" -name '*jdk*' | head -n 1) + end + + if test -z "$java_home" + echo "Error: Java version $argv[1] not found in /usr/lib/jvm" + return 1 + end + + set -gx JAVA_HOME "$java_home" + __fishrc_prepend_path "$JAVA_HOME/bin" +end + +function upload-daisy --description 'Upload a file to daisy-ddns' + set -l file (string join ' ' -- $argv) + curl -u azalea -F "path=@$file" 'https://daisy-ddns.hydev.org/upload?path=/' +end + +function ttmp --description 'Go to /tmp/tmp' + mkdir -p /tmp/tmp; and cd /tmp/tmp +end + +if has micro + set -gx EDITOR micro +else if has nano + set -gx EDITOR nano +end + +# Use the stable SSH agent socket maintained by ~/.ssh/rc inside SSH/tmux sessions. +if test -n "$SSH_TTY"; or test -n "$SSH_CONNECTION" + if test -n "$SSH_AUTH_SOCK"; and test "$SSH_AUTH_SOCK" != "$HOME/.ssh/current_agent.sock"; and test -S "$SSH_AUTH_SOCK" + mkdir -p "$HOME/.ssh" + ln -sf "$SSH_AUTH_SOCK" "$HOME/.ssh/current_agent.sock" + end + + if test -S "$HOME/.ssh/current_agent.sock" + set -gx SSH_AUTH_SOCK "$HOME/.ssh/current_agent.sock" + end +end + +if not set -q GRADLE; and has gradle + set -gx GRADLE (command -s gradle) +end + +function gradle --description 'Use ./gradlew when present, otherwise system gradle' + if test -f ./gradlew + ./gradlew $argv + else if set -q GRADLE; and test -n "$GRADLE" + $GRADLE $argv + else + echo 'Neither gradle nor ./gradlew is found, please install it and restart fish.' + return 1 + end +end + +function 7z --description 'Block the dangerous 7z d command' + if test (count $argv) -gt 0; and test "$argv[1]" = d + echo "7z d is blocked. It does not stand for decompress, it stands for delete." + else + command 7z $argv + end +end + +function reset-permissions-dangerous --description 'Reset file and directory permissions below the current directory' + __fishrc_as_root find . -type d -exec chmod 755 '{}' ';' + __fishrc_as_root find . -type f -exec chmod 644 '{}' ';' +end + +function lisp --description 'Run a lisp file through roswell' + ros run --load "$argv[1]" --quit +end + +function adblan --description 'Connect adb over LAN on port 16523' + adb connect "$argv[1]:16523" +end +alias adblan-start 'adb tcpip 16523' + +function addline --description 'Add a line to a file if it does not already exist' + if test (count $argv) -lt 2 + echo 'Usage: addline ' + return 1 + end + + grep -qxF "$argv[2]" "$argv[1]"; or echo "$argv[2]" >>"$argv[1]" +end + +function spushd --description 'Silent pushd' + pushd $argv >/dev/null; or return 1 +end + +function spopd --description 'Silent popd' + popd $argv >/dev/null; or return 1 +end + +function modern-replace --description 'Alias a command to a modern replacement when installed' + set -l orig_cmd $argv[1] + set -l new_cmd $argv[2] + set -l orig_cmd_with_args $argv[3] + set -l new_cmd_with_args $argv[4] + + test -n "$orig_cmd_with_args"; or set orig_cmd_with_args $orig_cmd + test -n "$new_cmd_with_args"; or set new_cmd_with_args $new_cmd + + if has "$new_cmd" + alias "$orig_cmd" "$new_cmd_with_args" + else + alias "$orig_cmd" "$orig_cmd_with_args" + end +end diff --git a/fish/includes/git.fish b/fish/includes/git.fish new file mode 100644 index 0000000..6228362 --- /dev/null +++ b/fish/includes/git.fish @@ -0,0 +1,152 @@ +# Git helpers. +function commit --description 'git commit wrapper' + if test (count $argv) -eq 0 + git commit + else + git commit -m (string join ' ' -- $argv) + end +end + +function commitall --description 'git add . and commit' + git add . + commit $argv +end +alias commita commitall + +function compush --description 'commitall and push' + commitall $argv + git push +end + +function git-ida --description 'Set git identity from git-id-list' + if test (count $argv) -eq 0 + echo 'Usage: git-ida ' + return 1 + end + + set -l identity (git-id-list get "$argv[1]") + git-id $identity[1] $identity[2] +end + +function git-id --description 'Set git identity for this shell' + set -gx GIT_USER "$argv[1]" + set -gx GIT_EMAIL "$argv[2]" + git-id-prompt +end + +function git-id-prompt --description 'Refresh git identity prompt segment' + if test -z "$GIT_USER"; and test -z "$GIT_EMAIL" + set -g __fishrc_git_id_segment '' + else + set -g __fishrc_git_id_segment "Git ID: $GIT_USER | $GIT_EMAIL " + end +end + +function git --description 'git wrapper with per-shell identity override' + if test -z "$GIT_USER" + command git $argv + else + command git -c "user.name=$GIT_USER" -c "user.email=$GIT_EMAIL" -c commit.gpgsign=false $argv + end +end + +function git-require-clean --description 'Require a clean git worktree' + command git rev-parse --is-inside-work-tree >/dev/null 2>&1; or return 1 + + set -l status_lines (command git status --porcelain 2>/dev/null) + if test (count $status_lines) -ne 0 + echo 'Workspace is not clean.' + command git status --short + return 1 + end +end + +function git-main-branch --description 'Print the repository main branch name' + set -l remote_head (command git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null) + if test -n "$remote_head" + string replace -r '^origin/' '' -- "$remote_head" + return 0 + end + + for branch in main master trunk develop + if command git show-ref --verify --quiet refs/heads/$branch + printf '%s\n' "$branch" + return 0 + end + if command git show-ref --verify --quiet refs/remotes/origin/$branch + printf '%s\n' "$branch" + return 0 + end + end + + echo 'Could not determine main branch.' >&2 + return 1 +end + +function git-update-main --description 'Checkout and fast-forward the main branch' + set -l main_branch $argv[1] + if test -z "$main_branch" + set main_branch (git-main-branch); or return 1 + end + + command git checkout "$main_branch"; or return 1 + command git pull --ff-only +end + +function br --description 'Switch to an existing branch, or create one from updated main' + if test (count $argv) -ne 1 + echo 'Usage: br ' + return 1 + end + + set -l branch "$argv[1]" + git-require-clean; or return 1 + + if command git show-ref --verify --quiet "refs/heads/$branch"; or command git show-ref --verify --quiet "refs/remotes/origin/$branch" + command git checkout "$branch" + return $status + end + + set -l main_branch (git-main-branch); or return 1 + git-update-main "$main_branch"; or return 1 + command git checkout -b "$branch" +end + +function bru --description 'Update the current branch by rebasing it on updated main' + set -l current_branch (command git symbolic-ref --quiet --short HEAD 2>/dev/null) + if test -z "$current_branch" + echo 'Could not determine current branch.' + return 1 + end + + git-require-clean; or return 1 + + set -l main_branch (git-main-branch); or return 1 + if test "$current_branch" = "$main_branch" + echo "Already on $main_branch." + return 1 + end + + git-update-main "$main_branch"; or return 1 + command git checkout "$current_branch"; or return 1 + command git rebase "$main_branch" +end + +function git-env --description 'Alias common git subcommands into the shell' + set -l git_commands add bisect branch checkout clone commit diff fetch grep init log merge pull push rebase reset restore show stash tag + for cmd in $git_commands + alias "$cmd" "git $cmd" + end + alias grm 'git rm' + alias gmv 'git mv' + alias st 'git status' +end + +function git-unenv --description 'Remove aliases created by git-env' + set -l git_commands add bisect branch checkout clone commit diff fetch grep init log merge pull push rebase reset restore show stash tag grm gmv st + for cmd in $git_commands + functions -q "$cmd"; and functions -e "$cmd" + end +end + +git-id-prompt diff --git a/fish/includes/modern.fish b/fish/includes/modern.fish new file mode 100644 index 0000000..6125eb5 --- /dev/null +++ b/fish/includes/modern.fish @@ -0,0 +1,19 @@ +# Modern unix replacements. +modern-replace ls eza 'ls -h --color=auto' eza +modern-replace df duf 'df -h' duf +modern-replace cat bat cat bat +modern-replace man tldr man tldr +modern-replace top btop top btop +modern-replace nano micro nano micro +modern-replace curl curlie curl curlie +modern-replace pacman paru 'pacman --color always' 'paru --color always' +modern-replace vi nvim vi nvim +modern-replace vim nvim vim nvim +modern-replace code visual-studio-code-electron code visual-studio-code-electron + +if not has docker; and has podman + alias docker podman + if has podman-compose + alias docker-compose podman-compose + end +end diff --git a/fish/includes/platform.fish b/fish/includes/platform.fish new file mode 100644 index 0000000..4fea0d3 --- /dev/null +++ b/fish/includes/platform.fish @@ -0,0 +1,73 @@ +# Application aliases. +alias va-restart 'sctl restart va' +alias va-log-all 'jctl -u va --output cat' +alias va-log 'va-log-all -f' +alias jctlog 'jctl --output cat -f -u' + +# Arch Linux setup. +if has pacman + if test (id -u) -eq 0 + alias upgrade 'pacman -Syu' + else + alias upgrade 'sudo pacman -Syu' + end + alias install 'pacman -Sy' + alias uninstall 'pacman -Rsn' + alias list-unused 'pacman -Qdtq' +end + +if test -f /etc/arch-release + __fishrc_prepend_path "$HOME/.local/share/JetBrains/Toolbox/scripts" + + alias gpg-init "echo hi | gpg --status-fd=2 -bsau E289FAC0DA92DD2B" + alias ibus-init 'ibus-daemon -drxR' + alias autoremove 'yay -c' + + function clean-cache --description 'Clean common package manager caches' + has yay; and yay -Sc --noconfirm + has pacman; and __fishrc_as_root pacman -Sc --noconfirm + has pacman; and __fishrc_as_root rm -rf /var/cache/pacman + has paru; and rm -rf "$HOME/.cache/paru" + has yarn; and yarn cache clean + has conda; and conda clean -a + has pip; and pip cache remove '*' + end + + if test -f "$ZSHRC_ROOT/plugins/find-the-command/usr/share/doc/find-the-command/ftc.fish" + source "$ZSHRC_ROOT/plugins/find-the-command/usr/share/doc/find-the-command/ftc.fish" + end +end + +# Mamba and Python environment setup. +alias mamba-install 'curl -L micro.mamba.pm/install.sh | bash' +set -q MAMBA_ROOT_PREFIX; or set -gx MAMBA_ROOT_PREFIX "$HOME/.conda" + +function mamba-init --description 'Initialize micromamba for fish' + set -l mamba_exe (command -s micromamba) + if test -z "$mamba_exe" + echo 'Failed to initialize mamba: micromamba not found.' + return 1 + end + + $mamba_exe shell hook --shell fish --root-prefix "$HOME/micromamba" | source + set -l ret $pipestatus[1] + if test $ret -ne 0 + echo "Failed to initialize mamba: Return code $ret." + echo "Note: this uses '--root-prefix' for mamba 2.0+. Upgrade with mamba-install if needed." + return $ret + end +end + +if has micromamba + mamba-init + if not has conda + alias conda mamba + end +end + +if has pyenv + pyenv init - fish | source + __fishrc_prepend_path (pyenv root)/shims +end + +alias mamba micromamba diff --git a/fish/includes/prompt.fish b/fish/includes/prompt.fish new file mode 100644 index 0000000..5d9351f --- /dev/null +++ b/fish/includes/prompt.fish @@ -0,0 +1,241 @@ +alias prompt "$SCR/helpers/prompt.py" + +function pcolor --description 'Colorize text using the repository prompt helper' + "$SCR/helpers/prompt.py" (string join ' ' -- $argv) color +end + +function prompt-reset --description 'Reset fish prompt state used by this rc' + set -g __fishrc_proxy_segment '' + git-id-prompt +end + +function __fishrc_prompt_pr_state --description 'Set GitHub PR prompt state for a branch' + set -l branch $argv[1] + test -n "$branch"; or return 1 + command -sq gh; or return 1 + + set -l repo_key (command git rev-parse --show-toplevel 2>/dev/null) + if test -z "$repo_key" + set repo_key (command jj root --ignore-working-copy 2>/dev/null) + end + set -l cache_key "$repo_key:$branch" + set -l now (date +%s) + + if test "$__fishrc_prompt_pr_cache_key" = "$cache_key" + if string match -qr '^[0-9]+$' -- "$__fishrc_prompt_pr_cache_time" + set -l cache_age (math "$now - $__fishrc_prompt_pr_cache_time" 2>/dev/null) + if string match -qr '^[0-9]+$' -- "$cache_age" + if test "$cache_age" -lt 300 + set -l cached_pr $__fishrc_prompt_pr_cache_value + test "$cached_pr[1]" != __none; or return 1 + if test -z "$cached_pr[2]" + set cached_pr[2] green + end + set -g __fishrc_vcs_pr_number "$cached_pr[1]" + set -g __fishrc_vcs_pr_color "$cached_pr[2]" + return 0 + end + end + end + end + + set -l pr_line + if command -sq timeout + set pr_line (command timeout 1s gh pr list --head "$branch" --state all --limit 20 --json number,state,updatedAt --jq 'map(select(.state == "OPEN" or .state == "MERGED")) | sort_by(.updatedAt) | reverse | .[0] | select(.number != null) | .number, .state' 2>/dev/null) + else + set pr_line (command gh pr list --head "$branch" --state all --limit 20 --json number,state,updatedAt --jq 'map(select(.state == "OPEN" or .state == "MERGED")) | sort_by(.updatedAt) | reverse | .[0] | select(.number != null) | .number, .state' 2>/dev/null) + end + + set -l pr_number (string trim -- "$pr_line[1]") + set -l pr_state (string trim -- "$pr_line[2]") + set -l pr_color green + if test "$pr_state" = MERGED + set pr_color purple + end + + set -g __fishrc_prompt_pr_cache_key "$cache_key" + set -g __fishrc_prompt_pr_cache_time "$now" + + if not string match -qr '^[0-9]+$' -- "$pr_number" + set -g __fishrc_prompt_pr_cache_value __none + return 1 + end + + set -g __fishrc_prompt_pr_cache_value "$pr_number" "$pr_color" + set -g __fishrc_vcs_pr_number "$pr_number" + set -g __fishrc_vcs_pr_color "$pr_color" +end + +function __fishrc_git_unpushed_count --description 'Print commits ahead of the git upstream or remotes' + set -l upstream (command git rev-parse --abbrev-ref --symbolic-full-name '@{upstream}' 2>/dev/null) + if test -n "$upstream" + command git rev-list --count "$upstream"..HEAD 2>/dev/null + return + end + + command git rev-list --count HEAD --not --remotes 2>/dev/null +end + +function __fishrc_git_prompt_state --description 'Set compact git repository state for the prompt' + command -sq git; or return 1 + command git rev-parse --is-inside-work-tree >/dev/null 2>&1; or return 1 + + set -l branch (command git symbolic-ref --quiet --short HEAD 2>/dev/null) + set -l pr_branch "$branch" + if test -z "$branch" + set branch (command git rev-parse --short HEAD 2>/dev/null) + end + test -n "$branch"; or return 1 + + set -l git_status (command git status --porcelain=v1 --branch 2>/dev/null) + set -l flags + set -l changed 0 + + set -l header $git_status[1] + set -l behind (string match -r 'behind [0-9]+' -- "$header" | string replace 'behind ' 'v') + + set -l ahead_count (__fishrc_git_unpushed_count) + if string match -qr '^[0-9]+$' -- "$ahead_count" + if test "$ahead_count" -gt 0 + set -a flags ^$ahead_count + set changed 1 + end + end + + test -n "$behind"; and set -a flags $behind + + for line in $git_status[2..-1] + set changed 1 + set -l index (string sub -s 1 -l 1 -- "$line") + set -l worktree (string sub -s 2 -l 1 -- "$line") + + switch "$line" + case 'UU*' 'AA*' 'DD*' 'AU*' 'UA*' 'DU*' 'UD*' + contains x $flags; or set -a flags x + continue + case '??*' + contains '?' $flags; or set -a flags '?' + continue + end + + if test "$index" != ' ' + contains + $flags; or set -a flags + + end + + if test "$worktree" != ' ' + contains '!' $flags; or set -a flags '!' + end + end + + set -l segment "git:$branch" + if test (count $flags) -gt 0 + set segment "$segment "(string join '' -- $flags) + end + + set -g __fishrc_vcs_segment "$segment" + set -g __fishrc_vcs_color 777777 + if test "$changed" -eq 1 + set -g __fishrc_vcs_color yellow + end + + __fishrc_prompt_pr_state "$pr_branch" + return 0 +end + +function __fishrc_jj_prompt_state --description 'Set compact jj workspace state for the prompt' + command -sq jj; or return 1 + command jj root --ignore-working-copy >/dev/null 2>&1; or return 1 + + set -l info (command jj log --no-graph --ignore-working-copy --color=never -r @ --template 'separate(" ", change_id.shortest(8), bookmarks.join("|"), if(conflict, "x")) ++ "\n"' 2>/dev/null) + test -n "$info"; or return 1 + + set -g __fishrc_vcs_segment "jj:$info" + set -g __fishrc_vcs_color 777777 + + set -l diff_summary (command jj diff --summary --ignore-working-copy 2>/dev/null) + if test -n "$diff_summary" + set -g __fishrc_vcs_color yellow + end + + set -l pr_branch (command jj log --no-graph --ignore-working-copy --color=never -r 'bookmarks() & @' --template 'bookmarks.join("\n") ++ "\n"' 2>/dev/null)[1] + set pr_branch (string replace -r '\*$' '' -- "$pr_branch") + __fishrc_prompt_pr_state "$pr_branch" + return 0 +end + +function __fishrc_vcs_prompt_state --description 'Set prompt VCS segment state' + set -g __fishrc_vcs_segment '' + set -g __fishrc_vcs_color 777777 + set -g __fishrc_vcs_pr_number '' + set -g __fishrc_vcs_pr_color green + + __fishrc_jj_prompt_state; or __fishrc_git_prompt_state +end + +function fish_prompt --description 'Repository fish prompt' + set -l host (prompt_hostname) + set host (string replace -r '^HyDEV-' '' -- "$host") + + printf '\n' + + if test "$host" = HyDEV + set_color magenta + printf '%s ' (date '+%a %m-%d %H:%M') + else + set_color 55CDFC + printf '%s ' (date '+%a') + set_color F7A8B8 + printf '%s' (date '+%m-') + set_color FFFFFF + printf '%s ' (date '+%d') + set_color F7A8B8 + printf '%s' (date '+%H:') + set_color 55CDFC + printf '%s ' (date '+%M') + end + + set_color blue + if test "$host" = HyDEV + set_color 55CDFC + printf H + set_color F7A8B8 + printf y + set_color FFFFFF + printf D + set_color F7A8B8 + printf E + set_color 55CDFC + printf 'V ' + else + printf '%s ' "$host" + end + + set_color yellow + if test -n "$__fishrc_git_id_segment" + printf '%s' "$__fishrc_git_id_segment" + else + printf '%s ' "$USER" + end + set_color brgreen + printf '%s' "$__fishrc_proxy_segment" + + set_color normal + printf '%s' (prompt_pwd) + + __fishrc_vcs_prompt_state + if test -n "$__fishrc_vcs_segment" + printf ' ' + set_color $__fishrc_vcs_color + printf '[%s' "$__fishrc_vcs_segment" + if test -n "$__fishrc_vcs_pr_number" + printf ' ' + set_color $__fishrc_vcs_pr_color + printf '#%s' "$__fishrc_vcs_pr_number" + set_color $__fishrc_vcs_color + end + printf ']' + set_color normal + end + + printf '\n> ' +end diff --git a/fish/includes/session.fish b/fish/includes/session.fish new file mode 100644 index 0000000..4746911 --- /dev/null +++ b/fish/includes/session.fish @@ -0,0 +1,63 @@ +set -g __fishrc_proxy_segment '' +set -g __fishrc_git_id_segment '' + +function setproxy --description 'Set common proxy environment variables' + set -l addr 127.0.0.1 + set -l port 7890 + test (count $argv) -ge 1; and set addr $argv[1] + test (count $argv) -ge 2; and set port $argv[2] + set -l full "$addr:$port" + + set -gx https_proxy "http://$full" + set -gx http_proxy "http://$full" + set -gx all_proxy "http://$full" + set -gx HTTPS_PROXY "http://$full" + set -gx HTTP_PROXY "http://$full" + set -gx ALL_PROXY "http://$full" + set -g __fishrc_proxy_segment "proxy $full " + + if has color + color "&aUsing proxy! $full&r" + else + echo "Using proxy! $full" + end +end + +function ssh --description 'Use xterm-256color when connecting from kitty' + if test "$TERM" = xterm-kitty + env TERM=xterm-256color command ssh $argv + else + command ssh $argv + end +end + +if status is-interactive; and test -z "$TMUX"; and test -n "$SSH_TTY"; and has tmux + tmux attach-session -t ssh_tmux; or tmux new-session -s ssh_tmux +end + +function subtitle --description 'Generate subtitles with auto_subtitle' + env CUDA_VISIBLE_DEVICES=1 auto_subtitle --srt_only True --model large "$argv[1]" +end + +function upload --description 'Upload a file to HyDEV daisy' + if test (count $argv) -eq 0 + echo 'Usage: upload ' + return 1 + end + + if not set -q UP_PASSWORD; or test -z "$UP_PASSWORD" + echo 'Error: Password not set, please export UP_PASSWORD=xxx' + return 1 + end + + set -l file $argv[1] + set -l server_url 'https://daisy.hydev.org/upload?path=/' + set -l up_username azalea + + if test -f "$file" + curl -u "$up_username:$UP_PASSWORD" -F "path=@$file" "$server_url" + else + echo 'Error: File not found.' + return 1 + end +end diff --git a/fish/rc.fish b/fish/rc.fish new file mode 100644 index 0000000..cbe3e18 --- /dev/null +++ b/fish/rc.fish @@ -0,0 +1,28 @@ +# Fish rc for this repository. +# Source this from ~/.config/fish/config.fish: +# source /path/to/zshrc/fish/rc.fish +# +# Fish already provides shared history, autosuggestions, syntax highlighting, +# completions, and good command-line editing, so the zsh-only equivalents are +# intentionally not ported here. macOS-only setup is also omitted. + +set -l __fishrc_dir (dirname (status --current-filename)) +set -gx FISHRC_DIR "$__fishrc_dir" +set -gx ZSHRC_ROOT (path resolve "$__fishrc_dir/..") +set -q SCR; or set -gx SCR "$ZSHRC_ROOT/scripts" +set -q BASEDIR; or set -gx BASEDIR "$ZSHRC_ROOT" + +for include in \ + core \ + aliases \ + functions \ + platform \ + config-sync \ + docker-nix \ + modern \ + session \ + git \ + prompt \ + final + source "$FISHRC_DIR/includes/$include.fish" +end diff --git a/install-fish b/install-fish new file mode 100755 index 0000000..b9ab93f --- /dev/null +++ b/install-fish @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + echo "Usage: install-fish [--uninstall]" +} + +repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" +rc_file="$repo_dir/fish/rc.fish" +config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/fish" +config_file="$config_dir/config.fish" + +escaped_rc_file="${rc_file//\\/\\\\}" +escaped_rc_file="${escaped_rc_file//\"/\\\"}" +source_line="source \"$escaped_rc_file\"" +legacy_source_line="source $rc_file" + +install_fish_rc() { + if [[ ! -f "$rc_file" ]]; then + echo "Fish rc not found: $rc_file" >&2 + exit 1 + fi + + mkdir -p "$config_dir" + touch "$config_file" + + if grep -Fxq "$source_line" "$config_file" || grep -Fxq "$legacy_source_line" "$config_file"; then + echo "Already installed in $config_file" + return + fi + + if [[ -s "$config_file" && $(tail -c 1 "$config_file") != "" ]]; then + printf '\n' >>"$config_file" + fi + + printf '%s\n' "$source_line" >>"$config_file" + echo "Installed fish rc in $config_file" +} + +uninstall_fish_rc() { + if [[ ! -f "$config_file" ]]; then + echo "Fish rc is not installed in $config_file" + return + fi + + if ! grep -Fxq "$source_line" "$config_file" && ! grep -Fxq "$legacy_source_line" "$config_file"; then + echo "Fish rc is not installed in $config_file" + return + fi + + tmp_file="$(mktemp)" + grep -Fxv "$source_line" "$config_file" | grep -Fxv "$legacy_source_line" >"$tmp_file" || true + mv "$tmp_file" "$config_file" + echo "Uninstalled fish rc from $config_file" +} + +case "${1:-}" in + "") + install_fish_rc + ;; + --uninstall) + uninstall_fish_rc + ;; + -h | --help) + usage + ;; + *) + usage >&2 + exit 1 + ;; +esac diff --git a/scripts/bin/compress-7zst b/scripts/bin/compress-7zst index 27fc11a..e9e6c6e 100755 --- a/scripts/bin/compress-7zst +++ b/scripts/bin/compress-7zst @@ -1,8 +1,13 @@ #!/usr/bin/env bash +set -euo pipefail + +if [[ $# -eq 0 ]]; then + echo "Usage: compress-7zst <7z args...>" + exit 1 +fi level="${level:-15}" - cores=$(python3 -c "import os; print(os.cpu_count())") + echo "Starting ZSTD compression with $cores cores and level $level" -# "$cmd" -I "zstd -T$cores -$level" --checkpoint=.1024 --totals --totals=SIGUSR1 -c -f "$@" -7z a -m0=zstd -mx"$level" -mmt"$cores" "$@" +exec 7z a -m0=zstd -mx"$level" -mmt"$cores" "$@" diff --git a/scripts/bin/video.py b/scripts/bin/video.py deleted file mode 100755 index fb7069f..0000000 --- a/scripts/bin/video.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python3 -from __future__ import annotations - -import os -import platform -import re -import shutil -from subprocess import Popen, check_call -import sys -import shlex -from datetime import datetime -from pathlib import Path - - -def comp(input: str = 'latest', proc: str = 'cpu', codec: str = 'x264', crf: int = 24, br: int = None, - cmd: bool = False, aargs: str = '', suffix: str = 'mp4'): - """ - Compress video - - :param input: Input file (Default: latest) - :param proc: cpu (c) or gpu (g) - :param codec: x264 (4) or x265 (5) - :param crf: CRF (quality) for cpu encoding - :param cmd: Whether to output command directly - :param aargs: Additional args - :param suffix: File suffix (Default mp4) - :return: - """ - if input == 'latest': - rename() - i = sorted([s for s in os.listdir('.') if s.startswith('Rec') and s.endswith('mov')])[-1] - else: - i = input - - proc = proc[0] - codec = {'4': {'c': 'x264', 'g': 'h264'}, '5': {'c': 'x265', 'g': 'hevc'}}[codec[-1]][proc] - - out = i[:i.rindex('.')] + f'.{codec}' - if proc == 'c': - out += f'-{crf}' - out += f'.{suffix}' - - c = ['ffmpeg', '-i', i] - - if proc == 'c': - c += ['-c:v', f'lib{codec}', '-crf', str(crf)] - elif proc == 'g': - if platform.system() == 'Darwin': - c += ['-c:v', f'{codec}_videotoolbox'] - else: - c += ['-c:v', f'{codec}_nvenc', '-cq', str(crf)] - else: - raise AssertionError(f'Processor is invalid ({codec}[0] not in "cg")') - - if br: - c += ['-b:v', f'{br}k', '-maxrate', f'{br}k', '-bufsize', f'2M'] - - c += shlex.split(aargs) + [out] - - print(c) - if not cmd: - Popen(c).wait() - - -def combine(format: str, output: str | Path): - """ - Combine videos - - :param format: Regex pattern - :param output: Output file name - """ - pattern = re.compile(format) - - # Find video files - print() - files = [f for f in os.listdir('.') if pattern.match(f)] - print(f'Combining these files: {files}') - - if len(files) == 0: - return print('No files to combine') - - # Write files to text - txt = Path('./temp.txt') - txt.write_text('\n'.join(f"file '{f}'" for f in files)) - - # Infer extension - if '.' not in output: - output = str(Path(output).with_suffix(Path(files[0]).suffix)) - - # Run FFmpeg - print('Running FFmpeg') - os.system(f'ffmpeg -f concat -safe 0 -i temp.txt -c copy {output}') - - # Remove temprary file - os.remove(txt) - - -def rename(): - for file in os.listdir('.'): - if file.startswith('Screen Recording ') or file.startswith('Screen Shot '): - pre = 'Rec' if 'Recording' in file else 'Shot' - end_index = (file.index('AM') if 'AM' in file else file.index('PM')) + 2 - datestr = file[17 if pre == 'Rec' else 12:end_index] - dt = datetime.strptime(datestr, '%Y-%m-%d at %I.%M.%S %p') - date = dt.strftime(f'{pre} %Y-%m-%d %H-%M' + file[end_index:]) - - print(f'Renaming {file} to {date}') - os.rename(file, date) - - -def convert_gnome(): - rec_dir = Path.home() / "Videos/Screencasts" - fs = [rec_dir / str(f) for f in os.listdir(rec_dir) if str(f).startswith("Screencast") and str(f).endswith(".webm")] - for inf in fs: - sp = inf.stem.split(" ") - ouf = rec_dir / f"Rec {sp[2]} {sp[3][:sp[3].rindex('-')]}.mp4" - if ouf.is_file(): - print(f"Already converted: {inf}") - continue - print(f"Converting '{inf}' to '{ouf}'") - check_call(['ffmpeg', '-i', inf, - '-c:v', 'libx264', - '-vf', 'crop=trunc(iw/2)*2:trunc(ih/2)*2, fps=30', - '-y', - ouf]) - - if input("Remove files? [y/N]") == "y": - [os.remove(f) for f in fs] - - -if __name__ == '__main__': - args = sys.argv[1:] - if args: - v = eval(args[0]) - if v: - print(v) diff --git a/scripts/includes/archlinux.sh b/scripts/includes/archlinux.sh index b137aaf..68b1e81 100644 --- a/scripts/includes/archlinux.sh +++ b/scripts/includes/archlinux.sh @@ -1,25 +1,11 @@ if command -v pacman &> /dev/null; then - alias upgrade='sudo pacman -Syu' + alias upgrade="${ZSHRC_SUDO}pacman -Syu" alias install='pacman -Sy' alias uninstall='pacman -Rsn' alias list-unused='pacman -Qdtq' fi if [ -f "/etc/arch-release" ]; then - # Java paths - export JDK8="/usr/lib/jvm/java-8-openjdk/" - export JDK11="/usr/lib/jvm/java-11-openjdk/" - export JDK17="/usr/lib/jvm/java-17-openjdk/" - export JDK18="/usr/lib/jvm/java-18-j9/" - export JDK19="/usr/lib/jvm/java-19-openjdk/" - alias java8="${JDK8}/bin/java" - alias java11="${JDK11}/bin/java" - alias java17="${JDK17}/bin/java" - alias java18="${JDK18}/bin/java" - alias java19="${JDK19}/bin/java" - export JAVA_HOME=${JDK17} - export PATH="${JDK17}/bin:$PATH" - export PATH="$HOME/.local/share/JetBrains/Toolbox/scripts:$PATH" # GPG Init @@ -32,8 +18,8 @@ if [ -f "/etc/arch-release" ]; then # Free up cache clean-cache() { has yay && yay -Sc --noconfirm - has pacman && sudo pacman -Sc --noconfirm - has pacman && rm -rf /var/cache/pacman + has pacman && _zshrc_as_root pacman -Sc --noconfirm + has pacman && _zshrc_as_root rm -rf /var/cache/pacman has paru && rm -rf "$HOME/.cache/paru" has yarn && yarn cache clean has conda && conda clean -a diff --git a/scripts/includes/docker.sh b/scripts/includes/docker.sh index 59366d3..3a4f6ad 100644 --- a/scripts/includes/docker.sh +++ b/scripts/includes/docker.sh @@ -4,7 +4,7 @@ else alias dc='docker compose' fi -if [[ $OSTYPE != 'darwin'* ]]; then +if [[ $OSTYPE != 'darwin'* && $EUID -ne 0 ]]; then alias docker="sudo docker" alias docker-compose="sudo docker-compose" fi @@ -21,19 +21,3 @@ docker-compose-path() docker inspect "$1" | grep "com.docker.compose.project.working_dir" } - -# Docker linux containers -alpine-create() -{ - docker rmi azalea/alpine - docker run -it --name alpine-init --hostname alpine alpine \ - /bin/sh -c 'apk add zsh bash git curl wget tar zstd python3 && bash <(curl -sL hydev.org/zsh)' - docker commit alpine-init azalea/alpine - docker rm alpine-init -} -alias alpine="docker start -ai alpine" -alias alpine-init="docker run -it --name alpine --hostname alpine azalea/alpine zsh" - -alias psqlt+="docker run --rm -dit --name psql-test --hostname psql -e POSTGRES_HOST_AUTH_METHOD=trust postgres && echo 'Created'" -alias psqlt-="docker stop psql-test && echo 'Deleted'" -alias psqlt='psql -h $(docker-ip psql-test) -p 5432 -U postgres' diff --git a/scripts/includes/later/git.zsh b/scripts/includes/later/git.zsh index 9ff86a2..8eb1453 100644 --- a/scripts/includes/later/git.zsh +++ b/scripts/includes/later/git.zsh @@ -1,7 +1,11 @@ # Git commit wrapper commit() { - msg="$@" - git commit -m "$msg" + if [[ $# -eq 0 ]]; then + git commit + else + msg="$@" + git commit -m "$msg" + fi } commitall() { @@ -44,18 +48,105 @@ git() { fi } +git-require-clean() { + command git rev-parse --is-inside-work-tree >/dev/null 2>&1 || return 1 + + if [[ -n "$(command git status --porcelain 2>/dev/null)" ]]; then + echo 'Workspace is not clean.' + command git status --short + return 1 + fi +} + +git-main-branch() { + local remote_head + remote_head=$(command git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null) + if [[ -n "$remote_head" ]]; then + echo "${remote_head#origin/}" + return 0 + fi + + local branch + for branch in main master trunk develop; do + if command git show-ref --verify --quiet "refs/heads/$branch"; then + echo "$branch" + return 0 + fi + if command git show-ref --verify --quiet "refs/remotes/origin/$branch"; then + echo "$branch" + return 0 + fi + done + + echo 'Could not determine main branch.' >&2 + return 1 +} + +git-update-main() { + local main_branch="$1" + if [[ -z "$main_branch" ]]; then + main_branch=$(git-main-branch) || return 1 + fi + + command git checkout "$main_branch" || return 1 + command git pull --ff-only +} + +br() { + if [[ $# -ne 1 ]]; then + echo 'Usage: br ' + return 1 + fi + + local branch="$1" + git-require-clean || return 1 + + if command git show-ref --verify --quiet "refs/heads/$branch" || command git show-ref --verify --quiet "refs/remotes/origin/$branch"; then + command git checkout "$branch" + return $? + fi + + local main_branch + main_branch=$(git-main-branch) || return 1 + git-update-main "$main_branch" || return 1 + command git checkout -b "$branch" +} + +bru() { + local current_branch + current_branch=$(command git symbolic-ref --quiet --short HEAD 2>/dev/null) + if [[ -z "$current_branch" ]]; then + echo 'Could not determine current branch.' + return 1 + fi + + git-require-clean || return 1 + + local main_branch + main_branch=$(git-main-branch) || return 1 + if [[ "$current_branch" == "$main_branch" ]]; then + echo "Already on $main_branch." + return 1 + fi + + git-update-main "$main_branch" || return 1 + command git checkout "$current_branch" || return 1 + command git rebase "$main_branch" +} + # Git environment git-env() { - git_commands=( add bisect branch checkout clone commit diff fetch grep init log merge pull push rebase reset restore show status tag ) + git_commands=( add bisect branch checkout clone commit diff fetch grep init log merge pull push rebase reset restore show stash tag ) for i in "${git_commands[@]}" do alias "$i"="git $i" done alias 'grm'='git rm' alias 'gmv'='git mv' + alias 'st'='git status' } git-unenv() { - git_commands=( add bisect branch checkout clone commit diff fetch grep init log merge pull push rebase reset restore show status tag grm gmv ) + git_commands=( add bisect branch checkout clone commit diff fetch grep init log merge pull push rebase reset restore show stash tag grm gmv st ) for i in "${git_commands[@]}" do unalias "$i" diff --git a/scripts/includes/media.sh b/scripts/includes/media.sh deleted file mode 100644 index a357ce9..0000000 --- a/scripts/includes/media.sh +++ /dev/null @@ -1,21 +0,0 @@ -# Cut videos - cut [start time (default 00:00:00)] -cutv() { - if [ "$#" -lt 2 ]; then - echo "Usage: cut [start time (00:00:00)]" - return 2 - fi - - local start="${3:-00:00:00}" - echo "$1" - echo "$2" - echo "$start" - ffmpeg -i "$1" -codec copy -ss "$start" -t "$2" Cut\ "$1" -} -alias vcomp="$BASEDIR/scripts/bin/video.py" -alias vcompy="ipython -i $BASEDIR/scripts/bin/video.py" - -flac2mp3() { - for file in *.flac; do - ffmpeg -i "$file" -ab 320k -map_metadata 0 -id3v2_version 3 "${file%.flac}.mp3" - done -} \ No newline at end of file diff --git a/scripts/includes/nix.sh b/scripts/includes/nix.sh deleted file mode 100644 index 4eb1b6d..0000000 --- a/scripts/includes/nix.sh +++ /dev/null @@ -1,35 +0,0 @@ -# Nixos only -if command -v nixos-rebuild &> /dev/null; then - alias rebuild="sudo nixos-rebuild switch" - alias gc="sudo nix-collect-garbage -d" - alias rebuild-gc="rebuild; gc" - - # Update git - nix-git-update() { - pushd /etc/nixos - - # Make sure there aren't any other changes - if git diff-index --quiet HEAD --; then - # No changes - update-nix-fetchgit *.nix - - # If there are changes after updating - if ! git diff-index --quiet HEAD --; then - # Has changes - rebuild-gc - git add *.nix - git commit -m "[U] Update fetchgit refs" - git push - echo "Successfully updated fetchgit refs" - else - echo "There aren't any updates" - fi - else - # Changes - echo "Error: There are uncommitted changes" - git status - fi - - popd - } -fi diff --git a/scripts/zshrc.sh b/scripts/zshrc.sh index bff7a90..9e09262 100755 --- a/scripts/zshrc.sh +++ b/scripts/zshrc.sh @@ -8,6 +8,20 @@ setopt SHARE_HISTORY export LANG=en_US.UTF-8 export LC_ALL=en_US.UTF-8 +if [[ $EUID -eq 0 ]]; then + ZSHRC_SUDO="" +else + ZSHRC_SUDO="sudo " +fi + +_zshrc_as_root() { + if [[ $EUID -eq 0 ]]; then + command "$@" + else + sudo "$@" + fi +} + BASEDIR="$(dirname "$(dirname "$0")")" # Bash-like shortcuts @@ -34,9 +48,10 @@ if command -v 'xdg-open' &> /dev/null; then alias open="xdg-open" fi -# 好用的简写w +# 好用的简写 alias ll='ls -l' alias l='ll' +alias llg='ll --git --git-repos' alias lla='ls -la' alias grep='grep --color' alias rm='rm -ir' @@ -44,46 +59,66 @@ alias mkdirs='mkdir -p' alias ip='ip -c -h -p' alias ipa='ip -br a' -alias ipj='ip -j' alias ipv4="curl https://1.0.0.1/cdn-cgi/trace -4 | grep ip" alias ipv6="curl 'https://[2606:4700:4700::1111]/cdn-cgi/trace' -6 | grep ip" -alias ports='netstat -tulpn | grep LISTEN' -alias suports='sudo netstat -tulpn | grep LISTEN' -alias findtxt='grep -IHrnws --exclude=\*.log -s '/' -e' +ports() { + if command -v ss &> /dev/null; then + ss -tulpn + else + netstat -tulpn | grep LISTEN + fi +} + +suports() { + if command -v ss &> /dev/null; then + _zshrc_as_root ss -tulpn + else + _zshrc_as_root netstat -tulpn | grep LISTEN + fi +} + +findtxt() { + if [[ -z $1 ]]; then + echo "Usage: findtxt " + return 1 + fi + + local pattern="$*" + if command -v rg &> /dev/null; then + rg -n --no-messages -- "$pattern" / + else + grep -IHrnws -s -e "$pattern" / + fi +} alias clr='reset' alias please='sudo' -alias tar-create='tar -cvf' -alias tar-expand='tar -zxvf' +if [[ "$IS_SANDBOX" == "1" ]]; then + alias codex='codex --dangerously-bypass-approvals-and-sandbox' + alias claude='claude --dangerously-skip-permissions' +fi alias du='du -h' -alias sortsize='sort -hr' -alias dus='du -shc * | sortsize' -alias dusa='du -hc --max-depth=1 | sortsize' alias ffmpeg="ffmpeg -hide_banner" alias ffprobe="ffprobe -hide_banner" -alias ts='sudo tailscale' +alias ts="${ZSHRC_SUDO}tailscale" alias ts-install='curl -fsSL https://tailscale.com/install.sh | sh' -alias vsucode='sudo code --user-data-dir /root/.config/vscode --no-sandbox' alias visucode='EDITOR="code --wait" sudoedit' alias gpu-temp='while sleep 1; do clear; gpustat; done' alias cpu-temp='s-tui' -alias mount-external='sudo mount -t cifs //192.168.2.1/external /smb/external -o rw,user=azalea,uid=1000,gid=1000,pass=' alias compress-json="find -name '*.json' -print0 | parallel --jobs 80% -0 zstd -z -19 -v -f --rm {}" -alias ds-clean="find . -name '.DS_Store' -delete -print" -alias dotclean="find . -name '._*' -delete -print" +dotclean() { + find . \( -name '.DS_Store' -o -name '._*' \) -delete -print +} alias clean-empty-dir="find . -type d -empty -delete -print" -alias restart-kwin="DISPLAY=:0 setsid kwin_x11 --replace" -alias mkfs.fat32="sudo mkfs.fat -F 32" -alias btrfs-fs-progress="sudo watch -d sudo btrfs fi us" -alias btrfs-balance-progress="sudo watch -d btrfs balance status" +alias mkfs.fat32="${ZSHRC_SUDO}mkfs.fat -F 32" # Rsync aliases by 依云, for synching (keep hard links, ACL, atime, xattr, etc) # Deletes files in destination that are not in source @@ -135,6 +170,7 @@ upload-daisy() { } # Automatic sudo +if [[ $EUID -ne 0 ]]; then alias sctl="sudo systemctl" alias sctlu="systemctl --user" alias jctl="sudo journalctl" @@ -144,33 +180,17 @@ alias nginx="sudo nginx" alias certbot="sudo certbot" alias apt="sudo apt" alias dpkg="sudo dpkg" +else +alias sctl="systemctl" +alias sctlu="systemctl --user" +alias jctl="journalctl" +alias jctlu="journalctl --user-unit" +fi has() { command -v "$1" &> /dev/null } -# Compress 7z zstd -compress-7zst() { - if [ -z "$1" ]; then - echo "Usage: compress-7zst " - return - fi - 7z a -m0=zstd -mx17 -mmt35 "$1" "$2" -} - -# Install using system package manager -install-package() { - if has pacman; then - pacman -Sy "$1" - elif has apt; then - apt install "$1" - elif has dnf; then - dnf install "$1" - elif has brew; then - brew install "$1" - fi -} - ttmp() { mkdir -p /tmp/tmp cd /tmp/tmp || return @@ -223,8 +243,8 @@ gradle() { # Unix permissions reset (Dangerous! This will make executable files no longer executable) reset-permissions-dangerous() { - sudo find . -type d -exec chmod 755 {} \; - sudo find . -type f -exec chmod 644 {} \; + _zshrc_as_root find . -type d -exec chmod 755 {} \; + _zshrc_as_root find . -type f -exec chmod 644 {} \; } export PATH="$SCR/bin:$PATH"