diff options
58 files changed, 314 insertions, 239 deletions
@@ -1,2 +1,2 @@ -tejr dotfiles v3.1.0 -Wed Dec 5 22:40:16 UTC 2018 +tejr dotfiles v3.2.0 +Fri Dec 14 00:14:00 UTC 2018 diff --git a/bash/bash_completion.d/_ssh_config_hosts.bash b/bash/bash_completion.d/_ssh_config_hosts.bash index 3f937a2a..0959f52b 100644 --- a/bash/bash_completion.d/_ssh_config_hosts.bash +++ b/bash/bash_completion.d/_ssh_config_hosts.bash @@ -1,31 +1,26 @@ # Complete ssh_config(5) hostnames _ssh_config_hosts() { - # Iterate through words from a subshell - local ci comp - while read -r comp ; do - COMPREPLY[ci++]=$comp - done < <( + # Iterate through SSH client config paths + local config + for config in "$HOME"/.ssh/config /etc/ssh/ssh_config ; do + [[ -e $config ]] || continue - # 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 + local option value ci + while read -r option value _ ; do + [[ $option == Host ]] || 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 + # No empties + '') ;; + # No wildcards + *'*'*) ;; + # Found a match; print it + "$2"*) COMPREPLY[ci++]=$value ;; + esac - # Check host value - case $value in - # No empties - ('') ;; - # No wildcards - (*'*'*) ;; - # Found a match; print it - ("$2"*) printf '%s\n' "$value" ;; - esac - - done < "$config" - done - ) + done < "$config" + done } diff --git a/bash/bash_completion.d/git.bash b/bash/bash_completion.d/git.bash new file mode 100644 index 00000000..c3a4d49c --- /dev/null +++ b/bash/bash_completion.d/git.bash @@ -0,0 +1,41 @@ +# Complete Git with branch names or tag names if specific keys are used, but +# fall back on filenames otherwise; it's too complicated to be worth trying to +# do it all contextually + +# Requires Bash >=4.0 for COMP_KEY +((BASH_VERSINFO[0] >= 4)) || return + +# Define and set helper function +_git() { + + # What completion to do + case $COMP_KEY in + + # Complete with branch names if C-x,B is pressed + 98) + local ci + while read -r _ ref ; do + branch=${ref#refs/heads/} + case $branch in + "$2"*) COMPREPLY[ci++]=$branch ;; + esac + done < <(git show-ref --heads) + ;; + + # Complete with tag names if C-x,T is pressed + 116) + local ci + while read -r _ ref ; do + tag=${ref#refs/tags/} + case $tag in + "$2"*) COMPREPLY[ci++]=$tag ;; + esac + done < <(git show-ref --tags) + ;; + + # Do no completion, so we fall back on filenames + *) return 1 ;; + + esac +} +complete -F _git -o bashdefault -o default git diff --git a/bash/bash_completion.d/gpg.bash b/bash/bash_completion.d/gpg.bash index c6f92676..5a055352 100644 --- a/bash/bash_completion.d/gpg.bash +++ b/bash/bash_completion.d/gpg.bash @@ -13,14 +13,9 @@ _gpg() { # Generate completion reply from gpg(1) options local ci comp while read -r comp ; do - COMPREPLY[ci++]=$comp - done < <( - gpg --dump-options 2>/dev/null | - while read -r option ; do - case $option in - ("$2"*) printf '%s\n' "$option" ;; - esac - done - ) + case $comp in + "$2"*) COMPREPLY[ci++]=$comp ;; + esac + done < <(gpg --dump-options 2>/dev/null) } complete -F _gpg -o bashdefault -o default gpg diff --git a/bash/bash_completion.d/make.bash b/bash/bash_completion.d/make.bash index 7f8b8125..909c52fb 100644 --- a/bash/bash_completion.d/make.bash +++ b/bash/bash_completion.d/make.bash @@ -34,11 +34,11 @@ _make() { esac # Break the target up with space delimiters - declare -a targets IFS=' ' read -a targets -r \ < <(printf '%s\n' "${line%%:*}") # Short-circuit if there are no targets + # shellcheck disable=SC2154 ((${#targets[@]})) || exit # Make matches behave correctly diff --git a/bash/bash_completion.d/man.bash b/bash/bash_completion.d/man.bash index 50ab852e..714fa493 100644 --- a/bash/bash_completion.d/man.bash +++ b/bash/bash_completion.d/man.bash @@ -56,7 +56,6 @@ _man() { fi # Add pages from each manual directory - local pages pi for mp in "${manpaths[@]}" ; do [[ -n $mp ]] || continue diff --git a/bash/bash_completion.d/mex.bash b/bash/bash_completion.d/mex.bash index b1e0e1a7..d9604b2c 100644 --- a/bash/bash_completion.d/mex.bash +++ b/bash/bash_completion.d/mex.bash @@ -51,4 +51,4 @@ _mex() { done ) } -complete -F _mex mex +complete -F _mex -o filenames mex diff --git a/bash/bash_completion.d/openssl.bash b/bash/bash_completion.d/openssl.bash index 1cb4bd07..1e2a9c58 100644 --- a/bash/bash_completion.d/openssl.bash +++ b/bash/bash_completion.d/openssl.bash @@ -8,25 +8,18 @@ _openssl() { ((COMP_CWORD == 1)) || return # Iterate through completions produced by subshell - local ci comp - while read -r comp ; do - COMPREPLY[ci++]=$comp + local -a subcmds + local ci subcmd + while read -a subcmds -r ; do + for subcmd in "${subcmds[@]}" ; do + case $subcmd in + "$2"*) COMPREPLY[ci++]=$subcmd ;; + esac + done done < <( - - # Run each of the command-listing commands; read each line into an - # array of subcommands (they are printed as a table) - for list in commands digest-commands cipher-commands ; do - openssl list -"$list" - done | { - declare -a subcmds - while read -a subcmds -r ; do - for subcmd in "${subcmds[@]}" ; do - case $subcmd in - ("$2"*) printf '%s\n' "$subcmd" ;; - esac - done - done - } + openssl list -commands \ + -cipher-commands \ + -digest-commands ) } complete -F _openssl -o bashdefault -o default openssl diff --git a/bash/bash_completion.d/pass.bash b/bash/bash_completion.d/pass.bash index 5a6e0b6c..760e774e 100644 --- a/bash/bash_completion.d/pass.bash +++ b/bash/bash_completion.d/pass.bash @@ -30,7 +30,7 @@ _pass() { # Try to iterate into subdirs, use depth search with ** if available if shopt -s globstar 2>/dev/null ; then - for entry in "$pass_dir"/"$2"**/*.gpg ; do + for entry in "$pass_dir"/"$2"*/**/*.gpg ; do entries[ei++]=$entry done else diff --git a/bash/bash_completion.d/path.bash b/bash/bash_completion.d/path.bash index 9234f132..c3bb7b80 100644 --- a/bash/bash_completion.d/path.bash +++ b/bash/bash_completion.d/path.bash @@ -62,11 +62,11 @@ _path() { fi # Break PATH into parts - declare -a paths IFS=: read -a paths -d '' -r \ < <(printf '%s\0' "$PATH") # Print shell-quoted matching parts, null-terminated + # shellcheck disable=SC2154 for path in "${paths[@]}" ; do case $path in ("$2"*) printf '%q\0' "$path" ;; diff --git a/bash/bashrc b/bash/bashrc index a05526f2..0400e41d 100644 --- a/bash/bashrc +++ b/bash/bashrc @@ -6,7 +6,7 @@ esac # Don't do anything if restricted, not even sourcing the ENV file # Testing $- for "r" doesn't work -! shopt -q restricted_shell >/dev/null 2>&1 || return +! shopt -q restricted_shell 2>/dev/null || 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/bash/bashrc.d/keep.bash b/bash/bashrc.d/keep.bash index 48196aeb..191dac4b 100644 --- a/bash/bashrc.d/keep.bash +++ b/bash/bashrc.d/keep.bash @@ -83,7 +83,7 @@ EOF # Iterate through the NAMEs given local name - for name ; do + for name do # Check NAMEs for validity case $name in diff --git a/bash/bashrc.d/vared.bash b/bash/bashrc.d/vared.bash index e024f48a..491e5bff 100644 --- a/bash/bashrc.d/vared.bash +++ b/bash/bashrc.d/vared.bash @@ -24,7 +24,7 @@ vared() { return 2 fi local name - for name ; do + for name do IFS= read -e -i "${!name}" -p "${prompt:-"$name"=}" -r -- "${name?}" done } @@ -10,7 +10,7 @@ shift # Iterate through the remaining args; it's legal for there to be none, but in # that case the user may as well just have invoked the command directly -for arg ; do +for arg do # If this is the first iteration, clear the params away (we grabbed them in # the for statement) @@ -16,7 +16,7 @@ shift 2 if [ "$#" -gt 0 ] ; then # Iterate through any remaining arguments - for carg ; do + for carg do # If this is the first command argument, then before we add it, we'll # add all the ones from the file first if it exists @@ -10,7 +10,7 @@ fi r=$(printf '\r') # Iterate over arguments and apply the same ed(1) script to each of them -for fn ; do +for fn do # Note the heredoc WORD is intentionally unquoted because we want to expand # $r within it to get a literal carriage return; the escape characters @@ -21,7 +21,7 @@ case :$PATH: in esac # Prepend the path to each of the names given if they don't look like options -for arg ; do +for arg do [ -n "$reset" ] || set -- && reset=1 case $arg in --) @@ -44,7 +44,7 @@ done "${VISUAL:-"${EDITOR:-ed}"}" "$@" # Make any created scripts executable if they now appear to be files -for script ; do +for script do [ -f "$script" ] || continue chmod +x -- "$script" done @@ -4,7 +4,7 @@ [ "$#" -gt 0 ] || set -- - # Iterate through arguments -for arg ; do +for arg do # We'll print the filename "-stdin-" rather than - just to be slightly more # explicit @@ -7,7 +7,7 @@ if [ "$#" -eq 0 ] ; then fi # Iterate through each search term and run an appropriate find(1) command -for pat ; do +for pat do # Skip dotfiles, dotdirs, and symbolic links; print anything that matches # the term as a substring (and stop iterating through it) @@ -9,7 +9,7 @@ if [ "$#" -eq 0 ] ; then fi # Iterate through the given names -for name ; do +for name do # Clear the found variable found= diff --git a/bin/mkcp.sh b/bin/mkcp.sh index 10308263..3acf12f0 100644 --- a/bin/mkcp.sh +++ b/bin/mkcp.sh @@ -7,7 +7,7 @@ if [ "$#" -lt 2 ] ; then fi # Get the last argument (the directory to create) -for dir ; do : ; done +for dir do : ; done # Create it, or bail mkdir -p -- "$dir" || exit diff --git a/bin/mked.sh b/bin/mked.sh index 4e280205..93e21573 100644 --- a/bin/mked.sh +++ b/bin/mked.sh @@ -1,6 +1,6 @@ #!/bin/sh # Create paths to all files before invoking editor -for file ; do +for file do mkdir -p -- "${file%/*}" || exit done exec "$EDITOR" "$@" diff --git a/bin/mkmv.sh b/bin/mkmv.sh index 53b5aa8f..832c205e 100644 --- a/bin/mkmv.sh +++ b/bin/mkmv.sh @@ -7,7 +7,7 @@ if [ "$#" -lt 2 ] ; then fi # Get the last argument (the directory to create) -for dir ; do : ; done +for dir do : ; done # Create it, or bail mkdir -p -- "$dir" || exit diff --git a/bin/mkvi.sh b/bin/mkvi.sh index 244b89f8..c5974383 100644 --- a/bin/mkvi.sh +++ b/bin/mkvi.sh @@ -1,6 +1,6 @@ #!/bin/sh # Create paths to all files before invoking editor -for file ; do +for file do mkdir -p -- "${file%/*}" || exit done exec "$VISUAL" "$@" @@ -1,5 +1,5 @@ # Print the full path to each argument; path need not exist -for arg ; do +for arg do case $arg in /*) path=$arg ;; *) path=$PWD/$arg ;; @@ -8,7 +8,7 @@ if [ "$#" -eq 0 ] ; then fi # Iterate through the given files -for sn ; do +for sn do # Strip trailing slash if any and then query string sn=${sn%/} diff --git a/bin/stbl.sh b/bin/stbl.sh index 23d77703..2f6702b1 100644 --- a/bin/stbl.sh +++ b/bin/stbl.sh @@ -7,7 +7,7 @@ if [ "$#" -eq 0 ] ; then fi # Iterate over arguments and apply the same ed(1) script to each of them -for fn ; do +for fn do ed -s -- "$fn" <<'EOF' || ex=1 $g/^ *$/d w diff --git a/bin/stex.sh b/bin/stex.sh index 14d2cabf..b27d9cf8 100644 --- a/bin/stex.sh +++ b/bin/stex.sh @@ -13,7 +13,7 @@ ext=$1 shift # Iterate through the given files (remaining args) -for sn ; do +for sn do # Strip trailing slash if any and then extension sn=${sn%/} diff --git a/bin/stws.sh b/bin/stws.sh index ce2c14d0..59a8652a 100644 --- a/bin/stws.sh +++ b/bin/stws.sh @@ -7,7 +7,7 @@ if [ "$#" -eq 0 ] ; then fi # Iterate over arguments and apply the same ed(1) script to each of them -for fn ; do +for fn do ed -s -- "$fn" <<'EOF' || ex=1 g/ *$/ s/ *$// w @@ -4,7 +4,7 @@ user= # Iterate over the given files -for file ; do +for file do # Get the file's owner, or bail file_owner=$(stat -c %U -- "$file") || exit @@ -10,7 +10,7 @@ fi r=$(printf '\r') # Iterate over arguments and apply the same ed(1) script to each of them -for fn ; do +for fn do # Note the heredoc WORD is intentionally unquoted because we want to expand # $r within it to get a literal carriage return; the escape characters @@ -7,7 +7,7 @@ if [ "$#" -eq 0 ] ; then fi # Iterate over the URL arguments -for url ; do ( +for url do ( # Look for patterns in the URL that suggest transformations case $url in diff --git a/check/bash.sh b/check/bash.sh index 1f9e1b38..510f2af0 100644 --- a/check/bash.sh +++ b/check/bash.sh @@ -5,7 +5,7 @@ set \ bash/bash_profile \ bash/bashrc \ bash/bashrc.d/*.bash -for bash ; do +for bash do bash -n -- "$bash" || exit done printf 'GNU Bash dotfiles parsed successfully.\n' diff --git a/check/ksh.sh b/check/ksh.sh index f4bade82..cf83bc1f 100644 --- a/check/ksh.sh +++ b/check/ksh.sh @@ -1,7 +1,7 @@ set \ ksh/kshrc \ ksh/kshrc.d/*.ksh -for ksh ; do +for ksh do ksh -n -- "$ksh" || exit done sh -n -- ksh/shrc.d/ksh.sh || exit diff --git a/check/sh.sh b/check/sh.sh index 92910c11..e0162f47 100644 --- a/check/sh.sh +++ b/check/sh.sh @@ -4,7 +4,7 @@ set \ sh/shinit \ sh/shrc \ sh/shrc.d/*.sh -for sh ; do +for sh do sh -n -- "$sh" || exit done printf 'POSIX shell dotfiles parsed successfully.\n' diff --git a/check/xinit.sh b/check/xinit.sh index fa235c9d..ae03b8c2 100644 --- a/check/xinit.sh +++ b/check/xinit.sh @@ -1,7 +1,7 @@ set \ X/xinitrc \ X/xinitrc.d/*.sh -for xinit ; do +for xinit do sh -n -- "$xinit" || exit done printf 'Xinit startup scripts parsed successfully.\n' diff --git a/check/zsh.sh b/check/zsh.sh index ce209584..0170e586 100644 --- a/check/zsh.sh +++ b/check/zsh.sh @@ -2,7 +2,7 @@ set \ zsh/zprofile \ zsh/zshrc.d/*.zsh \ zsh/zshrc -for zsh ; do +for zsh do zsh -n -- "$zsh" || exit done sh -n zsh/profile.d/zsh.sh || exit diff --git a/ksh/kshrc.d/keep.ksh b/ksh/kshrc.d/keep.ksh index f6593c3d..629b2fe6 100644 --- a/ksh/kshrc.d/keep.ksh +++ b/ksh/kshrc.d/keep.ksh @@ -94,7 +94,7 @@ EOF # Iterate through the NAMEs given typeset name - for name ; do + for name do # Check NAMEs for validity case $name in diff --git a/readline/inputrc b/readline/inputrc index c11d8fe7..857952cd 100644 --- a/readline/inputrc +++ b/readline/inputrc @@ -62,6 +62,12 @@ $if Bash # Alt+A cycles through completion options "\ea": menu-complete + # Special completion keys for git(1) + ## Branches + "\C-xb": complete + ## Tags + "\C-xt": complete + # Ctrl-Alt-L to clear screen; more ksh-like "\e\C-l": clear-screen @@ -1,5 +1,7 @@ # Add ~/.local/bin to PATH if it exists -[ -d "$HOME"/.local/bin ] && PATH=$HOME/.local/bin:$PATH +if [ -d "$HOME"/.local/bin ] ; then + PATH=$HOME/.local/bin:$PATH +fi # Load all supplementary scripts in ~/.profile.d for sh in "$HOME"/.profile.d/*.sh ; do @@ -13,11 +15,3 @@ if [ -f "$HOME"/.shinit ] ; then ENV=$HOME/.shinit export ENV fi - -# If ENV_FORCE is set and we're interactive, source ENV explicitly -# At the moment this is just for zsh-as-ksh/sh -if [ -n "$ENV_FORCE" ] ; then - case $- in *i*) - [ -f "$ENV" ] && . "$ENV" ;; - esac -fi diff --git a/sh/profile.d/downloads.sh b/sh/profile.d/downloads.sh index 865cb859..1a89bc3f 100644 --- a/sh/profile.d/downloads.sh +++ b/sh/profile.d/downloads.sh @@ -8,7 +8,7 @@ esac [ -z "$TMUX" ] || return # Not if ~/.hushlogin exists -[ -e "$HOME"/.hushlogin ] && return +! [ -e "$HOME"/.hushlogin ] || return # Not if ~/.downloads doesn't [ -f "$HOME"/.downloads ] || return @@ -27,5 +27,7 @@ esac printf 'You have %u unsorted files in %s.\n' "$#" "$dir" lc=$((lc+1)) done < "$HOME"/.downloads - [ "$((lc > 0))" -eq 1 ] && printf '\n' + if [ "$lc" -gt 0 ] ; then + printf '\n' + fi ) diff --git a/sh/profile.d/options.sh b/sh/profile.d/options.sh index 73f62243..58376fb3 100644 --- a/sh/profile.d/options.sh +++ b/sh/profile.d/options.sh @@ -22,9 +22,10 @@ options() { # Iterate through remaining arguments (desired options), creating files to # show they're available if found in the help output - for opt ; do - command -p grep -q -- '[^[:alnum:]]--'"$opt"'[^[:alnum:]]' help && - touch -- "$opt" + for opt do + command -p grep -q -- \ + '[^[:alnum:]]--'"$opt"'[^[:alnum:]]' help || continue + touch -- "$opt" done } diff --git a/sh/profile.d/welcome.sh b/sh/profile.d/welcome.sh index ede7a05f..cdd41edb 100644 --- a/sh/profile.d/welcome.sh +++ b/sh/profile.d/welcome.sh @@ -20,8 +20,10 @@ esac # Show a fortune if welcome fortune ; then - [ -d "$HOME"/.local/share/games/fortunes ] && - : "${FORTUNE_PATH:="$HOME"/.local/share/games/fortunes}" + if ! [ -n "$FORTUNE_PATH"] && + [ -d "$HOME"/.local/share/games/fortunes ] ; then + FORTUNE_PATH=$HOME/.local/share/games/fortunes + fi fortune -s "$FORTUNE_PATH" printf '\n' fi @@ -34,7 +36,9 @@ esac # Run verse(1) if we haven't seen it already today if welcome verse ; then - [ -f "$HOME"/.verse ] && read -r last <"$HOME"/.verse + if [ -f "$HOME"/.verse ] ; then + read -r last <"$HOME"/.verse + fi now=$(date +%Y%m%d) if [ "$now" -gt "${last:-0}" ] ; then verse @@ -1,4 +1,7 @@ -# If the shell is interactive, source ~/.shrc -case $- in *i*) - [ -f "$HOME"/.shrc ] && . "$HOME"/.shrc ;; +# If the shell is interactive, and ~/.shrc exists, source it +case $- in + *i*) + if [ -f "$HOME"/.shrc ] ; then + . "$HOME"/.shrc + fi esac @@ -22,5 +22,7 @@ done unset -v sh # If ENV_EXT was set and exists, source that too, then clean it away -[ -e "$ENV_EXT" ] && . "$ENV_EXT" +if [ -e "$ENV_EXT" ] ; then + . "$ENV_EXT" +fi unset -v ENV_EXT diff --git a/sh/shrc.d/bc.sh b/sh/shrc.d/bc.sh index aee88e09..591b4359 100644 --- a/sh/shrc.d/bc.sh +++ b/sh/shrc.d/bc.sh @@ -6,8 +6,9 @@ bc() { # Add --quiet to stop the annoying welcome banner - [ -e "$HOME"/.cache/sh/opt/bc/quiet ] && + if [ -e "$HOME"/.cache/sh/opt/bc/quiet ] ; then set -- --quiet "$@" + fi # Run bc(1) with the concluded arguments command bc "$@" diff --git a/sh/shrc.d/ed.sh b/sh/shrc.d/ed.sh index e6b6eee8..dc8433f6 100644 --- a/sh/shrc.d/ed.sh +++ b/sh/shrc.d/ed.sh @@ -12,16 +12,18 @@ ed() { fi # Add --verbose to explain errors - [ -e "$HOME"/.cache/sh/opt/ed/verbose ] && + if [ -e "$HOME"/.cache/sh/opt/ed/verbose ] ; then set -- --verbose "$@" + fi # Add an asterisk prompt (POSIX feature) set -- -p\* "$@" # Run in rlwrap(1) if available set -- ed "$@" - command -v rlwrap >/dev/null 2>&1 && + if command -v rlwrap >/dev/null 2>&1 ; then set -- rlwrap --history-filename=/dev/null "$@" + fi # Run determined command command "$@" diff --git a/sh/shrc.d/grep.sh b/sh/shrc.d/grep.sh index 43797ef5..997babc9 100644 --- a/sh/shrc.d/grep.sh +++ b/sh/shrc.d/grep.sh @@ -9,37 +9,43 @@ unset -v GREP_OPTIONS grep() { # Add --binary-files=without-match to gracefully skip binary files - [ -e "$HOME"/.cache/sh/opt/grep/binary-files ] && + if [ -e "$HOME"/.cache/sh/opt/grep/binary-files ] ; then set -- --binary-files=without-match "$@" + fi # Add --color=auto if the terminal has at least 8 colors - [ -e "$HOME"/.cache/sh/opt/grep/color ] && - [ "$({ tput colors||tput Co||echo 0; } 2>/dev/null)" -ge 8 ] && + if [ -e "$HOME"/.cache/sh/opt/grep/color ] && + [ "$({ tput colors||tput Co||echo 0; } 2>/dev/null)" -ge 8 ] ; then set -- --color=auto "$@" + fi # Add --devices=skip to gracefully skip devices - [ -e "$HOME"/.cache/sh/opt/grep/devices ] && + if [ -e "$HOME"/.cache/sh/opt/grep/devices ] ; then set -- --devices=skip "$@" + fi # Add --directories=skip to gracefully skip directories - [ -e "$HOME"/.cache/sh/opt/grep/directories ] && + if [ -e "$HOME"/.cache/sh/opt/grep/directories ] ; then set -- --directories=skip "$@" + fi # Add --exclude to ignore .gitignore and .gitmodules files - [ -e "$HOME"/.cache/sh/opt/grep/exclude ] && + if [ -e "$HOME"/.cache/sh/opt/grep/exclude ] ; then set -- \ --exclude=.gitignore \ --exclude=.gitmodules \ "$@" + fi # Add --exclude-dir to ignore version control dot-directories - [ -e "$HOME"/.cache/sh/opt/grep/exclude-dir ] && + if [ -e "$HOME"/.cache/sh/opt/grep/exclude-dir ] ; then set -- \ --exclude-dir=.cvs \ --exclude-dir=.git \ --exclude-dir=.hg \ --exclude-dir=.svn \ "$@" + fi # Run grep(1) with the concluded arguments command grep "$@" diff --git a/sh/shrc.d/gt.sh b/sh/shrc.d/gt.sh index 95ab4c2f..7a52571d 100644 --- a/sh/shrc.d/gt.sh +++ b/sh/shrc.d/gt.sh @@ -19,7 +19,9 @@ gt() { done # If target isn't a directory, chop to its parent - [ -d "$1" ] || set -- "${1%/*}" + if ! [ -d "$1" ] ; then + set -- "${1%/*}" + fi # Try to change into the determined directory, or root if empty command cd -- "${1:-/}" diff --git a/sh/shrc.d/ls.sh b/sh/shrc.d/ls.sh index 7e843cc7..1083dfca 100644 --- a/sh/shrc.d/ls.sh +++ b/sh/shrc.d/ls.sh @@ -12,26 +12,30 @@ unset -v LS_OPTIONS LS_COLORS # Define function proper ls() { - # -F to show trailing indicators of the filetype - # -q to replace control chars with '?' + # POSIX options: + ## -F to show trailing indicators of the filetype + ## -q to replace control chars with '?' set -- -Fq "$@" - - # If output is to a terminal, add -x to format entries across, not down - [ -t 1 ] && set -- -x "$@" - - # Add --block-size=K to always show the filesize in kibibytes - [ -e "$HOME"/.cache/sh/opt/ls/block-size ] && + ## -x to format entries across, not down, if output looks like a terminal + if [ -t 1 ] ; then + set -- -x "$@" + fi + + # GNU options: + ## Add --block-size=K to always show the filesize in kibibytes + if [ -e "$HOME"/.cache/sh/opt/ls/block-size ] ; then set -- --block-size=1024 "$@" - - # Add --color if the terminal has at least 8 colors - [ -e "$HOME"/.cache/sh/opt/ls/color ] && - [ "$({ tput colors||tput Co||echo 0; } 2>/dev/null)" -ge 8 ] && + fi + ## Add --color if the terminal has at least 8 colors + if [ -e "$HOME"/.cache/sh/opt/ls/color ] && + [ "$(exec 2>/dev/null;tput colors||tput Co||echo 0)" -ge 8 ] ; then set -- --color=auto "$@" - - # Add --time-style='+%Y-%m-%d %H:%M:%S' to show the date in my preferred - # (fixed) format - [ -e "$HOME"/.cache/sh/opt/ls/time-style ] && + fi + ## Add --time-style='+%Y-%m-%d %H:%M:%S' to show the date in my preferred + ## (fixed) format + if [ -e "$HOME"/.cache/sh/opt/ls/time-style ] ; then set -- --time-style='+%Y-%m-%d %H:%M:%S' "$@" + fi # If the operating system is FreeBSD, there are some specific options we # can add that might mean different things to e.g. GNU ls(1) diff --git a/sh/shrc.d/mkcd.sh b/sh/shrc.d/mkcd.sh index c59a8c54..cd882b51 100644 --- a/sh/shrc.d/mkcd.sh +++ b/sh/shrc.d/mkcd.sh @@ -1,4 +1,5 @@ # Create a directory and change into it mkcd() { - mkdir -p -- "$1" && command cd -- "$1" + command -p mkdir -p -- "$1" || return + command cd -- "$1" } diff --git a/sh/shrc.d/path.sh b/sh/shrc.d/path.sh index b6b1820f..a854e148 100644 --- a/sh/shrc.d/path.sh +++ b/sh/shrc.d/path.sh @@ -5,15 +5,16 @@ path() { case $1 in # List current directories in PATH - list|'') ( - path=$PATH: - while [ -n "$path" ] ; do - dir=${path%%:*} - path=${path#*:} - [ -n "$dir" ] || continue - printf '%s\n' "$dir" + list|'') + set -- "$PATH": + while [ -n "$1" ] ; do + case $1 in + :*) ;; + *) printf '%s\n' "${1%%:*}" ;; + esac + set -- "${1#*:}" done - ) ;; + ;; # Helper function checks directory argument makes sense _argcheck) @@ -33,7 +34,9 @@ path() { # Add a directory at the start of $PATH insert) - [ "$#" -eq 2 ] || set -- "$1" "$PWD" + if ! [ "$#" -eq 2 ] ; then + set -- "$1" "$PWD" + fi path _argcheck "$@" || return if path check "$2" ; then printf >&2 'path(): %s: %s already in PATH\n' "$@" @@ -44,7 +47,9 @@ path() { # Add a directory to the end of $PATH append) - [ "$#" -eq 2 ] || set -- "$1" "$PWD" + if ! [ "$#" -eq 2 ] ; then + set -- "$1" "$PWD" + fi path _argcheck "$@" || return if path check "$2" ; then printf >&2 'path(): %s: %s already in PATH\n' "$@" @@ -55,7 +60,9 @@ path() { # Remove a directory from $PATH remove) - [ "$#" -eq 2 ] || set -- "$1" "$PWD" + if ! [ "$#" -eq 2 ] ; then + set -- "$1" "$PWD" + fi path _argcheck "$@" || return if ! path check "$2" ; then printf >&2 'path(): %s: %s not in PATH\n' "$@" @@ -107,7 +114,9 @@ path() { # Check whether a directory is in PATH check) path _argcheck "$@" || return - [ "$#" -eq 2 ] || set -- "$1" "$PWD" + if ! [ "$#" -eq 2 ] ; then + set -- "$1" "$PWD" + fi case :$PATH: in *:"$2":*) return 0 ;; esac diff --git a/sh/shrc.d/tree.sh b/sh/shrc.d/tree.sh index d462f3e1..a7e5bef3 100644 --- a/sh/shrc.d/tree.sh +++ b/sh/shrc.d/tree.sh @@ -22,7 +22,7 @@ tree() { [ -t 1 ] || exit # Not if output terminal doesn't have at least 8 colors - [ "$({ tput colors||tput Co||echo 0; } 2>/dev/null)" -ge 8 ] + [ "$(exec 2>/dev/null;tput colors||tput Co||echo 0)" -ge 8 ] ) ; then set -- -C "$@" diff --git a/sh/shrc.d/vr.sh b/sh/shrc.d/vr.sh index 8b35357c..c7057ec2 100644 --- a/sh/shrc.d/vr.sh +++ b/sh/shrc.d/vr.sh @@ -11,9 +11,14 @@ vr() { exit 2 fi - # Get path from first argument, strip trailing slash + # Get path from first argument path=${1:-"$PWD"} - [ "$path" = / ] || path=${path%/} + + # Strip a trailing slash + case $path in + (/) ;; + (*) path=${path%/} ;; + esac # Step into the directory cd -- "$path" || exit @@ -34,7 +39,7 @@ vr() { # that is the root (bad) while svn info >/dev/null 2>&1 ; do root=$PWD - [ "$root" = / ] && break + ! [ "$root" = / ] || break cd .. || exit done if [ -n "$root" ] ; then diff --git a/vim/autoload/filetype.vim b/vim/autoload/filetype.vim new file mode 100644 index 00000000..d1e4e3d7 --- /dev/null +++ b/vim/autoload/filetype.vim @@ -0,0 +1,76 @@ +" Helper function to run the 'filetypedetect' group on a file with its +" extension stripped off +function! filetype#StripRepeat() abort + + " Check we have the fnameescape() function + if !exists('*fnameescape') + return + endif + + " Expand the match result + let l:fn = expand('<afile>') + + " Strip leading and trailing #hashes# + if l:fn =~# '^#\+.*#\+$' + let l:fn = substitute(l:fn, '^#\+\(.\+\)#\+$', '\1', '') + + " Strip trailing tilde~ + elseif l:fn =~# '\~$' + let l:fn = substitute(l:fn, '\~$', '', '') + + " Strip generic .extension + else + let l:fn = expand('<afile>:r') + endif + + " Re-run the group if there's anything left + if strlen(l:fn) + execute 'doautocmd filetypedetect BufRead ' . fnameescape(l:fn) + endif + +endfunction + +" Helper function to run the 'filetypedetect' group on a file in a temporary +" sudoedit(8) directory, modifying it with an attempt to reverse the temporary +" filename change +function! filetype#SudoRepeat() abort + + " Check we have the fnameescape() function + if !exists('*fnameescape') + return + endif + + " Expand the match result + let l:fn = expand('<afile>') + + " myfileXXQGS16A.conf: strip eight chars before final period + if l:fn =~# '/[^./]\+\w\{8}\.[^./]\+$' + let l:fr = expand('<afile>:r') + let l:fe = expand('<afile>:e') + let l:fn = strpart(l:fr, -8, strlen(l:fr)) . '.' . l:fe + + " myfile.XXQGS16A: strip extension + elseif l:fn =~# '/[^./]\+\.\w\{8}$' + let l:fn = expand('<afile>:r') + + " Unrecognised pattern; return, don't repeat + else + return + endif + + " Re-run the group if there's anything left + if strlen(l:fn) + execute 'doautocmd filetypedetect BufRead ' . fnameescape(l:fn) + endif + +endfunction + +" Check whether the first line was changed and looks like a shebang, and if +" so, re-run filetype detection +function! filetype#CheckShebang() abort + if line('''[') == 1 && getline(1) =~# '^#!' + doautocmd filetypedetect BufRead + endif +endfunction + + diff --git a/vim/filetype.vim b/vim/filetype.vim index cc0de4e4..3ac816d4 100644 --- a/vim/filetype.vim +++ b/vim/filetype.vim @@ -10,81 +10,6 @@ if !has('autocmd') || &compatible finish endif -" Helper function to run the 'filetypedetect' group on a file with its -" extension stripped off -function! s:StripRepeat() - - " Check we have the fnameescape() function - if !exists('*fnameescape') - return - endif - - " Expand the match result - let l:fn = expand('<afile>') - - " Strip leading and trailing #hashes# - if l:fn =~# '^#\+.*#\+$' - let l:fn = substitute(l:fn, '^#\+\(.\+\)#\+$', '\1', '') - - " Strip trailing tilde~ - elseif l:fn =~# '\~$' - let l:fn = substitute(l:fn, '\~$', '', '') - - " Strip generic .extension - else - let l:fn = expand('<afile>:r') - endif - - " Re-run the group if there's anything left - if strlen(l:fn) - execute 'doautocmd filetypedetect BufRead ' . fnameescape(l:fn) - endif - -endfunction - -" Helper function to run the 'filetypedetect' group on a file in a temporary -" sudoedit(8) directory, modifying it with an attempt to reverse the temporary -" filename change -function! s:SudoRepeat() - - " Check we have the fnameescape() function - if !exists('*fnameescape') - return - endif - - " Expand the match result - let l:fn = expand('<afile>') - - " myfileXXQGS16A.conf: strip eight chars before final period - if l:fn =~# '/[^./]\+\w\{8}\.[^./]\+$' - let l:fr = expand('<afile>:r') - let l:fe = expand('<afile>:e') - let l:fn = strpart(l:fr, -8, strlen(l:fr)) . '.' . l:fe - - " myfile.XXQGS16A: strip extension - elseif l:fn =~# '/[^./]\+\.\w\{8}$' - let l:fn = expand('<afile>:r') - - " Unrecognised pattern; return, don't repeat - else - return - endif - - " Re-run the group if there's anything left - if strlen(l:fn) - execute 'doautocmd filetypedetect BufRead ' . fnameescape(l:fn) - endif - -endfunction - -" Check whether the first line was changed and looks like a shebang, and if -" so, re-run filetype detection -function! s:CheckShebang() - if line('''[') == 1 && getline(1) =~# '^#!' - doautocmd filetypedetect BufRead - endif -endfunction - " Use our own filetype detection rules augroup filetypedetect autocmd! @@ -97,7 +22,7 @@ augroup filetypedetect \,?*~ \,?*.{bak,example,in,new,old,orig,sample,test} \,?*.dpkg-{bak,dist,new,old} - \ call s:StripRepeat() + \ call filetype#StripRepeat() " Stuff Tom cares about enough and edits often enough to type based on " filename patterns follows. @@ -534,7 +459,7 @@ augroup filetypedetect \ /var/tmp/?*????????.* \,/var/tmp/?*.???????? \ if !did_filetype() - \| call s:SudoRepeat() + \| call filetype#SudoRepeat() \|endif " Generic text, config, and log files, if no type assigned yet @@ -568,6 +493,6 @@ augroup filetypedetect " On leaving insert mode, check whether the first line was changed and looks " like a shebang format, and if so, re-run filetype detection - autocmd InsertLeave * call s:CheckShebang() + autocmd InsertLeave * call filetype#CheckShebang() augroup END diff --git a/zsh/profile.d/zsh.sh b/zsh/profile.d/zsh.sh index 47de6d4d..37ec8014 100644 --- a/zsh/profile.d/zsh.sh +++ b/zsh/profile.d/zsh.sh @@ -5,24 +5,33 @@ # ~/.profile is read. This seems to have been fixed in Zsh commit ID fde365e, # which was followed by release 5.3.0. -# Is this zsh masquerading as sh/ksh? +# This hack is only applicable to interactive zsh invoked as sh/ksh, when ENV +# exists, so check each of those: +## Interactive? +case $- in + *i*) ;; + *) return ;; +esac +## zsh? [ -n "$ZSH_VERSION" ] || return +## Invoked as sh or ksh? case $ZSH_NAME in sh|ksh) ;; *) return ;; esac +## ENV exists? +[ -e "$ENV" ] || return # Iterate through the zsh version number to see if it's at least 5.3.0; if not, -# we'll have ~/.profile force sourcing $ENV -if ! ( +# we'll source $ENV ourselves, since ~/.profile probably didn't do it +if ( zvs=$ZSH_VERSION for fv in 5 3 0 ; do zv=${zvs%%[!0-9]*} - [ "$((zv > fv))" -eq 1 ] && exit 0 - [ "$((zv < fv))" -eq 1 ] && exit 1 - zvs=${zvs#*.} - [ -n "$zvs" ] || exit 0 + ! [ "$zv" -gt "$fv" ] || exit 1 + ! [ "$zv" -lt "$fv" ] || exit 0 + zvs=${ZSH_VERSION#*.} done ) ; then - ENV_FORCE=1 + . "$ENV" fi diff --git a/zsh/zshrc.d/keep.zsh b/zsh/zshrc.d/keep.zsh index 59696301..c47748cd 100644 --- a/zsh/zshrc.d/keep.zsh +++ b/zsh/zshrc.d/keep.zsh @@ -83,7 +83,7 @@ EOF # Iterate through the NAMEs given local name - for name ; do + for name do # Check NAMEs for validity case $name in |