├── LICENSE ├── README.rst ├── functions ├── fill-vars-or-accept └── filter-select ├── sources ├── aliases.zsh ├── applications.zsh ├── bookmark.zsh ├── cdr.zsh ├── command-output.zsh ├── commands.zsh ├── fasd.zsh ├── functions.zsh ├── git-branches.zsh ├── git-files.zsh ├── git-log.zsh ├── git-recent-branches.zsh ├── git-reflog.zsh ├── git-status.zsh ├── history.zsh ├── locate.zsh ├── open-file.zsh ├── perldoc.zsh ├── process.zsh ├── programs.zsh ├── screens.zsh ├── searcher.zsh ├── ssh-hosts.zsh ├── tmux.zsh └── widgets.zsh ├── zaw-launcher.zsh ├── zaw.plugin.zsh └── zaw.zsh /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, NAKAMURA Yoshitaka 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 3. Neither the name of the author nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ================================= 2 | zaw - zsh anything.el-like widget 3 | ================================= 4 | 5 | install 6 | ======= 7 | 8 | :: 9 | 10 | $ git clone git://github.com/zsh-users/zaw.git 11 | remote: Counting objects: 136, done. 12 | remote: Compressing objects: 100% (86/86), done. 13 | remote: Total 136 (delta 43), reused 136 (delta 43) 14 | Receiving objects: 100% (136/136), 23.68 KiB, done. 15 | Resolving deltas: 100% (43/43), done. 16 | $ echo "source ${PWD}/zaw/zaw.zsh" >> ~/.zshrc 17 | 18 | and restart zsh or manualy source ``zaw.zsh``. 19 | 20 | 21 | usage 22 | ===== 23 | 24 | 1. Trigger `zaw` by pressing ``Ctrl-x ;`` (``^x;``). 25 | 2. select `source` and press ``enter``. 26 | 3. filter items with zsh patterns separated by spaces, use ``^N``, ``^P`` and select one. 27 | 4. execute action by pressing enter key or press ``Meta-enter`` for alternative action. 28 | 29 | instead, press tab key and select action you want to execute. 30 | 31 | 32 | sources 33 | ======= 34 | 35 | currently these sources are available: 36 | 37 | - aliases 38 | - applications 39 | - bookmark 40 | - cdr (needs cdr enabled. Google it or use `this packaged version `_) 41 | - commands 42 | - command-output 43 | - fasd 44 | - fasd-directories 45 | - fasd-files 46 | - functions 47 | - git-branches 48 | - git-recent-all-branches 49 | - git-recent-branches 50 | - git-files 51 | - git-files-legacy 52 | - git-log 53 | - git-reflog 54 | - git-status 55 | - history 56 | - locate 57 | - open-file 58 | - perldoc 59 | - process 60 | - programs 61 | - screens 62 | - searcher (ag/ack) 63 | - ssh-hosts 64 | - tmux 65 | - widgets 66 | 67 | (Note: git-files-legacy is an alternative for git-files. 68 | git-files classifies modified files, git-files-legacy doesn't do it for 69 | performance reason.) 70 | 71 | Additional sources can be installed as third-party plugins. Here is a list of all 72 | the ones we know about. Please let us know about any more you find or make! 73 | Installation is easiest with a plugin manager such as 74 | `zgen `_. Otherwise you can just source the 75 | .zsh file that contains the source. 76 | 77 | - calibre source: https://github.com/junkblocker/calibre-zaw-source 78 | - MPD source: https://github.com/willghatch/zsh-zaw-mpd 79 | - `pass `_ source: https://gist.github.com/f440/9992963 80 | - systemd source: https://github.com/termoshtt/zaw-systemd 81 | - `todoman `_ source: https://github.com/willghatch/zsh-zaw-todoman 82 | 83 | shortcut widgets 84 | ================ 85 | 86 | zaw automaticaly create shortcut widgets for each sources 87 | that directly access to the source. 88 | 89 | for example, execute ``bindkey '^R' zaw-history`` and 90 | press ``^R`` to access history source. 91 | 92 | you can get all available shortcut widgets' name using ``zaw-print-src``:: 93 | 94 | $ zaw-print-src 95 | source name shortcut widget name 96 | ---------------------------------------- 97 | ack zaw-ack 98 | applications zaw-applications 99 | bookmark zaw-bookmark 100 | git-branches zaw-git-branches 101 | git-recent-all-branches zaw-git-recent-all-branches 102 | git-recent-branches zaw-git-recent-branches 103 | git-files zaw-git-files 104 | git-files-legacy zaw-git-files-legacy 105 | git-status zaw-git-status 106 | history zaw-history 107 | open-file zaw-open-file 108 | perldoc zaw-perldoc 109 | process zaw-process 110 | screens zaw-screens 111 | ssh-hosts zaw-ssh-hosts 112 | tmux zaw-tmux 113 | fasd zaw-fasd 114 | fasd-directories zaw-directories 115 | fasd-files zaw-files 116 | 117 | 118 | key binds and styles 119 | ==================== 120 | 121 | zaw use ``filter-select`` to filter and select items. 122 | 123 | you can use these key binds:: 124 | 125 | enter: accept-line (execute default action) 126 | meta + enter: accept-search (execute alternative action) 127 | Tab: select-action 128 | ^G: send-break 129 | ^H, backspace: backward-delete-char 130 | ^F, right key: forward-char 131 | ^B, left key: backward-char 132 | ^A: beginning-of-line 133 | ^E: end-of-line 134 | ^W: backward-kill-word 135 | ^K: kill-line 136 | ^U: kill-whole-line 137 | ^N, down key: down-line-or-history (select next item) 138 | ^P, up key: up-line-or-history (select previous item) 139 | ^V, page up key: forward-word (page down) 140 | ^[V, page down key: backward-word (page up) 141 | ^[<, home key: beginning-of-history (select first item) 142 | ^[>, end key: end-of-history (select last item) 143 | 144 | and these zstyles to customize styles:: 145 | 146 | ':filter-select:highlight' selected 147 | ':filter-select:highlight' matched 148 | ':filter-select:highlight' marked 149 | ':filter-select:highlight' title 150 | ':filter-select:highlight' error 151 | ':filter-select' max-lines 152 | ':filter-select' rotate-list 153 | ':filter-select' case-insensitive 154 | ':filter-select' extended-search 155 | ':filter-select' hist-find-no-dups 156 | ':filter-select' escape-descriptions 157 | ':zaw:' default 158 | ':zaw:' alt 159 | 160 | example: 161 | zstyle ':filter-select:highlight' matched fg=yellow,standout 162 | zstyle ':filter-select' max-lines 10 # use 10 lines for filter-select 163 | zstyle ':filter-select' max-lines -10 # use $LINES - 10 for filter-select 164 | zstyle ':filter-select' rotate-list yes # enable rotation for filter-select 165 | zstyle ':filter-select' case-insensitive yes # enable case-insensitive search 166 | zstyle ':filter-select' extended-search yes # see below 167 | zstyle ':filter-select' hist-find-no-dups yes # ignore duplicates in history source 168 | zstyle ':filter-select' escape-descriptions no # display literal newlines, not \n, etc 169 | zstyle ':zaw:git-files' default zaw-callback-append-to-buffer # set default action for git-files 170 | zstyle ':zaw:git-files' alt zaw-callback-edit-file # set the alt action for git-files 171 | 172 | extended-search: 173 | If this style set to be true value, the searching bahavior will be 174 | extended as follows: 175 | 176 | ^ Match the beginning of the line if the word begins with ^ 177 | $ Match the end of the line if the word ends with $ 178 | ! Match anything except the word following it if the word begins with ! 179 | so-called smartcase searching 180 | 181 | If you want to search these metacharacters, please doubly escape them. 182 | 183 | environment variable 184 | ==================== 185 | 186 | ZAW_EDITOR editor command. If this variable is not set, use EDITOR value. 187 | ZAW_EDITOR_JUMP_PARAM open editor command with line params. 188 | %LINE% is replaced by line number. 189 | %FILE% is replaced by file path. 190 | default +%LINE% %FILE% 191 | 192 | 193 | making sources 194 | ============== 195 | 196 | If you want to make another source, please do! Look at https://github.com/termoshtt/zaw-systemd 197 | as an example of how to make a source repo. Note that it uses the .plugin.zsh 198 | convention that plugin managers like zgen and antigen expect for its main file. 199 | The sources directory contains the files for the actual sources. All the sources 200 | in this repository's ``sources`` directory are good references as well for what 201 | the source files should look like. They tend to be quite simple. 202 | If your source requires any additional configuration or dependencies, be sure to 203 | list all of that in your project's README file. 204 | 205 | Let us know when you make new plugins so we can add them to our list! 206 | 207 | license 208 | ======= 209 | 210 | BSD-3 211 | -------------------------------------------------------------------------------- /functions/fill-vars-or-accept: -------------------------------------------------------------------------------- 1 | # 2 | # fill-vars-or-accept 3 | # 4 | 5 | # by default, pattern match "${:-variable_name}" 6 | FILL_VARS_PATTERN='${:-[a-z_][a-z0-9_]#}' 7 | 8 | function fill-vars-or-accept() { 9 | # TODO: tab completion 10 | 11 | local REPLY 12 | local -a orig_region_highlight 13 | 14 | if ! _buffer_has_vars; then 15 | zle accept-line 16 | fi 17 | 18 | bindkey -N fillvars main 19 | bindkey -M fillvars '^i' go-to-next-var 20 | 21 | CURSOR=0 22 | 23 | _get-current-var 24 | if [[ -z "${REPLY}" ]]; then 25 | go-to-next-var 26 | fi 27 | 28 | local POSTDISPLAY=$'\n''[press tab key to move cursor to next variable]' 29 | 30 | while _buffer_has_vars && (( CURSOR < ${#BUFFER} )); do 31 | orig_region_highlight=("${(@)region_highlight}") 32 | _highlight-right-vars 33 | zle -Rc 34 | #zle -R '[press tab key to move next variable]' 35 | 36 | zle read-command -K fillvars 37 | reply="$?" 38 | cmd_name="${REPLY}" 39 | 40 | region_highlight=("${(@)orig_region_highlight}") 41 | 42 | if [[ "${reply}" != 0 ]]; then 43 | return 1 44 | fi 45 | 46 | if [[ "${cmd_name}" == accept* ]]; then 47 | zle "${cmd_name}" 48 | return 49 | 50 | else 51 | _get-current-var 52 | if [[ -n "${REPLY}" ]]; then 53 | if [[ "${cmd_name}" == self-insert* ]]; then 54 | # remove current var 55 | RBUFFER="${RBUFFER[$(( ${#REPLY} + 1)),-1]}" 56 | elif [[ "${cmd_name}" == (*-delete-*|*-kill-*) ]]; then 57 | # remove current var and continue 58 | RBUFFER="${RBUFFER[$(( ${#REPLY} + 1)),-1]}" 59 | continue 60 | fi 61 | fi 62 | fi 63 | 64 | zle "${cmd_name}" 65 | done 66 | } 67 | 68 | function _highlight-right-vars() { 69 | emulate -L zsh 70 | setopt local_options extended_glob 71 | 72 | local nl=$'\n' rbuffer="${RBUFFER}" REPLY 73 | local -a match mbegin mend 74 | integer offset="${#LBUFFER}" 75 | 76 | if _buffer_has_vars; then 77 | _get-current-var 78 | if [[ -n "${REPLY}" ]]; then 79 | region_highlight+=( "${offset} $(( offset + ${#REPLY} )) standout" ) 80 | rbuffer="${rbuffer[$(( ${#REPLY} )),-1]}" 81 | (( offset += ${#REPLY} - 1 )) 82 | fi 83 | 84 | region_highlight+=( "${(f)${(S)rbuffer//*(#b)(${~FILL_VARS_PATTERN})/$(( offset + mbegin[1] - 1 )) $(( offset + mend[1] )) fg=yellow,standout${nl}}%$nl*}" ) 85 | fi 86 | } 87 | 88 | function _buffer_has_vars() { 89 | emulate -L zsh 90 | setopt local_options extended_glob 91 | [[ "${BUFFER}" == *${~FILL_VARS_PATTERN}* ]] 92 | } 93 | 94 | function go-to-next-var() { 95 | emulate -L zsh 96 | setopt local_options extended_glob 97 | 98 | local -a match mbegin mend 99 | local rrbuffer="${RBUFFER[2,-1]}" 100 | if [[ "${rrbuffer}" == *${~FILL_VARS_PATTERN}* ]]; then 101 | # to match shortest, use variable expantion 102 | : "${(S)rrbuffer/*(#b)(${~FILL_VARS_PATTERN})}" 103 | (( CURSOR += ${mbegin[1]} )) 104 | else 105 | (( CURSOR = ${#BUFFER} )) 106 | fi 107 | } 108 | 109 | zle -N go-to-next-var 110 | 111 | function _get-current-var() { 112 | emulate -L zsh 113 | setopt local_options extended_glob 114 | 115 | REPLY="" 116 | if [[ "${RBUFFER}" == (#b)(${~FILL_VARS_PATTERN})* ]]; then 117 | REPLY="${match[1]}" 118 | fi 119 | } 120 | 121 | fill-vars-or-accept "$@" 122 | -------------------------------------------------------------------------------- /functions/filter-select: -------------------------------------------------------------------------------- 1 | # 2 | # filter-select 3 | # 4 | # using filter-select, you can incrementaly filter candidate 5 | # and select one with ^N/^P keys. 6 | # 7 | # press enter for filter-select to update $reply and return 0, 8 | # press meta (alt) + enter to update $reply but return 1, 9 | # and press ^C or ^G not to update $reply and return 1. 10 | # 11 | # you can use ^@ to mark items. marked items are stored in $reply_marked. 12 | # 13 | # you can customize keybinds using bindkey command. 14 | # first, you call:: 15 | # 16 | # autoload -U filter-select; filter-select -i 17 | # 18 | # to initialize `filterselect` keymap and then do like:: 19 | # 20 | # bindkey -M filterselect '^E' accept-search 21 | # 22 | # 23 | # usage: 24 | # filter-select [-t title] [-A assoc-array-name] 25 | # [-d array-of-description] [-D assoc-array-of-descrption] 26 | # [-s initial-filter-contents] 27 | # [-n] [-r] [-m] [-e exit-zle-widget-name]... [--] [arg]... 28 | # filter-select -i 29 | # 30 | # -t title 31 | # title string displayed top of selection. 32 | # 33 | # -A assoc-array-name 34 | # name of associative array that contains candidates. 35 | # this option is designed to speed up history selection. 36 | # 37 | # -d array-of-description 38 | # name of array that contains each candidate's descriptions. 39 | # it is used to display and filter candidates. 40 | # 41 | # if not specified, copied from candidates. 42 | # 43 | # -s initial-filter-contents 44 | # initial contents of the filter buffer that users type into 45 | # 46 | # -n 47 | # assign a number to the description when -d is not specified 48 | # 49 | # -D assoc-array-of-descrption 50 | # same as ``-d`` but associative array. 51 | # 52 | # -r 53 | # reverse order. 54 | # 55 | # -m 56 | # enable mark feature 57 | # 58 | # -e exit-zle-widget-name 59 | # if keys bound to `exit-zle-widget-name` is pressed, 60 | # filter-select exits and set it's name to $reply[1]. 61 | # 62 | # args 63 | # selection candidates. 64 | # 65 | # -i 66 | # only initialize `filterselect` keymaps. 67 | # 68 | # 69 | # default key binds in filterselect: 70 | # enter: accept-line (update $reply and return) 71 | # meta + enter: accept-search (update $reply but return 1) 72 | # ^G: send-break (return 0) 73 | # ^H, backspace: backward-delete-char 74 | # ^F, right key: forward-char 75 | # ^B, left key: backward-char 76 | # ^A: beginning-of-line 77 | # ^E: end-of-line 78 | # ^W: backward-kill-word 79 | # ^K: kill-line 80 | # ^U: kill-whole-line 81 | # ^N, down key: down-line-or-history (select next item) 82 | # ^P, up key: up-line-or-history (select previous item) 83 | # ^V, page up key: forward-word (page down) 84 | # ^[V, page down key: backward-word (page up) 85 | # ^[<, home key: beginning-of-history (select first item) 86 | # ^[>, end key: end-of-history (select last item) 87 | # 88 | # available zstyles: 89 | # ':filter-select:highlight' selected 90 | # ':filter-select:highlight' matched 91 | # ':filter-select:highlight' title 92 | # ':filter-select:highlight' error 93 | # ':filter-select' max-lines 94 | # ':filter-select' rotate-list 95 | # ':filter-select' case-insensitive 96 | # ':filter-select' extended-search 97 | # 98 | # example: 99 | # zstyle ':filter-select:highlight' matched fg=yellow,standout 100 | # zstyle ':filter-select' max-lines 10 # use 10 lines for filter-select 101 | # zstyle ':filter-select' max-lines -10 # use $LINES - 10 for filter-select 102 | # zstyle ':filter-select' rotate-list yes # enable rotation for filter-select 103 | # zstyle ':filter-select' case-insensitive yes # enable case-insensitive search 104 | # zstyle ':filter-select' extended-search yes # enable extended search regardless of the case-insensitive style 105 | # 106 | # extended-search: 107 | # If this style set to be true value, the searching bahavior will be 108 | # extended as follows: 109 | # 110 | # ^ Match the beginning of the line if the word begins with ^ 111 | # $ Match the end of the line if the word ends with $ 112 | # ! Match anything except the word following it if the word begins with ! 113 | # so-called smartcase searching 114 | # 115 | # If you want to search these metacharacters, please doubly escape them. 116 | 117 | typeset -ga reply_marked 118 | 119 | function filter-select() { 120 | emulate -L zsh 121 | setopt local_options extended_glob 122 | 123 | # save ZLE related variables 124 | local orig_lbuffer="${LBUFFER}" 125 | local orig_rbuffer="${RBUFFER}" 126 | local orig_predisplay="${PREDISPLAY}" 127 | local orig_postdisplay="${POSTDISPLAY}" 128 | local -a orig_region_highlight words 129 | orig_region_highlight=("${region_highlight[@]}") 130 | 131 | local key cand lines selected cand_disp buffer_pre_zle last_buffer initbuffer='' 132 | local opt pattern msg unused title='' exit_pattern nl=$'\n' 133 | local selected_index mark_idx_disp hi start end spec 134 | local desc desc_num desc_disp bounds 135 | 136 | local -a displays matched_desc_keys match mbegin mend outs exit_wigdets 137 | local -a init_region_highlight marked_lines 138 | local -A candidates descriptions matched_descs 139 | 140 | integer i bottom_lines cursor_line=1 display_head_line=1 cand_num disp_num ii num_desc 141 | integer offset display_bottom_line selected_num rev=0 ret=0 enum=0 142 | integer mark_idx markable=0 is_marked 143 | 144 | local hi_selected hi_matched hi_marked hi_title hi_error 145 | zstyle -s ':filter-select:highlight' selected hi_selected || hi_selected='standout' 146 | zstyle -s ':filter-select:highlight' matched hi_matched || hi_matched='fg=magenta,underline' 147 | zstyle -s ':filter-select:highlight' marked hi_marked || hi_marked='fg=blue,standout' 148 | zstyle -s ':filter-select:highlight' title hi_title || hi_title='bold' 149 | zstyle -s ':filter-select:highlight' error hi_error || hi_error='fg=white,bg=red' 150 | 151 | integer max_lines 152 | zstyle -s ':filter-select' max-lines max_lines || max_lines=0 153 | 154 | local rotate_list 155 | zstyle -b ':filter-select' rotate-list rotate_list 156 | 157 | _filter-select-init-keybind 158 | 159 | candidates=() 160 | descriptions=() 161 | exit_wigdets=(accept-line accept-search send-break) 162 | 163 | while getopts 't:A:d:D:nrme:s:i' opt; do 164 | case "${opt}" in 165 | t) 166 | title="${OPTARG}" 167 | ;; 168 | A) 169 | # copy input assc array 170 | candidates=("${(@kvP)${OPTARG}}") 171 | ;; 172 | d) 173 | # copy input array 174 | integer i=0 175 | for desc in "${(@P)${OPTARG}}"; do 176 | (( i++ )) 177 | descriptions+=( $i "${desc}" ) 178 | done 179 | ;; 180 | D) 181 | # copy input assc array 182 | descriptions=("${(@kvP)${OPTARG}}") 183 | ;; 184 | n) 185 | enum=1 186 | ;; 187 | r) 188 | # reverse ordering 189 | rev=1 190 | ;; 191 | m) 192 | # can use set-mark-command 193 | markable=1 194 | ;; 195 | e) 196 | exit_wigdets+="${OPTARG}" 197 | ;; 198 | s) 199 | initbuffer="${OPTARG}" 200 | ;; 201 | i) 202 | # do nothing. only keybinds are initialized 203 | return 204 | esac 205 | done 206 | 207 | if (( OPTIND > 1 )); then 208 | shift $(( OPTIND - 1 )) 209 | fi 210 | integer i=0 211 | for cand in "$@"; do 212 | (( i++ )) 213 | candidates+=( $i "${cand}" ) 214 | done 215 | 216 | if (( ${#descriptions} == 0 )); then 217 | # copy candidates 218 | descriptions=("${(@kv)candidates}") 219 | # add number 220 | if (( enum )); then 221 | num_desc="${#descriptions}" 222 | for i in {1.."$num_desc"}; do 223 | if (( rev )); then 224 | ii="$(($num_desc-$i+1))" 225 | else 226 | ii="$i" 227 | fi 228 | descriptions[$i]="${(r.5.)ii} ${descriptions[$i]}" 229 | done 230 | fi 231 | fi 232 | 233 | desc_num="${#descriptions}" 234 | matched_desc_keys=("${(onk@)descriptions}") 235 | if (( rev )); then 236 | matched_desc_keys=("${(Oa@)matched_desc_keys}") 237 | fi 238 | 239 | key='' 240 | bounds='' 241 | 242 | # clear edit buffer 243 | BUFFER="$initbuffer" 244 | 245 | # display original edit buffer's contants as PREDISPLAY 246 | PREDISPLAY="${orig_predisplay}${orig_lbuffer}${orig_rbuffer}${orig_postdisplay}${nl}" 247 | 248 | # re-calculate region_highlight 249 | init_region_highlight=() 250 | for hi in "${(@)orig_region_highlight}"; do 251 | if [[ "${hi}" == P* ]]; then 252 | init_region_highlight+="${hi}" 253 | else 254 | print -r -- "${hi}" | read -d ' ' start end spec 255 | init_region_highlight+="P$(( start + ${#orig_predisplay} )) $(( end + ${#orig_predisplay} )) $spec" 256 | fi 257 | done 258 | 259 | # prompt for filter-select 260 | PREDISPLAY+="filter: " 261 | 262 | # clear strings displayed below the command line 263 | zle -Rc 264 | 265 | _filter-select-reset 266 | 267 | exit_pattern="(${(j:|:)exit_wigdets})" 268 | 269 | while [[ "${bounds}" != ${~exit_pattern} ]]; do 270 | case "${bounds}" in 271 | set-mark-command) 272 | if (( markable )); then 273 | # check if ${selected_index} is already in the marked_lines 274 | if (( ${marked_lines[(ie)${selected_index}]} <= ${#marked_lines} )); then 275 | # remove selected_index 276 | marked_lines=("${(@)marked_lines:#${selected_index}}") 277 | else 278 | marked_lines+="${selected_index}" 279 | fi 280 | fi 281 | ;; 282 | *down-line-or-history) 283 | (( cursor_line++ )) 284 | ;; 285 | 286 | *up-line-or-history) 287 | (( cursor_line-- )) 288 | ;; 289 | 290 | *forward-word) 291 | (( cursor_line += bottom_lines )) 292 | ;; 293 | 294 | *backward-word) 295 | (( cursor_line -= bottom_lines )) 296 | ;; 297 | 298 | beginning-of-history) 299 | (( cursor_line = 1 )) 300 | (( display_head_line = 1 )) 301 | ;; 302 | 303 | end-of-history) 304 | (( cursor_line = desc_num )) 305 | ;; 306 | 307 | self-insert|undefined-key) 308 | LBUFFER="${LBUFFER}${key}" 309 | _filter-select-reset 310 | ;; 311 | 312 | '') 313 | # empty, initial state 314 | ;; 315 | 316 | *) 317 | buffer_pre_zle="${BUFFER}" 318 | 319 | zle "${bounds}" 320 | 321 | if [[ "${BUFFER}" != "${buffer_pre_zle}" ]]; then 322 | _filter-select-reset 323 | fi 324 | esac 325 | 326 | if (( cursor_line < 1 )); then 327 | (( display_head_line -= 1 - cursor_line )) 328 | if (( display_head_line < 1 )); then 329 | (( display_head_line = 1 )) 330 | fi 331 | if [[ $rotate_list == "yes" ]] && (( selected_num <= 1 )); then 332 | (( cursor_line = bottom_lines )) 333 | (( display_head_line = desc_num - bottom_lines + 1 )) 334 | else 335 | (( cursor_line = 1 )) 336 | fi 337 | 338 | elif (( bottom_lines == 0 )); then 339 | (( display_head_line = 1 )) 340 | (( cursor_line = 1 )) 341 | 342 | elif (( cursor_line > bottom_lines )); then 343 | (( display_head_line += cursor_line - bottom_lines )) 344 | if (( display_head_line > desc_num - bottom_lines + 1 )); then 345 | (( display_head_line = desc_num - bottom_lines + 1 )) 346 | fi 347 | if [[ $rotate_list == "yes" ]] && (( selected_num >= desc_num )); then 348 | (( cursor_line = 1 )) 349 | (( display_head_line = 1 )) 350 | else 351 | (( cursor_line = bottom_lines )) 352 | fi 353 | fi 354 | 355 | if (( ! PENDING )); then 356 | region_highlight=("${(@)init_region_highlight}") 357 | 358 | displays=() 359 | offset="${#BUFFER}" 360 | if [[ -n "${title}" ]]; then 361 | offset+=$(( 1 + ${#title} )) 362 | fi 363 | 364 | selected="" 365 | selected_num=0 366 | 367 | if [[ "${BUFFER}" != "${last_buffer}" ]]; then 368 | if [[ -n "${BUFFER}" ]]; then 369 | if _filter-select-buffer-words words; then 370 | matched_descs=("${(kv@)descriptions}") 371 | for pattern in $words; do 372 | matched_descs=("${(kv@)matched_descs[(R)*${pattern}*]}") 373 | done 374 | matched_desc_keys=("${(onk@)matched_descs}") 375 | else 376 | matched_desc_keys=("${(onk@)descriptions}") 377 | fi 378 | else 379 | matched_desc_keys=("${(onk@)descriptions}") 380 | fi 381 | if (( rev )); then 382 | matched_desc_keys=("${(Oa@)matched_desc_keys}") 383 | fi 384 | last_buffer="${BUFFER}" 385 | fi 386 | 387 | # nums pattern matched 388 | desc_num="${#matched_desc_keys}" 389 | 390 | # nums displayed 391 | disp_num=0 392 | 393 | _filter-select-update-bottom-lines 394 | display_bottom_line=$(( display_head_line + bottom_lines)) 395 | 396 | if (( desc_num )); then 397 | for i in "${(@)matched_desc_keys[${display_head_line},$(( display_bottom_line - 1 ))]}"; do 398 | (( disp_num++ )) 399 | desc="${descriptions[$i]}" 400 | 401 | desc_disp="${desc}" 402 | 403 | if zstyle -T ':filter-select' escape-descriptions ; then 404 | # escape \r\n\t\ 405 | desc_disp="${desc_disp//\\/\\\\}" 406 | desc_disp="${desc_disp//$'\n'/\\n}" 407 | desc_disp="${desc_disp//$'\r'/\\r}" 408 | desc_disp="${desc_disp//$'\t'/\\t}" 409 | fi 410 | 411 | mark_idx="${marked_lines[(ie)${i}]}" 412 | (( is_marked = mark_idx <= ${#marked_lines} )) 413 | 414 | if (( is_marked )); then 415 | mark_idx_disp=" (${mark_idx})" 416 | else 417 | mark_idx_disp="" 418 | fi 419 | 420 | if (( ${(m)#desc_disp} + ${#mark_idx_disp} > COLUMNS - 1 )); then 421 | # strip long line 422 | desc_disp="${(mr:$(( COLUMNS - ${#mark_idx_disp} - 6 )):::::)desc_disp} ...${mark_idx_disp}" 423 | else 424 | desc_disp="${desc_disp}${mark_idx_disp}" 425 | fi 426 | 427 | displays+="${desc_disp}" 428 | 429 | if [[ -n "${BUFFER}" ]]; then 430 | # highlight matched words 431 | for pattern in \ 432 | "(${(j.|.)${(@M)words:#*'(#e)'}})" \ 433 | "(${(j.|.)${(@)words:#(\~*|*'(#e)')}})" ; do 434 | if [[ "$pattern" != '()' ]]; then 435 | region_highlight+=( "${(f)${(S)desc_disp//*(#b)${~pattern}/$(( offset + mbegin[1] )) $(( offset + mend[1] + 1 )) ${hi_matched}${nl}}%$nl*}" ) 436 | fi 437 | done 438 | fi 439 | 440 | if (( is_marked )); then 441 | region_highlight+="${offset} $(( offset + ${#desc_disp} - ${#mark_idx_disp} + 1 )) ${hi_marked}" 442 | fi 443 | 444 | if (( disp_num == cursor_line )); then 445 | region_highlight+="${offset} $(( offset + ${#desc_disp} + 1 )) ${hi_selected}" 446 | selected="${candidates[$i]}" 447 | (( selected_num = display_head_line + disp_num - 1 )) 448 | selected_index="${i}" 449 | fi 450 | 451 | (( offset += ${#desc_disp} + 1 )) # +1 -> \n 452 | done 453 | fi 454 | 455 | POSTDISPLAY=$'\n' 456 | if [[ -n "${title}" ]]; then 457 | POSTDISPLAY+="${title}"$'\n' 458 | region_highlight+="${#BUFFER} $(( ${#BUFFER} + ${#title} + 1 )) ${hi_title}" 459 | fi 460 | 461 | if (( ${#displays} == 0 )); then 462 | if (( ${#candidates} == 0 )); then 463 | msg='no candidate' 464 | else 465 | msg='pattern not found' 466 | fi 467 | POSTDISPLAY+="${msg}" 468 | region_highlight+="${offset} $(( offset + ${#msg} + 1 )) ${hi_error}" 469 | fi 470 | 471 | POSTDISPLAY+="${(F)displays}"$'\n'"[${selected_num}/${desc_num}]" 472 | zle -R 473 | 474 | fi 475 | 476 | _filter-select-read-keys 477 | 478 | if [[ $? != 0 ]]; then 479 | # maybe ^C 480 | key='' 481 | bounds='' 482 | break 483 | else 484 | key="${reply}" 485 | # TODO: key sequence 486 | outs=("${(z)$( bindkey -M filterselect -- "${key}" )}") 487 | # XXX: will $outs contains more than two values? 488 | bounds="${outs[2]}" 489 | fi 490 | done 491 | 492 | if [[ -z "${key}" && -z "${bounds}" ]]; then 493 | # ^C 494 | reply=() 495 | reply_marked=() 496 | ret=1 497 | 498 | elif [[ "${bounds}" == send-break ]]; then 499 | # ^G 500 | reply=() 501 | reply_marked=() 502 | ret=1 503 | 504 | elif (( ${#displays} == 0 )); then 505 | # no candidate matches pattern (no candidate selected) 506 | reply=() 507 | reply_marked=() 508 | ret=1 509 | 510 | else 511 | reply=("${bounds}" "${selected}") 512 | reply_marked=() 513 | if (( ${#marked_lines} > 0 )); then 514 | for i in "${(@)marked_lines}"; do 515 | reply_marked+="${candidates[${i}]}" 516 | done 517 | fi 518 | ret=0 519 | fi 520 | 521 | LBUFFER="${orig_lbuffer}" 522 | RBUFFER="${orig_rbuffer}" 523 | PREDISPLAY="${orig_predisplay}" 524 | POSTDISPLAY="${orig_postdisplay}" 525 | region_highlight=("${orig_region_highlight[@]}") 526 | zle -Rc 527 | zle reset-prompt 528 | 529 | return $ret 530 | } 531 | 532 | function _filter-select-update-lines() { 533 | # XXX: this function override ${lines} 534 | # that define as local in filter-select 535 | # also use ${title} 536 | 537 | local _tmp_postdisplay="${POSTDISPLAY}" 538 | # to re-calculate ${BUFFERLINES} 539 | if [[ -n "${title}" ]]; then 540 | POSTDISPLAY="${title}"$'\n' 541 | else 542 | POSTDISPLAY="" 543 | fi 544 | zle -R 545 | 546 | # lines that can be used to display candidates 547 | # -1 for current/total number display area 548 | (( lines = LINES - BUFFERLINES - 1 )) 549 | 550 | POSTDISPLAY="${_tmp_postdisplay}" 551 | zle -R 552 | } 553 | 554 | function _filter-select-update-bottom-lines() { 555 | # cursor が移動できる一番下の行 556 | # ${max_lines} か ${lines} か ${desc_num} の小さい方を使う 557 | if (( max_lines > 0 && max_lines < lines )); then 558 | (( bottom_lines = max_lines )) 559 | elif (( max_lines < 0 )); then 560 | (( bottom_lines = lines + max_lines )) 561 | else 562 | (( bottom_lines = lines )) 563 | fi 564 | 565 | if (( desc_num < bottom_lines )); then 566 | (( bottom_lines = desc_num )) 567 | fi 568 | 569 | if (( bottom_lines < 1 )); then 570 | (( bottom_lines = 1 )) 571 | fi 572 | } 573 | 574 | function _filter-select-reset() { 575 | display_head_line=1 576 | cursor_line=1 577 | _filter-select-update-lines 578 | _filter-select-update-bottom-lines 579 | } 580 | 581 | function _filter-select-buffer-words() { 582 | local place="$1" 583 | local -a a 584 | local MATCH MBEGIN MEND 585 | # split into words using shell's command line parsing, 586 | # unquote the words, remove duplicated, 587 | # escape "(", ")", "[", "]" and "#" to avoid crash 588 | # also escape "|" and "~" 589 | a=("${(@)${(@Qu)${(z)BUFFER}}//(#m)[()[\]#\|~]/\\${MATCH}}") 590 | 591 | if ! zstyle -t ':filter-select' extended-search ; then 592 | if zstyle -t ':filter-select' case-insensitive; then 593 | : ${(A)a::=(#i)${^a}} 594 | fi 595 | else 596 | # remove single "\\", "!", 597 | # "^" like the history-incremental-pattern-searches', 598 | # and "!^". 599 | : ${(A)a::=${a:#([\\!^]|'!^')}} 600 | 601 | # escape "^" other than the beginning's 602 | # unescape "\\^" one level 603 | : ${(A)a::=${a//(#m)('^'~(#s)'^')/\\${MATCH}}} 604 | : ${(A)a::=${a//(#m)'\\^'/${MATCH#\\}}} 605 | 606 | # "!aoe" -> "~*aoe", 607 | # ("a!oe" should be held on, the beginning's "!" only be considered) 608 | # unescape "\\!" one level 609 | : ${(A)a::=${a/(#m)(#s)\!?##/\~\*${MATCH#\!}}} 610 | : ${(A)a::=${a//(#m)'\!'/${MATCH#\\}}} # XXX: not '\\!' though... 611 | 612 | # "^abc" -> "(#s)abc", 613 | # ("a^bc" should be held on, the beginning's "^" only be considered) 614 | : ${(A)a::=${a/(#m)(#s)\^?##/(#s)${MATCH#\^}}} 615 | 616 | # "xyz$" -> "xyz(#e)", 617 | # ("x$yz" shoud be held on, the ending's "$" only be considered) 618 | # unescape "\\$" one level 619 | : ${(A)a::=${a/(#m)*[^\\]\$(#e)/${MATCH%\$}(#e)}} 620 | : ${(A)a::=${a//(#m)'\$'/${MATCH#\\}}} # XXX: not '\\$' though... 621 | 622 | # smartcase searching ("(#i)(#I)Search" searches case sensitively) 623 | : ${(A)a::=${a/(#m)*[[:upper:]##]*/(#I)${MATCH}}} 624 | : ${(A)a::=(#i)${^a}} 625 | 626 | # make "~" to be at the beginning 627 | #: ${(A)a::=${a/#(#b)('(#i)'('(#I)')#)'~'/\~${match[1]}}} 628 | : ${(A)a::=${a/#'(#i)(#I)~'/\~(#i)(#I)}} 629 | : ${(A)a::=${a/#'(#i)~'/\~(#i)}} 630 | 631 | # fixup the '!^'; "~(#i)*\^" -> "~(#i)(#s)" 632 | # (for example, "!^aoe" -> "~(#i)*\^aoe" -> "~(#i)(#s)aoe") 633 | #: ${(A)a::=${a/#(#b)'~'('(#i)'('(#I)')#)'*\^'/\~${match[1]}(#s)}} 634 | : ${(A)a::=${a/#'~(#i)(#I)*\^'/'~(#i)(#I)(#s)'}} 635 | : ${(A)a::=${a/#'~(#i)*\^'/'~(#i)(#s)'}} 636 | fi 637 | : ${(PA)place::=$a} 638 | (( ${#a} > 1 )) || (( ${#a} == 1 )) && [[ -n "$a" ]] 639 | } 640 | 641 | function _filter-select-init-keybind() { 642 | integer fd ret 643 | 644 | # be quiet and check filterselect keybind defined 645 | exec {fd}>&2 2>/dev/null 646 | bindkey -l filterselect > /dev/null 647 | ret=$? 648 | exec 2>&${fd} {fd}>&- 649 | 650 | if (( ret != 0 )); then 651 | bindkey -N filterselect 652 | 653 | bindkey -M filterselect '^J' accept-line 654 | bindkey -M filterselect '^M' accept-line 655 | bindkey -M filterselect '\e^J' accept-search 656 | bindkey -M filterselect '\e^M' accept-search 657 | 658 | bindkey -M filterselect '\e^G' send-break 659 | bindkey -M filterselect '^G' send-break 660 | 661 | bindkey -M filterselect '^@' set-mark-command 662 | 663 | bindkey -M filterselect '^H' backward-delete-char 664 | bindkey -M filterselect '^?' backward-delete-char 665 | 666 | bindkey -M filterselect '^F' forward-char 667 | bindkey -M filterselect '\e[C' forward-char 668 | bindkey -M filterselect '\eOC' forward-char 669 | 670 | bindkey -M filterselect '^B' backward-char 671 | bindkey -M filterselect '\e[D' backward-char 672 | bindkey -M filterselect '\eOD' backward-char 673 | 674 | bindkey -M filterselect '^A' beginning-of-line 675 | bindkey -M filterselect '^E' end-of-line 676 | 677 | bindkey -M filterselect '^W' backward-kill-word 678 | bindkey -M filterselect '^K' kill-line 679 | bindkey -M filterselect '^U' kill-whole-line 680 | 681 | # move cursor down/up 682 | bindkey -M filterselect '^N' down-line-or-history 683 | bindkey -M filterselect '\e[B' down-line-or-history 684 | bindkey -M filterselect '\eOB' down-line-or-history 685 | bindkey -M filterselect '^P' up-line-or-history 686 | bindkey -M filterselect '\e[A' up-line-or-history 687 | bindkey -M filterselect '\eOA' up-line-or-history 688 | 689 | # page down/up 690 | bindkey -M filterselect '^V' forward-word 691 | bindkey -M filterselect '\e[6~' forward-word 692 | 693 | bindkey -M filterselect '\eV' backward-word 694 | bindkey -M filterselect '\ev' backward-word 695 | bindkey -M filterselect '\e[5~' backward-word 696 | 697 | # home/end 698 | bindkey -M filterselect '\e<' beginning-of-history 699 | bindkey -M filterselect '\e[1~' beginning-of-history 700 | 701 | bindkey -M filterselect '\e>' end-of-history 702 | bindkey -M filterselect '\e[4~' end-of-history 703 | fi 704 | } 705 | 706 | function _filter-select-read-keys() { 707 | local key key2 key3 nkey 708 | integer ret 709 | 710 | read -k key 711 | ret=$? 712 | reply="${key}" 713 | if [[ '#key' -eq '#\\e' ]]; then 714 | # M-... 715 | read -t $(( KEYTIMEOUT / 1000 )) -k key2 716 | if [[ "${key2}" == 'O' ]]; then 717 | # ^[O (SS3) affects next character only. 718 | # Example: cursor keys on some terminals. 719 | read -k key3 720 | ret=$? 721 | reply="${key}${key2}${key3}" 722 | else 723 | if [[ "${key2}" == '[' ]]; then 724 | # ^[[ (CSI) starts a sequence of [0-9;?] terminated by [@-~]. 725 | # Examples: Home, End, PgUp, PgDn ... 726 | reply="${key}${key2}" 727 | while true; do 728 | read -k nkey 729 | reply+=$nkey 730 | ret=$? 731 | (( $ret == 0 )) && [[ "${nkey}" =~ '^[0-9;?]$' ]] || break 732 | done 733 | else 734 | reply="${key}${key2}" 735 | fi 736 | fi 737 | else 738 | reply="${key}" 739 | fi 740 | return $ret 741 | } 742 | 743 | filter-select "$@" 744 | -------------------------------------------------------------------------------- /sources/aliases.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-aliases() { 2 | candidates=($(alias | cut -d '=' -f 1)) 3 | actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer view-alias-pager) 4 | act_descriptions=("execute" "append to buffer" "replace buffer" "view alias") 5 | } 6 | 7 | view-alias-pager() { 8 | alias $1 | ${PAGER:-less} 9 | } 10 | 11 | zaw-register-src -n aliases zaw-src-aliases 12 | -------------------------------------------------------------------------------- /sources/applications.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # zaw-src-applications 3 | # 4 | # zaw source for desktop applications 5 | # 6 | 7 | function zaw-src-applications() { 8 | emulate -L zsh 9 | setopt local_options extended_glob null_glob 10 | 11 | case "$OSTYPE" in 12 | [Dd]arwin*) 13 | candidates=( ) 14 | # Use the spotlight index to get application paths 15 | (( ${+commands[mdfind]} )) && \ 16 | candidates+=(${(f)"$(mdfind -onlyin / 'kMDItemKind == "Application"' 2>/dev/null)"}) 17 | 18 | # Use locate if available and no output from spotlight or if forced use by ZAW_SRC_APPLICATIONS_USE_LOCATE 19 | if (( ${+commands[locate]} )) && [ -n "$ZAW_SRC_APPLICATIONS_USE_LOCATE" -o ${#candidates} -eq 0 ]; then 20 | # Apps inside apps are not normally useful 21 | if [ -n "$ZAW_SRC_APPLICATIONS_INTERNAL_APPS_OK" ]; then 22 | candidates+=(${(f)"$(locate -i '*.app' 2>/dev/null)"}) 23 | elif [ ${+commands[grep]} -eq 1 ]; then 24 | candidates+=(${(f)"$((locate -i '*.app' | grep -iv '\.app/') 2>/dev/null)"}) 25 | fi 26 | fi 27 | 28 | # Glob common locations anyway since both of previous indexes may 29 | # be stale or non-existent 30 | candidates+=({,~}/Applications{,/Utilities}/*.app(N^M) /System/Library/CoreServices/*.app(N^M)) 31 | 32 | candidates=(${(iou)candidates[@]}) 33 | actions=("zaw-callback-launch-macapp" "zaw-callback-append-to-buffer") 34 | act_descriptions=("execute application" "append to edit buffer") 35 | ;; 36 | [Ll]inux*|*[Bb][Ss][Dd]*|[Ss]olaris*|[Ss]un[Oo][Ss]*) 37 | local d 38 | local -a match mbegin mend 39 | for d in /usr/share/applications/*.desktop; do 40 | local name="" comment="" exec_="" terminal=0 no_display=0 41 | while read line; do 42 | case "${line}" in 43 | Name=(#b)(*)) 44 | name="${match[1]}" 45 | ;; 46 | Comment=(#b)(*)) 47 | comment="${match[1]}" 48 | ;; 49 | Exec=(#b)(*)) 50 | exec_="${match[1]}" 51 | ;; 52 | Terminal=true) 53 | terminal=1 54 | ;; 55 | 56 | NoDisplay=true) 57 | no_display=1 58 | ;; 59 | esac 60 | done < "${d}" 61 | 62 | if (( no_display )); then 63 | continue 64 | fi 65 | 66 | # TODO: % expansion in $exec_ 67 | # remove args that match %* from $exec_ 68 | exec_="${(@m)${(z)exec_}:#%*}" 69 | 70 | if ! (( terminal )); then 71 | # disown 72 | exec_="${exec_} &!" 73 | fi 74 | 75 | candidates+=( "${exec_}" ) 76 | cand_descriptions+=( "${name} - ${comment}" ) 77 | done 78 | actions=("zaw-callback-execute" "zaw-callback-append-to-buffer") 79 | act_descriptions=("execute application" "append to edit buffer") 80 | ;; 81 | *) 82 | # Unsupported OS 83 | candidates=( ) 84 | actions=("zaw-callback-execute" "zaw-callback-append-to-buffer") 85 | act_descriptions=("execute application" "append to edit buffer") 86 | ;; 87 | esac 88 | 89 | } 90 | 91 | function zaw-callback-launch-macapp() { 92 | BUFFER="open -a \"${(j:; :)@}\"" 93 | zle accept-line 94 | } 95 | 96 | zaw-register-src -n applications zaw-src-applications 97 | -------------------------------------------------------------------------------- /sources/bookmark.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # zaw-src-bookmark 3 | # 4 | # bookmark your favorite command lines, access it using zaw interface. 5 | # you can bookmark command line using zaw-history's `bookmark this command line` action, 6 | # or bind some key to ``zaw-bookmark-add-buffer`` and use it. 7 | # 8 | 9 | zmodload zsh/system 10 | autoload -U fill-vars-or-accept 11 | 12 | typeset -g BOOKMARKFILE="${BOOKMARKFILE:-"${HOME}/.zaw-bookmarks"}" 13 | 14 | function zaw-src-bookmark() { 15 | if [[ -f "${BOOKMARKFILE}" ]]; then 16 | candidates=("${(Qf)$(zsystem flock -r "${BOOKMARKFILE}" && < "${BOOKMARKFILE}")}") 17 | fi 18 | actions=("zaw-bookmark-execute" "zaw-callback-replace-buffer" "zaw-callback-append-to-buffer" "zaw-bookmark-remove") 19 | act_descriptions=("execute" "replace edit buffer" "append to edit buffer" "removed bookmark") 20 | src_opts=("-m") 21 | } 22 | 23 | zaw-register-src -n bookmark zaw-src-bookmark 24 | 25 | 26 | # 27 | # helper functions for bookmark 28 | # 29 | 30 | function zaw-bookmark-execute() { 31 | zaw-callback-replace-buffer "$@" 32 | fill-vars-or-accept 33 | } 34 | 35 | function zaw-bookmark-add() { 36 | local -a bookmarks 37 | 38 | : >>| "${BOOKMARKFILE}" 39 | ( 40 | if zsystem flock -t 5 "${BOOKMARKFILE}"; then 41 | bookmarks=("${(f)$(< "${BOOKMARKFILE}")}" "${(q@)@}") 42 | 43 | # remove empty lines 44 | bookmarks=("${(@)bookmarks:#}") 45 | 46 | # remove duplicated lines, sort and write to ${BOOKMARKFILE} 47 | print -rl -- "${(@un)bookmarks}" >| "${BOOKMARKFILE}" 48 | else 49 | print "can't acquire lock for '${BOOKMARKFILE}'" >&2 50 | exit 1 51 | fi 52 | ) 53 | 54 | if [[ $? == 0 ]]; then 55 | zle -M "bookmark '${(j:', ':)@}'" 56 | fi 57 | } 58 | 59 | function zaw-bookmark-add-buffer() { 60 | zaw-bookmark-add "${BUFFER}" 61 | } 62 | 63 | zle -N zaw-bookmark-add-buffer 64 | 65 | function zaw-bookmark-remove() { 66 | local s 67 | local -a bookmarks 68 | 69 | : >>| "${BOOKMARKFILE}" 70 | ( 71 | if zsystem flock -t 5 "${BOOKMARKFILE}"; then 72 | bookmarks=("${(f)$(< "${BOOKMARKFILE}")}") 73 | for s in "${(q@)@}"; do 74 | bookmarks=("${(@)bookmarks:#${s}}") 75 | done 76 | 77 | # remove duplicated lines, sort and write to ${BOOKMARKFILE} 78 | print -rl -- "${(@un)bookmarks}" >| "${BOOKMARKFILE}" 79 | else 80 | print "can't acquire lock for '${BOOKMARKFILE}'" >&2 81 | exit 1 82 | fi 83 | ) 84 | 85 | if [[ $? == 0 ]]; then 86 | zle -M "bookmark '${(j:', ':)@}' removed" 87 | fi 88 | } 89 | 90 | function zaw-bookmark-remove-buffer() { 91 | zaw-bookmark-remove "${BUFFER}" 92 | } 93 | 94 | zle -N zaw-bookmark-remove-buffer 95 | -------------------------------------------------------------------------------- /sources/cdr.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # zaw-src-cdr 3 | # 4 | # zaw source for recent directories 5 | # 6 | 7 | (( $+functions[cdr] )) || return 8 | 9 | function zaw-src-cdr () { 10 | setopt local_options extended_glob 11 | : ${(A)candidates::=${${(f)"$(cdr -l)"}##<-> ##}} 12 | actions=(zaw-src-cdr-cd zaw-src-cdr-insert zaw-src-cdr-prune) 13 | act_descriptions=("cd" "insert" "prune") 14 | src_opts=("-m" "-s" "${BUFFER##cd(r|) }") 15 | } 16 | 17 | function zaw-src-cdr-cd () { 18 | BUFFER="cd $1" 19 | zle accept-line 20 | } 21 | 22 | function zaw-src-cdr-insert () { 23 | [[ -z "$LBUFFER" ]] || LBUFFER+=" " 24 | [[ "$LBUFFER[-1]" == " " ]] || LBUFFER+=" " 25 | LBUFFER+="${(j. .)@}" 26 | } 27 | 28 | function zaw-src-cdr-prune () { 29 | local -aU reply 30 | autoload -Uz chpwd_recent_filehandler 31 | chpwd_recent_filehandler 32 | : ${(A)reply::=${reply:#(${(~j.|.)${~@}})}} 33 | chpwd_recent_filehandler $reply 34 | } 35 | 36 | zaw-register-src -n cdr zaw-src-cdr 37 | -------------------------------------------------------------------------------- /sources/command-output.zsh: -------------------------------------------------------------------------------- 1 | # zaw source for locate 2 | 3 | autoload -U read-from-minibuffer 4 | 5 | function zaw-src-command-output() { 6 | local buf 7 | read-from-minibuffer "command: " 8 | buf=$(${(Q@)${(z)REPLY}}) 9 | if [[ $? != 0 ]]; then 10 | return 1 11 | fi 12 | : ${(A)candidates::=${(f)buf}} 13 | : ${(A)cand_descriptions::=${(f)buf}} 14 | actions=( zaw-callback-append-to-buffer ) 15 | act_descriptions=( "append to buffer" ) 16 | } 17 | 18 | zaw-register-src -n command-output zaw-src-command-output 19 | 20 | -------------------------------------------------------------------------------- /sources/commands.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-commands() { 2 | # fill the command hash 3 | hash -r 4 | hash -f 5 | candidates=($(hash | cut -d '=' -f 1)) 6 | candidates+=($(alias | cut -d '=' -f 1)) 7 | candidates+=($(print -l ${(ok)functions})) 8 | actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer) 9 | act_descriptions=("execute" "append to buffer" "replace buffer") 10 | } 11 | 12 | zaw-register-src -n commands zaw-src-commands 13 | -------------------------------------------------------------------------------- /sources/fasd.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-fasd () { 2 | candidates=($(fasd -alR)) 3 | actions=(zaw-callback-append-to-buffer) 4 | act_descriptions=("append to edit buffer") 5 | src_opts+=(-n -m) 6 | } 7 | 8 | 9 | function zaw-src-fasd-files () { 10 | candidates=($(fasd -flR)) 11 | actions=(zaw-callback-append-to-buffer) 12 | act_descriptions=("append to edit buffer") 13 | src_opts+=(-n -m) 14 | } 15 | 16 | 17 | function zaw-src-fasd-directories () { 18 | candidates=($(fasd -dlR)) 19 | actions=(zaw-callback-append-to-buffer) 20 | act_descriptions=("append to edit buffer") 21 | src_opts+=(-n -m) 22 | } 23 | 24 | 25 | zaw-register-src -n fasd zaw-src-fasd 26 | zaw-register-src -n fasd-directories zaw-src-fasd-directories 27 | zaw-register-src -n fasd-files zaw-src-fasd-files 28 | -------------------------------------------------------------------------------- /sources/functions.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-functions() { 2 | candidates=($(print -l ${(ok)functions})) 3 | actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer functions) 4 | act_descriptions=("call function" "append to buffer" "replace buffer" "view source") 5 | } 6 | 7 | zaw-register-src -n functions zaw-src-functions 8 | -------------------------------------------------------------------------------- /sources/git-branches.zsh: -------------------------------------------------------------------------------- 1 | # zaw source for git branch 2 | 3 | function zaw-src-git-branches() { 4 | git rev-parse --git-dir >/dev/null 2>&1 5 | if [[ $? == 0 ]]; then 6 | local branches_list="$(git show-ref | awk ' $2 != "refs/stash" { print $2 }' )" 7 | : ${(A)candidates::=${${(f)${branches_list}}#refs/}} 8 | : ${(A)cand_descriptions::=${${(f)${branches_list}}#refs/(remotes|heads|tags)/}} 9 | fi 10 | actions=( \ 11 | zaw-src-git-branches-checkout \ 12 | zaw-src-git-branches-simple-checkout \ 13 | zaw-callback-append-to-buffer \ 14 | zaw-src-git-branches-merge \ 15 | zaw-src-git-branches-merge-rebase \ 16 | zaw-src-git-branches-merge-no-ff \ 17 | zaw-src-git-branches-merge-to \ 18 | zaw-src-git-branches-reset \ 19 | zaw-src-git-branches-rebase \ 20 | zaw-src-git-branches-rebase-interactive \ 21 | zaw-src-git-branches-create \ 22 | zaw-src-git-branches-diff \ 23 | zaw-src-git-branches-diff-stat \ 24 | zaw-src-git-branches-reset-hard \ 25 | zaw-src-git-branches-delete \ 26 | zaw-src-git-branches-delete-force) 27 | act_descriptions=( 28 | "check out locally" \ 29 | "check out" \ 30 | "append to edit buffer" \ 31 | "merge" \ 32 | "merge rebase" \ 33 | "merge no ff" \ 34 | "merge to" \ 35 | "reset" \ 36 | "rebase" \ 37 | "rebase interactive from..." \ 38 | "create new branch from..." \ 39 | "diff" \ 40 | "diff statistics" \ 41 | "reset hard" \ 42 | "delete" \ 43 | "delete force") 44 | src_opts=() 45 | } 46 | 47 | function zaw-src-git-branches-checkout () { 48 | local b_type=${1%%/*} 49 | local b_name=${1#(heads|remotes|tags)/} 50 | case "$b_type" in 51 | "heads"|"tags") 52 | BUFFER="git checkout $b_name" 53 | zle accept-line 54 | ;; 55 | "remotes") 56 | BUFFER="git checkout -t $b_name" 57 | zle accept-line 58 | ;; 59 | esac 60 | } 61 | 62 | function zaw-src-git-branches-simple-checkout () { 63 | local b_name=${1#(heads|remotes|tags)/} 64 | BUFFER="git checkout $b_name" 65 | zle accept-line 66 | } 67 | 68 | function zaw-src-git-branches-create () { 69 | local b_name=${1#(heads|remotes|tags)/} 70 | LBUFFER="git checkout -b " 71 | RBUFFER=" $b_name" 72 | } 73 | 74 | function zaw-src-git-branches-merge () { 75 | local b_type=${1%%/*} 76 | local b_name=${1#(heads|remotes|tags)/} 77 | BUFFER="git merge $b_name" 78 | zle accept-line 79 | } 80 | 81 | function zaw-src-git-branches-merge-rebase () { 82 | local b_type=${1%%/*} 83 | local b_name=${1#(heads|remotes|tags)/} 84 | BUFFER="git merge --rebase $b_name" 85 | zle accept-line 86 | } 87 | 88 | function zaw-src-git-branches-merge-no-ff () { 89 | local b_type=${1%%/*} 90 | local b_name=${1#(heads|remotes|tags)/} 91 | BUFFER="git merge --no-ff $b_name" 92 | zle accept-line 93 | } 94 | 95 | function zaw-src-git-branches-merge-to () { 96 | local b_type=${1%%/*} 97 | local b_name=${1#(heads|remotes|tags)/} 98 | local b_now=${$(git symbolic-ref HEAD)#refs/heads/} 99 | if [[ "$b_type" == "heads" ]]; then 100 | BUFFER="git checkout $b_name && git merge --no-ff $b_now" 101 | zle accept-line 102 | fi 103 | } 104 | 105 | function zaw-src-git-branches-reset () { 106 | local b_type=${1%%/*} 107 | local b_name=${1#(heads|remotes|tags)/} 108 | BUFFER="git reset $b_name" 109 | zle accept-line 110 | } 111 | 112 | function zaw-src-git-branches-diff() { 113 | local b_name=${1#(heads|remotes|tags)/} 114 | BUFFER="git diff $b_name" 115 | zle accept-line 116 | } 117 | 118 | function zaw-src-git-branches-diff-stat() { 119 | local b_name=${1#(heads|remotes|tags)/} 120 | BUFFER="git diff --stat $b_name" 121 | } 122 | 123 | function zaw-src-git-branches-reset-hard () { 124 | local b_type=${1%%/*} 125 | local b_name=${1#(heads|remotes|tags)/} 126 | BUFFER="git reset --hard $b_name" 127 | zle accept-line 128 | } 129 | 130 | function zaw-src-git-branches-rebase () { 131 | local b_type=${1%%/*} 132 | local b_name=${1#(heads|remotes|tags)/} 133 | BUFFER="git rebase $b_name" 134 | zle accept-line 135 | } 136 | 137 | function zaw-src-git-branches-rebase-interactive () { 138 | local b_type=${1%%/*} 139 | local b_name=${1#(heads|remotes|tags)/} 140 | BUFFER="git rebase -i $b_name" 141 | zle accept-line 142 | } 143 | 144 | function zaw-src-git-branches-delete () { 145 | local b_type=${1%%/*} 146 | local b_name=${1#(heads|remotes|tags)/} 147 | if [[ "$b_type" == "heads" ]] ; then 148 | BUFFER="git branch -d $b_name" 149 | zle accept-line 150 | elif [[ "$b_type" == "remotes" ]] ; then 151 | local b_loc=${b_name%%/*} 152 | local b_base=${b_name#$b_loc/} 153 | BUFFER="git push $b_loc :$b_base" 154 | zle accept-line 155 | fi 156 | } 157 | 158 | function zaw-src-git-branches-delete-force () { 159 | local b_type=${1%%/*} 160 | local b_name=${1#(heads|remotes|tags)/} 161 | if [[ "$b_type" == "heads" ]] ; then 162 | BUFFER="git branch -D $b_name" 163 | zle accept-line 164 | elif [[ "$b_type" == "remotes" ]] ; then 165 | local b_loc=${b_name%%/*} 166 | local b_base=${b_name#$b_loc/} 167 | BUFFER="git push $b_loc :$b_base" 168 | zle accept-line 169 | fi 170 | } 171 | 172 | zaw-register-src -n git-branches zaw-src-git-branches 173 | -------------------------------------------------------------------------------- /sources/git-files.zsh: -------------------------------------------------------------------------------- 1 | # zaw source for git files 2 | 3 | function zaw-src-git-files-raw() { 4 | local ret=0 5 | git rev-parse --git-dir >/dev/null 2>&1 6 | ret=$? 7 | if (( ret != 0 )); then 8 | return ret 9 | fi 10 | 11 | "$1" 12 | ret=$? 13 | if (( ret != 0 )); then 14 | return ret 15 | fi 16 | 17 | 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) 18 | act_descriptions=("edit file" "add" "add -p" "reset" "checkout" "rm" "append to edit buffer") 19 | src_opts=(-m -n) 20 | return 0 21 | } 22 | 23 | function zaw-src-git-files-classify-aux() { 24 | local -a as ms ds os 25 | : ${(A)as::=${(0)"$(git ls-files $(git rev-parse --show-cdup) -z)"}} 26 | : ${(A)ms::=${(0)"$(git ls-files $(git rev-parse --show-cdup) -z -m)"}} 27 | if (( ${#ms} == 0 )) || (( ${#ms} == 1 )) && [[ -z "$ms" ]]; then 28 | candidates=($as) 29 | return 0 30 | fi 31 | 32 | if is-at-least 5.0.0 || [[ -n "${ZSH_PATCHLEVEL-}" ]] && \ 33 | is-at-least 1.5637 "$ZSH_PATCHLEVEL"; then 34 | os=(${as:|ms}) 35 | else 36 | os=(${as:#(${(~j.|.)ms})}) # TODO: too slower for large work tree 37 | fi 38 | candidates=($ms $os) 39 | 40 | : ${(A)ds::=${ms/%/ MODIFIED}} 41 | ds+=($os) 42 | cand_descriptions=($ds) 43 | return 0 44 | } 45 | 46 | function zaw-src-git-files-legacy-aux() { 47 | : ${(A)candidates::=${(0)"$(git ls-files $(git rev-parse --show-cdup) -z)"}} 48 | return 0 49 | } 50 | 51 | function zaw-src-git-files-add () { 52 | BUFFER="git add $1" 53 | zle accept-line 54 | } 55 | 56 | { 57 | function zaw-src-git-files-register-src() { 58 | eval "function $2 () { zaw-src-git-files-raw "$3" }" 59 | zaw-register-src -n "$1" "$2" 60 | } 61 | zaw-src-git-files-register-src git-files zaw-src-git-files zaw-src-git-files-classify-aux 62 | zaw-src-git-files-register-src git-files-legacy zaw-src-git-files-legacy{,-aux} 63 | } always { 64 | unfunction zaw-src-git-files-register-src 65 | } 66 | -------------------------------------------------------------------------------- /sources/git-log.zsh: -------------------------------------------------------------------------------- 1 | 2 | function zaw-src-git-log() { 3 | git rev-parse --git-dir >/dev/null 2>&1 4 | if [[ $? == 0 ]]; then 5 | local desc="$(git log --all --graph --decorate --oneline --no-color)" 6 | 7 | : ${(A)cand_descriptions::=${(f)desc}} 8 | : ${(A)candidates::=${(f)desc}} 9 | fi 10 | actions=(zaw-src-git-log-insert \ 11 | zaw-src-git-log-reset \ 12 | zaw-src-git-log-reset-hard \ 13 | zaw-src-git-log-cherry-pick \ 14 | zaw-src-git-log-create-branch \ 15 | zaw-src-git-log-revert) 16 | act_descriptions=("insert" \ 17 | "reset" \ 18 | "reset --hard" \ 19 | "cherry-pick" \ 20 | "create new branch from this hash value" \ 21 | "revert") 22 | src_opts=() 23 | } 24 | 25 | function _zaw-src-git-log-strip(){ 26 | echo $1 | sed -e 's/^[*|/\\ ]* \([a-f0-9]*\) .*/\1/' 27 | } 28 | 29 | function zaw-src-git-log-insert(){ 30 | local hash_val=$(_zaw-src-git-log-strip $1) 31 | zaw-callback-append-to-buffer $hash_val 32 | } 33 | 34 | function zaw-src-git-log-reset(){ 35 | local hash_val=$(_zaw-src-git-log-strip $1) 36 | BUFFER="git reset $hash_val" 37 | zle accept-line 38 | } 39 | 40 | function zaw-src-git-log-reset-hard(){ 41 | local hash_val=$(_zaw-src-git-log-strip $1) 42 | BUFFER="git reset --hard $hash_val" 43 | zle accept-line 44 | } 45 | 46 | function zaw-src-git-log-cherry-pick(){ 47 | local hash_val=$(_zaw-src-git-log-strip $1) 48 | BUFFER="git cherry-pick $hash_val" 49 | zle accept-line 50 | } 51 | 52 | function zaw-src-git-log-create-branch(){ 53 | local hash_val=$(_zaw-src-git-log-strip $1) 54 | LBUFFER="git checkout -b " 55 | RBUFFER=" $hash_val" 56 | } 57 | 58 | function zaw-src-git-log-revert(){ 59 | local hash_val=$(_zaw-src-git-log-strip $1) 60 | BUFFER="git revert $hash_val" 61 | zle accept-line 62 | } 63 | 64 | zaw-register-src -n git-log zaw-src-git-log 65 | -------------------------------------------------------------------------------- /sources/git-recent-branches.zsh: -------------------------------------------------------------------------------- 1 | # zaw source for git branches sorted by commit date 2 | 3 | function zaw-src-git-recent-branches () { 4 | git rev-parse --git-dir >/dev/null 2>&1 5 | if [[ $? == 0 ]]; then 6 | local branches="$(git for-each-ref --format='%(refname)' --sort=-committerdate refs/heads)" 7 | : ${(A)candidates::=${${(f)${branches}}#refs/}} 8 | : ${(A)cand_descriptions::=${${(f)${branches}}#refs/(remotes|heads|tags)/}} 9 | fi 10 | 11 | actions=( \ 12 | zaw-src-git-branches-checkout \ 13 | zaw-src-git-branches-simple-checkout \ 14 | zaw-callback-append-to-buffer \ 15 | zaw-src-git-branches-merge \ 16 | zaw-src-git-branches-merge-rebase \ 17 | zaw-src-git-branches-merge-no-ff \ 18 | zaw-src-git-branches-diff \ 19 | zaw-src-git-branches-diff-stat \ 20 | zaw-src-git-branches-reset \ 21 | zaw-src-git-branches-rebase \ 22 | zaw-src-git-branches-rebase-interactive \ 23 | zaw-src-git-branches-create \ 24 | zaw-src-git-branches-reset-hard \ 25 | zaw-src-git-branches-delete \ 26 | zaw-src-git-branches-delete-force) 27 | act_descriptions=( 28 | "check out locally" \ 29 | "check out" \ 30 | "append to edit buffer" \ 31 | "merge" \ 32 | "merge rebase" \ 33 | "merge no ff" \ 34 | "diff" \ 35 | "diff stat" \ 36 | "reset" \ 37 | "rebase" \ 38 | "rebase interactive from..." \ 39 | "create new branch from..." \ 40 | "reset hard" \ 41 | "delete" \ 42 | "delete force") 43 | src_opts=() 44 | } 45 | 46 | function zaw-src-git-recent-all-branches () { 47 | git rev-parse --git-dir >/dev/null 2>&1 48 | if [[ $? == 0 ]]; then 49 | local branches="$(git for-each-ref --format='%(refname)' --sort=-committerdate refs/heads refs/remotes)" 50 | : ${(A)candidates::=${${(f)${branches}}#refs/}} 51 | : ${(A)cand_descriptions::=${${(f)${branches}}#refs/(remotes|heads|tags)/}} 52 | fi 53 | 54 | actions=( \ 55 | zaw-src-git-branches-checkout \ 56 | zaw-src-git-branches-simple-checkout \ 57 | zaw-callback-append-to-buffer \ 58 | zaw-src-git-branches-merge \ 59 | zaw-src-git-branches-merge-rebase \ 60 | zaw-src-git-branches-merge-no-ff \ 61 | zaw-src-git-branches-diff \ 62 | zaw-src-git-branches-diff-stat \ 63 | zaw-src-git-branches-reset \ 64 | zaw-src-git-branches-rebase \ 65 | zaw-src-git-branches-rebase-interactive \ 66 | zaw-src-git-branches-create \ 67 | zaw-src-git-branches-reset-hard \ 68 | zaw-src-git-branches-delete \ 69 | zaw-src-git-branches-delete-force) 70 | act_descriptions=( 71 | "check out locally" \ 72 | "check out" \ 73 | "append to edit buffer" \ 74 | "merge" \ 75 | "merge rebase" \ 76 | "merge no ff" \ 77 | "diff" \ 78 | "diff stat" \ 79 | "reset" \ 80 | "rebase" \ 81 | "rebase interactive from..." \ 82 | "create new branch from..." \ 83 | "reset hard" \ 84 | "delete" \ 85 | "delete force") 86 | src_opts=() 87 | } 88 | 89 | function zaw-src-git-recent-branches-checkout () { 90 | local b_type=${1%%/*} 91 | local b_name=${1#(heads|remotes|tags)/} 92 | case "$b_type" in 93 | "heads"|"tags") 94 | BUFFER="git checkout $b_name" 95 | zle accept-line 96 | ;; 97 | "remotes") 98 | BUFFER="git checkout -t $b_name" 99 | zle accept-line 100 | ;; 101 | esac 102 | } 103 | 104 | function zaw-src-git-branches-diff() { 105 | local b_name=${1#(heads|remotes|tags)/} 106 | BUFFER="git diff $b_name" 107 | zle accept-line 108 | } 109 | 110 | function zaw-src-git-branches-diff-stat() { 111 | local b_name=${1#(heads|remotes|tags)/} 112 | BUFFER="git diff --stat $b_name" 113 | zle accept-line 114 | } 115 | 116 | zaw-register-src -n git-recent-branches zaw-src-git-recent-branches 117 | zaw-register-src -n git-recent-all-branches zaw-src-git-recent-all-branches 118 | -------------------------------------------------------------------------------- /sources/git-reflog.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-git-reflog () { 2 | git rev-parse --git-dir >/dev/null 2>&1 3 | if [[ $? == 0 ]]; then 4 | git reflog | \ 5 | while read id desc; do 6 | candidates+=("${id}") 7 | cand_descriptions+=("${id} ${desc}") 8 | done 9 | fi 10 | 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) 11 | act_descriptions=("append to edit buffer" "checkout" "reset" "rebase" "rebase interactive from..." "reset hard") 12 | src_opts=() 13 | } 14 | 15 | function zaw-src-git-commit-checkout () { 16 | BUFFER="git checkout $1" 17 | zle accept-line 18 | } 19 | 20 | function zaw-src-git-commit-reset () { 21 | BUFFER="git reset $1" 22 | zle accept-line 23 | } 24 | 25 | function zaw-src-git-commit-reset-hard () { 26 | BUFFER="git reset --hard $1" 27 | zle accept-line 28 | } 29 | 30 | function zaw-src-git-commit-rebase () { 31 | BUFFER="git rebase $1" 32 | zle accept-line 33 | } 34 | 35 | function zaw-src-git-commit-rebase-interactive () { 36 | BUFFER="git rebase -i $1" 37 | zle accept-line 38 | } 39 | 40 | zaw-register-src -n git-reflog zaw-src-git-reflog 41 | -------------------------------------------------------------------------------- /sources/git-status.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-git-status() { 2 | git rev-parse --git-dir >/dev/null 2>&1 3 | if [[ $? == 0 ]]; then 4 | local file_list="$(git status --porcelain)" 5 | : ${(A)candidates::=${(f)${file_list}}} 6 | 7 | : ${(A)cand_descriptions::=${${(f)${file_list}}/ M /[modified] }} 8 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/AM /[add|modified] }} 9 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/MM /[staged|modified] }} 10 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/M /[staged] }} 11 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/A /[staged(add)] }} 12 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/ D /[deleted] }} 13 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/UU /[conflict] }} 14 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/AA /[conflict] }} 15 | : ${(A)cand_descriptions::=${${(M)cand_descriptions}/\?\? /[untracked] }} 16 | 17 | fi 18 | 19 | actions=( \ 20 | zaw-src-git-status-add \ 21 | zaw-src-git-status-add-p \ 22 | zaw-src-git-status-reset \ 23 | zaw-src-git-status-checkout \ 24 | zaw-src-git-status-edit \ 25 | zaw-src-git-status-rm) 26 | act_descriptions=( \ 27 | "add" \ 28 | "add -p" \ 29 | "reset" \ 30 | "checkout" \ 31 | "edit" \ 32 | "rm") 33 | src_opts=() 34 | } 35 | 36 | function zaw-src-git-status-add() { 37 | local f_path=${1##?* } 38 | local git_base="$(git rev-parse --show-cdup)" 39 | BUFFER="git add '$git_base$f_path'" 40 | zle accept-line 41 | } 42 | 43 | function zaw-src-git-status-add-p() { 44 | local f_path=${1##?* } 45 | local git_base="$(git rev-parse --show-cdup)" 46 | BUFFER="git add -p '$git_base$f_path'" 47 | zle accept-line 48 | } 49 | 50 | function zaw-src-git-status-reset() { 51 | local f_path=${1##?* } 52 | local git_base="$(git rev-parse --show-cdup)" 53 | BUFFER="git reset '$git_base$f_path'" 54 | zle accept-line 55 | } 56 | 57 | function zaw-src-git-status-checkout() { 58 | local f_path=${1##?* } 59 | local git_base="$(git rev-parse --show-cdup)" 60 | BUFFER="git checkout '$git_base$f_path'" 61 | zle accept-line 62 | } 63 | 64 | function zaw-src-git-status-edit() { 65 | local f_path=${1##?* } 66 | local git_base="$(git rev-parse --show-cdup)" 67 | zaw-callback-edit-file "$git_base$f_path" 68 | } 69 | 70 | function zaw-src-git-status-rm() { 71 | local f_path=${1##?* } 72 | local git_base="$(git rev-parse --show-cdup)" 73 | BUFFER="git rm '$git_base$f_path'" 74 | zle accept-line 75 | } 76 | 77 | zaw-register-src -n git-status zaw-src-git-status 78 | -------------------------------------------------------------------------------- /sources/history.zsh: -------------------------------------------------------------------------------- 1 | zmodload zsh/parameter 2 | 3 | function zaw-src-history() { 4 | if zstyle -t ':filter-select' hist-find-no-dups ; then 5 | candidates=(${(@vu)history}) 6 | src_opts=("-m" "-s" "${BUFFER}") 7 | else 8 | cands_assoc=("${(@kv)history}") 9 | # have filter-select reverse the order (back to latest command first). 10 | # somehow, `cands_assoc` gets reversed while `candidates` doesn't. 11 | src_opts=("-r" "-m" "-s" "${BUFFER}") 12 | fi 13 | actions=("zaw-callback-execute" "zaw-callback-replace-buffer" "zaw-callback-append-to-buffer") 14 | act_descriptions=("execute" "replace edit buffer" "append to edit buffer") 15 | 16 | if (( $+functions[zaw-bookmark-add] )); then 17 | # zaw-src-bookmark is available 18 | actions+="zaw-bookmark-add" 19 | act_descriptions+="bookmark this command line" 20 | fi 21 | } 22 | 23 | zaw-register-src -n history zaw-src-history 24 | -------------------------------------------------------------------------------- /sources/locate.zsh: -------------------------------------------------------------------------------- 1 | # zaw source for locate 2 | 3 | autoload -U read-from-minibuffer 4 | 5 | function zaw-src-locate() { 6 | local buf 7 | read-from-minibuffer "locate " 8 | buf=$(locate ${(Q@)${(z)REPLY}}) 9 | if [[ $? != 0 ]]; then 10 | return 1 11 | fi 12 | : ${(A)candidates::=${(f)buf}} 13 | : ${(A)cand_descriptions::=${(f)buf}} 14 | actions=( zaw-callback-append-to-buffer ) 15 | act_descriptions=( "append to buffer" ) 16 | } 17 | 18 | zaw-register-src -n locate zaw-src-locate 19 | 20 | -------------------------------------------------------------------------------- /sources/open-file.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # zaw-open-file 3 | # 4 | # zaw source for xdg-open to open file 5 | # 6 | 7 | function zaw-src-open-file() { 8 | local root parent d f 9 | setopt local_options null_glob 10 | 11 | if (( $# == 0 )); then 12 | root="${PWD}/" 13 | else 14 | root="$1" 15 | fi 16 | 17 | parent="${root:h}" 18 | if [[ "${parent}" != */ ]]; then 19 | parent="${parent}/" 20 | fi 21 | candidates+=("${parent}") 22 | cand_descriptions+=("../") 23 | 24 | # TODO: symlink to directory 25 | for d in "${root%/}"/*(/); do 26 | candidates+=("${d}/") 27 | cand_descriptions+=("${d:t}/") 28 | done 29 | 30 | for f in "${root%/}"/*(^/); do 31 | candidates+=("${f}") 32 | cand_descriptions+=("${f:t}") 33 | done 34 | 35 | actions=( "zaw-callback-open-file" "zaw-callback-append-to-buffer" ) 36 | act_descriptions=( "open file or directory" "append to edit buffer" ) 37 | # TODO: open multiple files 38 | #src_opts=( "-m" ) 39 | src_opts=( "-t" "${root}" ) 40 | } 41 | 42 | zaw-register-src -n open-file zaw-src-open-file 43 | 44 | function zaw-callback-open-file() { 45 | local open 46 | case "${(L)OSTYPE}" in 47 | linux*|*bsd*) 48 | open="xdg-open" 49 | ;; 50 | darwin*) 51 | open="open" 52 | ;; 53 | *) 54 | # TODO: what is the best fallback? 55 | open="xdg-open" 56 | ;; 57 | esac 58 | 59 | # TODO: symlink to directory 60 | if [[ -d "$1" ]]; then 61 | zaw zaw-src-open-file "$1" 62 | else 63 | BUFFER="${open} ${(q)1}" 64 | zle accept-line 65 | fi 66 | } 67 | -------------------------------------------------------------------------------- /sources/perldoc.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-perldoc() { 2 | local code_wanted 3 | local -a words 4 | 5 | # XXX: override _wanted to capture module list _perl_modules generates 6 | code_wanted="${functions[_wanted]}" 7 | function _wanted() { 8 | candidates=("${(P@)${@[7]}}") 9 | } 10 | 11 | # required by _perl_modules 12 | words=(perldoc) 13 | 14 | _perl_modules 15 | 16 | # restore original function 17 | eval "function _wanted() { $code_wanted }" 18 | 19 | actions=("zaw-callback-perldoc-view" "zaw-callback-perldoc-vim") 20 | act_descriptions=("view perldoc" "open with vim") 21 | } 22 | 23 | zaw-register-src -n perldoc zaw-src-perldoc 24 | 25 | function zaw-callback-perldoc-view() { 26 | local orig_buffer="${BUFFER}" 27 | BUFFER=" perldoc '$1'" 28 | zle accept-line 29 | } 30 | 31 | function zaw-callback-perldoc-vim() { 32 | local orig_buffer="${BUFFER}" 33 | BUFFER=" vim -R $(perldoc -lm "$1")" 34 | zle accept-line 35 | } 36 | -------------------------------------------------------------------------------- /sources/process.zsh: -------------------------------------------------------------------------------- 1 | # zaw source for processes 2 | 3 | function zaw-src-process () { 4 | local ps_list title ps pid_list 5 | if [ $(uname) = "Darwin" ] ; then # for Macintosh 6 | ps_list="$(ps aux | awk '$11 !~ /^\[/ {print $0}')" # filter out kernel processes 7 | else 8 | ps_list="$(ps -aux --sort args | awk '$11 !~ /^\[/ {print $0}')" # filter out kernel processes 9 | fi 10 | title="${${(f)ps_list}[1]}" 11 | ps="$(echo $ps_list | sed '1d')" 12 | pid_list="$(echo $ps | awk '{print $2}')" 13 | : ${(A)candidates::=${(f)pid_list}} 14 | : ${(A)cand_descriptions::=${(f)ps}} 15 | actions=(zaw-callback-append-to-buffer zaw-src-process-kill) 16 | act_descriptions=("insert" "kill") 17 | src_opts=(-t "$title") 18 | } 19 | 20 | function zaw-src-process-kill () { 21 | local user="$(ps -ho user $1)" 22 | if [[ -z $user ]]; then 23 | echo "process with PID=$1 is not found" 24 | return 1 25 | fi 26 | if [[ $user = $USER ]]; then 27 | BUFFER="kill $1" 28 | else 29 | BUFFER="sudo kill $1" 30 | fi 31 | zle accept-line 32 | } 33 | 34 | zaw-register-src -n process zaw-src-process 35 | -------------------------------------------------------------------------------- /sources/programs.zsh: -------------------------------------------------------------------------------- 1 | function zaw-src-programs() { 2 | # fill the command hash 3 | hash -r 4 | hash -f 5 | candidates=($(hash | cut -d '=' -f 1)) 6 | actions=(zaw-callback-execute zaw-callback-append-to-buffer zaw-callback-replace-buffer) 7 | act_descriptions=("execute" "append to buffer" "replace buffer") 8 | } 9 | 10 | zaw-register-src -n programs zaw-src-programs 11 | -------------------------------------------------------------------------------- /sources/screens.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # zaw-src-screens 3 | # 4 | # select screen session and attache it 5 | # 6 | 7 | function zaw-src-screens() { 8 | local session state 9 | 10 | screen -ls | awk 'NR==1,/^There (is a|are) screens? on:/ { next } /^[0-9]+ Sockets? in/ { exit } 1' | \ 11 | while read session state; do 12 | candidates+=("${session}") 13 | cand_descriptions+=("${(r:30:::::)session} ${state}") 14 | done 15 | actions=('zaw-callback-screens-attach') 16 | act_descriptions=('attach session') 17 | } 18 | 19 | zaw-register-src -n screens zaw-src-screens 20 | 21 | function zaw-callback-screens-attach() { 22 | BUFFER="screen -rx ${(q)1}" 23 | zle accept-line 24 | } 25 | -------------------------------------------------------------------------------- /sources/searcher.zsh: -------------------------------------------------------------------------------- 1 | # zaw source for ack/ag searcher 2 | 3 | autoload -U read-from-minibuffer 4 | 5 | typeset -g ZAW_SEARCHER_CMD 6 | 7 | if (( $+commands[ag] )); then 8 | ZAW_SEARCHER_CMD="ag" 9 | elif (( $+commands[ack-grep] )); then 10 | ZAW_SEARCHER_CMD="ack-grep" 11 | elif (( $+commands[ack] )); then 12 | ZAW_SEARCHER_CMD="ack" 13 | else 14 | # ack/ag are not found, and disable this source 15 | return 16 | fi 17 | 18 | function zaw-src-searcher() { 19 | local buf 20 | read-from-minibuffer "${ZAW_SEARCHER_CMD} " 21 | buf=$($ZAW_SEARCHER_CMD ${(Q@)${(z)REPLY}}) 22 | if [[ $? != 0 ]]; then 23 | return 1 24 | fi 25 | : ${(A)candidates::=${(f)buf}} 26 | : ${(A)cand_descriptions::=${(f)buf}} 27 | actions=(\ 28 | zaw-src-searcher-edit \ 29 | ) 30 | act_descriptions=(\ 31 | "Edit" \ 32 | ) 33 | } 34 | 35 | function zaw-src-searcher-edit () { 36 | local filename=${1%%:*} 37 | local line=${${1#*:}%%:*} 38 | if [[ -z $ZAW_EDITOR_JUMP_PARAM ]]; then 39 | ZAW_EDITOR_JUMP_PARAM="+%LINE% %FILE%" 40 | fi 41 | BUFFER="${EDITOR} ${${ZAW_EDITOR_JUMP_PARAM/\%LINE\%/$line}/\%FILE\%/$filename}" 42 | zle accept-line 43 | } 44 | 45 | zaw-register-src -n searcher zaw-src-searcher 46 | -------------------------------------------------------------------------------- /sources/ssh-hosts.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # zaw-src-ssh-hosts 3 | # 4 | # Note: .ssh/config must have "HashKnownHosts no" (default) to make known hosts 5 | # values work. 6 | 7 | function zaw-src-ssh-hosts(){ 8 | local -a _global_ssh_known_hosts _global_ssh_known_hosts2 _ssh_known_hosts _ssh_known_hosts2 _etc_hosts _ssh_config_hosts 9 | [ -r /etc/ssh/ssh_known_hosts ] && _global_ssh_known_hosts=(${${${(f)"$(< /etc/ssh/ssh_known_hosts)"}%%\ *}%%,*}) 2>/dev/null || _global_ssh_known_hosts=() 10 | [ -r /etc/ssh/ssh_known_hosts2 ] && _global_ssh_known_hosts2=(${${${(f)"$(< /etc/ssh/ssh_known_hosts2)"}%%\ *}%%,*}) 2>/dev/null || _global_ssh_known_hosts2=() 11 | [ -r "$HOME/.ssh/known_hosts" ] && _ssh_known_hosts=(${${${(f)"$(< ~/.ssh/known_hosts)"}%%\ *}%%,*}) 2>/dev/null || _ssh_known_hosts=() 12 | [ -r "$HOME/.ssh/known_hosts2" ] && _ssh_known_hosts=(${${${(f)"$(< ~/.ssh/known_hosts2)"}%%\ *}%%,*}) 2>/dev/null || _ssh_known_hosts2=() 13 | [ -r /etc/hosts ] && : ${(A)_etc_hosts:=${(s: :)${(ps:\t:)${${(f)~~"$( 1 )); then 36 | shift $(( OPTIND - 1 )) 37 | fi 38 | 39 | zaw_args=() 40 | if [[ $# > 0 && "${zaw_sources[$1]}" != "" ]]; then 41 | zaw_args+="${zaw_sources[$1]}" 42 | fi 43 | 44 | 45 | # use zle-line-init to start zaw right after vared 46 | function zle-line-init() { 47 | zle zaw "${(@)zaw_args}" 48 | 49 | # return from vared 50 | zle accept-line 51 | } 52 | zle -N zle-line-init 53 | 54 | vared -c cmd 55 | 56 | if (( do_eval )); then 57 | eval "${cmd}" 58 | else 59 | print "${cmd}" 60 | fi 61 | -------------------------------------------------------------------------------- /zaw.plugin.zsh: -------------------------------------------------------------------------------- 1 | zaw.zsh -------------------------------------------------------------------------------- /zaw.zsh: -------------------------------------------------------------------------------- 1 | # 2 | # zaw - zsh anything.el-like widget 3 | # 4 | # usage: 5 | # 6 | # add following line to your .zshrc:: 7 | # 8 | # source /path/to/zaw.zsh 9 | # 10 | # and type "^X;" 11 | 12 | # to create namespace, use anonymous function 13 | function() { 14 | 15 | zmodload zsh/parameter 16 | autoload -U is-at-least 17 | 18 | local this_file="${funcsourcetrace[1]%:*}" 19 | if is-at-least 4.3.10; then 20 | # "A" flag (turn a file name into an absolute path with symlink 21 | # resolution) is only available on 4.3.10 and latter 22 | local cur_dir="${this_file:A:h}" 23 | else 24 | local cur_dir="${this_file:h}" 25 | fi 26 | fpath+=("${cur_dir}/functions") 27 | 28 | autoload -U filter-select 29 | 30 | typeset -g -A zaw_sources 31 | zaw_sources=() 32 | 33 | function zaw-register-src() { 34 | # register zaw source 35 | # 36 | # zaw-register-src [-n NAME] SOURCE 37 | # 38 | # SOURCE is function name that define (overrite) these variables 39 | # 40 | # $candidates -> array of candidates 41 | # $cands_assoc -> assoc array of candidates 42 | # $cand_descriptions -> (optional) array of candidates descriptions 43 | # $cand_descriptions_assoc -> (optional) assoc array of candidates descriptions 44 | # $actions -> list of callback function names that receive selected item 45 | # $act_descriptions -> (optional) list of callback function descriptions 46 | # $src_opts -> (optional) array of src_opts passed to filter-select 47 | # 48 | # whether one of candidates or cands-assoc is required 49 | local name func widget_name opts OPTARG OPTIND 50 | 51 | while getopts 'n:' opts; do 52 | name="${OPTARG}" 53 | done 54 | if (( OPTIND > 1 )); then 55 | shift $(( OPTIND - 1 )) 56 | fi 57 | 58 | func="$1" 59 | 60 | if [[ -z "${name}" ]]; then 61 | name="${func}" 62 | fi 63 | 64 | # TODO: check name duplication 65 | zaw_sources+=("${name}" "${func}") 66 | 67 | # define shortcut function 68 | widget_name="zaw-${(L)name// /-}" 69 | eval "function ${widget_name} { zle zaw ${func} \$@ }" 70 | eval "zle -N ${widget_name}" 71 | } 72 | 73 | function zaw-name-from-func() { 74 | local name func 75 | func="$1" 76 | for name in "${(@k)zaw_sources}"; do 77 | if [[ "${zaw_sources[$name]}" == "$func" ]]; then 78 | echo "$name" 79 | return 80 | fi 81 | done 82 | } 83 | 84 | function zaw-action() { 85 | local idx name value 86 | local -a styles 87 | styles=(default alt) 88 | name="$1" 89 | idx="$2" 90 | if zstyle -s ":zaw:${name}" "${styles[$idx]}" value && [[ ${actions[(ie)$value]} -le ${#actions} ]]; then 91 | echo "${value}" 92 | else 93 | echo "${actions[$idx]}" 94 | fi 95 | } 96 | 97 | function zaw() { 98 | local action ret func name 99 | local -a reply candidates actions act_descriptions src_opts selected cand_descriptions 100 | local -A cands_assoc 101 | 102 | if [[ $# == 0 ]]; then 103 | if zle zaw-select-src; then 104 | func="${reply[2]}" 105 | reply=() 106 | else 107 | return 0 108 | fi 109 | else 110 | func="$1" 111 | shift 112 | fi 113 | 114 | zle -R "now loading ..." 115 | 116 | # call source function to generate candidates 117 | "${func}" "$@" 118 | 119 | ret="$?" 120 | if [[ "${ret}" != 0 ]]; then 121 | return 1 122 | fi 123 | 124 | reply=() 125 | 126 | if (( ${#cand_descriptions} )); then 127 | src_opts=("-d" "cand_descriptions" "${(@)src_opts}") 128 | fi 129 | # TODO: cand_descriptions_assoc 130 | 131 | # call filter-select to allow user select item 132 | if (( ${#cands_assoc} )); then 133 | filter-select -e select-action -A cands_assoc "${(@)src_opts}" 134 | else 135 | filter-select -e select-action "${(@)src_opts}" -- "${(@)candidates}" 136 | fi 137 | 138 | if [[ $? == 0 ]]; then 139 | if (( ${#reply_marked} > 0 )); then 140 | selected=("${(@)reply_marked}") 141 | else 142 | selected=("${reply[2]}") 143 | fi 144 | 145 | name=$(zaw-name-from-func "${func}") 146 | 147 | case "${reply[1]}" in 148 | accept-line) 149 | action="$(zaw-action "${name}" 1)" 150 | ;; 151 | accept-search) 152 | action="$(zaw-action "${name}" 2)" 153 | ;; 154 | select-action) 155 | if [[ ${#actions} -eq 1 ]]; then 156 | action="$(zaw-action "${name}" 1)" 157 | else 158 | act_descriptions[${actions[(ie)$(zaw-action "${name}" 1)]}]+=" (Default)" 159 | act_descriptions[${actions[(ie)$(zaw-action "${name}" 2)]}]+=" (Alternative)" 160 | reply=() 161 | filter-select -e select-action -t "select action for '${(j:', ':)selected}'" -d act_descriptions -- "${(@)actions}" 162 | ret=$? 163 | 164 | if [[ $ret == 0 ]]; then 165 | action="${reply[2]}" 166 | else 167 | return 1 168 | fi 169 | fi 170 | ;; 171 | esac 172 | 173 | if [[ -n "${action}" ]]; then 174 | "${action}" "${(@)selected}" 175 | fi 176 | fi 177 | } 178 | 179 | zle -N zaw 180 | 181 | 182 | function zaw-select-src() { 183 | local name 184 | local -a cands descs 185 | cands=() 186 | descs=() 187 | for name in "${(@ko)zaw_sources}"; do 188 | cands+="${zaw_sources[${name}]}" 189 | descs+="${name}" 190 | done 191 | 192 | filter-select -e select-action -d descs -- "${(@)cands}" 193 | } 194 | 195 | zle -N zaw-select-src 196 | 197 | 198 | function zaw-print-src() { 199 | local name func widget_name 200 | printf '%-16s %s\n' "source name" "shortcut widget name" 201 | print -- '----------------------------------------' 202 | for name in "${(@ko)zaw_sources}"; do 203 | widget_name="zaw-${(L)name// /-}" 204 | printf '%-16s %s\n' "${name}" "${widget_name}" 205 | done 206 | } 207 | 208 | 209 | # common callbacks 210 | function zaw-callback-execute() { 211 | BUFFER="${(j:; :)@}" 212 | zle accept-line 213 | } 214 | 215 | function zaw-callback-replace-buffer() { 216 | LBUFFER="${(j:; :)@}" 217 | RBUFFER="" 218 | } 219 | 220 | function zaw-callback-append-to-buffer() { 221 | LBUFFER="${BUFFER}${(j:; :)@}" 222 | } 223 | 224 | function zaw-callback-edit-file() { 225 | local -a args 226 | args=("${(@q)@}") 227 | 228 | if [ ! ${ZAW_EDITOR} ]; then 229 | ZAW_EDITOR=${EDITOR} 230 | fi 231 | 232 | BUFFER="${ZAW_EDITOR} ${args}" 233 | zle accept-line 234 | } 235 | 236 | 237 | # load zaw sources 238 | setopt local_options extended_glob 239 | local src_dir="${cur_dir}/sources" f 240 | if [[ -d "${src_dir}" ]]; then 241 | for f in "${src_dir}"/^*.zwc; do 242 | source "${f}" 243 | done 244 | fi 245 | 246 | # dummy function 247 | # only used for exit-zle-widget-name 248 | function select-action() {}; zle -N select-action 249 | filter-select -i 250 | bindkey -M filterselect '^i' select-action 251 | 252 | bindkey '^X;' zaw 253 | 254 | } 255 | --------------------------------------------------------------------------------