Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Bug in the completion for qemu in zsh



I've worked on this for personal use. attaching it just in case someone
is interested in finishing it and cleaning it up a bit.

Only made it about half way through the qemu(1)
diff --git a/Completion/Unix/Command/_qemu b/Completion/Unix/Command/_qemu
index 8ba7140..ea0d81c 100644
--- a/Completion/Unix/Command/_qemu
+++ b/Completion/Unix/Command/_qemu
@@ -1,5 +1,132 @@
-#compdef -P qemu(|-system-*)
+#compdef -P qemu(|-system-*) qemu-img
 
+(( $+functions[_qemu-img] )) ||
+_qemu-img () {
+  local subcmd ret=1
+
+  if (( CURRENT == 2 )); then
+    _describe 'qemu-img subcommands' '(
+    check:"perform a consistency check"
+    create:"create image" 
+    commit:"commit changes to base image"
+    compare:"compare content of two images"
+    convert:"convert image format"
+    info:"print image information"
+    map:"print metadata of image(and chain)" 
+    snapshot:"snapshot management"
+    rebase:"change backing file of image"
+    resize:"resize image"
+    amend:"append options to image"
+    )' && ret=0
+  else
+    shift words; (( CURRENT-- ))
+    subcmd=$words[1]
+    curcontext=${curcontext%:*}-$service:
+    local -a args
+
+    case $subcmd in
+      check)
+        args=(
+          '-q[quiet]'
+          '-f[format]:format:(qcow2 qed)'
+          '--output=-[output format]:output format:(human json)'
+          '-r[repair]::repair:(leaks all)'
+          '1: :_files'
+          )
+          ;;
+      create)
+        args=(
+          '-q[quiet]'
+          '-f[format]:format:(vpc vhdx vdi raw host_cdrom host_floppy file qed 
+            qcow2 qcow cow)'
+          '-o[options]:format options:( \? )'
+          '1: :_files'
+          '2:size:'
+          )
+          ;;
+      commit)
+        args=(
+          '-f[format]:format:(qed qcow2)' # raw)' not sure if raw does snapshots
+          '-t[cache mode]:cache mode:(none writeback unsafe directsync writethrough)'
+          '1: :_files'
+          )
+          ;;
+      compare)
+        args=(
+          '-f[format of file1]:format:(raw qed qcow2 qcow cow)'
+          '-F[format of file2]:format:(raw qed qcow2 qcow cow)'
+          '-q[quiet]'
+          '-p[display progress]'
+          '-s[strict mode]'
+          '1: :_files'
+          '2: :_files'
+          )
+          ;;
+      convert)
+        args=(
+          '-p[display progress]'
+          '-s[snapshot id]:snapshot id:'
+          '-n[skip target creation]'
+          '-o[options]:format options:( \? )'
+          '-f[input format]:format:(vpc vhdx vdi raw host_cdrom host_floppy file qed 
+            qcow2 qcow cow rbd)'
+          '-O[output format]:format:(raw qcow2 qcow cow rbd)'
+          '-c[compress]'
+          '-l[snapshot id]:snapshot id or name:'
+          '-S[sparse size]:size:'
+          '*: :_files'
+          )
+          ;;
+      info|map)
+        args=(
+          '-f[format]:format:(raw qcow2 qcow cow)'
+          '--output=-[output format]:format:(human json)'
+          '1:image:_files'
+          )
+          [[ $subcmd == info ]] &&
+            args+=( '--backing-chain[display the complete chain]' )
+          ;;
+      snapshot)
+        args=(
+          '(-a -c -d)-l[list snapshots]'
+          '(-l -c -d)-a[apply snapshot]:snapshot:'
+          '(-l -a -d)-c[create snapshot]:snapshot name:'
+          '(-l -a -c)-d[delete snapshot]:snapshot:'
+          '1: :_files'
+          )
+          ;;
+      rebase)
+        args=(
+          '-f[format]:format:(qcow2 qed)'
+          '-t[cache mode]:cache mode:(none writeback unsafe directsync writethrough)'
+          '-p[display progress]'
+          '-u[unsafe mode]'
+          '-b[backing file]:backing file:_files'
+          '-F[backing format]:backing_fmt:' # not too sure what this is, but may just need (qcow2 qed) as the action
+          '1: :_files'
+          )
+          ;;
+      resize)
+        args=(
+          '1: :_files'
+          '2:size \(+more -less\):'
+          )
+          ;;
+      amend)
+        args=(
+          '-f[format]:format:(qcow2)'
+          '-o[options]:format options:( \? )'
+          '1: :_files'
+          )
+          ;;          
+    esac
+    _arguments : "$args[@]" && ret=0
+  fi
+
+  return ret
+}
+
+(( $+functions[_qemu_log_items] )) ||
 _qemu_log_items () {
   local -a opts hline
   $service -d \? | while read -A hline; do
@@ -9,47 +136,242 @@ _qemu_log_items () {
   _values -s , 'log items' $opts
 }
 
-local _qemu_machines
-
-_qemu_machines=(${${${(f)"$($service -M \?)"}[2,-1]}%% *})
-
-_arguments \
-  '-'{fda,fdb,hda,hdb,hdc,hdd,cdrom}':disk image:_files' \
-  '-M[target machine]:machine:('"${_qemu_machines:-none}"')' \
-  '-boot[specify which image to boot from]:boot device:((a\:floppy\ image\ a c\:hard\ disk d\:cdrom))' \
-  '-snapshot[write to temporary files instead of disk image files]' \
-  '-no-fd-bootchk[disable boot sig checking for floppies in Bochs BIOS]' \
-  '-m[virtual RAM size (default=128)]:megs:' \
-  '-smp[set the number of CPUs (default=1)]:number of CPUs:' \
-  '-nographic[disable graphical output]' \
-  '-vnc[listen on VNC display]:display:' \
-  '-k[use keyboard layout]:keyboard layout language:(ar de-ch es fo fr-ca hu ja mk no pt-br sv da en-gb et fr fr-ch is lt nl pl ru th de en-us fi fr-be hr it lv nl-be pt sl tr)' \
-  '-audio-help[show audio subsystem help]' \
-  '-soundhw[enable audio and selected sound hardware]:cards to enable:(all)' \
-  '-localtime[set rtc to local time]' \
-  '-full-screen[start in full screen]' \
-  '-pidfile:pidfile:_files' \
-  '-win2k-hack' \
-  '-usb[enable USB driver]' \
-  '-usbdevice:usb device:' \
-  '-net:net config:(none)' \
-  '-tftp[allow tftp access to files starting with prefix]:tftp prefix:_files' \
-  '-smb[allow SMB access to files in specified directory]:samba directory:_path_files -/' \
-  '-redir[redirect TCP or UDP connections from host to guest]:redirection: ' \
-  '-kernel[boot specified linux kernel]:kernel image:_files' \
-  '-append[use specified kernel command line]:command line: ' \
-  '-initrd[use specified initial ram disk]:ram disk:_files' \
-  '-serial:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
-  '-parallel:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
-  '-monitor:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
-  '-s[wait gdb connection to port 1234]' \
-  '-p[change gdb connection port]:port:_ports' \
-  '-S[do not start CPU at startup]' \
-  '-d[output log in /tmp/qemu.log]:log items:_qemu_log_items' \
-  '-hdachs[force hard disk 0 geometry (usually qemu can guess it)]:hd0 geometry c,h,s:' \
-  '-std-vga[simulate standard VGA]' \
-  '-no-acpi[disable ACPI]' \
-  '-loadvm[start right away with a saved state]:file:_files' \
-  '-g[set initial graphic mode]:graphic mode:' \
-  ':disk image:_files'
+(( $+functions[_qemu_device_drivers] )) ||
+_qemu_device_drivers () {
+  # TODO: refactor, so completing driver properties is possible.
+  local field1 field2 REPLY prop properties
+  local state state_descr line context driver
+  typeset -A val_args
+  typeset -a dev
+  #parsing out driver names
+  $service -device help 2>&1 | while read -r field1 field2 REPLY; do
+    if [[ $field1 == name ]]; then
+      dev+=( ${${field2%\",}#\"} )
+    fi
+  done
+  compadd -qS , -a dev
+  # parsing out driver properties. commented out since drivers are allowed to have commas in them, breaking this hack.
+  #driver=${PREFIX%,}
+  #$service -device $driver,help 2>&1 | while read -r prop; do 
+  #  properties+=( "${${prop#$driver.}%=*}:${prop#*=}:" )
+  #done
+  # not sure why this works, but it ignores the 'driver,' parts and lists properties.
+  #compset -P '*,'
+  #_values -s , properties $properties[@]
+}
+
+(( $+functions[_$service] )) ||
+_$service () {
+  local args context state state_descr line ret=1
+  typeset -A val_args opt_args
+  _arguments \
+    '-'{fda,fdb,hda,hdb,hdc,hdd,cdrom}':disk image\(deprecated\):_files' \
+    '-'{mtdblock,sd,pflash}':disk image:_files' \
+    '-M[target machine]:machine: compadd -- ${${(@)${${(f)"$($service -M \?)"}[2,-1]}%% *}\:-none}' \
+    '-machine[target machine]:machine:->machine'\
+    '-boot[specify which image to boot from]:boot device:->boot' \
+    '-balloon[virtio ballon device]:balloondev:->balloon' \
+    '-enable-kvm[enable kvm]' \
+    '-snapshot[write to temporary files instead of disk image files]' \
+    '-no-fd-bootchk[disable boot sig checking for floppies in Bochs BIOS]' \
+    '*-device[add device driver]:device: _qemu_device_drivers' \
+    '*-drive[define a drive]:drive:->drive' \
+    '-m[virtual RAM size (default=128)]:megs:' \
+    '-mem-path[allocate RAM from temp file]:mem-path: _files' \
+    '-mem-prealloc[preallocate memory from -mem-path]' \
+    '-cpu[CPU model]:cpumodel:->cpu' \
+    '-numa[simulate a multi node NUMA system]:numa:' \
+    '-name[set name of guest]:name:' \
+    '-uuid[set uuid of guest]:uuid:' \
+    '-add-fd[add file descriptor to a fd set]:fd:->fd' \
+    '-smp[set the number of CPUs (default=1)]:number of CPUs:->smp' \
+    '-set[parameter]:parameter: _message "parameter (group.id.arg=value)"' \
+    '-global[default value of a driver property]:property: _message "driver property value (driver.prop=value)"' \
+    '-nographic[disable graphical output]' \
+    '-vnc[listen on VNC display]:display:' \
+    '-spice[enable spice protocol]:spice:->spice' \
+    '-display[type of display to use]:display type:(sdl curses none vnc)' \
+    '-curses[use curses/ncurses for display]' \
+    '-portrait[rotate graphical output 90 degrees left]' \
+    '-rotate[rotate graphical output to left]:degrees:' \
+    '-no-frame[do not draw WM border]' \
+    '-alt-grab[use ctrl-alt-shit to grab mouse]' \
+    '-ctrl-grab[use right-ctrl to grab mouse]' \
+    '-sdl[enable SDL]' \
+    '-no-quit[disable SDL windows close capability]' \
+    '-k[use keyboard layout]:keyboard layout language:(ar de-ch es fo fr-ca hu ja mk no pt-br sv da en-gb et fr fr-ch is lt nl pl ru th de en-us fi fr-be hr it lv nl-be pt sl tr)' \
+    '-audio-help[show audio subsystem help]' \
+    '-soundhw[enable audio and selected sound hardware]:cards to enable:->soundhw' \
+    '-localtime[set rtc to local time]' \
+    '-full-screen[start in full screen]' \
+    '-pidfile:pidfile:_files' \
+    '*-fsdev[define filesystem device]:share:->fsdev' \
+    '*-virtfs[define filesystem device]:share:->virtfs' \
+    '*-virtfs_synth[define synthetic filesystem image]' \
+    '-win2k-hack' \
+    '-usb[enable USB driver]' \
+    '*-usbdevice[define USB device]:usb device:->usbdevice' \
+    '*-net:net config:(none)' \
+    '-tftp[allow tftp access to files starting with prefix]:tftp prefix:_files' \
+    '-smb[allow SMB access to files in specified directory]:samba directory:_path_files -/' \
+    '*-redir[redirect TCP or UDP connections from host to guest\(deprecated\)]:redirection: ' \
+    '-kernel[boot specified linux kernel]:kernel image:_files' \
+    '-append[use specified kernel command line]:command line: ' \
+    '-initrd[use specified initial ram disk]:ram disk:_files' \
+    '-serial:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
+    '-parallel:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
+    '-monitor:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
+    '-s[wait gdb connection to port 1234]' \
+    '-p[change gdb connection port]:port:_ports' \
+    '-S[do not start CPU at startup]' \
+    '-d[output log in /tmp/qemu.log]:log items:_qemu_log_items' \
+    '-hdachs[force hard disk 0 geometry (usually qemu can guess it)]:hd0 geometry c,h,s:' \
+    '-vga[define vga card]:VGA card type:(cirrus std vmware qxl xenfb none)' \
+    '-no-acpi[disable ACPI]' \
+    '-loadvm[start right away with a saved state]:file:_files' \
+    '-g[set initial graphic mode]:graphic mode:' \
+    ':disk image: _alternative "file:file:_files" "uri:uri:( iscsi\:// ssh\:// nbd\: nbd\:unix\:  sheepdog\:// sheepdog+tcp\:// sheepdog+udp\:// gluster\:// gluster+transport\://)"' &&
+    ret=0
+  #               ^ should turn that _alternative into a small function.
+
+
+  while (( $#state )); do
+    local -a suf
+    local curstate=$state sep
+    shift state
+    case $curstate in
+      ("machine")
+        args=(  
+          'accel[accelerator]:accel:(tcg kvm xen)' 
+          'kernel_irqchip[in-kernel irqchip support]:irqchip:(on off)' 
+          'kvm_shadow_size[KVM shadow MMU]:size: _message "size"' 
+          'dump-guest-core[add guest memory to coredump]:coredump:(on off)' 
+          'mem-merge[memory merge support]:mem-merge:(on off)'
+          )
+        ;;
+      ("smp")
+        args=(
+          'cpus[number of CPUS]:cpus: _message "number of CPUS"'
+          'cores[cores per socket]:socket: _message "number of cores per socket"'
+          'threads[threads per core]:threads: _message "number of threads per core"'
+          'sockets[total number of sockets]:sockets: _message "number of sockets"'
+          'maxcpus[max number of hotpluggable CPUs]:hotplug: _message "number of hotpluggable CPUS"'
+          )
+        ;;
+      ("fd")
+        args=(
+          'fd[file descriptor to duplicate]:fd:"'
+          'set[define ID of fd set]:ID:'
+          'opaque[free-form string for defining a fd]:opaque:'
+          )
+        ;;
+      ("boot")
+        args=(
+          'order[boot order]:boot order:((a\:floppy\ image\ a c\:hard\ disk d\:cdrom))'
+          'once[one time boot order]:tmp boot:((a\:floppy\ image\ a c\:hard\ disk d\:cdrom))'
+          'menu[display boot menus]:menu:(on off)'
+          'splash[display splash logo during POST]:logo: _files'
+          'splash-time[splash logo duration]:duration:'
+          'reboot-timeout[retry after failed boot]:timer: _message "time (milliseconds)"'
+          'strict[do strict boot]:strict boot:(yes no)'
+          )
+        ;;
+      ("soundhw")
+        args=(
+          'all' ${${(@)${${(f)"$($service -soundhw help)"}[2,-2]}%% *}\:-none} # pretty sure this isn't only eval'd when state=soundhw
+          )
+        ;;
+      ("balloon")
+        args=(
+          '(virtio)none'
+          '(none)virtio'
+          #'addr:addr: _message "address"' # need a way to only show if virtio is chosen.
+          )
+        ;;
+      ("drive")
+        args=(
+          'file[disk image to use]:image: _alternative "file:file:_files -S , -r  /\t\n\-" "uri:uri:( iscsi\:// ssh\:// nbd\: nbd\:unix\:  sheepdog\:// sheepdog+tcp\:// sheepdog+udp\:// gluster\:// gluster+transport\://)"'
+          'if[interface to connect to]:interface:(ide scsi sd mtd floppy pflash virtio)'
+          'bus[bus number]:bus number:'
+          'unit[unit id]:unit id:'
+          'index[index number for interface]:index:'
+          'media[media type]:media type:(cdrom disk)'
+          'cyls[number of cylinders]:cylinders:'
+          'heads[number of heads]:heads:'
+          'secs[number of sectors]:sectors:'
+          'trans[BIOS translation mode]:BIOS translation mode:(none lba auto)'
+          'snapshot[allow snapshots for drive]:snapshot:(on off)'
+          'cache[type of caching to use]:caching type:(none writeback unsafe directsync writethrough)'
+          'aio[asynchronous I/O operations]:aio:(threads native)'
+          'discard[allow discard (known as trim or unmap)]:discard:(( ignore\:"off" off\:"off"  unmap\:"on" on\:"on"))'
+          'format[specify the disk image format]:disk format:(raw cloop cow qcow qcow2 vmdk vdi)'
+          'serial[specify serial number for drive]:serial number:'
+          "addr[specify controller's PCI address (if=virtio only)]:PCI address:"
+          'rerror[perform action on read error]:rerror:(( ignore\:"ignore and continue" stop\:"pause qemu" report\:"report error to guest" enospc\:"only pause when host is full, report otherwise" ))'
+          'werror[perform action on write error]:werror:(( ignore\:"ignore and continue" stop\:"pause qemu" report\:"report error to guest" enospc\:"only pause when host is full, report otherwise" ))'
+          'readonly[open drive in ro]'
+          'copy-on-read[copy read backing file sectors into image file]:copy-on-read:(on off)'
+          )
+        ;;
+      ("fsdev"|"virtfs")
+        # TODO: local, handle or proxy has to appear first. pretty sure _values can't do it.
+        args=(
+          '(handle proxy)local'
+          '(proxy local)handle'
+          '(local handle)proxy'
+          'id[identifier for this device]:id:'
+          'path[export path]:path:_files -/ -S , -r " /\t\n\-"'
+          'security_model[security model for exported path]:security model:(passthrough mapped-xattr mapped-file none)'
+          'writeout[write notification]:writeout:(immediate)'
+          'readonly[export share as readonly]'
+          'socket[socket file for virtfs-proxy-helper]:socket:_files -S , -r " /\t\n\-"'
+          'sock_fd[socket fs for virtfs-proxy-helper]:socket fd:'
+          )
+          [[ $curstate == virtfs ]] && args+=( 'mount_tag[tag name to be used by the guest to mount this export point]:mount tag:' )
+        ;;
+      ("usbdevice")
+        sep=":"
+        args=(
+          'mouse[virtual mouse]'
+          'tablet[pointer dev that uses absolute coordinates]'
+          'disk[file based mass storage device]:UMS:_files -S , -r " /\t\n\-"' # optional format= option can be used format:file
+          'host[host device passthrough]:bus.addr or vendorid\:productid:'
+          'serial[serial to host char dev converter]:serial:(vc stdio pty null /dev/ttyS0 /dev/partport0)' # optional vendorid= and productid= options
+          'braille[braille device]'
+          'net[network adapter]:options:' # man page doesn't show possible options
+          )
+        ;;
+      ("spice")
+        args=(
+          'port[bind to TCP port]:TCP port:' # can't use names that _port outputs
+          'addr[bind to ip address]:ip address:_bind_addresses'
+          'ipv'{4,6}'[force IP version]'
+          'password[set password need to auth]:password:'
+          'sasl[require client to use SASL]'
+          'disable-ticketing[allow connections without authentication]'
+          'disable-copy-paste[disallow copy/paste between client and guest]'
+          'disable-agent-file-xfer[disallow spice-vdagent file-xfer]'
+          'tls-port[bind to TCP port\(for encrypted channels\)]:TCP port:'
+          'x509-dir[set x509 directory]:directory:_files -/ -S , -r " /\t\n\-"'
+          'x509-'{key,cert,cacert,dh-key}'-file:file:_files -S , -r " /\t\n\-"' 'x509-key-password:file:_files -S , -r " /\t\n\-"'
+          'tls-ciphers[ciphers to use]:list:' # no list of possible ciphers in the man page
+          '*'{tls,plaintext}'-channel[force specific channel]:channel:(default main display cursor inputs record playback)'
+          'image-compression[set image compression algorithm]:compression algorithm:(auto_glz auto_lz quic glz lz off)'
+          {jpeg,zlib-glz}'-wan-compression[use compression for slow links]: :(auto never always)'
+          'streaming-video[set video stream detection]: :(off all filter)'
+          'agent-mouse[enable/disable passing mouse events]: :(on off)'
+          'playback-compression[enable/disable auto stream compression]: :(on off)'
+          'seamless-migration[enable/disable spice seamless migration]: :(on off)'
+          )
+    esac
+    _values -s , -S ${sep:-=} $curstate "$args[@]"
+  done
+}
+
+_qemu_call_function() {
+  local ret=1
+  _call_function ret _$service
+  return ret
+}
 
+_qemu_call_function "$@"
#compdef -P qemu(|-system-*) qemu-img

(( $+functions[_qemu-img] )) ||
_qemu-img () {
  local subcmd ret=1

  if (( CURRENT == 2 )); then
    _describe 'qemu-img subcommands' '(
    check:"perform a consistency check"
    create:"create image" 
    commit:"commit changes to base image"
    compare:"compare content of two images"
    convert:"convert image format"
    info:"print image information"
    map:"print metadata of image(and chain)" 
    snapshot:"snapshot management"
    rebase:"change backing file of image"
    resize:"resize image"
    amend:"append options to image"
    )' && ret=0
  else
    shift words; (( CURRENT-- ))
    subcmd=$words[1]
    curcontext=${curcontext%:*}-$service:
    local -a args

    case $subcmd in
      check)
        args=(
          '-q[quiet]'
          '-f[format]:format:(qcow2 qed)'
          '--output=-[output format]:output format:(human json)'
          '-r[repair]::repair:(leaks all)'
          '1: :_files'
          )
          ;;
      create)
        args=(
          '-q[quiet]'
          '-f[format]:format:(vpc vhdx vdi raw host_cdrom host_floppy file qed 
            qcow2 qcow cow)'
          '-o[options]:format options:( \? )'
          '1: :_files'
          '2:size:'
          )
          ;;
      commit)
        args=(
          '-f[format]:format:(qed qcow2)' # raw)' not sure if raw does snapshots
          '-t[cache mode]:cache mode:(none writeback unsafe directsync writethrough)'
          '1: :_files'
          )
          ;;
      compare)
        args=(
          '-f[format of file1]:format:(raw qed qcow2 qcow cow)'
          '-F[format of file2]:format:(raw qed qcow2 qcow cow)'
          '-q[quiet]'
          '-p[display progress]'
          '-s[strict mode]'
          '1: :_files'
          '2: :_files'
          )
          ;;
      convert)
        args=(
          '-p[display progress]'
          '-s[snapshot id]:snapshot id:'
          '-n[skip target creation]'
          '-o[options]:format options:( \? )'
          '-f[input format]:format:(vpc vhdx vdi raw host_cdrom host_floppy file qed 
            qcow2 qcow cow rbd)'
          '-O[output format]:format:(raw qcow2 qcow cow rbd)'
          '-c[compress]'
          '-l[snapshot id]:snapshot id or name:'
          '-S[sparse size]:size:'
          '*: :_files'
          )
          ;;
      info|map)
        args=(
          '-f[format]:format:(raw qcow2 qcow cow)'
          '--output=-[output format]:format:(human json)'
          '1:image:_files'
          )
          [[ $subcmd == info ]] &&
            args+=( '--backing-chain[display the complete chain]' )
          ;;
      snapshot)
        args=(
          '(-a -c -d)-l[list snapshots]'
          '(-l -c -d)-a[apply snapshot]:snapshot:'
          '(-l -a -d)-c[create snapshot]:snapshot name:'
          '(-l -a -c)-d[delete snapshot]:snapshot:'
          '1: :_files'
          )
          ;;
      rebase)
        args=(
          '-f[format]:format:(qcow2 qed)'
          '-t[cache mode]:cache mode:(none writeback unsafe directsync writethrough)'
          '-p[display progress]'
          '-u[unsafe mode]'
          '-b[backing file]:backing file:_files'
          '-F[backing format]:backing_fmt:' # not too sure what this is, but may just need (qcow2 qed) as the action
          '1: :_files'
          )
          ;;
      resize)
        args=(
          '1: :_files'
          '2:size \(+more -less\):'
          )
          ;;
      amend)
        args=(
          '-f[format]:format:(qcow2)'
          '-o[options]:format options:( \? )'
          '1: :_files'
          )
          ;;          
    esac
    _arguments : "$args[@]" && ret=0
  fi

  return ret
}

(( $+functions[_qemu_log_items] )) ||
_qemu_log_items () {
  local -a opts hline
  $service -d \? | while read -A hline; do
    [[ $hline[1] = Log ]] && continue
    opts=($opts "${hline[1]}[${hline[2,-1]}]")
  done
  _values -s , 'log items' $opts
}

(( $+functions[_qemu_device_drivers] )) ||
_qemu_device_drivers () {
  # TODO: refactor, so completing driver properties is possible.
  local field1 field2 REPLY prop properties
  local state state_descr line context driver
  typeset -A val_args
  typeset -a dev
  #parsing out driver names
  $service -device help 2>&1 | while read -r field1 field2 REPLY; do
    if [[ $field1 == name ]]; then
      dev+=( ${${field2%\",}#\"} )
    fi
  done
  compadd -qS , -a dev
  # parsing out driver properties. commented out since drivers are allowed to have commas in them, breaking this hack.
  #driver=${PREFIX%,}
  #$service -device $driver,help 2>&1 | while read -r prop; do 
  #  properties+=( "${${prop#$driver.}%=*}:${prop#*=}:" )
  #done
  # not sure why this works, but it ignores the 'driver,' parts and lists properties.
  #compset -P '*,'
  #_values -s , properties $properties[@]
}

(( $+functions[_$service] )) ||
_$service () {
  local args context state state_descr line ret=1
  typeset -A val_args opt_args
  _arguments \
    '-'{fda,fdb,hda,hdb,hdc,hdd,cdrom}':disk image\(deprecated\):_files' \
    '-'{mtdblock,sd,pflash}':disk image:_files' \
    '-M[target machine]:machine: compadd -- ${${(@)${${(f)"$($service -M \?)"}[2,-1]}%% *}\:-none}' \
    '-machine[target machine]:machine:->machine'\
    '-boot[specify which image to boot from]:boot device:->boot' \
    '-balloon[virtio ballon device]:balloondev:->balloon' \
    '-enable-kvm[enable kvm]' \
    '-snapshot[write to temporary files instead of disk image files]' \
    '-no-fd-bootchk[disable boot sig checking for floppies in Bochs BIOS]' \
    '*-device[add device driver]:device: _qemu_device_drivers' \
    '*-drive[define a drive]:drive:->drive' \
    '-m[virtual RAM size (default=128)]:megs:' \
    '-mem-path[allocate RAM from temp file]:mem-path: _files' \
    '-mem-prealloc[preallocate memory from -mem-path]' \
    '-cpu[CPU model]:cpumodel:->cpu' \
    '-numa[simulate a multi node NUMA system]:numa:' \
    '-name[set name of guest]:name:' \
    '-uuid[set uuid of guest]:uuid:' \
    '-add-fd[add file descriptor to a fd set]:fd:->fd' \
    '-smp[set the number of CPUs (default=1)]:number of CPUs:->smp' \
    '-set[parameter]:parameter: _message "parameter (group.id.arg=value)"' \
    '-global[default value of a driver property]:property: _message "driver property value (driver.prop=value)"' \
    '-nographic[disable graphical output]' \
    '-vnc[listen on VNC display]:display:' \
    '-spice[enable spice protocol]:spice:->spice' \
    '-display[type of display to use]:display type:(sdl curses none vnc)' \
    '-curses[use curses/ncurses for display]' \
    '-portrait[rotate graphical output 90 degrees left]' \
    '-rotate[rotate graphical output to left]:degrees:' \
    '-no-frame[do not draw WM border]' \
    '-alt-grab[use ctrl-alt-shit to grab mouse]' \
    '-ctrl-grab[use right-ctrl to grab mouse]' \
    '-sdl[enable SDL]' \
    '-no-quit[disable SDL windows close capability]' \
    '-k[use keyboard layout]:keyboard layout language:(ar de-ch es fo fr-ca hu ja mk no pt-br sv da en-gb et fr fr-ch is lt nl pl ru th de en-us fi fr-be hr it lv nl-be pt sl tr)' \
    '-audio-help[show audio subsystem help]' \
    '-soundhw[enable audio and selected sound hardware]:cards to enable:->soundhw' \
    '-localtime[set rtc to local time]' \
    '-full-screen[start in full screen]' \
    '-pidfile:pidfile:_files' \
    '*-fsdev[define filesystem device]:share:->fsdev' \
    '*-virtfs[define filesystem device]:share:->virtfs' \
    '*-virtfs_synth[define synthetic filesystem image]' \
    '-win2k-hack' \
    '-usb[enable USB driver]' \
    '*-usbdevice[define USB device]:usb device:->usbdevice' \
    '*-net:net config:(none)' \
    '-tftp[allow tftp access to files starting with prefix]:tftp prefix:_files' \
    '-smb[allow SMB access to files in specified directory]:samba directory:_path_files -/' \
    '*-redir[redirect TCP or UDP connections from host to guest\(deprecated\)]:redirection: ' \
    '-kernel[boot specified linux kernel]:kernel image:_files' \
    '-append[use specified kernel command line]:command line: ' \
    '-initrd[use specified initial ram disk]:ram disk:_files' \
    '-serial:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
    '-parallel:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
    '-monitor:dev:(vc stdio pty null /dev/ttyS0 /dev/partport0)' \
    '-s[wait gdb connection to port 1234]' \
    '-p[change gdb connection port]:port:_ports' \
    '-S[do not start CPU at startup]' \
    '-d[output log in /tmp/qemu.log]:log items:_qemu_log_items' \
    '-hdachs[force hard disk 0 geometry (usually qemu can guess it)]:hd0 geometry c,h,s:' \
    '-vga[define vga card]:VGA card type:(cirrus std vmware qxl xenfb none)' \
    '-no-acpi[disable ACPI]' \
    '-loadvm[start right away with a saved state]:file:_files' \
    '-g[set initial graphic mode]:graphic mode:' \
    ':disk image: _alternative "file:file:_files" "uri:uri:( iscsi\:// ssh\:// nbd\: nbd\:unix\:  sheepdog\:// sheepdog+tcp\:// sheepdog+udp\:// gluster\:// gluster+transport\://)"' &&
    ret=0
  #               ^ should turn that _alternative into a small function.


  while (( $#state )); do
    local -a suf
    local curstate=$state sep
    shift state
    case $curstate in
      ("machine")
        args=(  
          'accel[accelerator]:accel:(tcg kvm xen)' 
          'kernel_irqchip[in-kernel irqchip support]:irqchip:(on off)' 
          'kvm_shadow_size[KVM shadow MMU]:size: _message "size"' 
          'dump-guest-core[add guest memory to coredump]:coredump:(on off)' 
          'mem-merge[memory merge support]:mem-merge:(on off)'
          )
        ;;
      ("smp")
        args=(
          'cpus[number of CPUS]:cpus: _message "number of CPUS"'
          'cores[cores per socket]:socket: _message "number of cores per socket"'
          'threads[threads per core]:threads: _message "number of threads per core"'
          'sockets[total number of sockets]:sockets: _message "number of sockets"'
          'maxcpus[max number of hotpluggable CPUs]:hotplug: _message "number of hotpluggable CPUS"'
          )
        ;;
      ("fd")
        args=(
          'fd[file descriptor to duplicate]:fd:"'
          'set[define ID of fd set]:ID:'
          'opaque[free-form string for defining a fd]:opaque:'
          )
        ;;
      ("boot")
        args=(
          'order[boot order]:boot order:((a\:floppy\ image\ a c\:hard\ disk d\:cdrom))'
          'once[one time boot order]:tmp boot:((a\:floppy\ image\ a c\:hard\ disk d\:cdrom))'
          'menu[display boot menus]:menu:(on off)'
          'splash[display splash logo during POST]:logo: _files'
          'splash-time[splash logo duration]:duration:'
          'reboot-timeout[retry after failed boot]:timer: _message "time (milliseconds)"'
          'strict[do strict boot]:strict boot:(yes no)'
          )
        ;;
      ("soundhw")
        args=(
          'all' ${${(@)${${(f)"$($service -soundhw help)"}[2,-2]}%% *}\:-none} # pretty sure this isn't only eval'd when state=soundhw
          )
        ;;
      ("balloon")
        args=(
          '(virtio)none'
          '(none)virtio'
          #'addr:addr: _message "address"' # need a way to only show if virtio is chosen.
          )
        ;;
      ("drive")
        args=(
          'file[disk image to use]:image: _alternative "file:file:_files -S , -r  /\t\n\-" "uri:uri:( iscsi\:// ssh\:// nbd\: nbd\:unix\:  sheepdog\:// sheepdog+tcp\:// sheepdog+udp\:// gluster\:// gluster+transport\://)"'
          'if[interface to connect to]:interface:(ide scsi sd mtd floppy pflash virtio)'
          'bus[bus number]:bus number:'
          'unit[unit id]:unit id:'
          'index[index number for interface]:index:'
          'media[media type]:media type:(cdrom disk)'
          'cyls[number of cylinders]:cylinders:'
          'heads[number of heads]:heads:'
          'secs[number of sectors]:sectors:'
          'trans[BIOS translation mode]:BIOS translation mode:(none lba auto)'
          'snapshot[allow snapshots for drive]:snapshot:(on off)'
          'cache[type of caching to use]:caching type:(none writeback unsafe directsync writethrough)'
          'aio[asynchronous I/O operations]:aio:(threads native)'
          'discard[allow discard (known as trim or unmap)]:discard:(( ignore\:"off" off\:"off"  unmap\:"on" on\:"on"))'
          'format[specify the disk image format]:disk format:(raw cloop cow qcow qcow2 vmdk vdi)'
          'serial[specify serial number for drive]:serial number:'
          "addr[specify controller's PCI address (if=virtio only)]:PCI address:"
          'rerror[perform action on read error]:rerror:(( ignore\:"ignore and continue" stop\:"pause qemu" report\:"report error to guest" enospc\:"only pause when host is full, report otherwise" ))'
          'werror[perform action on write error]:werror:(( ignore\:"ignore and continue" stop\:"pause qemu" report\:"report error to guest" enospc\:"only pause when host is full, report otherwise" ))'
          'readonly[open drive in ro]'
          'copy-on-read[copy read backing file sectors into image file]:copy-on-read:(on off)'
          )
        ;;
      ("fsdev"|"virtfs")
        # TODO: local, handle or proxy has to appear first. pretty sure _values can't do it.
        args=(
          '(handle proxy)local'
          '(proxy local)handle'
          '(local handle)proxy'
          'id[identifier for this device]:id:'
          'path[export path]:path:_files -/ -S , -r " /\t\n\-"'
          'security_model[security model for exported path]:security model:(passthrough mapped-xattr mapped-file none)'
          'writeout[write notification]:writeout:(immediate)'
          'readonly[export share as readonly]'
          'socket[socket file for virtfs-proxy-helper]:socket:_files -S , -r " /\t\n\-"'
          'sock_fd[socket fs for virtfs-proxy-helper]:socket fd:'
          )
          [[ $curstate == virtfs ]] && args+=( 'mount_tag[tag name to be used by the guest to mount this export point]:mount tag:' )
        ;;
      ("usbdevice")
        sep=":"
        args=(
          'mouse[virtual mouse]'
          'tablet[pointer dev that uses absolute coordinates]'
          'disk[file based mass storage device]:UMS:_files -S , -r " /\t\n\-"' # optional format= option can be used format:file
          'host[host device passthrough]:bus.addr or vendorid\:productid:'
          'serial[serial to host char dev converter]:serial:(vc stdio pty null /dev/ttyS0 /dev/partport0)' # optional vendorid= and productid= options
          'braille[braille device]'
          'net[network adapter]:options:' # man page doesn't show possible options
          )
        ;;
      ("spice")
        args=(
          'port[bind to TCP port]:TCP port:' # can't use names that _port outputs
          'addr[bind to ip address]:ip address:_bind_addresses'
          'ipv'{4,6}'[force IP version]'
          'password[set password need to auth]:password:'
          'sasl[require client to use SASL]'
          'disable-ticketing[allow connections without authentication]'
          'disable-copy-paste[disallow copy/paste between client and guest]'
          'disable-agent-file-xfer[disallow spice-vdagent file-xfer]'
          'tls-port[bind to TCP port\(for encrypted channels\)]:TCP port:'
          'x509-dir[set x509 directory]:directory:_files -/ -S , -r " /\t\n\-"'
          'x509-'{key,cert,cacert,dh-key}'-file:file:_files -S , -r " /\t\n\-"' 'x509-key-password:file:_files -S , -r " /\t\n\-"'
          'tls-ciphers[ciphers to use]:list:' # no list of possible ciphers in the man page
          '*'{tls,plaintext}'-channel[force specific channel]:channel:(default main display cursor inputs record playback)'
          'image-compression[set image compression algorithm]:compression algorithm:(auto_glz auto_lz quic glz lz off)'
          {jpeg,zlib-glz}'-wan-compression[use compression for slow links]: :(auto never always)'
          'streaming-video[set video stream detection]: :(off all filter)'
          'agent-mouse[enable/disable passing mouse events]: :(on off)'
          'playback-compression[enable/disable auto stream compression]: :(on off)'
          'seamless-migration[enable/disable spice seamless migration]: :(on off)'
          )
    esac
    _values -s , -S ${sep:-=} $curstate "$args[@]"
  done
}

_qemu_call_function() {
  local ret=1
  _call_function ret _$service
  return ret
}

_qemu_call_function "$@"


Messages sorted by: Reverse Date, Date, Thread, Author