git-extras.plugin.zsh
history-substring-search.zsh
per-directory-history.plugin.zsh
+ zaw.zsh
)
for file in $plugins; do
debug "PLUGIN: Trying to load ${file}"...
#k# search history and present a menu
bind2maps emacs vicmd -- -s "$key_info[Control]X$key_info[Control]X" history-beginning-search-menu
+#k# Trigger zsh anything.el
+if which zaw >/dev/null; then
+ bind2maps emacs viins -- -s "$key_info[Control]X;" zaw
+fi
+
#k# Insert files and test globbing
is4 && bind2maps emacs viins -- -s "$key_info[Control]Xf" insert-files
#k# Edit the current line in \kbd{\$EDITOR}
--- /dev/null
+Copyright (c) 2011, NAKAMURA Yoshitaka
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. Neither the name of the author nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+=================================
+zaw - zsh anything.el-like widget
+=================================
+
+install
+=======
+
+::
+
+ $ git clone git://github.com/zsh-users/zaw.git
+ remote: Counting objects: 136, done.
+ remote: Compressing objects: 100% (86/86), done.
+ remote: Total 136 (delta 43), reused 136 (delta 43)
+ Receiving objects: 100% (136/136), 23.68 KiB, done.
+ Resolving deltas: 100% (43/43), done.
+ $ echo "source ${PWD}/zaw/zaw.zsh" >> ~/.zshrc
+
+and restart zsh or manualy source ``zaw.zsh``.
+
+
+usage
+=====
+
+1. Trigger `zaw` by pressing ``Ctrl-x ;`` (``^x;``).
+2. select `source` and press ``enter``.
+3. filter items with zsh patterns separated by spaces, use ``^N``, ``^P`` and select one.
+4. execute action by pressing enter key or press ``Meta-enter`` for alternative action.
+
+ instead, press tab key and select action you want to execute.
+
+
+sources
+=======
+
+currently these sources are available:
+
+- aliases
+- applications
+- bookmark
+- cdr (needs cdr enabled. Google it or use `this packaged version <https://github.com/willghatch/zsh-cdr>`_)
+- commands
+- command-output
+- fasd
+- fasd-directories
+- fasd-files
+- functions
+- git-branches
+- git-recent-all-branches
+- git-recent-branches
+- git-files
+- git-files-legacy
+- git-log
+- git-reflog
+- git-status
+- history
+- locate
+- open-file
+- perldoc
+- process
+- programs
+- screens
+- searcher (ag/ack)
+- ssh-hosts
+- tmux
+- widgets
+
+(Note: git-files-legacy is an alternative for git-files.
+git-files classifies modified files, git-files-legacy doesn't do it for
+performance reason.)
+
+Additional sources can be installed as third-party plugins. Here is a list of all
+the ones we know about. Please let us know about any more you find or make!
+Installation is easiest with a plugin manager such as
+`zgen <https://github.com/tarjoilija/zgen>`_. Otherwise you can just source the
+.zsh file that contains the source.
+
+- calibre source: https://github.com/junkblocker/calibre-zaw-source
+- MPD source: https://github.com/willghatch/zsh-zaw-mpd
+- `pass <http://www.passwordstore.org>`_ source: https://gist.github.com/f440/9992963
+- systemd source: https://github.com/termoshtt/zaw-systemd
+- `todoman <https://github.com/hobarrera/todoman>`_ source: https://github.com/willghatch/zsh-zaw-todoman
+
+shortcut widgets
+================
+
+zaw automaticaly create shortcut widgets for each sources
+that directly access to the source.
+
+for example, execute ``bindkey '^R' zaw-history`` and
+press ``^R`` to access history source.
+
+you can get all available shortcut widgets' name using ``zaw-print-src``::
+
+ $ zaw-print-src
+ source name shortcut widget name
+ ----------------------------------------
+ ack zaw-ack
+ applications zaw-applications
+ bookmark zaw-bookmark
+ git-branches zaw-git-branches
+ git-recent-all-branches zaw-git-recent-all-branches
+ git-recent-branches zaw-git-recent-branches
+ git-files zaw-git-files
+ git-files-legacy zaw-git-files-legacy
+ git-status zaw-git-status
+ history zaw-history
+ open-file zaw-open-file
+ perldoc zaw-perldoc
+ process zaw-process
+ screens zaw-screens
+ ssh-hosts zaw-ssh-hosts
+ tmux zaw-tmux
+ fasd zaw-fasd
+ fasd-directories zaw-directories
+ fasd-files zaw-files
+
+
+key binds and styles
+====================
+
+zaw use ``filter-select`` to filter and select items.
+
+you can use these key binds::
+
+ enter: accept-line (execute default action)
+ meta + enter: accept-search (execute alternative action)
+ Tab: select-action
+ ^G: send-break
+ ^H, backspace: backward-delete-char
+ ^F, right key: forward-char
+ ^B, left key: backward-char
+ ^A: beginning-of-line
+ ^E: end-of-line
+ ^W: backward-kill-word
+ ^K: kill-line
+ ^U: kill-whole-line
+ ^N, down key: down-line-or-history (select next item)
+ ^P, up key: up-line-or-history (select previous item)
+ ^V, page up key: forward-word (page down)
+ ^[V, page down key: backward-word (page up)
+ ^[<, home key: beginning-of-history (select first item)
+ ^[>, end key: end-of-history (select last item)
+
+and these zstyles to customize styles::
+
+ ':filter-select:highlight' selected
+ ':filter-select:highlight' matched
+ ':filter-select:highlight' marked
+ ':filter-select:highlight' title
+ ':filter-select:highlight' error
+ ':filter-select' max-lines
+ ':filter-select' rotate-list
+ ':filter-select' case-insensitive
+ ':filter-select' extended-search
+ ':filter-select' hist-find-no-dups
+ ':filter-select' escape-descriptions
+
+ example:
+ zstyle ':filter-select:highlight' matched fg=yellow,standout
+ zstyle ':filter-select' max-lines 10 # use 10 lines for filter-select
+ zstyle ':filter-select' max-lines -10 # use $LINES - 10 for filter-select
+ zstyle ':filter-select' rotate-list yes # enable rotation for filter-select
+ zstyle ':filter-select' case-insensitive yes # enable case-insensitive search
+ zstyle ':filter-select' extended-search yes # see below
+ zstyle ':filter-select' hist-find-no-dups yes # ignore duplicates in history source
+ zstyle ':filter-select' escape-descriptions no # display literal newlines, not \n, etc
+
+ extended-search:
+ If this style set to be true value, the searching bahavior will be
+ extended as follows:
+
+ ^ Match the beginning of the line if the word begins with ^
+ $ Match the end of the line if the word ends with $
+ ! Match anything except the word following it if the word begins with !
+ so-called smartcase searching
+
+ If you want to search these metacharacters, please doubly escape them.
+
+environment variable
+====================
+
+ZAW_EDITOR editor command. If this variable is not set, use EDITOR value.
+ZAW_EDITOR_JUMP_PARAM open editor command with line params.
+ %LINE% is replaced by line number.
+ %FILE% is replaced by file path.
+ default +%LINE% %FILE%
+
+
+making sources
+==============
+
+If you want to make another source, please do! Look at https://github.com/termoshtt/zaw-systemd
+as an example of how to make a source repo. Note that it uses the <name>.plugin.zsh
+convention that plugin managers like zgen and antigen expect for its main file.
+The sources directory contains the files for the actual sources. All the sources
+in this repository's ``sources`` directory are good references as well for what
+the source files should look like. They tend to be quite simple.
+If your source requires any additional configuration or dependencies, be sure to
+list all of that in your project's README file.
+
+Let us know when you make new plugins so we can add them to our list!
+
+license
+=======
+
+BSD-3
--- /dev/null
+#
+# fill-vars-or-accept
+#
+
+# by default, pattern match "${:-variable_name}"
+FILL_VARS_PATTERN='${:-[a-z_][a-z0-9_]#}'
+
+function fill-vars-or-accept() {
+ # TODO: tab completion
+
+ local REPLY
+ local -a orig_region_highlight
+
+ if ! _buffer_has_vars; then
+ zle accept-line
+ fi
+
+ bindkey -N fillvars main
+ bindkey -M fillvars '^i' go-to-next-var
+
+ CURSOR=0
+
+ _get-current-var
+ if [[ -z "${REPLY}" ]]; then
+ go-to-next-var
+ fi
+
+ local POSTDISPLAY=$'\n''[press tab key to move cursor to next variable]'
+
+ while _buffer_has_vars && (( CURSOR < ${#BUFFER} )); do
+ orig_region_highlight=("${(@)region_highlight}")
+ _highlight-right-vars
+ zle -Rc
+ #zle -R '[press tab key to move next variable]'
+
+ zle read-command -K fillvars
+ reply="$?"
+ cmd_name="${REPLY}"
+
+ region_highlight=("${(@)orig_region_highlight}")
+
+ if [[ "${reply}" != 0 ]]; then
+ return 1
+ fi
+
+ if [[ "${cmd_name}" == accept* ]]; then
+ zle "${cmd_name}"
+ return
+
+ else
+ _get-current-var
+ if [[ -n "${REPLY}" ]]; then
+ if [[ "${cmd_name}" == self-insert* ]]; then
+ # remove current var
+ RBUFFER="${RBUFFER[$(( ${#REPLY} + 1)),-1]}"
+ elif [[ "${cmd_name}" == (*-delete-*|*-kill-*) ]]; then
+ # remove current var and continue
+ RBUFFER="${RBUFFER[$(( ${#REPLY} + 1)),-1]}"
+ continue
+ fi
+ fi
+ fi
+
+ zle "${cmd_name}"
+ done
+}
+
+function _highlight-right-vars() {
+ emulate -L zsh
+ setopt local_options extended_glob
+
+ local nl=$'\n' rbuffer="${RBUFFER}" REPLY
+ local -a match mbegin mend
+ integer offset="${#LBUFFER}"
+
+ if _buffer_has_vars; then
+ _get-current-var
+ if [[ -n "${REPLY}" ]]; then
+ region_highlight+=( "${offset} $(( offset + ${#REPLY} )) standout" )
+ rbuffer="${rbuffer[$(( ${#REPLY} )),-1]}"
+ (( offset += ${#REPLY} - 1 ))
+ fi
+
+ region_highlight+=( "${(f)${(S)rbuffer//*(#b)(${~FILL_VARS_PATTERN})/$(( offset + mbegin[1] - 1 )) $(( offset + mend[1] )) fg=yellow,standout${nl}}%$nl*}" )
+ fi
+}
+
+function _buffer_has_vars() {
+ emulate -L zsh
+ setopt local_options extended_glob
+ [[ "${BUFFER}" == *${~FILL_VARS_PATTERN}* ]]
+}
+
+function go-to-next-var() {
+ emulate -L zsh
+ setopt local_options extended_glob
+
+ local -a match mbegin mend
+ local rrbuffer="${RBUFFER[2,-1]}"
+ if [[ "${rrbuffer}" == *${~FILL_VARS_PATTERN}* ]]; then
+ # to match shortest, use variable expantion
+ : "${(S)rrbuffer/*(#b)(${~FILL_VARS_PATTERN})}"
+ (( CURSOR += ${mbegin[1]} ))
+ else
+ (( CURSOR = ${#BUFFER} ))
+ fi
+}
+
+zle -N go-to-next-var
+
+function _get-current-var() {
+ emulate -L zsh
+ setopt local_options extended_glob
+
+ REPLY=""
+ if [[ "${RBUFFER}" == (#b)(${~FILL_VARS_PATTERN})* ]]; then
+ REPLY="${match[1]}"
+ fi
+}
+
+fill-vars-or-accept "$@"
--- /dev/null
+#
+# filter-select
+#
+# using filter-select, you can incrementaly filter candidate
+# and select one with ^N/^P keys.
+#
+# press enter for filter-select to update $reply and return 0,
+# press meta (alt) + enter to update $reply but return 1,
+# and press ^C or ^G not to update $reply and return 1.
+#
+# you can use ^@ to mark items. marked items are stored in $reply_marked.
+#
+# you can customize keybinds using bindkey command.
+# first, you call::
+#
+# autoload -U filter-select; filter-select -i
+#
+# to initialize `filterselect` keymap and then do like::
+#
+# bindkey -M filterselect '^E' accept-search
+#
+#
+# usage:
+# filter-select [-t title] [-A assoc-array-name]
+# [-d array-of-description] [-D assoc-array-of-descrption]
+# [-s initial-filter-contents]
+# [-n] [-r] [-m] [-e exit-zle-widget-name]... [--] [arg]...
+# filter-select -i
+#
+# -t title
+# title string displayed top of selection.
+#
+# -A assoc-array-name
+# name of associative array that contains candidates.
+# this option is designed to speed up history selection.
+#
+# -d array-of-description
+# name of array that contains each candidate's descriptions.
+# it is used to display and filter candidates.
+#
+# if not specified, copied from candidates.
+#
+# -s initial-filter-contents
+# initial contents of the filter buffer that users type into
+#
+# -n
+# assign a number to the description when -d is not specified
+#
+# -D assoc-array-of-descrption
+# same as ``-d`` but associative array.
+#
+# -r
+# reverse order.
+#
+# -m
+# enable mark feature
+#
+# -e exit-zle-widget-name
+# if keys bound to `exit-zle-widget-name` is pressed,
+# filter-select exits and set it's name to $reply[1].
+#
+# args
+# selection candidates.
+#
+# -i
+# only initialize `filterselect` keymaps.
+#
+#
+# default key binds in filterselect:
+# enter: accept-line (update $reply and return)
+# meta + enter: accept-search (update $reply but return 1)
+# ^G: send-break (return 0)
+# ^H, backspace: backward-delete-char
+# ^F, right key: forward-char
+# ^B, left key: backward-char
+# ^A: beginning-of-line
+# ^E: end-of-line
+# ^W: backward-kill-word
+# ^K: kill-line
+# ^U: kill-whole-line
+# ^N, down key: down-line-or-history (select next item)
+# ^P, up key: up-line-or-history (select previous item)
+# ^V, page up key: forward-word (page down)
+# ^[V, page down key: backward-word (page up)
+# ^[<, home key: beginning-of-history (select first item)
+# ^[>, end key: end-of-history (select last item)
+#
+# available zstyles:
+# ':filter-select:highlight' selected
+# ':filter-select:highlight' matched
+# ':filter-select:highlight' title
+# ':filter-select:highlight' error
+# ':filter-select' max-lines
+# ':filter-select' rotate-list
+# ':filter-select' case-insensitive
+# ':filter-select' extended-search
+#
+# example:
+# zstyle ':filter-select:highlight' matched fg=yellow,standout
+# zstyle ':filter-select' max-lines 10 # use 10 lines for filter-select
+# zstyle ':filter-select' max-lines -10 # use $LINES - 10 for filter-select
+# zstyle ':filter-select' rotate-list yes # enable rotation for filter-select
+# zstyle ':filter-select' case-insensitive yes # enable case-insensitive search
+# zstyle ':filter-select' extended-search yes # enable extended search regardless of the case-insensitive style
+#
+# extended-search:
+# If this style set to be true value, the searching bahavior will be
+# extended as follows:
+#
+# ^ Match the beginning of the line if the word begins with ^
+# $ Match the end of the line if the word ends with $
+# ! Match anything except the word following it if the word begins with !
+# so-called smartcase searching
+#
+# If you want to search these metacharacters, please doubly escape them.
+
+typeset -ga reply_marked
+
+function filter-select() {
+ emulate -L zsh
+ setopt local_options extended_glob
+
+ # save ZLE related variables
+ local orig_lbuffer="${LBUFFER}"
+ local orig_rbuffer="${RBUFFER}"
+ local orig_predisplay="${PREDISPLAY}"
+ local orig_postdisplay="${POSTDISPLAY}"
+ local -a orig_region_highlight words
+ orig_region_highlight=("${region_highlight[@]}")
+
+ local key cand lines selected cand_disp buffer_pre_zle last_buffer initbuffer=''
+ local opt pattern msg unused title='' exit_pattern nl=$'\n'
+ local selected_index mark_idx_disp hi start end spec
+ local desc desc_num desc_disp bounds
+
+ local -a displays matched_desc_keys match mbegin mend outs exit_wigdets
+ local -a init_region_highlight marked_lines
+ local -A candidates descriptions matched_descs
+
+ integer i bottom_lines cursor_line=1 display_head_line=1 cand_num disp_num ii num_desc
+ integer offset display_bottom_line selected_num rev=0 ret=0 enum=0
+ integer mark_idx markable=0 is_marked
+
+ local hi_selected hi_matched hi_marked hi_title hi_error
+ zstyle -s ':filter-select:highlight' selected hi_selected || hi_selected='standout'
+ zstyle -s ':filter-select:highlight' matched hi_matched || hi_matched='fg=magenta,underline'
+ zstyle -s ':filter-select:highlight' marked hi_marked || hi_marked='fg=blue,standout'
+ zstyle -s ':filter-select:highlight' title hi_title || hi_title='bold'
+ zstyle -s ':filter-select:highlight' error hi_error || hi_error='fg=white,bg=red'
+
+ integer max_lines
+ zstyle -s ':filter-select' max-lines max_lines || max_lines=0
+
+ local rotate_list
+ zstyle -b ':filter-select' rotate-list rotate_list
+
+ _filter-select-init-keybind
+
+ candidates=()
+ descriptions=()
+ exit_wigdets=(accept-line accept-search send-break)
+
+ while getopts 't:A:d:D:nrme:s:i' opt; do
+ case "${opt}" in
+ t)
+ title="${OPTARG}"
+ ;;
+ A)
+ # copy input assc array
+ candidates=("${(@kvP)${OPTARG}}")
+ ;;
+ d)
+ # copy input array
+ integer i=0
+ for desc in "${(@P)${OPTARG}}"; do
+ (( i++ ))
+ descriptions+=( $i "${desc}" )
+ done
+ ;;
+ D)
+ # copy input assc array
+ descriptions=("${(@kvP)${OPTARG}}")
+ ;;
+ n)
+ enum=1
+ ;;
+ r)
+ # reverse ordering
+ rev=1
+ ;;
+ m)
+ # can use set-mark-command
+ markable=1
+ ;;
+ e)
+ exit_wigdets+="${OPTARG}"
+ ;;
+ s)
+ initbuffer="${OPTARG}"
+ ;;
+ i)
+ # do nothing. only keybinds are initialized
+ return
+ esac
+ done
+
+ if (( OPTIND > 1 )); then
+ shift $(( OPTIND - 1 ))
+ fi
+ integer i=0
+ for cand in "$@"; do
+ (( i++ ))
+ candidates+=( $i "${cand}" )
+ done
+
+ if (( ${#descriptions} == 0 )); then
+ # copy candidates
+ descriptions=("${(@kv)candidates}")
+ # add number
+ if (( enum )); then
+ num_desc="${#descriptions}"
+ for i in {1.."$num_desc"}; do
+ if (( rev )); then
+ ii="$(($num_desc-$i+1))"
+ else
+ ii="$i"
+ fi
+ descriptions[$i]="${(r.5.)ii} ${descriptions[$i]}"
+ done
+ fi
+ fi
+
+ desc_num="${#descriptions}"
+ matched_desc_keys=("${(onk@)descriptions}")
+ if (( rev )); then
+ matched_desc_keys=("${(Oa@)matched_desc_keys}")
+ fi
+
+ key=''
+ bounds=''
+
+ # clear edit buffer
+ BUFFER="$initbuffer"
+
+ # display original edit buffer's contants as PREDISPLAY
+ PREDISPLAY="${orig_predisplay}${orig_lbuffer}${orig_rbuffer}${orig_postdisplay}${nl}"
+
+ # re-calculate region_highlight
+ init_region_highlight=()
+ for hi in "${(@)orig_region_highlight}"; do
+ if [[ "${hi}" == P* ]]; then
+ init_region_highlight+="${hi}"
+ else
+ print -r -- "${hi}" | read start end spec
+ init_region_highlight+="P$(( start + ${#orig_predisplay} )) $(( end + ${#orig_predisplay} )) $spec"
+ fi
+ done
+
+ # prompt for filter-select
+ PREDISPLAY+="filter: "
+
+ # clear strings displayed below the command line
+ zle -Rc
+
+ _filter-select-reset
+
+ exit_pattern="(${(j:|:)exit_wigdets})"
+
+ while [[ "${bounds}" != ${~exit_pattern} ]]; do
+ case "${bounds}" in
+ set-mark-command)
+ if (( markable )); then
+ # check if ${selected_index} is already in the marked_lines
+ if (( ${marked_lines[(ie)${selected_index}]} <= ${#marked_lines} )); then
+ # remove selected_index
+ marked_lines=("${(@)marked_lines:#${selected_index}}")
+ else
+ marked_lines+="${selected_index}"
+ fi
+ fi
+ ;;
+ *down-line-or-history)
+ (( cursor_line++ ))
+ ;;
+
+ *up-line-or-history)
+ (( cursor_line-- ))
+ ;;
+
+ *forward-word)
+ (( cursor_line += bottom_lines ))
+ ;;
+
+ *backward-word)
+ (( cursor_line -= bottom_lines ))
+ ;;
+
+ beginning-of-history)
+ (( cursor_line = 1 ))
+ (( display_head_line = 1 ))
+ ;;
+
+ end-of-history)
+ (( cursor_line = desc_num ))
+ ;;
+
+ self-insert|undefined-key)
+ LBUFFER="${LBUFFER}${key}"
+ _filter-select-reset
+ ;;
+
+ '')
+ # empty, initial state
+ ;;
+
+ *)
+ buffer_pre_zle="${BUFFER}"
+
+ zle "${bounds}"
+
+ if [[ "${BUFFER}" != "${buffer_pre_zle}" ]]; then
+ _filter-select-reset
+ fi
+ esac
+
+ if (( cursor_line < 1 )); then
+ (( display_head_line -= 1 - cursor_line ))
+ if (( display_head_line < 1 )); then
+ (( display_head_line = 1 ))
+ fi
+ if [[ $rotate_list == "yes" ]] && (( selected_num <= 1 )); then
+ (( cursor_line = bottom_lines ))
+ (( display_head_line = desc_num - bottom_lines + 1 ))
+ else
+ (( cursor_line = 1 ))
+ fi
+
+ elif (( bottom_lines == 0 )); then
+ (( display_head_line = 1 ))
+ (( cursor_line = 1 ))
+
+ elif (( cursor_line > bottom_lines )); then
+ (( display_head_line += cursor_line - bottom_lines ))
+ if (( display_head_line > desc_num - bottom_lines + 1 )); then
+ (( display_head_line = desc_num - bottom_lines + 1 ))
+ fi
+ if [[ $rotate_list == "yes" ]] && (( selected_num >= desc_num )); then
+ (( cursor_line = 1 ))
+ (( display_head_line = 1 ))
+ else
+ (( cursor_line = bottom_lines ))
+ fi
+ fi
+
+ if (( ! PENDING )); then
+ region_highlight=("${(@)init_region_highlight}")
+
+ displays=()
+ offset="${#BUFFER}"
+ if [[ -n "${title}" ]]; then
+ offset+=$(( 1 + ${#title} ))
+ fi
+
+ selected=""
+ selected_num=0
+
+ if [[ "${BUFFER}" != "${last_buffer}" ]]; then
+ if [[ -n "${BUFFER}" ]]; then
+ if _filter-select-buffer-words words; then
+ matched_descs=("${(kv@)descriptions}")
+ for pattern in $words; do
+ matched_descs=("${(kv@)matched_descs[(R)*${pattern}*]}")
+ done
+ matched_desc_keys=("${(onk@)matched_descs}")
+ else
+ matched_desc_keys=("${(onk@)descriptions}")
+ fi
+ else
+ matched_desc_keys=("${(onk@)descriptions}")
+ fi
+ if (( rev )); then
+ matched_desc_keys=("${(Oa@)matched_desc_keys}")
+ fi
+ last_buffer="${BUFFER}"
+ fi
+
+ # nums pattern matched
+ desc_num="${#matched_desc_keys}"
+
+ # nums displayed
+ disp_num=0
+
+ _filter-select-update-bottom-lines
+ display_bottom_line=$(( display_head_line + bottom_lines))
+
+ if (( desc_num )); then
+ for i in "${(@)matched_desc_keys[${display_head_line},$(( display_bottom_line - 1 ))]}"; do
+ (( disp_num++ ))
+ desc="${descriptions[$i]}"
+
+ desc_disp="${desc}"
+
+ if zstyle -T ':filter-select' escape-descriptions ; then
+ # escape \r\n\t\
+ desc_disp="${desc_disp//\\/\\\\}"
+ desc_disp="${desc_disp//$'\n'/\\n}"
+ desc_disp="${desc_disp//$'\r'/\\r}"
+ desc_disp="${desc_disp//$'\t'/\\t}"
+ fi
+
+ mark_idx="${marked_lines[(ie)${i}]}"
+ (( is_marked = mark_idx <= ${#marked_lines} ))
+
+ if (( is_marked )); then
+ mark_idx_disp=" (${mark_idx})"
+ else
+ mark_idx_disp=""
+ fi
+
+ if (( ${(m)#desc_disp} + ${#mark_idx_disp} > COLUMNS - 1 )); then
+ # strip long line
+ desc_disp="${(mr:$(( COLUMNS - ${#mark_idx_disp} - 6 )):::::)desc_disp} ...${mark_idx_disp}"
+ else
+ desc_disp="${desc_disp}${mark_idx_disp}"
+ fi
+
+ displays+="${desc_disp}"
+
+ if [[ -n "${BUFFER}" ]]; then
+ # highlight matched words
+ for pattern in \
+ "(${(j.|.)${(@M)words:#*'(#e)'}})" \
+ "(${(j.|.)${(@)words:#(\~*|*'(#e)')}})" ; do
+ if [[ "$pattern" != '()' ]]; then
+ region_highlight+=( "${(f)${(S)desc_disp//*(#b)${~pattern}/$(( offset + mbegin[1] )) $(( offset + mend[1] + 1 )) ${hi_matched}${nl}}%$nl*}" )
+ fi
+ done
+ fi
+
+ if (( is_marked )); then
+ region_highlight+="${offset} $(( offset + ${#desc_disp} - ${#mark_idx_disp} + 1 )) ${hi_marked}"
+ fi
+
+ if (( disp_num == cursor_line )); then
+ region_highlight+="${offset} $(( offset + ${#desc_disp} + 1 )) ${hi_selected}"
+ selected="${candidates[$i]}"
+ (( selected_num = display_head_line + disp_num - 1 ))
+ selected_index="${i}"
+ fi
+
+ (( offset += ${#desc_disp} + 1 )) # +1 -> \n
+ done
+ fi
+
+ POSTDISPLAY=$'\n'
+ if [[ -n "${title}" ]]; then
+ POSTDISPLAY+="${title}"$'\n'
+ region_highlight+="${#BUFFER} $(( ${#BUFFER} + ${#title} + 1 )) ${hi_title}"
+ fi
+
+ if (( ${#displays} == 0 )); then
+ if (( ${#candidates} == 0 )); then
+ msg='no candidate'
+ else
+ msg='pattern not found'
+ fi
+ POSTDISPLAY+="${msg}"
+ region_highlight+="${offset} $(( offset + ${#msg} + 1 )) ${hi_error}"
+ fi
+
+ POSTDISPLAY+="${(F)displays}"$'\n'"[${selected_num}/${desc_num}]"
+ zle -R
+
+ fi
+
+ _filter-select-read-keys
+
+ if [[ $? != 0 ]]; then
+ # maybe ^C
+ key=''
+ bounds=''
+ break
+ else
+ key="${reply}"
+ # TODO: key sequence
+ outs=("${(z)$( bindkey -M filterselect -- "${key}" )}")
+ # XXX: will $outs contains more than two values?
+ bounds="${outs[2]}"
+ fi
+ done
+
+ if [[ -z "${key}" && -z "${bounds}" ]]; then
+ # ^C
+ reply=()
+ reply_marked=()
+ ret=1
+
+ elif [[ "${bounds}" == send-break ]]; then
+ # ^G
+ reply=()
+ reply_marked=()
+ ret=1
+
+ elif (( ${#displays} == 0 )); then
+ # no candidate matches pattern (no candidate selected)
+ reply=()
+ reply_marked=()
+ ret=1
+
+ else
+ reply=("${bounds}" "${selected}")
+ reply_marked=()
+ if (( ${#marked_lines} > 0 )); then
+ for i in "${(@)marked_lines}"; do
+ reply_marked+="${candidates[${i}]}"
+ done
+ fi
+ ret=0
+ fi
+
+ LBUFFER="${orig_lbuffer}"
+ RBUFFER="${orig_rbuffer}"
+ PREDISPLAY="${orig_predisplay}"
+ POSTDISPLAY="${orig_postdisplay}"
+ region_highlight=("${orig_region_highlight[@]}")
+ zle -Rc
+ zle reset-prompt
+
+ return $ret
+}
+
+function _filter-select-update-lines() {
+ # XXX: this function override ${lines}
+ # that define as local in filter-select
+ # also use ${title}
+
+ local _tmp_postdisplay="${POSTDISPLAY}"
+ # to re-calculate ${BUFFERLINES}
+ if [[ -n "${title}" ]]; then
+ POSTDISPLAY="${title}"$'\n'
+ else
+ POSTDISPLAY=""
+ fi
+ zle -R
+
+ # lines that can be used to display candidates
+ # -1 for current/total number display area
+ (( lines = LINES - BUFFERLINES - 1 ))
+
+ POSTDISPLAY="${_tmp_postdisplay}"
+ zle -R
+}
+
+function _filter-select-update-bottom-lines() {
+ # cursor が移動できる一番下の行
+ # ${max_lines} か ${lines} か ${desc_num} の小さい方を使う
+ if (( max_lines > 0 && max_lines < lines )); then
+ (( bottom_lines = max_lines ))
+ elif (( max_lines < 0 )); then
+ (( bottom_lines = lines + max_lines ))
+ else
+ (( bottom_lines = lines ))
+ fi
+
+ if (( desc_num < bottom_lines )); then
+ (( bottom_lines = desc_num ))
+ fi
+
+ if (( bottom_lines < 1 )); then
+ (( bottom_lines = 1 ))
+ fi
+}
+
+function _filter-select-reset() {
+ display_head_line=1
+ cursor_line=1
+ _filter-select-update-lines
+ _filter-select-update-bottom-lines
+}
+
+function _filter-select-buffer-words() {
+ local place="$1"
+ local -a a
+ local MATCH MBEGIN MEND
+ # split into words using shell's command line parsing,
+ # unquote the words, remove duplicated,
+ # escape "(", ")", "[", "]" and "#" to avoid crash
+ # also escape "|" and "~"
+ a=("${(@)${(@Qu)${(z)BUFFER}}//(#m)[()[\]#\|~]/\\${MATCH}}")
+
+ if ! zstyle -t ':filter-select' extended-search ; then
+ if zstyle -t ':filter-select' case-insensitive; then
+ : ${(A)a::=(#i)${^a}}
+ fi
+ else
+ # remove single "\\", "!",
+ # "^" like the history-incremental-pattern-searches',
+ # and "!^".
+ : ${(A)a::=${a:#([\\!^]|'!^')}}
+
+ # escape "^" other than the beginning's
+ # unescape "\\^" one level
+ : ${(A)a::=${a//(#m)('^'~(#s)'^')/\\${MATCH}}}
+ : ${(A)a::=${a//(#m)'\\^'/${MATCH#\\}}}
+
+ # "!aoe" -> "~*aoe",
+ # ("a!oe" should be held on, the beginning's "!" only be considered)
+ # unescape "\\!" one level
+ : ${(A)a::=${a/(#m)(#s)\!?##/\~\*${MATCH#\!}}}
+ : ${(A)a::=${a//(#m)'\!'/${MATCH#\\}}} # XXX: not '\\!' though...
+
+ # "^abc" -> "(#s)abc",
+ # ("a^bc" should be held on, the beginning's "^" only be considered)
+ : ${(A)a::=${a/(#m)(#s)\^?##/(#s)${MATCH#\^}}}
+
+ # "xyz$" -> "xyz(#e)",
+ # ("x$yz" shoud be held on, the ending's "$" only be considered)
+ # unescape "\\$" one level
+ : ${(A)a::=${a/(#m)*[^\\]\$(#e)/${MATCH%\$}(#e)}}
+ : ${(A)a::=${a//(#m)'\$'/${MATCH#\\}}} # XXX: not '\\$' though...
+
+ # smartcase searching ("(#i)(#I)Search" searches case sensitively)
+ : ${(A)a::=${a/(#m)*[[:upper:]##]*/(#I)${MATCH}}}
+ : ${(A)a::=(#i)${^a}}
+
+ # make "~" to be at the beginning
+ #: ${(A)a::=${a/#(#b)('(#i)'('(#I)')#)'~'/\~${match[1]}}}
+ : ${(A)a::=${a/#'(#i)(#I)~'/\~(#i)(#I)}}
+ : ${(A)a::=${a/#'(#i)~'/\~(#i)}}
+
+ # fixup the '!^'; "~(#i)*\^" -> "~(#i)(#s)"
+ # (for example, "!^aoe" -> "~(#i)*\^aoe" -> "~(#i)(#s)aoe")
+ #: ${(A)a::=${a/#(#b)'~'('(#i)'('(#I)')#)'*\^'/\~${match[1]}(#s)}}
+ : ${(A)a::=${a/#'~(#i)(#I)*\^'/'~(#i)(#I)(#s)'}}
+ : ${(A)a::=${a/#'~(#i)*\^'/'~(#i)(#s)'}}
+ fi
+ : ${(PA)place::=$a}
+ (( ${#a} > 1 )) || (( ${#a} == 1 )) && [[ -n "$a" ]]
+}
+
+function _filter-select-init-keybind() {
+ integer fd ret
+
+ # be quiet and check filterselect keybind defined
+ exec {fd}>&2 2>/dev/null
+ bindkey -l filterselect > /dev/null
+ ret=$?
+ exec 2>&${fd} {fd}>&-
+
+ if (( ret != 0 )); then
+ bindkey -N filterselect
+
+ bindkey -M filterselect '^J' accept-line
+ bindkey -M filterselect '^M' accept-line
+ bindkey -M filterselect '\e^J' accept-search
+ bindkey -M filterselect '\e^M' accept-search
+
+ bindkey -M filterselect '\e^G' send-break
+ bindkey -M filterselect '^G' send-break
+
+ bindkey -M filterselect '^@' set-mark-command
+
+ bindkey -M filterselect '^H' backward-delete-char
+ bindkey -M filterselect '^?' backward-delete-char
+
+ bindkey -M filterselect '^F' forward-char
+ bindkey -M filterselect '\e[C' forward-char
+ bindkey -M filterselect '\eOC' forward-char
+
+ bindkey -M filterselect '^B' backward-char
+ bindkey -M filterselect '\e[D' backward-char
+ bindkey -M filterselect '\eOD' backward-char
+
+ bindkey -M filterselect '^A' beginning-of-line
+ bindkey -M filterselect '^E' end-of-line
+
+ bindkey -M filterselect '^W' backward-kill-word
+ bindkey -M filterselect '^K' kill-line
+ bindkey -M filterselect '^U' kill-whole-line
+
+ # move cursor down/up
+ bindkey -M filterselect '^N' down-line-or-history
+ bindkey -M filterselect '\e[B' down-line-or-history
+ bindkey -M filterselect '\eOB' down-line-or-history
+ bindkey -M filterselect '^P' up-line-or-history
+ bindkey -M filterselect '\e[A' up-line-or-history
+ bindkey -M filterselect '\eOA' up-line-or-history
+
+ # page down/up
+ bindkey -M filterselect '^V' forward-word
+ bindkey -M filterselect '\e[6~' forward-word
+
+ bindkey -M filterselect '\eV' backward-word
+ bindkey -M filterselect '\ev' backward-word
+ bindkey -M filterselect '\e[5~' backward-word
+
+ # home/end
+ bindkey -M filterselect '\e<' beginning-of-history
+ bindkey -M filterselect '\e[1~' beginning-of-history
+
+ bindkey -M filterselect '\e>' end-of-history
+ bindkey -M filterselect '\e[4~' end-of-history
+ fi
+}
+
+function _filter-select-read-keys() {
+ local key key2 key3 nkey
+ integer ret
+
+ read -k key
+ ret=$?
+ reply="${key}"
+ if [[ '#key' -eq '#\\e' ]]; then
+ # M-...
+ read -t $(( KEYTIMEOUT / 1000 )) -k key2
+ if [[ "${key2}" == 'O' ]]; then
+ # ^[O (SS3) affects next character only.
+ # Example: cursor keys on some terminals.
+ read -k key3
+ ret=$?
+ reply="${key}${key2}${key3}"
+ else
+ if [[ "${key2}" == '[' ]]; then
+ # ^[[ (CSI) starts a sequence of [0-9;?] terminated by [@-~].
+ # Examples: Home, End, PgUp, PgDn ...
+ reply="${key}${key2}"
+ while true; do
+ read -k nkey
+ reply+=$nkey
+ ret=$?
+ (( $ret == 0 )) && [[ "${nkey}" =~ '^[0-9;?]$' ]] || break
+ done
+ else
+ reply="${key}${key2}"
+ fi
+ fi
+ else
+ reply="${key}"
+ fi
+ return $ret
+}
+
+filter-select "$@"
--- /dev/null
+function zaw-src-aliases() {
+ candidates=($(alias | cut -d '=' -f 1))
+ actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer view-alias-pager)
+ act_descriptions=("execute" "append to buffer" "replace buffer" "view alias")
+}
+
+view-alias-pager() {
+ alias $1 | ${PAGER:-less}
+}
+
+zaw-register-src -n aliases zaw-src-aliases
--- /dev/null
+#
+# zaw-src-applications
+#
+# zaw source for desktop applications
+#
+
+function zaw-src-applications() {
+ emulate -L zsh
+ setopt local_options extended_glob null_glob
+
+ case "$OSTYPE" in
+ [Dd]arwin*)
+ candidates=( )
+ # Use the spotlight index to get application paths
+ (( ${+commands[mdfind]} )) && \
+ candidates+=(${(f)"$(mdfind -onlyin / 'kMDItemKind == "Application"' 2>/dev/null)"})
+
+ # Use locate if available and no output from spotlight or if forced use by ZAW_SRC_APPLICATIONS_USE_LOCATE
+ if (( ${+commands[locate]} )) && [ -n "$ZAW_SRC_APPLICATIONS_USE_LOCATE" -o ${#candidates} -eq 0 ]; then
+ # Apps inside apps are not normally useful
+ if [ -n "$ZAW_SRC_APPLICATIONS_INTERNAL_APPS_OK" ]; then
+ candidates+=(${(f)"$(locate -i '*.app' 2>/dev/null)"})
+ elif [ ${+commands[grep]} -eq 1 ]; then
+ candidates+=(${(f)"$((locate -i '*.app' | grep -iv '\.app/') 2>/dev/null)"})
+ fi
+ fi
+
+ # Glob common locations anyway since both of previous indexes may
+ # be stale or non-existent
+ candidates+=({,~}/Applications{,/Utilities}/*.app(N^M) /System/Library/CoreServices/*.app(N^M))
+
+ candidates=(${(iou)candidates[@]})
+ actions=("zaw-callback-launch-macapp" "zaw-callback-append-to-buffer")
+ act_descriptions=("execute application" "append to edit buffer")
+ ;;
+ [Ll]inux*|*[Bb][Ss][Dd]*|[Ss]olaris*|[Ss]un[Oo][Ss]*)
+ local d
+ local -a match mbegin mend
+ for d in /usr/share/applications/*.desktop; do
+ local name="" comment="" exec_="" terminal=0 no_display=0
+ while read line; do
+ case "${line}" in
+ Name=(#b)(*))
+ name="${match[1]}"
+ ;;
+ Comment=(#b)(*))
+ comment="${match[1]}"
+ ;;
+ Exec=(#b)(*))
+ exec_="${match[1]}"
+ ;;
+ Terminal=true)
+ terminal=1
+ ;;
+
+ NoDisplay=true)
+ no_display=1
+ ;;
+ esac
+ done < "${d}"
+
+ if (( no_display )); then
+ continue
+ fi
+
+ # TODO: % expansion in $exec_
+ # remove args that match %* from $exec_
+ exec_="${(@m)${(z)exec_}:#%*}"
+
+ if ! (( terminal )); then
+ # disown
+ exec_="${exec_} &!"
+ fi
+
+ candidates+=( "${exec_}" )
+ cand_descriptions+=( "${name} - ${comment}" )
+ done
+ actions=("zaw-callback-execute" "zaw-callback-append-to-buffer")
+ act_descriptions=("execute application" "append to edit buffer")
+ ;;
+ *)
+ # Unsupported OS
+ candidates=( )
+ actions=("zaw-callback-execute" "zaw-callback-append-to-buffer")
+ act_descriptions=("execute application" "append to edit buffer")
+ ;;
+ esac
+
+}
+
+function zaw-callback-launch-macapp() {
+ BUFFER="open -a \"${(j:; :)@}\""
+ zle accept-line
+}
+
+zaw-register-src -n applications zaw-src-applications
--- /dev/null
+#
+# zaw-src-bookmark
+#
+# bookmark your favorite command lines, access it using zaw interface.
+# you can bookmark command line using zaw-history's `bookmark this command line` action,
+# or bind some key to ``zaw-bookmark-add-buffer`` and use it.
+#
+
+zmodload zsh/system
+autoload -U fill-vars-or-accept
+
+typeset -g BOOKMARKFILE="${BOOKMARKFILE:-"${HOME}/.zaw-bookmarks"}"
+
+function zaw-src-bookmark() {
+ if [[ -f "${BOOKMARKFILE}" ]]; then
+ candidates=("${(Qf)$(zsystem flock -r "${BOOKMARKFILE}" && < "${BOOKMARKFILE}")}")
+ fi
+ actions=("zaw-bookmark-execute" "zaw-callback-replace-buffer" "zaw-callback-append-to-buffer" "zaw-bookmark-remove")
+ act_descriptions=("execute" "replace edit buffer" "append to edit buffer" "removed bookmark")
+ options=("-m")
+}
+
+zaw-register-src -n bookmark zaw-src-bookmark
+
+
+#
+# helper functions for bookmark
+#
+
+function zaw-bookmark-execute() {
+ zaw-callback-replace-buffer "$@"
+ fill-vars-or-accept
+}
+
+function zaw-bookmark-add() {
+ local -a bookmarks
+
+ : >>| "${BOOKMARKFILE}"
+ (
+ if zsystem flock -t 5 "${BOOKMARKFILE}"; then
+ bookmarks=("${(f)$(< "${BOOKMARKFILE}")}" "${(q@)@}")
+
+ # remove empty lines
+ bookmarks=("${(@)bookmarks:#}")
+
+ # remove duplicated lines, sort and write to ${BOOKMARKFILE}
+ print -rl -- "${(@un)bookmarks}" >| "${BOOKMARKFILE}"
+ else
+ print "can't acquire lock for '${BOOKMARKFILE}'" >&2
+ exit 1
+ fi
+ )
+
+ if [[ $? == 0 ]]; then
+ zle -M "bookmark '${(j:', ':)@}'"
+ fi
+}
+
+function zaw-bookmark-add-buffer() {
+ zaw-bookmark-add "${BUFFER}"
+}
+
+zle -N zaw-bookmark-add-buffer
+
+function zaw-bookmark-remove() {
+ local s
+ local -a bookmarks
+
+ : >>| "${BOOKMARKFILE}"
+ (
+ if zsystem flock -t 5 "${BOOKMARKFILE}"; then
+ bookmarks=("${(f)$(< "${BOOKMARKFILE}")}")
+ for s in "${(q@)@}"; do
+ bookmarks=("${(@)bookmarks:#${s}}")
+ done
+
+ # remove duplicated lines, sort and write to ${BOOKMARKFILE}
+ print -rl -- "${(@un)bookmarks}" >| "${BOOKMARKFILE}"
+ else
+ print "can't acquire lock for '${BOOKMARKFILE}'" >&2
+ exit 1
+ fi
+ )
+
+ if [[ $? == 0 ]]; then
+ zle -M "bookmark '${(j:', ':)@}' removed"
+ fi
+}
+
+function zaw-bookmark-remove-buffer() {
+ zaw-bookmark-remove "${BUFFER}"
+}
+
+zle -N zaw-bookmark-remove-buffer
--- /dev/null
+#
+# zaw-src-cdr
+#
+# zaw source for recent directories
+#
+
+(( $+functions[cdr] )) || return
+
+function zaw-src-cdr () {
+ setopt local_options extended_glob
+ : ${(A)candidates::=${${(f)"$(cdr -l)"}##<-> ##}}
+ actions=(zaw-src-cdr-cd zaw-src-cdr-insert zaw-src-cdr-prune)
+ act_descriptions=("cd" "insert" "prune")
+ options=("-m" "-s" "${BUFFER##cd(r|) }")
+}
+
+function zaw-src-cdr-cd () {
+ BUFFER="cd $1"
+ zle accept-line
+}
+
+function zaw-src-cdr-insert () {
+ [[ -z "$LBUFFER" ]] || LBUFFER+=" "
+ [[ "$LBUFFER[-1]" == " " ]] || LBUFFER+=" "
+ LBUFFER+="${(j. .)@}"
+}
+
+function zaw-src-cdr-prune () {
+ local -aU reply
+ autoload -Uz chpwd_recent_filehandler
+ chpwd_recent_filehandler
+ : ${(A)reply::=${reply:#(${(~j.|.)${~@}})}}
+ chpwd_recent_filehandler $reply
+}
+
+zaw-register-src -n cdr zaw-src-cdr
--- /dev/null
+# zaw source for locate
+
+autoload -U read-from-minibuffer
+
+function zaw-src-command-output() {
+ local buf
+ read-from-minibuffer "command: "
+ buf=$(${(Q@)${(z)REPLY}})
+ if [[ $? != 0 ]]; then
+ return 1
+ fi
+ : ${(A)candidates::=${(f)buf}}
+ : ${(A)cand_descriptions::=${(f)buf}}
+ actions=( zaw-callback-append-to-buffer )
+ act_descriptions=( "append to buffer" )
+}
+
+zaw-register-src -n command-output zaw-src-command-output
+
--- /dev/null
+function zaw-src-commands() {
+ # fill the command hash
+ hash -r
+ hash -f
+ candidates=($(hash | cut -d '=' -f 1))
+ candidates+=($(alias | cut -d '=' -f 1))
+ candidates+=($(print -l ${(ok)functions}))
+ actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer)
+ act_descriptions=("execute" "append to buffer" "replace buffer")
+}
+
+zaw-register-src -n commands zaw-src-commands
--- /dev/null
+function zaw-src-fasd () {
+ candidates=($(fasd -alR))
+ actions=(zaw-callback-append-to-buffer)
+ act_descriptions=("append to edit buffer")
+ options+=(-n -m)
+}
+
+
+function zaw-src-fasd-files () {
+ candidates=($(fasd -flR))
+ actions=(zaw-callback-append-to-buffer)
+ act_descriptions=("append to edit buffer")
+ options+=(-n -m)
+}
+
+
+function zaw-src-fasd-directories () {
+ candidates=($(fasd -dlR))
+ actions=(zaw-callback-append-to-buffer)
+ act_descriptions=("append to edit buffer")
+ options+=(-n -m)
+}
+
+
+zaw-register-src -n fasd zaw-src-fasd
+zaw-register-src -n fasd-directories zaw-src-fasd-directories
+zaw-register-src -n fasd-files zaw-src-fasd-files
--- /dev/null
+function zaw-src-functions() {
+ candidates=($(print -l ${(ok)functions}))
+ actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer functions)
+ act_descriptions=("call function" "append to buffer" "replace buffer" "view source")
+}
+
+zaw-register-src -n functions zaw-src-functions
--- /dev/null
+# zaw source for git branch
+
+function zaw-src-git-branches() {
+ git rev-parse --git-dir >/dev/null 2>&1
+ if [[ $? == 0 ]]; then
+ local branches_list="$(git show-ref | awk ' $2 != "refs/stash" { print $2 }' )"
+ : ${(A)candidates::=${${(f)${branches_list}}#refs/}}
+ : ${(A)cand_descriptions::=${${(f)${branches_list}}#refs/(remotes|heads|tags)/}}
+ fi
+ actions=( \
+ zaw-src-git-branches-checkout \
+ zaw-src-git-branches-simple-checkout \
+ zaw-callback-append-to-buffer \
+ zaw-src-git-branches-merge \
+ zaw-src-git-branches-merge-rebase \
+ zaw-src-git-branches-merge-no-ff \
+ zaw-src-git-branches-merge-to \
+ zaw-src-git-branches-reset \
+ zaw-src-git-branches-rebase \
+ zaw-src-git-branches-rebase-interactive \
+ zaw-src-git-branches-create \
+ zaw-src-git-branches-diff \
+ zaw-src-git-branches-diff-stat \
+ zaw-src-git-branches-reset-hard \
+ zaw-src-git-branches-delete \
+ zaw-src-git-branches-delete-force)
+ act_descriptions=(
+ "check out locally" \
+ "check out" \
+ "append to edit buffer" \
+ "merge" \
+ "merge rebase" \
+ "merge no ff" \
+ "merge to" \
+ "reset" \
+ "rebase" \
+ "rebase interactive from..." \
+ "create new branch from..." \
+ "diff" \
+ "diff statistics" \
+ "reset hard" \
+ "delete" \
+ "delete force")
+ options=()
+}
+
+function zaw-src-git-branches-checkout () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ case "$b_type" in
+ "heads"|"tags")
+ BUFFER="git checkout $b_name"
+ zle accept-line
+ ;;
+ "remotes")
+ BUFFER="git checkout -t $b_name"
+ zle accept-line
+ ;;
+ esac
+}
+
+function zaw-src-git-branches-simple-checkout () {
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git checkout $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-create () {
+ local b_name=${1#(heads|remotes|tags)/}
+ LBUFFER="git checkout -b "
+ RBUFFER=" $b_name"
+}
+
+function zaw-src-git-branches-merge () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git merge $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-merge-rebase () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git merge --rebase $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-merge-no-ff () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git merge --no-ff $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-merge-to () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ local b_now=${$(git symbolic-ref HEAD)#refs/heads/}
+ if [[ "$b_type" == "heads" ]]; then
+ BUFFER="git checkout $b_name && git merge --no-ff $b_now"
+ zle accept-line
+ fi
+}
+
+function zaw-src-git-branches-reset () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git reset $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-diff() {
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git diff $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-diff-stat() {
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git diff --stat $b_name"
+}
+
+function zaw-src-git-branches-reset-hard () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git reset --hard $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-rebase () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git rebase $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-rebase-interactive () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git rebase -i $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-delete () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ if [[ "$b_type" == "heads" ]] ; then
+ BUFFER="git branch -d $b_name"
+ zle accept-line
+ elif [[ "$b_type" == "remotes" ]] ; then
+ local b_loc=${b_name%%/*}
+ local b_base=${b_name#$b_loc/}
+ BUFFER="git push $b_loc :$b_base"
+ zle accept-line
+ fi
+}
+
+function zaw-src-git-branches-delete-force () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ if [[ "$b_type" == "heads" ]] ; then
+ BUFFER="git branch -D $b_name"
+ zle accept-line
+ elif [[ "$b_type" == "remotes" ]] ; then
+ local b_loc=${b_name%%/*}
+ local b_base=${b_name#$b_loc/}
+ BUFFER="git push $b_loc :$b_base"
+ zle accept-line
+ fi
+}
+
+zaw-register-src -n git-branches zaw-src-git-branches
--- /dev/null
+# zaw source for git files
+
+function zaw-src-git-files-raw() {
+ local ret=0
+ git rev-parse --git-dir >/dev/null 2>&1
+ ret=$?
+ if (( ret != 0 )); then
+ return ret
+ fi
+
+ "$1"
+ ret=$?
+ if (( ret != 0 )); then
+ return ret
+ fi
+
+ actions=(zaw-callback-edit-file zaw-src-git-status-add zaw-src-git-status-add-p zaw-src-git-status-reset zaw-src-git-status-checkout zaw-src-git-status-rm zaw-callback-append-to-buffer)
+ act_descriptions=("edit file" "add" "add -p" "reset" "checkout" "rm" "append to edit buffer")
+ options=(-m -n)
+ return 0
+}
+
+function zaw-src-git-files-classify-aux() {
+ local -a as ms ds os
+ : ${(A)as::=${(0)"$(git ls-files $(git rev-parse --show-cdup) -z)"}}
+ : ${(A)ms::=${(0)"$(git ls-files $(git rev-parse --show-cdup) -z -m)"}}
+ if (( ${#ms} == 0 )) || (( ${#ms} == 1 )) && [[ -z "$ms" ]]; then
+ candidates=($as)
+ return 0
+ fi
+
+ if is-at-least 5.0.0 || [[ -n "${ZSH_PATCHLEVEL-}" ]] && \
+ is-at-least 1.5637 "$ZSH_PATCHLEVEL"; then
+ os=(${as:|ms})
+ else
+ os=(${as:#(${(~j.|.)ms})}) # TODO: too slower for large work tree
+ fi
+ candidates=($ms $os)
+
+ : ${(A)ds::=${ms/%/ MODIFIED}}
+ ds+=($os)
+ cand_descriptions=($ds)
+ return 0
+}
+
+function zaw-src-git-files-legacy-aux() {
+ : ${(A)candidates::=${(0)"$(git ls-files $(git rev-parse --show-cdup) -z)"}}
+ return 0
+}
+
+function zaw-src-git-files-add () {
+ BUFFER="git add $1"
+ zle accept-line
+}
+
+{
+ function zaw-src-git-files-register-src() {
+ eval "function $2 () { zaw-src-git-files-raw "$3" }"
+ zaw-register-src -n "$1" "$2"
+ }
+ zaw-src-git-files-register-src git-files zaw-src-git-files zaw-src-git-files-classify-aux
+ zaw-src-git-files-register-src git-files-legacy zaw-src-git-files-legacy{,-aux}
+} always {
+ unfunction zaw-src-git-files-register-src
+}
--- /dev/null
+
+function zaw-src-git-log() {
+ git rev-parse --git-dir >/dev/null 2>&1
+ if [[ $? == 0 ]]; then
+ local desc="$(git log --all --graph --decorate --oneline --no-color)"
+
+ : ${(A)cand_descriptions::=${(f)desc}}
+ : ${(A)candidates::=${(f)desc}}
+ fi
+ actions=(zaw-src-git-log-insert \
+ zaw-src-git-log-reset \
+ zaw-src-git-log-reset-hard \
+ zaw-src-git-log-cherry-pick \
+ zaw-src-git-log-create-branch \
+ zaw-src-git-log-revert)
+ act_descriptions=("insert" \
+ "reset" \
+ "reset --hard" \
+ "cherry-pick" \
+ "create new branch from this hash value" \
+ "revert")
+ options=()
+}
+
+function _zaw-src-git-log-strip(){
+ echo $1 | sed -e 's/^[*|/\\ ]* \([a-f0-9]*\) .*/\1/'
+}
+
+function zaw-src-git-log-insert(){
+ local hash_val=$(_zaw-src-git-log-strip $1)
+ zaw-callback-append-to-buffer $hash_val
+}
+
+function zaw-src-git-log-reset(){
+ local hash_val=$(_zaw-src-git-log-strip $1)
+ BUFFER="git reset $hash_val"
+ zle accept-line
+}
+
+function zaw-src-git-log-reset-hard(){
+ local hash_val=$(_zaw-src-git-log-strip $1)
+ BUFFER="git reset --hard $hash_val"
+ zle accept-line
+}
+
+function zaw-src-git-log-cherry-pick(){
+ local hash_val=$(_zaw-src-git-log-strip $1)
+ BUFFER="git cherry-pick $hash_val"
+ zle accept-line
+}
+
+function zaw-src-git-log-create-branch(){
+ local hash_val=$(_zaw-src-git-log-strip $1)
+ LBUFFER="git checkout -b "
+ RBUFFER=" $hash_val"
+}
+
+function zaw-src-git-log-revert(){
+ local hash_val=$(_zaw-src-git-log-strip $1)
+ BUFFER="git revert $hash_val"
+ zle accept-line
+}
+
+zaw-register-src -n git-log zaw-src-git-log
--- /dev/null
+# zaw source for git branches sorted by commit date
+
+function zaw-src-git-recent-branches () {
+ git rev-parse --git-dir >/dev/null 2>&1
+ if [[ $? == 0 ]]; then
+ local branches="$(git for-each-ref --format='%(refname)' --sort=-committerdate refs/heads)"
+ : ${(A)candidates::=${${(f)${branches}}#refs/}}
+ : ${(A)cand_descriptions::=${${(f)${branches}}#refs/(remotes|heads|tags)/}}
+ fi
+
+ actions=( \
+ zaw-src-git-branches-checkout \
+ zaw-src-git-branches-simple-checkout \
+ zaw-callback-append-to-buffer \
+ zaw-src-git-branches-merge \
+ zaw-src-git-branches-merge-rebase \
+ zaw-src-git-branches-merge-no-ff \
+ zaw-src-git-branches-diff \
+ zaw-src-git-branches-diff-stat \
+ zaw-src-git-branches-reset \
+ zaw-src-git-branches-rebase \
+ zaw-src-git-branches-rebase-interactive \
+ zaw-src-git-branches-create \
+ zaw-src-git-branches-reset-hard \
+ zaw-src-git-branches-delete \
+ zaw-src-git-branches-delete-force)
+ act_descriptions=(
+ "check out locally" \
+ "check out" \
+ "append to edit buffer" \
+ "merge" \
+ "merge rebase" \
+ "merge no ff" \
+ "diff" \
+ "diff stat" \
+ "reset" \
+ "rebase" \
+ "rebase interactive from..." \
+ "create new branch from..." \
+ "reset hard" \
+ "delete" \
+ "delete force")
+ options=()
+}
+
+function zaw-src-git-recent-all-branches () {
+ git rev-parse --git-dir >/dev/null 2>&1
+ if [[ $? == 0 ]]; then
+ local branches="$(git for-each-ref --format='%(refname)' --sort=-committerdate refs/heads refs/remotes)"
+ : ${(A)candidates::=${${(f)${branches}}#refs/}}
+ : ${(A)cand_descriptions::=${${(f)${branches}}#refs/(remotes|heads|tags)/}}
+ fi
+
+ actions=( \
+ zaw-src-git-branches-checkout \
+ zaw-src-git-branches-simple-checkout \
+ zaw-callback-append-to-buffer \
+ zaw-src-git-branches-merge \
+ zaw-src-git-branches-merge-rebase \
+ zaw-src-git-branches-merge-no-ff \
+ zaw-src-git-branches-diff \
+ zaw-src-git-branches-diff-stat \
+ zaw-src-git-branches-reset \
+ zaw-src-git-branches-rebase \
+ zaw-src-git-branches-rebase-interactive \
+ zaw-src-git-branches-create \
+ zaw-src-git-branches-reset-hard \
+ zaw-src-git-branches-delete \
+ zaw-src-git-branches-delete-force)
+ act_descriptions=(
+ "check out locally" \
+ "check out" \
+ "append to edit buffer" \
+ "merge" \
+ "merge rebase" \
+ "merge no ff" \
+ "diff" \
+ "diff stat" \
+ "reset" \
+ "rebase" \
+ "rebase interactive from..." \
+ "create new branch from..." \
+ "reset hard" \
+ "delete" \
+ "delete force")
+ options=()
+}
+
+function zaw-src-git-recent-branches-checkout () {
+ local b_type=${1%%/*}
+ local b_name=${1#(heads|remotes|tags)/}
+ case "$b_type" in
+ "heads"|"tags")
+ BUFFER="git checkout $b_name"
+ zle accept-line
+ ;;
+ "remotes")
+ BUFFER="git checkout -t $b_name"
+ zle accept-line
+ ;;
+ esac
+}
+
+function zaw-src-git-branches-diff() {
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git diff $b_name"
+ zle accept-line
+}
+
+function zaw-src-git-branches-diff-stat() {
+ local b_name=${1#(heads|remotes|tags)/}
+ BUFFER="git diff --stat $b_name"
+ zle accept-line
+}
+
+zaw-register-src -n git-recent-branches zaw-src-git-recent-branches
+zaw-register-src -n git-recent-all-branches zaw-src-git-recent-all-branches
--- /dev/null
+function zaw-src-git-reflog () {
+ git rev-parse --git-dir >/dev/null 2>&1
+ if [[ $? == 0 ]]; then
+ git reflog | \
+ while read id desc; do
+ candidates+=("${id}")
+ cand_descriptions+=("${id} ${desc}")
+ done
+ fi
+ actions=(zaw-callback-append-to-buffer zaw-src-git-commit-checkout zaw-src-git-commit-reset zaw-src-git-commit-rebase zaw-src-git-commit-rebase-interactive zaw-src-git-commit-reset-hard)
+ act_descriptions=("append to edit buffer" "checkout" "reset" "rebase" "rebase interactive from..." "reset hard")
+ options=()
+}
+
+function zaw-src-git-commit-checkout () {
+ BUFFER="git checkout $1"
+ zle accept-line
+}
+
+function zaw-src-git-commit-reset () {
+ BUFFER="git reset $1"
+ zle accept-line
+}
+
+function zaw-src-git-commit-reset-hard () {
+ BUFFER="git reset --hard $1"
+ zle accept-line
+}
+
+function zaw-src-git-commit-rebase () {
+ BUFFER="git rebase $1"
+ zle accept-line
+}
+
+function zaw-src-git-commit-rebase-interactive () {
+ BUFFER="git rebase -i $1"
+ zle accept-line
+}
+
+zaw-register-src -n git-reflog zaw-src-git-reflog
--- /dev/null
+function zaw-src-git-status() {
+ git rev-parse --git-dir >/dev/null 2>&1
+ if [[ $? == 0 ]]; then
+ local file_list="$(git status --porcelain)"
+ : ${(A)candidates::=${(f)${file_list}}}
+
+ : ${(A)cand_descriptions::=${${(f)${file_list}}/ M /[modified] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/AM /[add|modified] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/MM /[staged|modified] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/M /[staged] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/A /[staged(add)] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/ D /[deleted] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/UU /[conflict] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/AA /[conflict] }}
+ : ${(A)cand_descriptions::=${${(M)cand_descriptions}/\?\? /[untracked] }}
+
+ fi
+
+ actions=( \
+ zaw-src-git-status-add \
+ zaw-src-git-status-add-p \
+ zaw-src-git-status-reset \
+ zaw-src-git-status-checkout \
+ zaw-src-git-status-edit \
+ zaw-src-git-status-rm)
+ act_descriptions=( \
+ "add" \
+ "add -p" \
+ "reset" \
+ "checkout" \
+ "edit" \
+ "rm")
+ options=()
+}
+
+function zaw-src-git-status-add() {
+ local f_path=${1##?* }
+ local git_base="$(git rev-parse --show-cdup)"
+ BUFFER="git add '$git_base$f_path'"
+ zle accept-line
+}
+
+function zaw-src-git-status-add-p() {
+ local f_path=${1##?* }
+ local git_base="$(git rev-parse --show-cdup)"
+ BUFFER="git add -p '$git_base$f_path'"
+ zle accept-line
+}
+
+function zaw-src-git-status-reset() {
+ local f_path=${1##?* }
+ local git_base="$(git rev-parse --show-cdup)"
+ BUFFER="git reset '$git_base$f_path'"
+ zle accept-line
+}
+
+function zaw-src-git-status-checkout() {
+ local f_path=${1##?* }
+ local git_base="$(git rev-parse --show-cdup)"
+ BUFFER="git checkout '$git_base$f_path'"
+ zle accept-line
+}
+
+function zaw-src-git-status-edit() {
+ local f_path=${1##?* }
+ local git_base="$(git rev-parse --show-cdup)"
+ zaw-callback-edit-file "$git_base$f_path"
+}
+
+function zaw-src-git-status-rm() {
+ local f_path=${1##?* }
+ local git_base="$(git rev-parse --show-cdup)"
+ BUFFER="git rm '$git_base$f_path'"
+ zle accept-line
+}
+
+zaw-register-src -n git-status zaw-src-git-status
--- /dev/null
+zmodload zsh/parameter
+
+function zaw-src-history() {
+ if zstyle -t ':filter-select' hist-find-no-dups ; then
+ candidates=(${(@vu)history})
+ options=("-m" "-s" "${BUFFER}")
+ else
+ cands_assoc=("${(@kv)history}")
+ # have filter-select reverse the order (back to latest command first).
+ # somehow, `cands_assoc` gets reversed while `candidates` doesn't.
+ options=("-r" "-m" "-s" "${BUFFER}")
+ fi
+ actions=("zaw-callback-execute" "zaw-callback-replace-buffer" "zaw-callback-append-to-buffer")
+ act_descriptions=("execute" "replace edit buffer" "append to edit buffer")
+
+ if (( $+functions[zaw-bookmark-add] )); then
+ # zaw-src-bookmark is available
+ actions+="zaw-bookmark-add"
+ act_descriptions+="bookmark this command line"
+ fi
+}
+
+zaw-register-src -n history zaw-src-history
--- /dev/null
+# zaw source for locate
+
+autoload -U read-from-minibuffer
+
+function zaw-src-locate() {
+ local buf
+ read-from-minibuffer "locate "
+ buf=$(locate ${(Q@)${(z)REPLY}})
+ if [[ $? != 0 ]]; then
+ return 1
+ fi
+ : ${(A)candidates::=${(f)buf}}
+ : ${(A)cand_descriptions::=${(f)buf}}
+ actions=( zaw-callback-append-to-buffer )
+ act_descriptions=( "append to buffer" )
+}
+
+zaw-register-src -n locate zaw-src-locate
+
--- /dev/null
+#
+# zaw-open-file
+#
+# zaw source for xdg-open to open file
+#
+
+function zaw-src-open-file() {
+ local root parent d f
+ setopt local_options null_glob
+
+ if (( $# == 0 )); then
+ root="${PWD}/"
+ else
+ root="$1"
+ fi
+
+ parent="${root:h}"
+ if [[ "${parent}" != */ ]]; then
+ parent="${parent}/"
+ fi
+ candidates+=("${parent}")
+ cand_descriptions+=("../")
+
+ # TODO: symlink to directory
+ for d in "${root%/}"/*(/); do
+ candidates+=("${d}/")
+ cand_descriptions+=("${d:t}/")
+ done
+
+ for f in "${root%/}"/*(^/); do
+ candidates+=("${f}")
+ cand_descriptions+=("${f:t}")
+ done
+
+ actions=( "zaw-callback-open-file" "zaw-callback-append-to-buffer" )
+ act_descriptions=( "open file or directory" "append to edit buffer" )
+ # TODO: open multiple files
+ #options=( "-m" )
+ options=( "-t" "${root}" )
+}
+
+zaw-register-src -n open-file zaw-src-open-file
+
+function zaw-callback-open-file() {
+ local open
+ case "${(L)OSTYPE}" in
+ linux*|*bsd*)
+ open="xdg-open"
+ ;;
+ darwin*)
+ open="open"
+ ;;
+ *)
+ # TODO: what is the best fallback?
+ open="xdg-open"
+ ;;
+ esac
+
+ # TODO: symlink to directory
+ if [[ -d "$1" ]]; then
+ zaw zaw-src-open-file "$1"
+ else
+ BUFFER="${open} ${(q)1}"
+ zle accept-line
+ fi
+}
--- /dev/null
+function zaw-src-perldoc() {
+ local code_wanted
+ local -a words
+
+ # XXX: override _wanted to capture module list _perl_modules generates
+ code_wanted="${functions[_wanted]}"
+ function _wanted() {
+ candidates=("${(P@)${@[7]}}")
+ }
+
+ # required by _perl_modules
+ words=(perldoc)
+
+ _perl_modules
+
+ # restore original function
+ eval "function _wanted() { $code_wanted }"
+
+ actions=("zaw-callback-perldoc-view" "zaw-callback-perldoc-vim")
+ act_descriptions=("view perldoc" "open with vim")
+}
+
+zaw-register-src -n perldoc zaw-src-perldoc
+
+function zaw-callback-perldoc-view() {
+ local orig_buffer="${BUFFER}"
+ BUFFER=" perldoc '$1'"
+ zle accept-line
+}
+
+function zaw-callback-perldoc-vim() {
+ local orig_buffer="${BUFFER}"
+ BUFFER=" vim -R $(perldoc -lm "$1")"
+ zle accept-line
+}
--- /dev/null
+# zaw source for processes
+
+function zaw-src-process () {
+ local ps_list title ps pid_list
+ if [ $(uname) = "Darwin" ] ; then # for Macintosh
+ ps_list="$(ps aux | awk '$11 !~ /^\[/ {print $0}')" # filter out kernel processes
+ else
+ ps_list="$(ps -aux --sort args | awk '$11 !~ /^\[/ {print $0}')" # filter out kernel processes
+ fi
+ title="${${(f)ps_list}[1]}"
+ ps="$(echo $ps_list | sed '1d')"
+ pid_list="$(echo $ps | awk '{print $2}')"
+ : ${(A)candidates::=${(f)pid_list}}
+ : ${(A)cand_descriptions::=${(f)ps}}
+ actions=(zaw-callback-append-to-buffer zaw-src-process-kill)
+ act_descriptions=("insert" "kill")
+ options=(-t "$title")
+}
+
+function zaw-src-process-kill () {
+ local user="$(ps -ho user $1)"
+ if [[ -z $user ]]; then
+ echo "process with PID=$1 is not found"
+ return 1
+ fi
+ if [[ $user = $USER ]]; then
+ BUFFER="kill $1"
+ else
+ BUFFER="sudo kill $1"
+ fi
+ zle accept-line
+}
+
+zaw-register-src -n process zaw-src-process
--- /dev/null
+function zaw-src-programs() {
+ # fill the command hash
+ hash -r
+ hash -f
+ candidates=($(hash | cut -d '=' -f 1))
+ actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer)
+ act_descriptions=("execute" "append to buffer" "replace buffer")
+}
+
+zaw-register-src -n programs zaw-src-programs
--- /dev/null
+#
+# zaw-src-screens
+#
+# select screen session and attache it
+#
+
+function zaw-src-screens() {
+ local session state
+
+ screen -ls | awk 'NR==1,/^There (is a|are) screens? on:/ { next } /^[0-9]+ Sockets? in/ { exit } 1' | \
+ while read session state; do
+ candidates+=("${session}")
+ cand_descriptions+=("${(r:30:::::)session} ${state}")
+ done
+ actions=('zaw-callback-screens-attach')
+ act_descriptions=('attach session')
+}
+
+zaw-register-src -n screens zaw-src-screens
+
+function zaw-callback-screens-attach() {
+ BUFFER="screen -rx ${(q)1}"
+ zle accept-line
+}
--- /dev/null
+# zaw source for ack/ag searcher
+
+autoload -U read-from-minibuffer
+
+typeset -g ZAW_SEARCHER_CMD
+
+if (( $+commands[ag] )); then
+ ZAW_SEARCHER_CMD="ag"
+elif (( $+commands[ack-grep] )); then
+ ZAW_SEARCHER_CMD="ack-grep"
+elif (( $+commands[ack] )); then
+ ZAW_SEARCHER_CMD="ack"
+else
+ # ack/ag are not found, and disable this source
+ return
+fi
+
+function zaw-src-searcher() {
+ local buf
+ read-from-minibuffer "${ZAW_SEARCHER_CMD} "
+ buf=$($ZAW_SEARCHER_CMD ${(Q@)${(z)REPLY}})
+ if [[ $? != 0 ]]; then
+ return 1
+ fi
+ : ${(A)candidates::=${(f)buf}}
+ : ${(A)cand_descriptions::=${(f)buf}}
+ actions=(\
+ zaw-src-searcher-edit \
+ )
+ act_descriptions=(\
+ "Edit" \
+ )
+}
+
+function zaw-src-searcher-edit () {
+ local filename=${1%%:*}
+ local line=${${1#*:}%%:*}
+ if [[ -z $ZAW_EDITOR_JUMP_PARAM ]]; then
+ ZAW_EDITOR_JUMP_PARAM="+%LINE% %FILE%"
+ fi
+ BUFFER="${EDITOR} ${${ZAW_EDITOR_JUMP_PARAM/\%LINE\%/$line}/\%FILE\%/$filename}"
+ zle accept-line
+}
+
+zaw-register-src -n searcher zaw-src-searcher
--- /dev/null
+#
+# zaw-src-ssh-hosts
+#
+# Note: .ssh/config must have "HashKnownHosts no" (default) to make known hosts
+# values work.
+
+function zaw-src-ssh-hosts(){
+ local -a _global_ssh_known_hosts _global_ssh_known_hosts2 _ssh_known_hosts _ssh_known_hosts2 _etc_hosts _ssh_config_hosts
+ [ -r /etc/ssh/ssh_known_hosts ] && _global_ssh_known_hosts=(${${${(f)"$(< /etc/ssh/ssh_known_hosts)"}%%\ *}%%,*}) 2>/dev/null || _global_ssh_known_hosts=()
+ [ -r /etc/ssh/ssh_known_hosts2 ] && _global_ssh_known_hosts2=(${${${(f)"$(< /etc/ssh/ssh_known_hosts2)"}%%\ *}%%,*}) 2>/dev/null || _global_ssh_known_hosts2=()
+ [ -r "$HOME/.ssh/known_hosts" ] && _ssh_known_hosts=(${${${(f)"$(< ~/.ssh/known_hosts)"}%%\ *}%%,*}) 2>/dev/null || _ssh_known_hosts=()
+ [ -r "$HOME/.ssh/known_hosts2" ] && _ssh_known_hosts=(${${${(f)"$(< ~/.ssh/known_hosts2)"}%%\ *}%%,*}) 2>/dev/null || _ssh_known_hosts2=()
+ [ -r /etc/hosts ] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$(</etc/hosts)"}%%\#*}##[:blank:]#[^[:blank:]]#}}} || _etc_hosts=()
+ [ -r "$HOME/.ssh/config" ] && _ssh_config_hosts=(${${${(@M)${(f)"$(< ~/.ssh/config)"}:#Host *}#Host }:#*[*?]*}) || _ssh_config_hosts=()
+ candidates=(
+ $_global_ssh_known_hosts[@]
+ $_global_ssh_known_hosts2[@]
+ $_ssh_known_hosts[@]
+ $_ssh_known_hosts2[@]
+ $_etc_hosts[@]
+ $_ssh_config_hosts[@]
+ "$HOST"
+ ::1
+ localhost
+ 127.0.0.1
+ )
+ candidates=(${(iou)candidates[@]})
+
+ actions=("zaw-callback-ssh-connect" "zaw-callback-append-to-buffer" )
+
+ act_descriptions=("ssh to the host" "append to edit buffer")
+}
+
+zaw-register-src -n ssh-hosts zaw-src-ssh-hosts
+
+function zaw-callback-ssh-connect(){
+ local orig_buffer="${BUFFER}"
+ BUFFER="ssh $1"
+ zle accept-line
+}
--- /dev/null
+# -*- mode:sh -*-
+#
+# zaw-src-tmux
+#
+# select tmux session and attach it
+#
+
+function zaw-src-tmux() {
+ local session state
+
+ tmux list-sessions | \
+ while read session state; do
+ candidates+=("${session}")
+ cand_descriptions+=("${(r:30:::::)session} ${state}")
+ done
+ actions=('zaw-callback-tmux-attach')
+ act_descriptions=('attach session')
+ actions+=('zaw-callback-tmux-kill')
+ act_descriptions+=('kill session')
+}
+
+zaw-register-src -n tmux zaw-src-tmux
+
+function zaw-callback-tmux-attach() {
+ if [ -z $TMUX ]; then
+ BUFFER="tmux attach -t ${(q)1}"
+ else
+ BUFFER="tmux switch-client -t ${(q)1}"
+ fi
+ zle accept-line
+}
+
+function zaw-callback-tmux-kill() {
+ BUFFER="tmux kill-session -t ${(q)1}"
+ zle accept-line
+}
--- /dev/null
+function zaw-src-widgets() {
+ candidates=($(zle -l | cut -d ' ' -f 1))
+ actions=(zle-call)
+ act_descriptions=("call function with zle")
+}
+
+zle-call(){
+ zle $1
+}
+
+zaw-register-src -n widgets zaw-src-widgets
--- /dev/null
+#!/bin/zsh
+#
+# zaw-launcher.zsh
+#
+# launcher script to start zaw as command
+
+# source zaw.zsh
+local this_file="$0"
+local cur_dir="${this_file:A:h}"
+source "${cur_dir}/zaw.zsh"
+
+
+# parse arguments
+do_eval=0
+
+while getopts 'eh' opt; do
+ case "${opt}" in
+ e)
+ do_eval=1
+ ;;
+
+ h)
+ print \
+"Usage: $0 [options] [source name]
+
+Options:
+ -h show this help
+ -e eval result string
+"
+ exit
+ ;;
+ esac
+done
+
+if (( OPTIND > 1 )); then
+ shift $(( OPTIND - 1 ))
+fi
+
+zaw_args=()
+if [[ $# > 0 && "${zaw_sources[$1]}" != "" ]]; then
+ zaw_args+="${zaw_sources[$1]}"
+fi
+
+
+# use zle-line-init to start zaw right after vared
+function zle-line-init() {
+ zle zaw "${(@)zaw_args}"
+
+ # return from vared
+ zle accept-line
+}
+zle -N zle-line-init
+
+vared -c cmd
+
+if (( do_eval )); then
+ eval "${cmd}"
+else
+ print "${cmd}"
+fi
--- /dev/null
+zaw.zsh
\ No newline at end of file
--- /dev/null
+#
+# zaw - zsh anything.el-like widget
+#
+# usage:
+#
+# add following line to your .zshrc::
+#
+# source /path/to/zaw.zsh
+#
+# and type "^X;"
+
+# to create namespace, use anonymous function
+function() {
+
+zmodload zsh/parameter
+autoload -U is-at-least
+
+local this_file="${funcsourcetrace[1]%:*}"
+if is-at-least 4.3.10; then
+ # "A" flag (turn a file name into an absolute path with symlink
+ # resolution) is only available on 4.3.10 and latter
+ local cur_dir="${this_file:A:h}"
+else
+ local cur_dir="${this_file:h}"
+fi
+fpath+=("${cur_dir}/functions")
+
+autoload -U filter-select
+
+typeset -g -A zaw_sources
+zaw_sources=()
+
+function zaw-register-src() {
+ # register zaw source
+ #
+ # zaw-register-src [-n NAME] SOURCE
+ #
+ # SOURCE is function name that define (overrite) these variables
+ #
+ # $candidates -> array of candidates
+ # $cands_assoc -> assoc array of candidates
+ # $cand_descriptions -> (optional) array of candidates descriptions
+ # $cand_descriptions_assoc -> (optional) assoc array of candidates descriptions
+ # $actions -> list of callback function names that receive selected item
+ # $act_descriptions -> (optional) list of callback function descriptions
+ # $options -> (optional) array of options passed to filter-select
+ #
+ # whether one of candidates or cands-assoc is required
+ local name func widget_name opts OPTARG OPTIND
+
+ while getopts 'n:' opts; do
+ name="${OPTARG}"
+ done
+ if (( OPTIND > 1 )); then
+ shift $(( OPTIND - 1 ))
+ fi
+
+ func="$1"
+
+ if [[ -z "${name}" ]]; then
+ name="${func}"
+ fi
+
+ # TODO: check name duplication
+ zaw_sources+=("${name}" "${func}")
+
+ # define shortcut function
+ widget_name="zaw-${(L)name// /-}"
+ eval "function ${widget_name} { zle zaw ${func} \$@ }"
+ eval "zle -N ${widget_name}"
+}
+
+
+function zaw() {
+ local action ret func
+ local -a reply candidates actions act_descriptions options selected cand_descriptions
+ local -A cands_assoc
+
+ if [[ $# == 0 ]]; then
+ if zle zaw-select-src; then
+ func="${reply[2]}"
+ reply=()
+ else
+ return 0
+ fi
+ else
+ func="$1"
+ shift
+ fi
+
+ zle -R "now loading ..."
+
+ # call source function to generate candidates
+ "${func}" "$@"
+
+ ret="$?"
+ if [[ "${ret}" != 0 ]]; then
+ return 1
+ fi
+
+ reply=()
+
+ if (( ${#cand_descriptions} )); then
+ options=("-d" "cand_descriptions" "${(@)options}")
+ fi
+ # TODO: cand_descriptions_assoc
+
+ # call filter-select to allow user select item
+ if (( ${#cands_assoc} )); then
+ filter-select -e select-action -A cands_assoc "${(@)options}"
+ else
+ filter-select -e select-action "${(@)options}" -- "${(@)candidates}"
+ fi
+
+ if [[ $? == 0 ]]; then
+ if (( ${#reply_marked} > 0 )); then
+ selected=("${(@)reply_marked}")
+ else
+ selected=("${reply[2]}")
+ fi
+
+ case "${reply[1]}" in
+ accept-line)
+ action="${actions[1]}"
+ ;;
+ accept-search)
+ action="${actions[2]}"
+ ;;
+ select-action)
+ reply=()
+ filter-select -t "select action for '${(j:', ':)selected}'" -d act_descriptions -- "${(@)actions}"
+ ret=$?
+
+ if [[ $ret == 0 ]]; then
+ action="${reply[2]}"
+ else
+ return 1
+ fi
+ ;;
+ esac
+
+ if [[ -n "${action}" ]]; then
+ "${action}" "${(@)selected}"
+ fi
+ fi
+}
+
+zle -N zaw
+
+
+function zaw-select-src() {
+ local name
+ local -a cands descs
+ cands=()
+ descs=()
+ for name in "${(@ko)zaw_sources}"; do
+ cands+="${zaw_sources[${name}]}"
+ descs+="${name}"
+ done
+
+ filter-select -e select-action -d descs -- "${(@)cands}"
+}
+
+zle -N zaw-select-src
+
+
+function zaw-print-src() {
+ local name func widget_name
+ printf '%-16s %s\n' "source name" "shortcut widget name"
+ print -- '----------------------------------------'
+ for name in "${(@ko)zaw_sources}"; do
+ widget_name="zaw-${(L)name// /-}"
+ printf '%-16s %s\n' "${name}" "${widget_name}"
+ done
+}
+
+
+# common callbacks
+function zaw-callback-execute() {
+ BUFFER="${(j:; :)@}"
+ zle accept-line
+}
+
+function zaw-callback-replace-buffer() {
+ LBUFFER="${(j:; :)@}"
+ RBUFFER=""
+}
+
+function zaw-callback-append-to-buffer() {
+ LBUFFER="${BUFFER}${(j:; :)@}"
+}
+
+function zaw-callback-edit-file() {
+ local -a args
+ args=("${(@q)@}")
+
+ if [ ! ${ZAW_EDITOR} ]; then
+ ZAW_EDITOR=${EDITOR}
+ fi
+
+ BUFFER="${ZAW_EDITOR} ${args}"
+ zle accept-line
+}
+
+
+# load zaw sources
+setopt local_options extended_glob
+local src_dir="${cur_dir}/sources" f
+if [[ -d "${src_dir}" ]]; then
+ for f in "${src_dir}"/^*.zwc; do
+ source "${f}"
+ done
+fi
+
+# dummy function
+# only used for exit-zle-widget-name
+function select-action() {}; zle -N select-action
+filter-select -i
+bindkey -M filterselect '^i' select-action
+
+bindkey '^X;' zaw
+
+}
## what you load.
# zstyle ':ganneff:config' plugins git-extras.plugin.zsh \
# history-substring-search.zsh \
-# per-directory-history.plugin.zsh
+# per-directory-history.plugin.zsh \
+# zaw.zsh
## oh-my-zsh plugins can also be loaded, in case you like one of it.
## Simply list their names here, and put their directories into