diff options
| author | littleblack111 <littleblack11111@gmail.com> | 2025-10-13 22:56:18 +0800 |
|---|---|---|
| committer | littleblack111 <littleblack11111@gmail.com> | 2025-10-13 22:58:22 +0800 |
| commit | 542fa9ffaef0691a3a9f4ffef65f12e22c57d849 (patch) | |
| tree | e3f56a823778188e418eeec2642d5785d3ae3c0e /dot-config/fish/functions | |
| parent | 0c7001019bb345d59892de88c355b653d2680fdb (diff) | |
bump
Diffstat (limited to 'dot-config/fish/functions')
| -rw-r--r-- | dot-config/fish/functions/__z.fish | 177 | ||||
| -rw-r--r-- | dot-config/fish/functions/__z_add.fish | 49 | ||||
| -rw-r--r-- | dot-config/fish/functions/__z_clean.fish | 11 | ||||
| -rw-r--r-- | dot-config/fish/functions/__z_complete.fish | 13 | ||||
| -rw-r--r-- | dot-config/fish/functions/fish_command_not_found.fish | 59 | ||||
| -rw-r--r-- | dot-config/fish/functions/fish_mode_prompt.fish | 4 | ||||
| -rw-r--r-- | dot-config/fish/functions/fish_prompt.fish | 131 | ||||
| -rw-r--r-- | dot-config/fish/functions/fish_user_key_bindings.fish | 25 |
8 files changed, 469 insertions, 0 deletions
diff --git a/dot-config/fish/functions/__z.fish b/dot-config/fish/functions/__z.fish new file mode 100644 index 00000000..8043f8f3 --- /dev/null +++ b/dot-config/fish/functions/__z.fish @@ -0,0 +1,177 @@ +function __z -d "Jump to a recent directory." + function __print_help -d "Print z help." + printf "Usage: $Z_CMD [-celrth] string1 string2...\n\n" + printf " -c --clean Removes directories that no longer exist from $Z_DATA\n" + printf " -d --dir Opens matching directory using system file manager.\n" + printf " -e --echo Prints best match, no cd\n" + printf " -l --list List matches and scores, no cd\n" + printf " -p --purge Delete all entries from $Z_DATA\n" + printf " -r --rank Search by rank\n" + printf " -t --recent Search by recency\n" + printf " -x --delete Removes the current directory from $Z_DATA\n" + printf " -h --help Print this help\n\n" + end + function __z_legacy_escape_regex + # taken from escape_string_pcre2 in fish + # used to provide compatibility with fish 2 + for c in (string split -- '' $argv) + if contains $c (string split '' '.^$*+()?[{}\\|-]') + printf \\ + end + printf '%s' $c + end + end + + set -l options h/help c/clean e/echo l/list p/purge r/rank t/recent d/directory x/delete + + argparse $options -- $argv + + if set -q _flag_help + __print_help + return 0 + else if set -q _flag_clean + __z_clean + printf "%s cleaned!\n" $Z_DATA + return 0 + else if set -q _flag_purge + echo >$Z_DATA + printf "%s purged!\n" $Z_DATA + return 0 + else if set -q _flag_delete + sed -i -e "\:^$PWD|.*:d" $Z_DATA + return 0 + end + + set -l typ + + if set -q _flag_rank + set typ rank + else if set -q _flag_recent + set typ recent + end + + set -l z_script ' + function frecent(rank, time) { + dx = t-time + if( dx < 3600 ) return rank*4 + if( dx < 86400 ) return rank*2 + if( dx < 604800 ) return rank/2 + return rank/4 + } + + function output(matches, best_match, common) { + # list or return the desired directory + if( list ) { + cmd = "sort -nr" + for( x in matches ) { + if( matches[x] ) { + printf "%-10s %s\n", matches[x], x | cmd + } + } + } else { + if( common ) best_match = common + print best_match + } + } + + function common(matches) { + # find the common root of a list of matches, if it exists + for( x in matches ) { + if( matches[x] && (!short || length(x) < length(short)) ) { + short = x + } + } + if( short == "/" ) return + for( x in matches ) if( matches[x] && index(x, short) != 1 ) { + return + } + return short + } + + BEGIN { + hi_rank = ihi_rank = -9999999999 + } + { + if( typ == "rank" ) { + rank = $2 + } else if( typ == "recent" ) { + rank = $3 - t + } else rank = frecent($2, $3) + if( $1 ~ q ) { + matches[$1] = rank + } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank + if( matches[$1] && matches[$1] > hi_rank ) { + best_match = $1 + hi_rank = matches[$1] + } else if( imatches[$1] && imatches[$1] > ihi_rank ) { + ibest_match = $1 + ihi_rank = imatches[$1] + } + } + + END { + # prefer case sensitive + if( best_match ) { + output(matches, best_match, common(matches)) + } else if( ibest_match ) { + output(imatches, ibest_match, common(imatches)) + } + } + ' + + set -l qs + for arg in $argv + set -l escaped $arg + if string escape --style=regex '' >/dev/null 2>&1 # use builtin escape if available + set escaped (string escape --style=regex -- $escaped) + else + set escaped (__z_legacy_escape_regex $escaped) + end + # Need to escape twice, see https://www.math.utah.edu/docs/info/gawk_5.html#SEC32 + set escaped (string replace --all -- \\ \\\\ $escaped) + set qs $qs $escaped + end + set -l q (string join -- '.*' $qs) + + if set -q _flag_list + # Handle list separately as it can print common path information to stderr + # which cannot be captured from a subcommand. + command awk -v t=(date +%s) -v list="list" -v typ="$typ" -v q="$q" -F "|" $z_script "$Z_DATA" + return + end + + if set -q q[1] + set target (command awk -v t=(date +%s) -v typ="$typ" -v q="$q" -F "|" $z_script "$Z_DATA") + else + set target $HOME + end + if test "$status" -gt 0 + return + end + + if test -z "$target" + printf "'%s' did not match any results\n" "$argv" + return 1 + end + + if set -q _flag_echo + printf "%s\n" "$target" + else if set -q _flag_directory + if test -n "$ZO_METHOD" + type -q "$ZO_METHOD"; and "$ZO_METHOD" "$target"; and return $status + echo "Cannot open with ZO_METHOD set to $ZO_METHOD"; and return 1 + else if test "$OS" = Windows_NT + # Be careful, in msys2, explorer always return 1 + type -q explorer; and explorer "$target" + return 0 + echo "Cannot open file explorer" + return 1 + else + type -q xdg-open; and xdg-open "$target"; and return $status + type -q open; and open "$target"; and return $status + echo "Not sure how to open file manager"; and return 1 + end + else + pushd "$target" + end +end diff --git a/dot-config/fish/functions/__z_add.fish b/dot-config/fish/functions/__z_add.fish new file mode 100644 index 00000000..20d5d7e5 --- /dev/null +++ b/dot-config/fish/functions/__z_add.fish @@ -0,0 +1,49 @@ +function __z_add -d "Add PATH to .z file" + test -n "$fish_private_mode"; and return 0 + + for i in $Z_EXCLUDE + if string match -r $i $PWD >/dev/null + return 0 #Path excluded + end + end + + set -l tmpfile (mktemp $Z_DATA.XXXXXX) + + if test -f $tmpfile + set -l path (string replace --all \\ \\\\ $PWD) + command awk -v path=$path -v now=(date +%s) -F "|" ' + BEGIN { + rank[path] = 1 + time[path] = now + } + $2 >= 1 { + if( $1 == path ) { + rank[$1] = $2 + 1 + time[$1] = now + } + else { + rank[$1] = $2 + time[$1] = $3 + } + count += $2 + } + END { + if( count > 1000 ) { + for( i in rank ) print i "|" 0.9*rank[i] "|" time[i] # aging + } + else for( i in rank ) print i "|" rank[i] "|" time[i] + } + ' $Z_DATA 2>/dev/null >$tmpfile + + if test ! -z "$Z_OWNER" + chown $Z_OWNER:(id -ng $Z_OWNER) $tmpfile + end + # + # Don't use redirection here as it can lead to a race condition where $Z_DATA is clobbered. + # Note: There is a still a possible race condition where an old version of $Z_DATA is + # read by one instance of Fish before another instance of Fish writes its copy. + # + command mv $tmpfile $Z_DATA + or command rm $tmpfile + end +end diff --git a/dot-config/fish/functions/__z_clean.fish b/dot-config/fish/functions/__z_clean.fish new file mode 100644 index 00000000..ae1721a0 --- /dev/null +++ b/dot-config/fish/functions/__z_clean.fish @@ -0,0 +1,11 @@ +function __z_clean -d "Clean up .z file to remove paths no longer valid" + set -l tmpfile (mktemp $Z_DATA.XXXXXX) + + if test -f $tmpfile + while read line + set -l path (string split '|' $line)[1] + test -d $path; and echo $line + end <$Z_DATA >$tmpfile + command mv -f $tmpfile $Z_DATA + end +end diff --git a/dot-config/fish/functions/__z_complete.fish b/dot-config/fish/functions/__z_complete.fish new file mode 100644 index 00000000..a6264561 --- /dev/null +++ b/dot-config/fish/functions/__z_complete.fish @@ -0,0 +1,13 @@ +function __z_complete -d "add completions" + complete -c $Z_CMD -a "(__z -l | string replace -r '^\\S*\\s*' '')" -f -k + complete -c $ZO_CMD -a "(__z -l | string replace -r '^\\S*\\s*' '')" -f -k + + complete -c $Z_CMD -s c -l clean -d "Cleans out $Z_DATA" + complete -c $Z_CMD -s e -l echo -d "Prints best match, no cd" + complete -c $Z_CMD -s l -l list -d "List matches, no cd" + complete -c $Z_CMD -s p -l purge -d "Purges $Z_DATA" + complete -c $Z_CMD -s r -l rank -d "Searches by rank, cd" + complete -c $Z_CMD -s t -l recent -d "Searches by recency, cd" + complete -c $Z_CMD -s h -l help -d "Print help" + complete -c $Z_CMD -s x -l delete -d "Removes the current directory from $Z_DATA" +end diff --git a/dot-config/fish/functions/fish_command_not_found.fish b/dot-config/fish/functions/fish_command_not_found.fish new file mode 100644 index 00000000..63706737 --- /dev/null +++ b/dot-config/fish/functions/fish_command_not_found.fish @@ -0,0 +1,59 @@ +function fish_command_not_found --description "Fish: suggest/install AUR pkg when command not found" + set -l cmd $argv + set -l pkgs + + printf '\033[0;31m\033[1m==> ERROR: Command not found:\033[0m %s\n' "$cmd" + printf '\033[0m' + printf 'Checking for package.' + + # spinner: print dots until pkgfile finishes + set -l spinner_pid + fish -c ' + while true + sleep 0.1 + printf "." + end + ' & + set spinner_pid $last_pid + + # query pkgfile; -b (binaries), -v (verbose) to include repo/pkg paths + set -l out (pkgfile -b -v -- "$cmd" ^/dev/null) + + # stop spinner + kill $spinner_pid 2>/dev/null + echo + + if test -n "$out" + # Split lines into array + set pkgs $out + + printf 'The application %s is not installed. It may be found in the following AUR packages:\n' "$cmd" + for p in $pkgs + printf ' %s\n' "$p" + end + + # Emulate original logic: take second field after splitting first match by "/" + # Example line format often like: "aur/pkgname usr/bin/cmd" + set -l first $pkgs[1] + set -l parts (string split -m1 ' ' -- $first)[1] + set -l repo_pkg (string split '/' -- $parts) + set -l pkgname $repo_pkg[2] + + if test -n "$pkgname" + printf 'Do you want to Install AUR package %s? (y/N) ' "$pkgname" + read -l -n 1 choice + echo + if test (string lower -- "$choice") = y + echo "Executing command: yay -S $pkgname" + yay -S "$pkgname" --noconfirm + echo + return + else + echo + return + end + end + end 1>&2 + + return 127 +end diff --git a/dot-config/fish/functions/fish_mode_prompt.fish b/dot-config/fish/functions/fish_mode_prompt.fish new file mode 100644 index 00000000..ace718c5 --- /dev/null +++ b/dot-config/fish/functions/fish_mode_prompt.fish @@ -0,0 +1,4 @@ +# Vi-mode +# The default mode prompt would be prefixed, which ruins our alignment. +function fish_mode_prompt +end diff --git a/dot-config/fish/functions/fish_prompt.fish b/dot-config/fish/functions/fish_prompt.fish new file mode 100644 index 00000000..be2b7e2e --- /dev/null +++ b/dot-config/fish/functions/fish_prompt.fish @@ -0,0 +1,131 @@ +function fish_prompt + # This prompt shows: + # - green lines if the last return command is OK, red otherwise + # - your user name, in red if root or yellow otherwise + # - your hostname, in cyan if ssh or blue otherwise + # - the current path (with prompt_pwd) + # - date +%X + # - the current virtual environment, if any + # - the current git status, if any, with fish_git_prompt + # - the current battery state, if any, and if your power cable is unplugged, and if you have "acpi" + # - current background jobs, if any + + # It goes from: + # ┬─[nim@Hattori:~]─[11:39:00] + # ╰─>$ echo here + + # To: + # ┬─[nim@Hattori:~/w/dashboard]─[11:37:14]─[V:django20]─[G:master↑1|●1✚1…1]─[B:85%, 05:41:42 remaining] + # │ 2 15054 0% arrêtée sleep 100000 + # │ 1 15048 0% arrêtée sleep 100000 + # ╰─>$ echo there + + set -l retc red + set -l prompt_status $status + test $prompt_status = 0; and set retc green + + set -q __fish_git_prompt_showupstream + or set -g __fish_git_prompt_showupstream auto + + function _nim_prompt_wrapper + set retc $argv[1] + set -l field_name $argv[2] + set -l field_value $argv[3] + + set_color normal + set_color $retc + echo -n '─' + set_color -o green + echo -n '[' + set_color normal + test -n $field_name + and echo -n $field_name: + set_color $retc + echo -n $field_value + set_color -o green + echo -n ']' + end + + set_color $retc + echo -n '┬─' + set_color -o green + echo -n [ + + if functions -q fish_is_root_user; and fish_is_root_user + set_color -o red + else + set_color -o yellow + end + + echo -n $USER + set_color -o white + echo -n @ + + if test -z "$SSH_CLIENT" + set_color -o blue + else + set_color -o cyan + end + + echo -n (prompt_hostname) + set_color -o white + echo -n :(prompt_pwd) + set_color -o green + echo -n ']' + + # Date + _nim_prompt_wrapper $retc '' (date +%X) + + if test "$fish_key_bindings" = fish_vi_key_bindings + or test "$fish_key_bindings" = fish_hybrid_key_bindings + set -l mode + switch $fish_bind_mode + case default + set mode (set_color --bold red)N + case insert + set mode (set_color --bold green)I + case replace_one + set mode (set_color --bold green)R + echo '[R]' + case replace + set mode (set_color --bold cyan)R + case visual + set mode (set_color --bold magenta)V + end + set mode $mode(set_color normal) + _nim_prompt_wrapper $retc '' $mode + end + + # Virtual Environment + set -q VIRTUAL_ENV_DISABLE_PROMPT + or set -g VIRTUAL_ENV_DISABLE_PROMPT true + set -q VIRTUAL_ENV + and _nim_prompt_wrapper $retc '' (path basename "$VIRTUAL_ENV") + + # git + set -l prompt_git (fish_git_prompt '%s') + test -n "$prompt_git" + and _nim_prompt_wrapper $retc '' $prompt_git + + test ! $prompt_status = 0; and _nim_prompt_wrapper $retc '' (fish_status_to_signal $prompt_status) + + # New line + echo + + # Background jobs + set_color normal + + for job in (jobs) + set_color $retc + echo -n '│ ' + set_color brown + echo $job + end + + set_color normal + set_color $retc + echo -n '╰─>' + set_color -o red + echo -n '$ ' + set_color normal +end diff --git a/dot-config/fish/functions/fish_user_key_bindings.fish b/dot-config/fish/functions/fish_user_key_bindings.fish new file mode 100644 index 00000000..df44927f --- /dev/null +++ b/dot-config/fish/functions/fish_user_key_bindings.fish @@ -0,0 +1,25 @@ +function fish_user_key_bindings + for m in default insert + bind -M $m ctrl-f accept-autosuggestion + bind -M $m ctrl-backspace backward-kill-word + end + + for m in default insert normal + bind -M $m alt-up 'commandline -f cancel; cd ..; commandline -f repaint' + bind -M $m ctrl-r history-pager + end + + bind -M normal U redo + + for m in default insert normal replace replace_one + bind --preset --erase -M $m ctrl-h + bind -M $m ctrl-h backward-char + bind --preset --erase -M $m ctrl-j + bind -M $m ctrl-j down-or-search + bind --preset --erase -M $m ctrl-k + bind -M $m ctrl-k up-or-search + # clear overrode + bind --preset --erase -M $m ctrl-l + bind -M $m ctrl-l forward-char + end +end |
