aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ISSUES.md2
-rw-r--r--Makefile4
-rw-r--r--VERSION4
-rw-r--r--bash/bash_completion.d/_abook_addresses.bash37
-rw-r--r--bash/bash_completion.d/_ssh_config_hosts.bash62
-rw-r--r--bash/bash_completion.d/_text_filenames.bash191
-rw-r--r--bash/bash_completion.d/awk.bash3
-rw-r--r--bash/bash_completion.d/bd.bash13
-rw-r--r--bash/bash_completion.d/cat.bash3
-rw-r--r--bash/bash_completion.d/ed.bash3
-rw-r--r--bash/bash_completion.d/eds.bash31
-rw-r--r--bash/bash_completion.d/ex.bash3
-rw-r--r--bash/bash_completion.d/find.bash4
-rw-r--r--bash/bash_completion.d/ftp.bash2
-rw-r--r--bash/bash_completion.d/git.bash13
-rw-r--r--bash/bash_completion.d/gpg.bash15
-rw-r--r--bash/bash_completion.d/grep.bash3
-rw-r--r--bash/bash_completion.d/head.bash3
-rw-r--r--bash/bash_completion.d/keep.bash101
-rw-r--r--bash/bash_completion.d/m4.bash3
-rw-r--r--bash/bash_completion.d/mail.bash7
-rw-r--r--bash/bash_completion.d/make.bash7
-rw-r--r--bash/bash_completion.d/man.bash43
-rw-r--r--bash/bash_completion.d/mex.bash3
-rw-r--r--bash/bash_completion.d/mutt.bash3
-rw-r--r--bash/bash_completion.d/mysql.bash31
-rw-r--r--bash/bash_completion.d/pass.bash31
-rw-r--r--bash/bash_completion.d/path.bash51
-rw-r--r--bash/bash_completion.d/sd.bash39
-rw-r--r--bash/bash_completion.d/sftp.bash3
-rw-r--r--bash/bash_completion.d/ssh-copy-id.bash3
-rw-r--r--bash/bash_completion.d/ssh.bash3
-rw-r--r--bash/bash_completion.d/td.bash10
-rw-r--r--bash/bash_completion.d/ud.bash24
-rw-r--r--bash/bashrc4
-rw-r--r--check/login-shell.sh6
-rw-r--r--install/conf.sh (renamed from install/install-conf.sh)0
-rw-r--r--install/login-shell.sh (renamed from install/install-login-shell.sh)6
38 files changed, 423 insertions, 351 deletions
diff --git a/ISSUES.md b/ISSUES.md
index 4e70c0ed..b2601de9 100644
--- a/ISSUES.md
+++ b/ISSUES.md
@@ -28,3 +28,5 @@ Known issues
it?
* The b:undo\_indent definition for the perl filetype can probably be pushed
upstream.
+* The `_text_filenames` completion handler for Bash won't work on files with
+ newlines in their names. Can it be made to?
diff --git a/Makefile b/Makefile
index 3093b96d..f9ed21ac 100644
--- a/Makefile
+++ b/Makefile
@@ -352,7 +352,7 @@ install: install-bin \
install-vim
install-conf:
- sh install/install-conf.sh
+ sh install/conf.sh
install-abook:
mkdir -p -- $(HOME)/.abook
@@ -465,7 +465,7 @@ install-ksh: check-ksh install-sh
cp -p -- ksh/kshrc.d/* $(HOME)/.kshrc.d
install-login-shell: check-login-shell
- sh install/install-login-shell.sh
+ sh install/login-shell.sh
install-perlcritic:
cp -p -- perlcritic/perlcriticrc $(HOME)/.perlcriticrc
diff --git a/VERSION b/VERSION
index a7367f3b..8e55d49a 100644
--- a/VERSION
+++ b/VERSION
@@ -1,2 +1,2 @@
-tejr dotfiles v2.5.0
-Fri Nov 30 01:30:00 UTC 2018
+tejr dotfiles v2.6.0
+Fri Nov 30 13:48:02 UTC 2018
diff --git a/bash/bash_completion.d/_abook_addresses.bash b/bash/bash_completion.d/_abook_addresses.bash
index 8e341172..e79eef42 100644
--- a/bash/bash_completion.d/_abook_addresses.bash
+++ b/bash/bash_completion.d/_abook_addresses.bash
@@ -1,10 +1,33 @@
# Email addresses from abook(1)
_abook_addresses() {
- while IFS=$'\t' read -r address _ ; do
- case $address in
- "${COMP_WORDS[COMP_CWORD]}"*)
- COMPREPLY[${#COMPREPLY[@]}]=$address
- ;;
- esac
- done < <(abook --mutt-query \@)
+
+ # Needs abook(1)
+ hash abook 2>/dev/null || return
+
+ # Iterate through words produced by subshell
+ local word
+ while read -r word ; do
+ [[ -n $word ]] || continue
+ COMPREPLY[${#COMPREPLY[@]}]=$word
+ done < <(
+
+ # Set case-insensitive matching if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocasematch 2>/dev/null
+ break
+ ;;
+ esac
+ done < <(bind -v)
+
+ # Generate list of email addresses from abook(1)
+ while IFS=$'\t' read -r address _ ; do
+ case $address in
+ ("${COMP_WORDS[COMP_CWORD]}"*)
+ printf '%s\n' "$address"
+ ;;
+ esac
+ done < <(abook --mutt-query \@)
+ )
}
diff --git a/bash/bash_completion.d/_ssh_config_hosts.bash b/bash/bash_completion.d/_ssh_config_hosts.bash
index 8f45c412..c26457cf 100644
--- a/bash/bash_completion.d/_ssh_config_hosts.bash
+++ b/bash/bash_completion.d/_ssh_config_hosts.bash
@@ -1,22 +1,48 @@
# Complete ssh_config(5) hostnames
_ssh_config_hosts() {
- # Read hostnames from existent config files, no asterisks
- local -a hosts
- local config option value
- for config in "$HOME"/.ssh/config /etc/ssh/ssh_config ; do
- [[ -e $config ]] || continue
- while read -r option value _ ; do
- [[ $option == Host ]] || continue
- [[ $value != *'*'* ]] || continue
- hosts[${#hosts[@]}]=$value
- done < "$config"
- done
-
- # Generate completion reply
- local host
- for host in "${hosts[@]}" ; do
- [[ $host == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$host
- done
+ # Don't complete anything that wouldn't be in a valid hostname
+ case ${COMP_WORDS[COMP_CWORD]} in
+ *[!a-zA-Z0-9.-]*) return 1 ;;
+ esac
+
+ # Iterate through words from a subshell
+ while read -r word ; do
+ [[ -n $word ]] || continue
+ COMPREPLY[${#COMPREPLY[@]}]=$word
+ done < <(
+
+ # Check bind settings to see if we should match case insensitively
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -qs nocasematch 2>/dev/null
+ break
+ ;;
+ esac
+ done < <(bind -v)
+
+ # Iterate through SSH client config paths
+ for config in "$HOME"/.ssh/config /etc/ssh/ssh_config ; do
+ [[ -e $config ]] || continue
+
+ # Read Host options and their first value from file
+ while read -r option value _ ; do
+ [[ $option == Host ]] || continue
+
+ # Check host value
+ case $value in
+
+ # Don't complete with wildcard characters
+ (*'*'*) ;;
+
+ # Found a match; print it
+ ("${COMP_WORDS[COMP_CWORD]}"*)
+ printf '%s\n' "$value"
+ ;;
+ esac
+
+ done < "$config"
+ done
+ )
}
diff --git a/bash/bash_completion.d/_text_filenames.bash b/bash/bash_completion.d/_text_filenames.bash
index a9d767b7..9cc1c722 100644
--- a/bash/bash_completion.d/_text_filenames.bash
+++ b/bash/bash_completion.d/_text_filenames.bash
@@ -14,71 +14,146 @@ _text_filenames() {
# Exclude blanks
[[ -n $item ]] || continue
+ # Exclude nonexistent (some sort of error)
+ [[ -e $item ]] || continue
+
+ # Exclude files with block, character, pipe, or socket type
+ ! [[ -b $item ]] || continue
+ ! [[ -c $item ]] || continue
+ ! [[ -p $item ]] || continue
+ ! [[ -S $item ]] || continue
+
# Accept directories
if [[ -d $item ]] ; then
COMPREPLY[${#COMPREPLY[@]}]=$item
continue
fi
- # Exclude files with block, character, pipe, or socket type
- [[ ! -b $item ]] || continue
- [[ ! -c $item ]] || continue
- [[ ! -p $item ]] || continue
- [[ ! -S $item ]] || continue
-
# Check the filename extension to know what to exclude
- case $item in
-
- # Binary image file formats
- *.bmp|*.gif|*.ico|*.jpeg|*.jpg|*.png|*.tif|*.xcf) ;;
- *.BMP|*.GIF|*.ICO|*.JPEG|*.JPG|*.PNG|*.TIF|*.XCF) ;;
-
- # Video file formats
- *.avi|*.gifv|*.mkv|*.mov|*.mpg|*.rm|*.webm) ;;
- *.AVI|*.GIFV|*.MKV|*.MOV|*.MPG|*.RM|*.WEBM) ;;
-
- # Lossy audio file formats
- *.au|*.m4a|*.mp[34]|*.ogg|*.snd|*.wma) ;;
- *.AU|*.M4A|*.MP[34]|*.OGG|*.SND|*.WMA) ;;
-
- # Lossless/source audio file formats
- *.aup|*.flac|*.mid|*.h2song|*.nwc|*.s3m|*.wav) ;;
- *.AUP|*.FLAC|*.MID|*.H2SONG|*.NWC|*.S3M|*.WAV) ;;
-
- # Compressed/archived file formats
- *.cab|*.deb|*.lzm|*.pack|*.tar|*.tar.bz2|*.tar.gz|*.tar.xz|*.zip) ;;
- *.CAB|*.DEB|*.LZM|*.PACK|*.TAR|*.TAR.BZ2|*.TAR.GZ|*.TAR.XZ|*.ZIP) ;;
-
- # Document formats
- # (Not .doc, it's a plaintext format sometimes)
- *.cbr|*.docx|*.epub|*.odp|*.odt|*.pdf|*.xls|*.xlsx) ;;
- *.CBR|*.DOCX|*.EPUB|*.ODP|*.ODT|*.PDF|*.XLS|*.XLSX) ;;
-
- # Filesystems/disk images
- *.bin|*.cue|*.hdf|*.img|*.iso|*.mdf|*.raw) ;;
- *.BIN|*.CUE|*.HDF|*.IMG|*.ISO|*.MDF|*.RAW) ;;
-
- # Font files
- *.ttf) ;;
- *.TTF) ;;
-
- # Index file formats
- *.idx) ;;
- *.IDX) ;;
-
- # Encrypted file formats
- *.gpg) ;;
- *.GPG) ;;
-
- # Other known binary extensions
- # (I haven't included .com; on UNIX, that's more likely to be
- # something I saved from a website and named after the domain)
- *.a|*.drv|*.exe|*.o|*.torrent|*.wad|*.rom) ;;
- *.A|*.DRV|*.EXE|*.O|*.TORRENT|*.WAD|*.ROM) ;;
-
- # Complete everything else; some of it will still be binary
- *) COMPREPLY[${#COMPREPLY[@]}]=$item ;;
+ (
+ # Case-insensitive matching available since 3.1-alpha
+ shopt -qs nocasematch 2>/dev/null
+
+ # Match against known binary patterns
+ case $item in
+
+ # Archives
+ (*.7z) ;;
+ (*.bz2) ;;
+ (*.gz) ;;
+ (*.jar) ;;
+ (*.rar) ;;
+ (*.tar) ;;
+ (*.xz) ;;
+ (*.zip) ;;
+
+ # Bytecode
+ (*.class) ;;
+ (*.pyc) ;;
+
+ # Databases
+ (*.db) ;;
+ (*.dbm) ;;
+ (*.sdbm) ;;
+ (*.sqlite) ;;
+
+ # Disk
+ (*.adf) ;;
+ (*.bin) ;;
+ (*.hdf) ;;
+ (*.iso) ;;
+
+ # Documents
+ (*.docx) ;;
+ (*.djvu) ;;
+ (*.odp) ;;
+ (*.ods) ;;
+ (*.odt) ;;
+ (*.pdf) ;;
+ (*.ppt) ;;
+ (*.xls) ;;
+ (*.xlsx) ;;
+
+ # Encrypted
+ (*.asc) ;;
+ (*.gpg) ;;
+
+ # Executables
+ (*.exe) ;;
+
+ # Fonts
+ (*.ttf) ;;
+
+ # Images
+ (*.bmp) ;;
+ (*.gd2) ;;
+ (*.gif) ;;
+ (*.ico) ;;
+ (*.jpeg) ;;
+ (*.jpg) ;;
+ (*.pbm) ;;
+ (*.png) ;;
+ (*.psd) ;;
+ (*.tga) ;;
+ (*.xbm) ;;
+ (*.xcf) ;;
+ (*.xpm) ;;
+
+ # Incomplete
+ (*.filepart) ;;
+
+ # Objects
+ (*.a) ;;
+ (*.o) ;;
+
+ # Sound
+ (*.au) ;;
+ (*.aup) ;;
+ (*.flac) ;;
+ (*.mid) ;;
+ (*.m4a) ;;
+ (*.mp3) ;;
+ (*.ogg) ;;
+ (*.opus) ;;
+ (*.s3m) ;;
+ (*.wav) ;;
+
+ # System-specific
+ (.DS_Store) ;;
+
+ # Translation
+ (*.gmo) ;;
+
+ # Version control
+ (.git) ;;
+ (.hg) ;;
+ (.svn) ;;
+
+ # Video
+ (*.avi) ;;
+ (*.gifv) ;;
+ (*.mp4) ;;
+ (*.ogv) ;;
+ (*.rm) ;;
+ (*.swf) ;;
+ (*.webm) ;;
+
+ # Vim
+ (*~) ;;
+ (*.swp) ;;
+
+ # Not binary that we can tell; maybe editable
+ (*) exit 0 ;;
+
+ esac
+
+ # Known usually-binary extension; flag failure
+ exit 1
+
+ ) || continue
+
+ # Complete everything else; some of it will still be binary
+ COMPREPLY[${#COMPREPLY[@]}]=$item
- esac
done < <(compgen -A file -- "${COMP_WORDS[COMP_CWORD]}")
}
diff --git a/bash/bash_completion.d/awk.bash b/bash/bash_completion.d/awk.bash
index 1e01381a..5f121d8a 100644
--- a/bash/bash_completion.d/awk.bash
+++ b/bash/bash_completion.d/awk.bash
@@ -1,4 +1,5 @@
# Completion for awk(1) with files that look editable
-declare -F _text_filenames >/dev/null ||
+if ! declare -F _text_filenames >/dev/null ; then
source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _text_filenames -o filenames awk
diff --git a/bash/bash_completion.d/bd.bash b/bash/bash_completion.d/bd.bash
index 86146a4e..e67cdd09 100644
--- a/bash/bash_completion.d/bd.bash
+++ b/bash/bash_completion.d/bd.bash
@@ -2,21 +2,24 @@
_bd() {
# Only makes sense for the first argument
- ((COMP_CWORD == 1)) || return 1
+ ((COMP_CWORD == 1)) || return
# Build a list of dirnames in $PWD
local -a dirnames
IFS=/ read -rd '' -a dirnames < <(printf '%s\0' "${PWD#/}")
# Remove the last element in the array (the current directory)
- ((${#dirnames[@]})) || return 1
- dirnames=("${dirnames[@]:0:$((${#dirnames[@]}-1))}")
+ ((${#dirnames[@]})) || return
+ dirnames=("${dirnames[@]:0:${#dirnames[@]}-1}")
# Add the matching dirnames to the reply
local dirname
for dirname in "${dirnames[@]}" ; do
- [[ $dirname == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$(printf %q "$dirname")
+ case $dirname in
+ "${COMP_WORDS[COMP_CWORD]}"*)
+ COMPREPLY[${#COMPREPLY[@]}]=$(printf %q "$dirname")
+ ;;
+ esac
done
}
complete -F _bd bd
diff --git a/bash/bash_completion.d/cat.bash b/bash/bash_completion.d/cat.bash
index 430cd58c..2da60ff0 100644
--- a/bash/bash_completion.d/cat.bash
+++ b/bash/bash_completion.d/cat.bash
@@ -1,4 +1,5 @@
# Completion for cat(1) with files that look editable
-declare -F _text_filenames >/dev/null ||
+if ! declare -F _text_filenames >/dev/null ; then
source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _text_filenames -o filenames cat
diff --git a/bash/bash_completion.d/ed.bash b/bash/bash_completion.d/ed.bash
index c7fc6fde..b9651957 100644
--- a/bash/bash_completion.d/ed.bash
+++ b/bash/bash_completion.d/ed.bash
@@ -1,4 +1,5 @@
# Completion for ed(1) with files that look editable
-declare -F _text_filenames >/dev/null ||
+if ! declare -F _text_filenames >/dev/null ; then
source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _text_filenames -o filenames ed
diff --git a/bash/bash_completion.d/eds.bash b/bash/bash_completion.d/eds.bash
index ea6de618..1c5b2aa2 100644
--- a/bash/bash_completion.d/eds.bash
+++ b/bash/bash_completion.d/eds.bash
@@ -11,17 +11,12 @@ _eds() {
done < <(
shopt -s dotglob nullglob
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Make globbing case-insensitive if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
@@ -30,18 +25,14 @@ _eds() {
files=("${EDSPATH:-"$HOME"/.local/bin}"/"${COMP_WORDS[COMP_CWORD]}"*)
declare -a executables
for file in "${files[@]}" ; do
- [[ -f $file && -x $file ]] || continue
+ ! [[ -d $file ]] || continue
+ [[ -e $file ]] || continue
+ [[ -x $file ]] || continue
executables[${#executables[@]}]=${file##*/}
done
- # Print quoted entries, null-delimited, if there was at least one;
- # otherwise, just print a null character to stop this hanging in Bash
- # 4.4
- if ((${#executables[@]})) ; then
- printf '%q\0' "${executables[@]}"
- else
- printf '\0'
- fi
+ # Print quoted entries, null-delimited
+ printf '%q\0' "${executables[@]}"
)
}
complete -F _eds eds
diff --git a/bash/bash_completion.d/ex.bash b/bash/bash_completion.d/ex.bash
index 6805b8b1..00875df5 100644
--- a/bash/bash_completion.d/ex.bash
+++ b/bash/bash_completion.d/ex.bash
@@ -1,4 +1,5 @@
# Completion for ex(1) with files that look editable
-declare -F _text_filenames >/dev/null ||
+if ! declare -F _text_filenames >/dev/null ; then
source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _text_filenames -o filenames ex
diff --git a/bash/bash_completion.d/find.bash b/bash/bash_completion.d/find.bash
index 007a83bd..7e2ae9c3 100644
--- a/bash/bash_completion.d/find.bash
+++ b/bash/bash_completion.d/find.bash
@@ -30,7 +30,7 @@ _find() {
local item
while read -r item ; do
[[ -n $item ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$item
+ COMPREPLY+=("$item")
done < <(
# If the word being completed starts with a dash, just complete it as
@@ -64,7 +64,7 @@ _find() {
# Otherwise, look at the word *before* this one to figure out what to
# complete
- case "${COMP_WORDS[COMP_CWORD-1]}" in
+ case ${COMP_WORDS[COMP_CWORD-1]} in
# Args to -exec and -execdir should be commands
(-exec|-execdir)
diff --git a/bash/bash_completion.d/ftp.bash b/bash/bash_completion.d/ftp.bash
index d7ee8963..a584dd81 100644
--- a/bash/bash_completion.d/ftp.bash
+++ b/bash/bash_completion.d/ftp.bash
@@ -4,7 +4,7 @@ _ftp() {
# Bail if the .netrc file is illegible
local netrc
netrc=$HOME/.netrc
- [[ -r $netrc ]] || return 1
+ [[ -r $netrc ]] || return
# Tokenize the file
local -a tokens
diff --git a/bash/bash_completion.d/git.bash b/bash/bash_completion.d/git.bash
index 2fd1bb98..a2edb468 100644
--- a/bash/bash_completion.d/git.bash
+++ b/bash/bash_completion.d/git.bash
@@ -12,16 +12,14 @@ _git() {
refs)
local ref
while IFS= read -r ref ; do
- [[ -n $ref ]] || continue
ref=${ref#refs/*/}
case $ref in
+ '') continue ;;
"${COMP_WORDS[COMP_CWORD]}"*)
COMPREPLY[${#COMPREPLY[@]}]=$ref
;;
esac
- done < <(git for-each-ref \
- --format '%(refname)' \
- 2>/dev/null)
+ done < <(git for-each-ref --format '%(refname)' 2>/dev/null)
return
;;
@@ -51,9 +49,7 @@ _git() {
COMPREPLY[${#COMPREPLY[@]}]=$alias
;;
esac
- done < <(git config \
- --get-regexp '^alias\.' \
- 2>/dev/null)
+ done < <(git config --get-regexp '^alias\.' 2>/dev/null)
return
;;
@@ -63,7 +59,8 @@ _git() {
execpath=$(git --exec-path) || return
local path
for path in "$execpath"/git-"${COMP_WORDS[COMP_CWORD]}"* ; do
- [[ -f $path ]] || continue
+ ! [[ -d $path ]] || continue
+ [[ -e $path ]] || continue
[[ -x $path ]] || continue
COMPREPLY[${#COMPREPLY[@]}]=${path#"$execpath"/git-}
done
diff --git a/bash/bash_completion.d/gpg.bash b/bash/bash_completion.d/gpg.bash
index f98cb193..697e4a65 100644
--- a/bash/bash_completion.d/gpg.bash
+++ b/bash/bash_completion.d/gpg.bash
@@ -2,18 +2,21 @@
_gpg() {
# Bail if no gpg(1)
- hash gpg 2>/dev/null || return 1
+ hash gpg 2>/dev/null || return
# Bail if not completing an option
- [[ ${COMP_WORDS[COMP_CWORD]} == --* ]] || return 1
+ case ${COMP_WORDS[COMP_CWORD]} in
+ --*) return 1 ;;
+ esac
# Generate completion reply from gpg(1) options
local option
while read -r option ; do
- [[ $option == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$option
+ case $option in
+ "${COMP_WORDS[COMP_CWORD]}"*)
+ COMPREPLY[${#COMPREPLY[@]}]=$option
+ ;;
+ esac
done < <(gpg --dump-options 2>/dev/null)
}
-
-# bashdefault requires Bash >=3.0
complete -F _gpg -o bashdefault -o default gpg
diff --git a/bash/bash_completion.d/grep.bash b/bash/bash_completion.d/grep.bash
index 86c191cb..e9986b15 100644
--- a/bash/bash_completion.d/grep.bash
+++ b/bash/bash_completion.d/grep.bash
@@ -1,4 +1,5 @@
# Completion for grep(1) with files that look editable
-declare -F _text_filenames >/dev/null ||
+if ! declare -F _text_filenames >/dev/null ; then
source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _text_filenames -o filenames grep
diff --git a/bash/bash_completion.d/head.bash b/bash/bash_completion.d/head.bash
index fa7cb878..0f4a7131 100644
--- a/bash/bash_completion.d/head.bash
+++ b/bash/bash_completion.d/head.bash
@@ -1,4 +1,5 @@
# Completion for head(1) with files that look editable
-declare -F _text_filenames >/dev/null ||
+if ! declare -F _text_filenames >/dev/null ; then
source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _text_filenames -o filenames head
diff --git a/bash/bash_completion.d/keep.bash b/bash/bash_completion.d/keep.bash
index 77b37059..00b1469e 100644
--- a/bash/bash_completion.d/keep.bash
+++ b/bash/bash_completion.d/keep.bash
@@ -2,71 +2,56 @@
# stuff that's already kept
_keep() {
- # Default is to complete with function and variable names
+ # Determine what we're doing based on first completion word
local mode
- mode=names
-
- # Iterate through the words up to the previous word to figure out how to
- # complete this one
- local i
- for ((i = 0; i < COMP_CWORD; i++)) ; do
- case ${COMP_WORDS[i]} in
- --)
- mode=names
- break
- ;;
- -d)
- mode=kept
- break
- ;;
+ mode=keep
+ if ((COMP_CWORD > 1)) ; then
+ case ${COMP_WORDS[1]} in
+ -h) return 1 ;;
+ -d) mode=delete ;;
esac
- done
+ fi
- # Complete with appropriate mode
- case $mode in
- names)
- local word
- while IFS= read -r word ; do
- [[ -n $word ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$word
- done < <(compgen -A function -A variable \
- -- "${COMP_WORDS[COMP_CWORD]}")
- ;;
- kept)
- local word
- while IFS= read -r word ; do
- [[ -n $word ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$word
- done < <(
- shopt -s dotglob nullglob
+ # Collect words from an appropriate type of completion
+ local word
+ while read -r word ; do
+ [[ -n $word ]] || continue
+ COMPREPLY[${#COMPREPLY[@]}]=$word
+ done < <(
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Switch on second word; is it a -d option?
+ case $mode in
+
+ # Keepable names: all functions and variables
+ (keep)
+ compgen -A function -A variable \
+ -- "${COMP_WORDS[COMP_CWORD]}"
+ ;;
+
+ # Kept names: .bash-suffixed names in keep dir
+ (delete)
+ # Make globs behave correctly
+ shopt -s nullglob
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
- keep=${BASHKEEP:-"$HOME"/.bashkeep.d}
- declare -a keeps
- keeps=("$keep"/"${COMP_WORDS[COMP_CWORD]}"*.bash)
- keeps=("${keeps[@]##*/}")
- keeps=("${keeps[@]%.bash}")
- if ((${#keeps[@]})) ; then
- printf '%s\n' "${keeps[@]}"
- else
- printf '\n'
- fi
- )
- ;;
- esac
+ # Build list of kept names
+ dir=${BASHKEEP:-"$HOME"/.bashkeep.d}
+ cword=${COMP_WORDS[COMP_CWORD]}
+ kept=("$dir"/"$cword"*.bash)
+ kept=("${kept[@]##*/}")
+ kept=("${kept[@]%.bash}")
+
+ # Print kept names
+ printf '%s\n' "${kept[@]}"
+ ;;
+ esac
+ )
}
complete -F _keep keep
diff --git a/bash/bash_completion.d/m4.bash b/bash/bash_completion.d/m4.bash
index 5811fd5b..bb50f3b2 100644
--- a/bash/bash_completion.d/m4.bash
+++ b/bash/bash_completion.d/m4.bash
@@ -1,4 +1,5 @@
# Completion for m4(1) with files that look editable
-declare -F _text_filenames >/dev/null ||
+if ! declare -F _text_filenames >/dev/null ; then
source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _text_filenames -o filenames m4
diff --git a/bash/bash_completion.d/mail.bash b/bash/bash_completion.d/mail.bash
index 65c4ae80..5d1cdec0 100644
--- a/bash/bash_completion.d/mail.bash
+++ b/bash/bash_completion.d/mail.bash
@@ -1,6 +1,5 @@
# Completion for mail(1) with abook(1) email addresses
-declare -F _abook_addresses >/dev/null ||
- source "$HOME"/.bash_completion.d/_abook_addresses.bash
-
-# bashdefault requires Bash >=3.0
+if ! declare -F _text_filenames >/dev/null ; then
+ source "$HOME"/.bash_completion.d/_text_filenames.bash
+fi
complete -F _abook_addresses -o bashdefault -o default mail
diff --git a/bash/bash_completion.d/make.bash b/bash/bash_completion.d/make.bash
index c36a039a..0f39ef4b 100644
--- a/bash/bash_completion.d/make.bash
+++ b/bash/bash_completion.d/make.bash
@@ -5,9 +5,10 @@ _make() {
# first, then "Makefile"). You may want to add "GNU-makefile" after this.
local mf
for mf in makefile Makefile '' ; do
- [[ -f $mf ]] && break
+ [[ -e $mf ]] || continue
+ break
done
- [[ -n $mf ]] || return 1
+ [[ -n $mf ]] || return
# Iterate through the Makefile, line by line
local line
@@ -39,7 +40,7 @@ _make() {
*[^[:word:]./-]*) ;;
# Add targets that match what we're completing
- ${COMP_WORDS[COMP_CWORD]}*)
+ "${COMP_WORDS[COMP_CWORD]}"*)
COMPREPLY[${#COMPREPLY[@]}]=$target
;;
esac
diff --git a/bash/bash_completion.d/man.bash b/bash/bash_completion.d/man.bash
index 1efa7c52..ffef48ec 100644
--- a/bash/bash_completion.d/man.bash
+++ b/bash/bash_completion.d/man.bash
@@ -2,7 +2,7 @@
_man() {
# Don't even bother if we don't have manpath(1)
- hash manpath 2>/dev/null || return 1
+ hash manpath 2>/dev/null || return
# Snarf the word
local word
@@ -17,9 +17,13 @@ _man() {
# If this is the second word, and the previous word started with a number,
# we'll assume that's the section to search
local section subdir
- if ((COMP_CWORD > 1)) && [[ ${COMP_WORDS[COMP_CWORD-1]} == [0-9]* ]] ; then
- section=${COMP_WORDS[COMP_CWORD-1]}
- subdir=man${section%%[^0-9]*}
+ if ((COMP_CWORD > 1)) ; then
+ case ${COMP_WORDS[COMP_CWORD-1]} in
+ [0-9]*)
+ section=${COMP_WORDS[COMP_CWORD-1]}
+ subdir=man${section%%[^0-9]*}
+ ;;
+ esac
fi
# Read completion results from a subshell and add them to the COMPREPLY
@@ -35,17 +39,12 @@ _man() {
shopt -u dotglob
shopt -s extglob nullglob
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Make globbing case-insensitive if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
@@ -59,7 +58,9 @@ _man() {
for manpath in "${manpaths[@]}" ; do
[[ -n $manpath ]] || continue
if [[ -n $section ]] ; then
- for page in "$manpath"/"$subdir"/"$word"*."$section"?(.[glx]z|.bz2|.lzma|.Z) ; do
+ for page in \
+ "$manpath"/"$subdir"/"$word"*."$section"?(.[glx]z|.bz2|.lzma|.Z)
+ do
pages[${#pages[@]}]=$page
done
else
@@ -74,14 +75,8 @@ _man() {
pages=("${pages[@]%.@([glx]z|bz2|lzma|Z)}")
pages=("${pages[@]%.[0-9]*}")
- # Print quoted entries, null-delimited, if there was at least one;
- # otherwise, just print a null character to stop this hanging in Bash
- # 4.4
- if ((${#pages[@]})) ; then
- printf '%q\0' "${pages[@]}"
- else
- printf '\0'
- fi
+ # Print quoted entries, null-delimited
+ printf '%q\0' "${pages[@]}"
)
}
complete -F _man -o bashdefault -o default man
diff --git a/bash/bash_completion.d/mex.bash b/bash/bash_completion.d/mex.bash
index d25f1824..bc3d2c7b 100644
--- a/bash/bash_completion.d/mex.bash
+++ b/bash/bash_completion.d/mex.bash
@@ -6,7 +6,8 @@ _mex() {
for dir in "${path[@]}" ; do
[[ -d $dir ]] || continue
for name in "$dir"/* ; do
- [[ -f $name ]] || continue
+ [[ -e $name ]] || continue
+ ! [[ -d $name ]] || continue
! [[ -x $name ]] || continue
COMPREPLY[${#COMPREPLY[@]}]=${name##*/}
done
diff --git a/bash/bash_completion.d/mutt.bash b/bash/bash_completion.d/mutt.bash
index c7f02ac7..002eb48e 100644
--- a/bash/bash_completion.d/mutt.bash
+++ b/bash/bash_completion.d/mutt.bash
@@ -1,4 +1,5 @@
# Completion for mutt(1) with abook(1) email addresses
-declare -F _abook_addresses >/dev/null ||
+if ! declare -F _abook_addresses >/dev/null ; then
source "$HOME"/.bash_completion.d/_abook_addresses.bash
+fi
complete -F _abook_addresses -o bashdefault -o default mutt
diff --git a/bash/bash_completion.d/mysql.bash b/bash/bash_completion.d/mysql.bash
index ad153adc..3ff97090 100644
--- a/bash/bash_completion.d/mysql.bash
+++ b/bash/bash_completion.d/mysql.bash
@@ -2,12 +2,12 @@
_mysql() {
# Only makes sense for first argument
- ((COMP_CWORD == 1)) || return 1
+ ((COMP_CWORD == 1)) || return
# Bail if directory doesn't exist
local dirname
dirname=$HOME/.mysql
- [[ -d $dirname ]] || return 1
+ [[ -d $dirname ]] || return
# Return the names of the .cnf files sans prefix as completions
local db
@@ -19,17 +19,12 @@ _mysql() {
# Set options so that globs expand correctly
shopt -s dotglob nullglob
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Make globbing case-insensitive if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
@@ -40,14 +35,8 @@ _mysql() {
cnfs=("${cnfs[@]#"$dirname"/}")
cnfs=("${cnfs[@]%.cnf}")
- # Print quoted entries, null-delimited, if there was at least one;
- # otherwise, just print a null character to stop this hanging in Bash
- # 4.4
- if ((${#cnfs[@]})) ; then
- printf '%q\0' "${cnfs[@]}"
- else
- printf '\0'
- fi
+ # Print quoted entries, null-delimited
+ printf '%q\0' "${cnfs[@]}"
)
}
complete -F _mysql -o bashdefault -o default mysql
diff --git a/bash/bash_completion.d/pass.bash b/bash/bash_completion.d/pass.bash
index ec5959be..176886dc 100644
--- a/bash/bash_completion.d/pass.bash
+++ b/bash/bash_completion.d/pass.bash
@@ -8,7 +8,7 @@ _pass()
# If we can't read the password directory, just bail
local passdir
passdir=${PASSWORD_STORE_DIR:-"$HOME"/.password-store}
- [[ -r $passdir ]] || return 1
+ [[ -r $passdir ]] || return
# Iterate through list of .gpg paths, extension stripped, null-delimited,
# and filter them down to the ones matching the completing word (compgen
@@ -16,24 +16,19 @@ _pass()
local entry
while IFS= read -rd '' entry ; do
[[ -n $entry ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$entry
+ COMPREPLY+=("$entry")
done < <(
# Set shell options to expand globs the way we expect
shopt -u dotglob
shopt -s globstar nullglob
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Make globbing case-insensitive if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
@@ -45,14 +40,8 @@ _pass()
entries=("${entries[@]#"$passdir"/}")
entries=("${entries[@]%.gpg}")
- # Print quoted entries, null-delimited, if there was at least one;
- # otherwise, just print a null character to stop this hanging in Bash
- # 4.4
- if ((${#entries[@]})) ; then
- printf '%q\0' "${entries[@]}"
- else
- printf '\0'
- fi
+ # Print quoted entries, null-delimited
+ printf '%q\0' "${entries[@]}"
)
}
complete -F _pass pass
diff --git a/bash/bash_completion.d/path.bash b/bash/bash_completion.d/path.bash
index 8b72a062..7143b448 100644
--- a/bash/bash_completion.d/path.bash
+++ b/bash/bash_completion.d/path.bash
@@ -6,10 +6,18 @@ _path() {
# Complete operation as first word
local cmd
- for cmd in list insert append remove shift pop check help ; do
- [[ $cmd == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
+ while read -r cmd ; do
COMPREPLY[${#COMPREPLY[@]}]=$cmd
- done
+ done < <(compgen -W '
+ append
+ check
+ help
+ insert
+ list
+ pop
+ remove
+ shift
+ ' -- "${COMP_WORDS[COMP_CWORD]}")
# Complete with either directories or $PATH entries as all other words
else
@@ -26,17 +34,12 @@ _path() {
# Set options to glob correctly
shopt -s dotglob nullglob
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Make globbing case-insensitive if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
@@ -46,25 +49,23 @@ _path() {
dirnames=("${COMP_WORDS[COMP_CWORD]}"*/)
dirnames=("${dirnames[@]%/}")
- # Print quoted entries, null-delimited, if there was at
- # least one; otherwise, just print a null character to stop
- # this hanging in Bash 4.4
- if ((${#dirnames[@]})) ; then
- printf '%q\0' "${dirnames[@]}"
- else
- printf '\0'
- fi
+ # Print quoted entries, null-delimited
+ printf '%q\0' "${dirnames[@]}"
)
;;
# Complete with directories from PATH
remove)
local -a promptarr
- IFS=: read -rd '' -a promptarr < <(printf '%s\0' "$PATH")
+ IFS=: read -rd '' -a promptarr < \
+ <(printf '%s\0' "$PATH")
local part
for part in "${promptarr[@]}" ; do
- [[ $part == "${COMP_WORDS[COMP_CWORD]}"* ]] || continue
- COMPREPLY[${#COMPREPLY[@]}]=$(printf '%q' "$part")
+ case $part in
+ "${COMP_WORDS[COMP_CWORD]}"*)
+ COMPREPLY[${#COMPREPLY[@]}]=$(printf '%q' "$part")
+ ;;
+ esac
done
;;
diff --git a/bash/bash_completion.d/sd.bash b/bash/bash_completion.d/sd.bash
index 578a69fd..e7e82f80 100644
--- a/bash/bash_completion.d/sd.bash
+++ b/bash/bash_completion.d/sd.bash
@@ -2,10 +2,12 @@
_sd() {
# Only makes sense for the first argument
- ((COMP_CWORD == 1)) || return 1
+ ((COMP_CWORD == 1)) || return
# Current directory can't be root directory
- [[ $PWD != / ]] || return 1
+ case $PWD in
+ /) return 1 ;;
+ esac
# Build list of matching sibling directories
local dirname
@@ -17,17 +19,12 @@ _sd() {
# Set options to glob correctly
shopt -s dotglob nullglob
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Make globbing case-insensitive if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
@@ -42,18 +39,14 @@ _sd() {
local -a sibs
local dirname
for dirname in "${dirnames[@]}" ; do
- [[ $dirname != "${PWD##*/}" ]] || continue
- sibs[${#sibs[@]}]=$dirname
+ case $dirname in
+ "${PWD##*/}") ;;
+ *) sibs[${#sibs[@]}]=$dirname ;;
+ esac
done
- # Print quoted sibs, null-delimited, if there was at least one;
- # otherwise, just print a null character to stop this hanging in Bash
- # 4.4
- if ((${#sibs[@]})) ; then
- printf '%q\0' "${sibs[@]}"
- else
- printf '\0'
- fi
+ # Print quoted sibling directories, null-delimited
+ printf '%q\0' "${sibs[@]}"
)
}
complete -F _sd sd
diff --git a/bash/bash_completion.d/sftp.bash b/bash/bash_completion.d/sftp.bash
index ad4d406f..b54b06b7 100644
--- a/bash/bash_completion.d/sftp.bash
+++ b/bash/bash_completion.d/sftp.bash
@@ -1,4 +1,5 @@
# Completion for sftp(1) with ssh_config(5) hostnames
-declare -F _ssh_config_hosts >/dev/null ||
+if ! declare -F _ssh_config_hosts >/dev/null ; then
source "$HOME"/.bash_completion.d/_ssh_config_hosts.bash
+fi
complete -F _ssh_config_hosts -o bashdefault -o default sftp
diff --git a/bash/bash_completion.d/ssh-copy-id.bash b/bash/bash_completion.d/ssh-copy-id.bash
index 336df4ea..cbecfa5f 100644
--- a/bash/bash_completion.d/ssh-copy-id.bash
+++ b/bash/bash_completion.d/ssh-copy-id.bash
@@ -1,4 +1,5 @@
# Completion for ssh-copy-id(1) with ssh_config(5) hostnames
-declare -F _ssh_config_hosts >/dev/null ||
+if ! declare -F _ssh_config_hosts >/dev/null ; then
source "$HOME"/.bash_completion.d/_ssh_config_hosts.bash
+fi
complete -F _ssh_config_hosts -o bashdefault -o default ssh-copy-id
diff --git a/bash/bash_completion.d/ssh.bash b/bash/bash_completion.d/ssh.bash
index 7ec82596..6d327c91 100644
--- a/bash/bash_completion.d/ssh.bash
+++ b/bash/bash_completion.d/ssh.bash
@@ -1,4 +1,5 @@
# Completion for ssh(1) with ssh_config(5) hostnames
-declare -F _ssh_config_hosts >/dev/null ||
+if ! declare -F _ssh_config_hosts >/dev/null ; then
source "$HOME"/.bash_completion.d/_ssh_config_hosts.bash
+fi
complete -F _ssh_config_hosts -o bashdefault -o default ssh
diff --git a/bash/bash_completion.d/td.bash b/bash/bash_completion.d/td.bash
index 377ef6ce..92927c28 100644
--- a/bash/bash_completion.d/td.bash
+++ b/bash/bash_completion.d/td.bash
@@ -29,14 +29,8 @@ _td() {
fns=("$dir"/"${COMP_WORDS[COMP_CWORD]}"*)
fns=("${fns[@]#"$dir"/}")
- # Print quoted entries, null-delimited, if there was at least one;
- # otherwise, just print a null character to stop this hanging in Bash
- # 4.4
- if ((${#fns[@]})) ; then
- printf '%q\0' "${fns[@]}"
- else
- printf '\0'
- fi
+ # Print quoted entries, null-delimited
+ printf '%q\0' "${fns[@]}"
)
}
complete -F _td td
diff --git a/bash/bash_completion.d/ud.bash b/bash/bash_completion.d/ud.bash
index aa59a4fc..c7dee582 100644
--- a/bash/bash_completion.d/ud.bash
+++ b/bash/bash_completion.d/ud.bash
@@ -2,40 +2,32 @@
_ud() {
# Only makes sense for the second argument
- ((COMP_CWORD == 2)) || return 1
+ ((COMP_CWORD == 2)) || return
# Iterate through directories, null-separated, add them to completions
local dirname
while IFS= read -rd '' dirname ; do
+ [[ -n "$dirname" ]] || continue
COMPREPLY[${#COMPREPLY[@]}]=$dirname
done < <(
# Set options to glob correctly
shopt -s dotglob nullglob
- # Make globbing case-insensitive if appropriate; is there a cleaner way
- # to find this value?
- while read -r _ option value ; do
- case $option in
- (completion-ignore-case)
- case $value in
- (on)
- shopt -s nocaseglob
- break
- ;;
- esac
+ # Make globbing case-insensitive if appropriate
+ while read -r _ setting ; do
+ case $setting in
+ ('completion-ignore-case on')
+ shopt -s nocaseglob
+ break
;;
esac
done < <(bind -v)
# Collect directory names, strip trailing slashes
- local -a dirnames
dirnames=("${COMP_WORDS[COMP_CWORD]}"*/)
dirnames=("${dirnames[@]%/}")
- # Bail if no results to prevent empty output
- ((${#dirnames[@]})) || exit 1
-
# Print results null-delimited
printf '%s\0' "${dirnames[@]}"
)
diff --git a/bash/bashrc b/bash/bashrc
index dcf3df53..3b4c91bd 100644
--- a/bash/bashrc
+++ b/bash/bashrc
@@ -6,9 +6,7 @@ esac
# Don't do anything if restricted, not even sourcing the ENV file
# Testing $- for "r" doesn't work
-if shopt -q restricted_shell >/dev/null 2>&1 ; then
- return
-fi
+! shopt -q restricted_shell >/dev/null 2>&1 || return
# Clear away all aliases; we do this here rather than in the $ENV file shared
# between POSIX shells, because ksh relies on aliases to implement certain
diff --git a/check/login-shell.sh b/check/login-shell.sh
index 2972d98d..88eac59e 100644
--- a/check/login-shell.sh
+++ b/check/login-shell.sh
@@ -1,10 +1,12 @@
-target=check-sh
-case ${SHELL##*/} in
+shell=$(getent passwd "$USER" | cut -d: -f7)
+case ${shell##*/} in
bash)
target=check-bash ;;
ksh|ksh88|ksh93|mksh|pdksh)
target=check-ksh ;;
zsh)
target=check-zsh ;;
+ *)
+ target=check-sh ;;
esac
make "$target"
diff --git a/install/install-conf.sh b/install/conf.sh
index f50cde73..f50cde73 100644
--- a/install/install-conf.sh
+++ b/install/conf.sh
diff --git a/install/install-login-shell.sh b/install/login-shell.sh
index f38aa0c1..54741fde 100644
--- a/install/install-login-shell.sh
+++ b/install/login-shell.sh
@@ -1,10 +1,12 @@
-target=install-sh
-case ${SHELL##*/} in
+shell=$(getent passwd "$USER" | cut -d: -f7)
+case ${shell##*/} in
bash)
target=install-bash ;;
ksh|ksh88|ksh93|mksh|pdksh)
target=install-ksh ;;
zsh)
target=install-zsh ;;
+ *)
+ target=install-sh ;;
esac
make "$target"