240 lines
9.6 KiB
Plaintext
240 lines
9.6 KiB
Plaintext
#autoload
|
|
|
|
# Filename: _completion_helpers
|
|
# Description: Extra utility functions to help create zsh completion functions
|
|
# Author: Joe Bloggs <vapniks@yahoo.com>
|
|
# Copyleft (Ↄ) 2015, Joe Bloggs, all rites reversed.
|
|
# Created: 2015-12-19 19:00:00
|
|
# By: Joe Bloggs
|
|
# URL: https://github.com/vapniks/zsh-completions
|
|
|
|
## License:
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3, or (at your option)
|
|
# any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; see the file COPYING.
|
|
# If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# To use the following functions add a call to "_completion_helpers" in your completion script,
|
|
# in order to load this file first.
|
|
|
|
# This function joins together groups of consecutive lines. The first line in each group is identified by having
|
|
# less initial whitespace that subsequent lines in the group (i.e. it is indented less).
|
|
# This is useful for preprocessing the output from a command called with its --help argument.
|
|
# The function reads input from a pipe and takes the following three arguments:
|
|
# 1) A separator to place between joined lines.
|
|
# 2) A regular expression matching the initial line of each group. All lines subsequent to the initial line will
|
|
# be appended to it (after removing leading & trailing whitespace) until the next initial line of a group.
|
|
# Alternatively this argument can be the maximum number of leading whitespace chars for the initial line.
|
|
# Any lines with more than this many leading whitespace chars will be appended to previous lines.
|
|
# 3) An optional regular expression matching the line before the beginning of the section of output to be processed.
|
|
# If this is set to the empty string then processing will start from the beginning of the output.
|
|
# 4) An optional regular expression matching the line after the end of the section of output to be processed
|
|
# (if this arg is omitted then all output upto the last line will be processed).
|
|
function _join_lines() {
|
|
awk -v SEP="$1" -v ARG2="$2" -v START="$3" -v END2="$4" 'BEGIN {if(START==""){f=1}{f=0};
|
|
if(ARG2 ~ "^[0-9]+"){LINE1 = "^[[:space:]]{,"ARG2"}[^[:space:]]"}else{LINE1 = ARG2}}
|
|
($0 ~ END2 && f>0 && END2!="") {exit}
|
|
($0 ~ START && f<1) {f=1; if(length(START)!=0){next}}
|
|
($0 ~ LINE1 && f>0) {if(f<2){f=2; printf("%s",$0)}else{printf("\n%s",$0)}; next}
|
|
(f>1) {gsub(/^[[:space:]]+|[[:space:]]+$/,"",$0); printf("%s%s",SEP, $0); next}
|
|
END {print ""}'
|
|
}
|
|
|
|
# This function can be used to extract parts of lines into arrays. This is useful for extracting
|
|
# completion information about commands by using the --help option.
|
|
# It takes a variable number of arguments: a regexp (first arg), and the names of any number
|
|
# array variables (other args).
|
|
# For each line of input piped into the function it will try and match the regexp on the line
|
|
# and save each parenthesised subexpression into one of the arrays (first subexpression into
|
|
# the first array, second subexpression into the second array, etc.)
|
|
# For each line that doesn't match the regexp empty elements will be added to the arrays.
|
|
# If a line matches but a subexpressions doesn't then whatever is stored in the corresponding
|
|
# element of $match (see zsh documentation) will be used instead.
|
|
function _extract_parts() {
|
|
OLDIFS=$IFS;IFS=;
|
|
while read -r inputtxt; do
|
|
local i=2 rx="${*[1]}" matched="no"
|
|
if [[ "$inputtxt" =~ "$rx" ]]; then
|
|
matched="yes"
|
|
fi
|
|
while [[ "$i" -le "$#" ]]; do
|
|
local arr="${*[$i]}"
|
|
if [[ -n "$arr" ]]; then
|
|
if [[ "$matched" =~ "yes" ]]; then
|
|
eval "$arr+=\$match[$i-1]"
|
|
else
|
|
eval "$arr+=''"
|
|
fi
|
|
fi
|
|
let i=i+1
|
|
done
|
|
done
|
|
IFS=$OLDIFS
|
|
}
|
|
|
|
# Given three arrays of strings, apply _regex_words to triples formed by taking corresponding elements
|
|
# from the arrays. The result will be stored in the $reply array, and can be viewed with: echo "${reply[@]}"
|
|
# See documentation of _regex_words for more info.
|
|
# This command takes 5 arguments:
|
|
# 1) A tag name for the resulting call to _regex_words
|
|
# 2) A description for the call to _regex_words
|
|
# 3) The name of an array var containing completion words (each used in first part of a _regex_words spec)
|
|
# 4) The name of an array var containing descriptions (each used in second part of a _regex_words spec)
|
|
# 5) Optionally: the name of an array var containing further completions (each used in third part of a _regex_words spec)
|
|
# 6) Optionally: the name of an array var in which to store the results from _regex_words
|
|
# (otherwise they can be found in ${reply[@]})
|
|
function _arrays_to_regex_words() {
|
|
local opts="${*[3]}" descs="${*[4]}" args="${*[5]}"
|
|
local -a regexwords
|
|
local i=1 desc
|
|
while [[ "$i" -le "${(@P)#opts}" ]]; do
|
|
desc="${${${${${(@P)descs}[$i]//:/-}//\[/(}//]/)}//\'/}"
|
|
regexwords+="${${(@P)opts}[$i]}:$desc:${${(@P)args}[$i]}"
|
|
let i=i+1
|
|
done
|
|
_regex_words "$1" "$2" "${regexwords[@]}"
|
|
if [[ -n "${*[6]}" ]]; then
|
|
set -A "${*[6]}" "${reply[@]}"
|
|
fi
|
|
}
|
|
|
|
# This function can be used for substituting values in an indexed array (1st arg) according to rules defined in another
|
|
# associative array (2nd arg)
|
|
# Any elements of the indexed array that match a key of the associative array will be replaced with the corresponding value
|
|
# of the associative array.
|
|
# This can be used for replacing option argument names (extracted from command help info) with corresponding definitions
|
|
# for _regex_words (also using _arrays_to_regex_words).
|
|
function _replace_vals_in_array() {
|
|
local vals="$1" arg2="$2"
|
|
typeset -A repls
|
|
set -A repls "${(kvP@)arg2}"
|
|
local i=1 newval val repl
|
|
while [[ "$i" -le "${(P)#vals}" ]]; do
|
|
val="${${(@P)vals}[i]}"
|
|
repl="${repls[$val]}"
|
|
if [[ -n "$repl" ]]; then
|
|
typeset -g "$vals""[$i]"="$repl"
|
|
fi
|
|
let i=i+1
|
|
done
|
|
}
|
|
|
|
# This function makes multiple substitutions in the input string and outputs the result.
|
|
# It takes a single argument: the name of an associative array whose keys are the strings
|
|
# to be replaced and whose values are the replacements.
|
|
_multi_substitute () {
|
|
local instring="$(cat)"
|
|
local key val
|
|
typeset -A repls
|
|
set -A repls "${(kvP@)1}"
|
|
for key in "${(k@)repls}"
|
|
do
|
|
val="${repls[$key]}"
|
|
instring="${instring//$key/$val}"
|
|
done
|
|
print "$instring"
|
|
}
|
|
|
|
# This function creates an associative array from a pair of indexed arrays of keys and values.
|
|
# It takes the following arguments:
|
|
# 1) a name for the resulting associative array
|
|
# 2) the name of an indexed array of keys
|
|
# 3) the name of an indexed array of values (with order corresponding to the keys array)
|
|
# If there are fewer keys than values then any excess values will be omitted from the results.
|
|
# If there are more keys than values then the extra keys will not be assigned values
|
|
function _create_assoc_array() {
|
|
typeset -g -A "$1"
|
|
local i=1 key val
|
|
local keys="$2" vals="$3"
|
|
while [[ "$i" -le "${(P@)#keys}" ]]; do
|
|
key="${${(P@)keys}[$i]}"
|
|
val="${${(P@)vals}[$i]}"
|
|
typeset -g "$1""[$key]"="$val"
|
|
let i=i+1
|
|
done
|
|
}
|
|
|
|
# This function tests whether its only argument is a shell option or not.
|
|
function _is_option() {
|
|
[[ -n "$1" ]] \
|
|
&& ( (setopt | grep "^$1\$" >/dev/null) \
|
|
|| (unsetopt | grep "^$1\$" >/dev/null) )
|
|
}
|
|
|
|
# This function saves current shell option values to an associative array.
|
|
# The first argument can be the name of a variable to save the option to,
|
|
# or an option name.
|
|
# All other arguments are names of options to save. If the first argument
|
|
# is an option name then it save with the other option name arguments into
|
|
# the SAVED_SHELL_OPTIONS variable instead.
|
|
# The options can be restored using the _restore_options function.
|
|
function _save_options() {
|
|
local savename
|
|
if _is_option "$1"; then
|
|
savename=SAVED_SHELL_OPTIONS
|
|
else
|
|
savename="$1"
|
|
shift
|
|
fi
|
|
local -a opts states
|
|
opts=("$@")
|
|
local i=1
|
|
while [[ "$i" -le "${#opts}" ]]; do
|
|
if ( setopt | grep "^$opts[i]\$" > /dev/null ); then
|
|
states[i]=on
|
|
elif ( unsetopt | grep "^$opts[i]\$" > /dev/null ); then
|
|
states[i]=off
|
|
else
|
|
echo "Invalid option $opts[i] !"
|
|
fi
|
|
let i=i+1
|
|
done
|
|
_create_assoc_array "$savename" opts states
|
|
}
|
|
|
|
# This function is used for restoring options previously saved with _save_options
|
|
# The first argument can be the name of a variable containing the saved options,
|
|
# or an option name. All other arguments are the names of options to restore.
|
|
# If no option names are supplied then all saved options will be restored.
|
|
# If the first argument is an option name, then it will be restored with the other
|
|
# option name arguments from the SAVED_SHELL_OPTIONS variable instead.
|
|
# If there are no arguments then all options in SAVED_SHELL_OPTIONS will be restored.
|
|
function _restore_options () {
|
|
local savename
|
|
if _is_option "$1"; then
|
|
savename=SAVED_SHELL_OPTIONS
|
|
else
|
|
savename="$1"
|
|
shift
|
|
fi
|
|
typeset -A savedoptions
|
|
set -A savedoptions "${(kvP@)savename}"
|
|
local -a opts
|
|
opts=("$@")
|
|
local opt state
|
|
for opt in "${(k@)savedoptions}"; do
|
|
if [[ "${#opts}" -eq 0 || "${opts[(r)$opt]}" == "$opt" ]]; then
|
|
state="${savedoptions[$opt]}"
|
|
if [[ "$state" =~ "on" ]]; then
|
|
setopt "$opt"
|
|
elif [[ "$state" =~ "off" ]]; then
|
|
unsetopt "$opt"
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Local Variables:"
|
|
# mode:sh"
|
|
# End:"
|