#!/bin/bash ############################################################################ # bfs # # Copyright (C) 2020 Benjamin Mundt # # Copyright (C) 2020 Tavian Barnes # # # # Permission to use, copy, modify, and/or distribute this software for any # # purpose with or without fee is hereby granted. # # # # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES # # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF # # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR # # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES # # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN # # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. # ############################################################################ # bash completion script for bfs _bfs() { local cword="$COMP_CWORD" local cur="${COMP_WORDS[cword]}" local prev prev2 if ((cword > 0)); then prev="${COMP_WORDS[cword-1]}" fi if ((cword > 1)); then prev2="${COMP_WORDS[cword-2]}" fi # Options with a special completion procedure local special=( -D -S -exec -execdir -fprintf -fstype -gid -group -ok -okdir -perm -regextype -type -uid -user -xtype ) # Options whose values should not be completed # (e.g. because they are numeric, glob, regexp, time, etc.) local nocomp=( -{a,B,c,m}{min,since,time} -ilname -iname -inum -ipath -iregex -iwholename -links -lname -maxdepth -mindepth -name -newer{a,B,c,m}t -path -printf -regex -since -size -used -wholename -xattrname ) # Options whose value is a filename local filecomp=( -{a,B,c,m}newer -f -fls -fprint -fprint0 -newer -newer{a,B,c,m}{a,B,c,m} -samefile ) local operators=( -a -and -exclude -not -o -or ) # Flags that take no arguments local nullary_flags=( -E -H -L -O{0,1,2,3,4,fast} -P -X -d -x ) # Options that take no arguments local nullary_options=( -color -daystart -depth -follow -ignore_readdir_race -maxdepth -mindepth -mount -nocolor -noignore_readdir_race -noleaf -nowarn -status -unique -warn -xdev ) # Tests that take no arguments local nullary_tests=( -capable -empty -executable -false -hidden -nogroup -nohidden -nouser -readable -sparse -true -writable -xattr -xattrname ) # Actions that take no arguments local nullary_actions=( --help --version -delete -exit -help -ls -print -print0 -printx -prune -quit -rm -version ) local everything=( "${special[@]}" "${nocomp[@]}" "${filecomp[@]}" "${operators[@]}" "${nullary_flags[@]}" "${nullary_options[@]}" "${nullary_tests[@]}" "${nullary_actions[@]}" ) # Completing -exec requires matching the whole command line local iscmd isarg word for word in "${COMP_WORDS[@]::cword}"; do case "$word" in -exec|-execdir|-ok|-okdir) iscmd=y ;; \\\;|+) if [[ -n "$iscmd" ]] || [[ -n "$isarg" ]]; then iscmd= isarg= fi ;; *) if [[ -n "$iscmd" ]]; then iscmd= isarg=y fi ;; esac done if [[ -n "$iscmd" ]]; then COMPREPLY=($(compgen -c -- "$cur")) return elif [[ -n "$isarg" ]]; then COMPREPLY=($(compgen -o default -o bashdefault -W "{} + \\\\;" -- "$cur")) return fi # Completions with 2-word lookbehind case "$prev2" in -fprintf) # -fprintf FORMAT FILE # Like -ls/-print/-print0/-printf, but write to FILE instead of standard # output # when -fprintf is prev2, current word is FILE; perform file completion COMPREPLY=($(compgen -f -- "$cur")) return ;; esac # No completion for numbers, globs, regexes, times, etc. if [[ " ${nocomp[@]} " =~ " $prev " ]]; then COMPREPLY=() return fi # Complete filenames if [[ " ${filecomp[@]} " =~ " $prev " ]]; then COMPREPLY=($(compgen -o filenames -f -- "$cur")) return fi # Other completions with 1-word lookbehind case "$prev" in -type|-xtype) # -type [bcdlpfswD] # Find files of the given type # -xtype [bcdlpfswD] # Find files of the given type, following links when -type would not, and # vice versa COMPREPLY=() if [[ -n $cur ]] && ! [[ $cur =~ ,$ ]]; then COMPREPLY+=("$cur") cur+=, fi COMPREPLY+=("$cur"{b,c,d,l,p,f,s,w,D}) return ;; -gid|-uid) # -gid [-+]N # -uid [-+]N # Find files owned by group/user ID N # TODO: list numeric uids/gids COMPREPLY=() return ;; -group) # -group NAME # Find files owned by the group NAME COMPREPLY=($(compgen -g -- "$cur")) return ;; -user) # -user NAME # Find files owned by the user NAME COMPREPLY=($(compgen -u -- "$cur")) return ;; -S) # -S bfs|dfs|ids|eds # Use breadth-first/depth-first/iterative/exponential deepening search # (default: -S bfs) COMPREPLY=($(compgen -W 'bfs dfs ids eds' -- "$cur")) return ;; -D) # -D FLAG # Turn on a debugging flag (see -D help) COMPREPLY=($(compgen -W 'help cost exec opt rates search stat tree all' -- "$cur")) return ;; -regextype) # -regextype TYPE # Use TYPE-flavored regexes (default: posix-basic; see -regextype help) COMPREPLY=($(compgen -W 'help posix-basic posix-extended' -- "$cur")) return ;; -fstype) # -fstype TYPE # Find files on file systems with the given TYPE #TODO: parse the mount table for a list of mounted filesystem types COMPREPLY=() return ;; (-perm) # -perm [-]MODE # Find files with a matching mode # sample syntax: # -perm 777 # -perm 507 # -perm u+rw # -perm og-rx if [[ -z "$cur" ]]; then # initial completion COMPREPLY=(0 1 2 3 4 5 6 7 u g o) return elif [[ "$cur" =~ [rwx][rwx][rwx]$ ]] || [[ "$cur" =~ [0-7][0-7][0-7]$ ]]; then # final completion (filled in all possible mode bits) COMPREPLY=("$cur") return elif [[ "$cur" =~ [0-7]$ ]]; then # intermediate completion, octal mode specifier COMPREPLY=("$cur"{0,1,2,3,4,5,6,7}) return elif [[ "$cur" =~ ^[ugo]*[+-][rwx]*$ ]]; then # intermediate completion, symbolic mode specifier COMPREPLY=() [[ "$cur" =~ [rwx]$ ]] && COMPREPLY+=("${cur}") [[ "$cur" =~ [+-][wx]*r ]] || COMPREPLY+=("${cur}r") [[ "$cur" =~ [+-][rx]*w ]] || COMPREPLY+=("${cur}w") [[ "$cur" =~ [+-][rw]*x ]] || COMPREPLY+=("${cur}x") return 0 elif [[ "$cur" =~ ^[ugo] ]]; then # intermediate completion, symbolic group specifier COMPREPLY=(+ -) [[ "$cur" =~ ^[go]*u ]] || COMPREPLY+=("${cur}u") [[ "$cur" =~ ^[uo]*g ]] || COMPREPLY+=("${cur}g") [[ "$cur" =~ ^[ug]*o ]] || COMPREPLY+=("${cur}o") return 0 fi COMPREPLY=() return ;; esac # Completions with no lookbehind if [[ "$cur" == -* ]]; then # complete all options COMPREPLY=($(compgen -o default -o bashdefault -W "${everything[*]}" -- "$cur")) return fi # default completion COMPREPLY=($(compgen -o default -o bashdefault -f -W "${everything[*]} ! ," -- "$cur")) return } && complete -F _bfs bfs