diff --git a/plugins/percol/_percol b/plugins/percol/_percol new file mode 100644 index 00000000..b950c719 --- /dev/null +++ b/plugins/percol/_percol @@ -0,0 +1,17 @@ +#compdef percol + +local context state line +typeset -A opt_args + +_arguments : \ + '1:input file name:_files' \ + '(--help -h)'{--help,-h}'[show this help message and exit]' \ + '--tty=[path to the TTY]:tty:{compadd $(find /dev/pts -print)}' \ + '--rcfile=[path to the settings file]:rc.py:_files -g \*\.py' \ + '--encoding=[encoding for input and output]:encoding:' \ + '--query=[pre-input query]:query:' \ + '--match-method=[specify matching method for query.]:match method:((string\:normal\ match regex\:regular\ expression migemo\:migemo))' \ + '--caret-position=[position of the caret]:caret position:' \ + '--initial-index=[position of the initial index of the selection]:initial index:(first last)' \ + '--peep[exit immediately without doing anything]' + diff --git a/plugins/percol/percol.zsh b/plugins/percol/percol.zsh new file mode 100644 index 00000000..f48222d6 --- /dev/null +++ b/plugins/percol/percol.zsh @@ -0,0 +1,251 @@ +#!zsh + +# This script arranges some percol-related userful zle-widgets and +# commands +# +# To use this script, put a following line into your .zshrc +# +# source PATH_TO_THIS_FILE +# +# Then, you can bind percol's zle-widgets to some key, by calling +# bindkey. +# +# bindkey '^R' percol_select_history +# +# Here is the list of zle-widgets provided by this script. +# +# * percol_select_history +# * percol_cd_sibling +# * percol_cd_upper_dirs +# * percol_cd_bookmark +# * percol_cd_repository +# * percol_insert_bookmark +# * percol_insert_ls +# +# And this script also provides following commands. +# +# * ppgrep +# * ppkill +# +# Enjoy! + +# ------------------------------------------------------------ # +# Initialize +# ------------------------------------------------------------ # + +PERCOL_ENABLED=true + +function exists() { + which $1 &> /dev/null +} + +# Define tac wrapper +exists gtac && _PERCOL_TAC="gtac" || \ + { exists tac && _PERCOL_TAC="tac" || \ + { _PERCOL_TAC="tail -r" } } +function _percol_tac() { + eval $_PERCOL_TAC +} + +# Arrange a tmp dir for percol +PERCOL_TMP_DIR=/tmp/percol.zsh.tmp +if ! [ -d ${PERCOL_TMP_DIR} ]; then + mkdir ${PERCOL_TMP_DIR} +fi + +# ------------------------------------------------------------ # +# FIFO for percol_popup +# ------------------------------------------------------------ # + +# Arrange fifos +local PERCOL_IN=${PERCOL_TMP_DIR}/percol-channel-in-$$ +local PERCOL_OUT=${PERCOL_TMP_DIR}/percol-channel-out-$$ +function _percol_create_fifo() { + [ -p $PERCOL_IN ] || { command rm -f $PERCOL_IN; mkfifo -m 600 $PERCOL_IN } + [ -p $PERCOL_OUT ] || { command rm -f $PERCOL_OUT; mkfifo -m 600 $PERCOL_OUT } +} +function _percol_clean_fifos() { + command rm -f $PERCOL_IN + command rm -f $PERCOL_OUT +} +trap _percol_clean_fifos EXIT SIGINT SIGTERM + +# ------------------------------------------------------------ # +# Arrange percol_popup on top of tmux +# ------------------------------------------------------------ # + +function _percol_popup_tmux() { + _percol_create_fifo + tmux split-window "percol $* < ${PERCOL_IN} > ${PERCOL_OUT}" +} + +function _percol_popup() { + INPUT=$1 + PERCOL_OPTION=$2 + if [[ -n $TMUX && -n $PERCOL_USE_TMUX ]]; then + eval "_percol_popup_tmux ${PERCOL_OPTION}; ${INPUT} > ${PERCOL_IN} &; cat ${PERCOL_OUT}" + else + eval "${INPUT} | percol ${(Q)PERCOL_OPTION}" + fi +} + +# ------------------------------------------------------------ # +# Common functions +# ------------------------------------------------------------ # + +# TODO: I'm not sure whether this process is proper or not +function _percol_clean_prompt() { + if [[ -n $TMUX ]]; then + zle reset-prompt + else + zle -R -c + fi +} + +function _percol_list_upper_directories() { + local dir_cursor + dir_cursor=$(dirname ${PWD}) + local dir_prefix="../../" + while [[ ${dir_cursor} != "/" ]]; do + echo ${dir_prefix}$(basename ${dir_cursor}) + dir_cursor=$(dirname ${dir_cursor}) + dir_prefix="../"${dir_prefix} + done + echo "/" +} + +function _percol_list_siblings() { + local mydirname=$(basename $PWD) + local parentdir=$(dirname $PWD) + find $parentdir -maxdepth 1 -type d ! -iname ".*" -printf "%f\n" | sed -n '/${mydirname}/!p' +} + +function _percol_get_destination_from_history() { + _percol_popup 'sort ${CD_HISTORY_FILE} | uniq -c | sort -r | \ + sed -e "s/^[ ]*[0-9]*[ ]*//" | \ + sed -e s"/^${HOME//\//\\/}/~/"' +} + +function _percol_go_to_repository_top() { + cd ./$(git rev-parse --show-cdup) + if [ $# = 1 ]; then + cd $1 + fi +} + +function _percol_get_repository_dir() { + _percol_go_to_repository_top > /dev/null; + destination=$(_percol_popup 'find . -path "*/.git" -prune -o -type d') + if [[ $destination != "" ]]; then + r > /dev/null + cd $destination > /dev/null + echo $PWD + else + echo "" + fi +} + +# ------------------------------------------------------------ # +# Define percol widgets +# ------------------------------------------------------------ # + +function percol_select_history() { + output=$(_percol_popup 'history -n 1 | _percol_tac' '--query \"${LBUFFER}\"') + + if [[ $output != "" ]]; then + BUFFER=$output + CURSOR=$#BUFFER + fi + + _percol_clean_prompt +} +zle -N percol_select_history + +function percol_cd_sibling() { + destination=$(_percol_popup "_percol_list_siblings") + if [[ $destination != "" ]]; then + cd $destination + fi + _percol_clean_prompt +} +zle -N percol_cd_sibling + +function percol_cd_upper_dirs() { + destination=$(_percol_popup "_percol_list_upper_directories") + if [[ $destination != "" ]]; then + cd $destination + fi + _percol_clean_prompt +} +zle -N percol_cd_upper_dirs + +function percol_insert_bookmark() { + local destination=$(_percol_get_destination_from_history) + if [ $? -eq 0 ]; then + local new_left="${LBUFFER} ${destination} " + BUFFER=${new_left}${RBUFFER} + CURSOR=${#new_left} + fi + _percol_clean_prompt +} +zle -N percol_insert_bookmark + +function percol_cd_bookmark() { + local destination=$(_percol_get_destination_from_history) + [ -n $destination ] && cd ${destination/#\~/${HOME}} + _percol_clean_prompt +} +zle -N percol_cd_bookmark + +function percol_insert_ls() { + local basedir + local left + basedir=$(echo ${LBUFFER} | perl -e ' =~ /((?:[^ ]|\\\\ )+)$/; print "$1";') + left=$(echo ${LBUFFER} | perl -e ' =~ /(.*)((?:[^ ]|\\\\ )+)$/; print "$1";') + + local destination + if [ -n $basedir ]; then + destination=$(\ls $basedir | percol) + else + destination=$(\ls | percol) + fi + if [ $? -eq 0 ]; then + local new_left="${left}${destination} " + BUFFER=${new_left}${RBUFFER} + CURSOR=${#new_left} + fi + _percol_clean_prompt +} +zle -N percol_insert_ls + +function percol_cd_repository() { + local destination + destination=$(_percol_get_repository_dir) + [[ $destination != "" ]] && cd ${destination} + _percol_clean_prompt +} +zle -N percol_cd_repository + +# ------------------------------------------------------------ +# Define useful commands +# ------------------------------------------------------------ + +function ppgrep() { + if [[ $1 == "" ]]; then + PERCOL=percol + else + PERCOL="percol --query $1" + fi + ps aux | eval $PERCOL | awk '{ print $2 }' +} + +function ppkill() { + if [[ $1 =~ "^-" ]]; then + QUERY="" # options only + else + QUERY=$1 # with a query + [[ $# > 0 ]] && shift + fi + ppgrep $QUERY | xargs kill $* +} +