mirror of
https://github.com/ohmyzsh/ohmyzsh.git
synced 2026-01-02 02:19:06 +01:00
Merge 19f7520c6a into 54f17588b3
This commit is contained in:
commit
70f04ce6d1
3 changed files with 358 additions and 1 deletions
3
plugins/f/f.plugin.zsh
Normal file
3
plugins/f/f.plugin.zsh
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# See https://github.com/clvv/f for more info
|
||||
|
||||
source $ZSH/plugins/f/f.sh
|
||||
353
plugins/f/f.sh
Normal file
353
plugins/f/f.sh
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
# This tool gives you quick access to your frequent/recent files
|
||||
#
|
||||
# INSTALL:
|
||||
# Source this file somewhere in your shell rc (.bashrc or .zshrc).
|
||||
#
|
||||
# SYNOPSIS:
|
||||
# _f [options] [query ...]
|
||||
# options:
|
||||
# -s show list of files with their ranks
|
||||
# -l list paths only
|
||||
# -e <cmd> set command to execute on the result file
|
||||
# -a match files and directories
|
||||
# -d match directories only
|
||||
# -f match files only
|
||||
# -r match by rank only
|
||||
# -h show a brief help message
|
||||
#
|
||||
# EXAMPLES:
|
||||
# f foo # list recent files mathcing foo
|
||||
# f foo bar # list recent files mathcing foo and bar
|
||||
# f -e vim foo # run vim on the most frecent file matching foo
|
||||
#
|
||||
# TIPS:
|
||||
# alias z="f -d -e cd"
|
||||
# alias v="f -e vim"
|
||||
# alias m="f -e mplayer"
|
||||
# alias o="f -e xdg-open"
|
||||
|
||||
_f() {
|
||||
|
||||
if [ "$1" = "--add" ]; then # add entries
|
||||
shift
|
||||
|
||||
# bail out if we don't own ~/.f (we're another user but our ENV is still set)
|
||||
[ -f "$_F_DATA" -a ! -O "$_F_DATA" ] && return
|
||||
|
||||
# blacklists
|
||||
local each
|
||||
for each in "${_F_BLACKLIST[@]}"; do
|
||||
[[ "$*" =~ "$each" ]] && return
|
||||
done
|
||||
|
||||
# shifts
|
||||
for each in "${_F_SHIFT[@]}"; do
|
||||
while [ "$1" = "$each" ]; do shift; done
|
||||
done
|
||||
|
||||
# ignores
|
||||
[[ "${_F_IGNORE[@]}" =~ "$1" ]] && return
|
||||
shift
|
||||
|
||||
local FILES
|
||||
while [ "$1" ]; do
|
||||
# add the adsolute path of the file to FILES, and a delimiter "|"
|
||||
FILES+="$($_F_READLINK -e -- "$1" 2>> "$_F_SINK")|"
|
||||
shift
|
||||
done
|
||||
|
||||
# add current pwd if the option set
|
||||
[ "$_F_TRACK_PWD" = "1" -a "$(pwd -P)" != "$HOME" ] && FILES+="$(pwd -P)"
|
||||
|
||||
[ -z "${FILES//|/}" ] && return # stop if we have nothing to add
|
||||
|
||||
# maintain the file
|
||||
local tempfile
|
||||
tempfile="$(mktemp $_F_DATA.XXXXXX)" || return
|
||||
$_F_AWK -v list="$FILES" -v now="$(date +%s)" -v max="$_F_MAX" -F"|" '
|
||||
BEGIN {
|
||||
split(list, files, "|")
|
||||
for(i in files) {
|
||||
path = files[i]
|
||||
if ( path == "" ) continue
|
||||
paths[path] = path # array for checking
|
||||
rank[path] = 1
|
||||
time[path] = now
|
||||
}
|
||||
}
|
||||
$2 >= 1 {
|
||||
if( $1 in paths ) {
|
||||
rank[$1] = $2 + 1
|
||||
time[$1] = now
|
||||
} else {
|
||||
rank[$1] = $2
|
||||
time[$1] = $3
|
||||
}
|
||||
count += $2
|
||||
}
|
||||
END {
|
||||
if( count > max )
|
||||
for( i in rank ) print i "|" 0.9*rank[i] "|" time[i] # aging
|
||||
else
|
||||
for( i in rank ) print i "|" rank[i] "|" time[i]
|
||||
}' "$_F_DATA" 2>> "$_F_SINK" >| "$tempfile"
|
||||
if [ $? -ne 0 -a -f "$_F_DATA" ]; then
|
||||
env rm -f "$tempfile"
|
||||
else
|
||||
env mv -f "$tempfile" "$_F_DATA"
|
||||
fi
|
||||
|
||||
elif [ "$1" = "--query" ]; then
|
||||
# query the database, this need some local variables to be set
|
||||
while read line; do
|
||||
[ -${typ:-e} "${line%%|*}" ] && echo "$line"
|
||||
done < "$_F_DATA" | \
|
||||
$_F_AWK -v t="$(date +%s)" -v mode="$mode" -v q="$fnd" -F"|" '
|
||||
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 likelihood(pattern, path) {
|
||||
m = gsub( "/+", "/", path )
|
||||
r = 1
|
||||
for( i in pattern ) {
|
||||
tmp = path
|
||||
gsub( ".*" pattern[i], "", tmp)
|
||||
n = gsub( "/+", "/", tmp )
|
||||
if( n == m )
|
||||
return 0
|
||||
else if( n == 0 )
|
||||
r *= 20 # F
|
||||
else
|
||||
r *= 1 - ( n / m )
|
||||
}
|
||||
return r
|
||||
}
|
||||
function getRank() {
|
||||
if( mode == "rank" )
|
||||
f = $2
|
||||
else
|
||||
f = frecent($2, $3)
|
||||
wcase[$1] = f * likelihood( pattern, $1 )
|
||||
nocase[$1] = f * likelihood( pattern2, tolower($1) )
|
||||
}
|
||||
BEGIN {
|
||||
split(q, pattern, " ")
|
||||
for( i in pattern ) pattern2[i] = tolower(pattern[i]) # nocase
|
||||
}
|
||||
{
|
||||
getRank()
|
||||
cx = cx || wcase[$1]
|
||||
ncx = ncx || nocase[$1]
|
||||
}
|
||||
END {
|
||||
if( cx ) {
|
||||
for( i in wcase )
|
||||
if( wcase[i] ) printf "%-10s %s\n", wcase[i], i
|
||||
} else if( ncx ) {
|
||||
for( i in nocase )
|
||||
if( nocase[i] ) printf "%-10s %s\n", nocase[i], i
|
||||
}
|
||||
}' - 2>> "$_F_SINK"
|
||||
|
||||
else
|
||||
# parsing logic and processing
|
||||
[ -f "$_F_DATA" ] || return # no db yet
|
||||
local fnd last
|
||||
while [ "$1" ]; do case "$1" in
|
||||
--complete) [ "$2" = "--" ] && shift; set -- $(echo $2); local list=1 r=r;;
|
||||
--) while [ "$2" ]; do shift; fnd+="$1 "; last="$1"; done;;
|
||||
-*) [ "$ZSH_VERSION" ] && local x='o=${o[2,#o]}' || local x='o=${o:1}'
|
||||
local o=${1#-}; while [ "$o" ]; do case $o in
|
||||
s*) local show=1;;
|
||||
l*) local list=1;;
|
||||
r*) local mode=rank;;
|
||||
t*) local mode=recent;;
|
||||
e*) eval $x; if [ "$o" ]; then # there are characters after "-e"
|
||||
local exec=$o # anything after "-e"
|
||||
else # use the next argument
|
||||
local exec=${2:?"Argument needed after -e"}
|
||||
shift
|
||||
fi; break;;
|
||||
a*) local typ=e;;
|
||||
d*) local typ=d;;
|
||||
f*) local typ=f;;
|
||||
h*) echo "_f [options] [query ...]
|
||||
options:
|
||||
-s show list of files with their ranks
|
||||
-l list paths only
|
||||
-e <cmd> set command to execute on the result file
|
||||
-a match files and directories
|
||||
-d match directories only
|
||||
-f match files only
|
||||
-r match by rank only
|
||||
-h show a brief help message" >&2; return;;
|
||||
#*) fnd+="$1 "; last="$1"; break;; # unknown option detected
|
||||
esac; eval $x; done;;
|
||||
*) fnd+="$1 "; last="$1";;
|
||||
esac; shift; done
|
||||
|
||||
# if we hit enter on a completion just execute
|
||||
case "$last" in
|
||||
# completions will always start with /
|
||||
/*) [ -z "$show$list" -a -${typ:-e} "$last" -a "$exec" ] \
|
||||
&& $exec "$last" && return;;
|
||||
esac
|
||||
|
||||
local result
|
||||
result="$(_f --query 2>> "$_F_SINK")" # query the database
|
||||
[ $? -gt 0 ] && return
|
||||
if [ "$list" ]; then
|
||||
echo "$result" | sort -n${r} | sed 's/^[0-9.]*[ ]*//'
|
||||
elif [ "$show" ]; then
|
||||
echo "$result" | sort -n${r}
|
||||
elif [ "$fnd" -a "$exec" ]; then # exec
|
||||
$exec "$(echo "$result" | sort -n | sed -n '$s/^[0-9.]*[ ]*//p')"
|
||||
elif [ "$fnd" ] && [ "$ZSH_SUBSHELL$BASH_SUBSHELL" != "0" ]; then # echo
|
||||
echo "$(echo "$result" | sort -n | sed -n '$s/^[0-9.]*[ ]*//p')"
|
||||
else # no args, show
|
||||
echo "$result" | sort -n${r}
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
# set default options
|
||||
alias ${_F_CMD_A:=a}='_f -a'
|
||||
alias ${_F_CMD_S:=s}='_f -s'
|
||||
alias ${_F_CMD_D:=d}='_f -d'
|
||||
alias ${_F_CMD_F:=f}='_f -f'
|
||||
|
||||
[ -z "$_F_DATA" ] && _F_DATA="$HOME/.f"
|
||||
[ -z "$_F_BLACKLIST" ] && _F_BLACKLIST=(--help)
|
||||
[ -z "$_F_SHIFT" ] && _F_SHIFT=(sudo busybox)
|
||||
[ -z "$_F_IGNORE" ] && _F_IGNORE=(_f cd ls echo)
|
||||
[ -z "$_F_SINK" ] && _F_SINK=/dev/null
|
||||
[ -z "$_F_TRACK_PWD" ] && _F_TRACK_PWD=1
|
||||
[ -z "$_F_MAX" ] && _F_MAX=2000
|
||||
[ -z "$_F_QUERY_SEPARATOR" ] && _F_QUERY_SEPARATOR=,
|
||||
|
||||
if [ -z "$_F_AWK" ]; then
|
||||
# awk preferences
|
||||
for awk in gawk original-awk nawk mawk awk; do
|
||||
$awk "" >> "$_F_SINK" 2>&1 && _F_AWK=$awk && break
|
||||
done
|
||||
fi
|
||||
|
||||
if readlink -e / >> "$_F_SINK" 2>&1; then
|
||||
_F_READLINK=readlink
|
||||
elif greadlink -e / >> "$_F_SINK" 2>&1; then
|
||||
_F_READLINK=greadlink
|
||||
else # fall back on emulated readlink
|
||||
_f_readlink() {
|
||||
# function that mimics readlink from GNU coreutils
|
||||
[ "$1" = "-e" ] && shift && local e=1 # existence option
|
||||
[ "$1" = "--" ] && shift
|
||||
[ "$1" = "/" ] && echo / && return
|
||||
[ "$1" = "." ] && echo "$(pwd -P)" && return
|
||||
local path
|
||||
if [ "${1##*/}" = ".." ]; then
|
||||
path="$(cd "$1" >> "$_F_SINK" 2>&1 && pwd -P)"
|
||||
[ -z "$path" ] && return 1 # if cd fails
|
||||
elif [[ "${1#/}" =~ "/" ]]; then
|
||||
# if target contains "/" (not counting top level) or target is ".."
|
||||
local base="$(cd "${1%/*}" >> "$_F_SINK" 2>&1 && pwd -P)"
|
||||
[ -z "$base" ] && return 1 # if cd fails
|
||||
path="${base%/}/${1##*/}"
|
||||
elif [ -z "${1##/*}" ]; then # straight top level
|
||||
path="$1"
|
||||
else # anything within where we are
|
||||
path="$(pwd -P)"'/'"$1"
|
||||
fi
|
||||
[ "$path" = "/" ] && echo / && return
|
||||
path=${path%/} # strip off trailing "/"
|
||||
[ "$e" = "1" -a ! -e "$path" ] && return
|
||||
echo "$path"
|
||||
}
|
||||
_F_READLINK=_f_readlink
|
||||
fi
|
||||
|
||||
if compctl >> "$_F_SINK" 2>&1; then # zsh
|
||||
_f_zsh_cmd_complete() {
|
||||
local compl
|
||||
read -c compl
|
||||
compstate[insert]=menu # no expand
|
||||
reply=(${(f)"$(_f --complete "$compl")"})
|
||||
}
|
||||
compctl -U -K _f_zsh_cmd_complete -V f -x 'C[-1,-*e],s[-]n[1,e]' -c -- _f
|
||||
_f_zsh_word_complete() {
|
||||
local fnd="$(echo "${words[CURRENT]}" | sed 's/'"$_F_QUERY_SEPARATOR"'/ /g')"
|
||||
local typ=${1:-e}
|
||||
_f --query 2>> "$_F_SINK" | sort -nr | sed 's/^[0-9.]*[ ]*//' | while read line; do
|
||||
compadd -U -V f "$line"
|
||||
done
|
||||
compstate[insert]=menu # no expand
|
||||
}
|
||||
_f_zsh_word_complete_trigger() {
|
||||
[[ ${words[CURRENT]} == "$_F_QUERY_SEPARATOR"* ]] && _f_zsh_word_complete
|
||||
}
|
||||
_f_zsh_word_complete_f() { _f_zsh_word_complete f ; }
|
||||
_f_zsh_word_complete_d() { _f_zsh_word_complete d ; }
|
||||
{ zstyle ':completion:*' completer _complete _ignored \
|
||||
_f_zsh_word_complete_trigger
|
||||
zle -C f-complete menu-select _f_zsh_word_complete
|
||||
zle -C f-complete-f menu-select _f_zsh_word_complete_f
|
||||
zle -C f-complete-d menu-select _f_zsh_word_complete_d
|
||||
} >> "$_F_SINK" 2>&1
|
||||
# add zsh hook
|
||||
autoload -U add-zsh-hook
|
||||
function _f_preexec () { eval "_f --add $3" >> "$_F_SINK" 2>&1; }
|
||||
add-zsh-hook preexec _f_preexec
|
||||
elif complete >> "$_F_SINK" 2>&1; then # bash
|
||||
_f_bash_cmd_complete() {
|
||||
# complete command after "-e"
|
||||
local cur=${COMP_WORDS[COMP_CWORD]}
|
||||
[[ ${COMP_WORDS[COMP_CWORD-1]} == -*e ]] && \
|
||||
COMPREPLY=( $(compgen -A command $cur) ) && return
|
||||
# get completion results using expanded aliases
|
||||
local RESULT=$( _f --complete "$(alias -p ${COMP_WORDS} | \
|
||||
sed -n "\$s/^.*'\(.*\)'/\1/p") ${COMP_LINE#* }" )
|
||||
local IFS=$'\n'
|
||||
COMPREPLY=( $RESULT )
|
||||
}
|
||||
_f_bash_hook_cmd_complete() {
|
||||
for cmd in $*; do
|
||||
complete -F _f_bash_cmd_complete $cmd
|
||||
done
|
||||
}
|
||||
_f_bash_hook_cmd_complete $_F_CMD_A $_F_CMD_S $_F_CMD_D $_F_CMD_F
|
||||
_f_bash_word_complete() {
|
||||
local cur=${COMP_WORDS[COMP_CWORD]}
|
||||
if [[ $cur == "$_F_QUERY_SEPARATOR"* ]]; then
|
||||
local fnd="$(echo "$cur" | sed 's/'"$_F_QUERY_SEPARATOR"'/ /g')"
|
||||
local typ=e
|
||||
local RESULT=$(_f --query 2>> "$_F_SINK" | sed 's/^[0-9.]*[ ]*//')
|
||||
local IFS=$'\n'
|
||||
COMPREPLY=( $RESULT )
|
||||
fi
|
||||
}
|
||||
_f_bash_word_complete_wrap() {
|
||||
_f_bash_word_complete
|
||||
# try original comp func
|
||||
[ "$COMPREPLY" ] || eval "$( echo "$_F_BASH_COMPLETE_P" | \
|
||||
grep -e "${COMP_WORDS[0]}$" | sed -n 's/.*-F \(.*\) .*/\1/p' )"
|
||||
# fall back on original complete options
|
||||
[ "$COMPREPLY" ] || COMPREPLY=( $(eval "$(echo "$_F_BASH_COMPLETE_P" | \
|
||||
grep -e "${COMP_WORDS[0]}$" | sed 's/complete/compgen/') \
|
||||
${COMP_WORDS[COMP_CWORD]}" 2>> "$_F_SINK") )
|
||||
}
|
||||
_f_bash_hook_word_complete_wrap_all() {
|
||||
export _F_BASH_COMPLETE_P="$(complete -p)"
|
||||
for cmd in $(complete -p | awk '{print $NF}' | tr '\n' ' '); do
|
||||
complete -F _f_bash_word_complete_wrap $cmd
|
||||
done
|
||||
}
|
||||
complete -D -F _f_bash_word_complete >> "$_F_SINK" 2>&1
|
||||
# add bash hook
|
||||
echo $PROMPT_COMMAND | grep -v -q "_f --add" && \
|
||||
PROMPT_COMMAND='eval "_f --add $(history 1 | \
|
||||
sed -e "s/^[ ]*[0-9]*[ ]*//")" >> "$_F_SINK" 2>&1;'"$PROMPT_COMMAND"
|
||||
fi
|
||||
|
|
@ -2,4 +2,5 @@ ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[blue]%}["
|
|||
ZSH_THEME_GIT_PROMPT_SUFFIX="]%{$reset_color%} "
|
||||
ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg_bold[red]%} x%{$fg_bold[blue]%}"
|
||||
|
||||
PROMPT='%{$(git_prompt_info)%}%{$fg_bold[green]%}{%{$(rvm current)%}}%{$reset_color%} %{$fg[cyan]%}%c%{$reset_color%} '
|
||||
PROMPT='%{$(git_prompt_info)%}%{$fg_bold[green]%}{%{$(rvm current)%}}%{$reset_color%} %{$fg[cyan]%}%c%{$reset_color%}
|
||||
$ '
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue