#compdef btrfs local curcontext="$curcontext" curstate state line expl grp cmd ret=1 local -a groups args groups=( subvolume filesystem device scrub balance inspect-internal help version ) cmds_1=( create delete list snapshot get-default set-default find-new help ) cmds_2=( df show sync defragment resize label balance help ) cmds_3=( add delete scan help ) cmds_4=( start cancel resume status help ) cmds_5=( start pause cancel resume status ) cmds_6=( inode-resolve logical-resolve help ) [[ $words[2] = h(|e(|l(|p))) ]] && args=( '--full[display detailed help]' ) _arguments -C "$args[@]" \ '(- *)--help[print help information]' \ '(- *)--version[print version information]' \ '(--version)1: :->groups' \ '2: :->cmds' \ '*:: :->args' && ret=0 while (( $#state )); do curstate=$state shift state case $curstate in groups) _wanted command-groups expl 'btrfs command group' compadd -a groups && ret=0 ;; cmds) : $words local grp=${groups[(i)$words[2]*]} : $grp (( grp && grp < 7 )) || return 1 curcontext="${curcontext%:*:*}:$service-${groups[grp]}:" _wanted commands expl command compadd -a cmds_$grp && ret=0 ;; args) : $words local grp=${groups[(i)$words[1]*]} (( grp && grp < 7 )) || return 1 local group=cmds_$grp local cmd=${${(P)group}[(i)$words[2]*]} (( cmd )) || return 1 curcontext="${curcontext%:*:*}:$service-${groups[grp]}-${${(P)group}[cmd]}:" args=( '(-)--help[print help information]' ) case ${groups[grp]}:${${(P)group}[cmd]} in filesystem:balance) if (( CURRENT == 3 )); then state+=cmds else shift words (( CURRENT-- )) state+=args fi continue ;; subvolume:create) args+=( '1:destination:->mounts' );; subvolume:delete) args+=( '1:subvolume:_files -/' );; subvolume:snapshot) args+=( '-r[readonly snapshot]' '1:snapshot:_files -/' );; subvolume:list) args+=( '-p[include parent ID in output]' '1:path:->mounts' );; subvolume:set-default) args+=( '1:id:_guard "[0-9]#" id' '2:path:->mounts' );; filesystem:resize) args+=( '1:size:_guart "(|+|-)[0-9]#[GKM]"' '2:path:->mounts' );; filesystem:defragment) args+=( '-v[verbose]' '-c[compress files while defragmenting]' '-f[flush after defragmenting]' '-s[start position]:byte position' '-l[defragment limited number of bytes]:length (bytes)' '-t[defragment only files over a certain size]:minimum size (bytes)' '*:file:_files' ) ;; filesystem:label) args+=( '1:device:_files -g "*(d)"' '2:label' );; filesystem:show) args+=( '(1 -)--all-devices[scan all devices in /dev]' '1: :_guard "^-*" uuid or label' );; device:(add|delete)) args+=( '1:device:_files -g "*(d)"' '2:path:->mounts' );; device:scan) args+=( '(1 -)--all-devices[scan all devices in /dev]' '1:device:_files -g "*(d)"' );; scrub:(start|resume)) args+=( "-B[don't background and print statistics at end]" '-d[print separate statistics for each device]' '-q[omit error message and statistics]' '-r[read only mode]' '-u[scrub unused space too]' '1:path or device:_files' ) ;; scrub:cancel) args+=( '1:path or device' );; scrub:status) args+=( '-d[separate statistics for each device]' '1:path or device:_files' );; balance:start) args+=( '(-m -s)-d+[act on data chunks]:filter:->filters' '(-d -s)-m+[act on metadata chunks]:filter:->filters' '(-d -m)-s+[act on system chunks (only under -f)]:filters:->filters' '-v[verbose mode]' '-f[force reducing of metadata integrity]' '1:path:_files -/' ) ;; balance:status) args+=( '-v[verbose mode]' '2:path:_files -/' );; balance:(pause|cancel|resume)) args+=( '2:path:_files -/' );; inspect*:inode*) args+=( '-v[verbose mode]' '1:inode:_files' '2:path:_files -/' );; inspect*:logical*) args+=( '-v[verbose mode]' '-P[skip the path resolving and print the inodes instead]' '1:logical address:_files' '2:filesystem path:_files -/' ) ;; subvolume:get-default) ;& *:sync) ;& *:df) args+=( '1:path:->mounts' );; *) args+=( '*: :_default' );; # fallback for unknown subcommands esac shift words (( CURRENT-- )) _arguments -C "$args[@]" && ret=0 ;; mounts) _wanted mount-points expl 'mount point' compadd \ ${${${(M)${(f)"$(profiles' \ 'usage[balance block groups with usage below percentage]:percentage' \ 'devid[limit by device ID]:device ID' \ 'drange[balance block groups overlapping byte range]:range' \ 'vrange[balance block groups overlapping byte range in virtual address space]:range' \ 'convert[convert block groups to given profile]:profile:->profiles' \ 'soft[leave chunks that already have target profile]' && ret=0 state=( $state ) ;; profiles) compset -P '*\|' _values -s ',' profile raid0 raid1 raid10 dup single && ret=0 ;; esac done return ret