Add Zsh completion files for public LTTng CLI commands
[lttng-tools.git] / extras / zsh-completion / _lttng
diff --git a/extras/zsh-completion/_lttng b/extras/zsh-completion/_lttng
new file mode 100644 (file)
index 0000000..a27915c
--- /dev/null
@@ -0,0 +1,2040 @@
+#compdef lttng
+#
+# Copyright (c) 2015-2023 Philippe Proulx <eeppeliteloop@gmail.com>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+#
+# This is a Zsh completion function for the lttng(1) command (see
+# <https://lttng.org/>), for versions 2.5 to 2.14.
+#
+# If you want, at your own risk, the function to work with versions
+# above 2.14, set `LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1`.
+#
+# Each subcommand changes the command part of the current context so
+# that you can target a specific subcommand with `zstyle`, for
+# example:
+#
+#     $ zstyle ':completion:*:*:lttng-start:*:sessions' verbose yes
+#     $ zstyle ':completion:*:*:lttng-add-context:type-option:*' \
+#              group-order perf-context-types static-context-types
+#
+# The relevant style arguments and tags are:
+#
+# `actions` tag (with the `lttng-snapshot` command):
+#     Snapshot action names.
+#
+# `channel` argument and `channels` tag:
+#     Channel names.
+#
+#     The `verbose` style controls whether or not this function adds
+#     completions as a list (with channel information for each item) or
+#     simple channel names.
+#
+#     If the verbose style is enabled, then the information part of each
+#     item starts with either `  [enabled` or `  [disabled` (note the
+#     two leading spaces), depending on the status of the channel.
+#
+# `commands` tag:
+#     lttng(1) subcommand names.
+#
+# `log-levels` tag:
+#     Log level names.
+#
+# `session` argument and `sessions` tag:
+#     Recording session names.
+#
+#     The `verbose` style controls whether or not this function adds
+#     completions as a list (with recording session information for each
+#     item) or simple recording session names.
+#
+#     If the verbose style is enabled, then the information part of each
+#     item starts with either `  [active` or `  [inactive` (note the two
+#     leading spaces), depending on the status of the recording session.
+#
+# `type-option` argument:
+#     `static-context-types` tag:
+#         Statically-known context field types.
+#
+#     `perf-context-types` tag:
+#         perf counter context field types.
+#
+# `triggers` tag:
+#     Trigger names.
+
+# Sets the `minor_version` variable to the minor version of LTTng-tools,
+# or to `0` if not found.
+__lttng_set_minor_version() {
+  minor_version=0
+
+  local -a match
+
+  if [[ $($prog_name --version) =~ '[[:blank:]]+2\.([[:digit:]]+)' ]]; then
+    minor_version=$match[1]
+  fi
+}
+
+# Runs the `lttng` command with `"$@"` using `$tracing_group`.
+__lttng_run() {
+  $prog_name --no-sessiond --group=$tracing_group "$@" 2>/dev/null
+}
+
+# Runs the `lttng --mi=xml` command using the selected tracing group
+# (`$tracing_group`) with:
+#
+# `$1`:
+#     A message of what's expected to show on error.
+#
+# Other arguments:
+#     Passed to the command as is.
+#
+# This function returns 1 with LTTng-tools < 2.6 and if `xmllint` isn't
+# available.
+__lttng_mi_run() {
+  local -r msg=$1
+
+  shift
+
+  if ((minor_version < 6)); then
+    # MI output requires LTTng-tools ≥ 2.6
+    _message -e descriptions $msg
+    return 1
+  fi
+
+  if ((! $+commands[xmllint])); then
+    # XML output parsing requires xmllint
+    _message -e descriptions $msg
+    return 1
+  fi
+
+  __lttng_run --mi=xml "$@"
+
+  if (($? != 0)); then
+    # Command failed
+    _message -e descriptions $msg
+    return 1
+  fi
+}
+
+# Call this instead of _arguments() within this function when you don't
+# need the `-C` option.
+__lttng_arguments() {
+  _arguments -s -W : "$@"
+}
+
+# Returns whether or not the verbose style is enabled for the given
+# argument (`$1`) and tag (`$2`), using `$curcontext` for the other
+# parts of the full completion context.
+__lttng_style_is_verbose() {
+  local -r arg=$1 tag=$2
+  local -r ccparts=("${(@s.:.)curcontext}")
+
+  zstyle -t :completion:${ccparts[1]}:${ccparts[2]}:${ccparts[3]}:$arg:$tag verbose
+}
+
+# Returns 0 if a Linux kernel tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_kernel_domain_opt_is_set() {
+  (($+opt_args[-k] || $+opt_args[--kernel] ||
+    $+opt_args[domain--k] || $+opt_args[domain---kernel]))
+}
+
+# Returns 0 if a user space tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_user_domain_opt_is_set() {
+  (($+opt_args[-u] || $+opt_args[--userspace] ||
+    $+opt_args[domain--u] || $+opt_args[domain---userspace]))
+}
+
+# Returns 0 if a `java.util.logging` tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_jul_domain_opt_is_set() {
+  (($+opt_args[-j] || $+opt_args[--jul] ||
+    $+opt_args[domain--j] || $+opt_args[domain---jul]))
+}
+
+# Returns 0 if an Apache log4j tracing domain option is set in
+# `$opt_args`, or `1` otherwise.
+__lttng_log4j_domain_opt_is_set() {
+  (($+opt_args[-l] || $+opt_args[--log4j] ||
+    $+opt_args[domain--l] || $+opt_args[domain---log4j]))
+}
+
+# Returns 0 if a Python tracing domain option is set in `$opt_args`,
+# or `1` otherwise.
+__lttng_python_domain_opt_is_set() {
+  (($+opt_args[-p] || $+opt_args[--python] ||
+    $+opt_args[domain--p] || $+opt_args[domain---python]))
+}
+
+# Adds completions for the name of an `lttng` command.
+__lttng_complete_cmd_name() {
+  # LTTng-tools 2.5+
+  local cmd_names=(
+    'add-context:add context fields to be recorded'
+    'create:create a recording session'
+    'destroy:destroy a recording session'
+    'disable-channel:disable channels'
+    'disable-event:disable recording event rules'
+    'enable-channel:create or enable a channel'
+    'enable-event:create or enable recording event rules'
+    'help:show the help of a command'
+    'list:list recording sessions and instrumentation points'
+    'set-session:set the current recording session'
+    'snapshot:take a recording session snapshot'
+    'start:start a recording session'
+    'stop:stop a recording session'
+    'version:show LTTng-tools version information'
+    'view:launch a trace reader'
+  )
+
+  # LTTng-tools 2.6+
+  if ((minor_version >= 6)); then
+    cmd_names+=(
+      'load:load recording session configurations'
+      'save:save recording session configurations'
+    )
+  fi
+
+  # LTTng-tools 2.7+
+  if ((minor_version >= 7)); then
+    cmd_names+=(
+      'track:allow specific processes to record events'
+      'untrack:disallow specific processes to record events'
+    )
+  fi
+
+  # LTTng-tools 2.8+
+  if ((minor_version >= 8)); then
+    cmd_names+=(
+      'status:show the status of the current recording session'
+    )
+  fi
+
+  # LTTng-tools 2.9+
+  if ((minor_version >= 9)); then
+    cmd_names+=(
+      'regenerate:regenerate specific recording session data'
+    )
+  fi
+
+  # LTTng-tools 2.11+
+  if ((minor_version >= 11)); then
+    cmd_names+=(
+      'rotate:archive the current trace chunk of a recording session'
+      'enable-rotation:set a recording session rotation schedule'
+      'disable-rotation:unset a recording session rotation schedule'
+    )
+  fi
+
+  # LTTng-tools 2.12+
+  if ((minor_version >= 12)); then
+    cmd_names+=(
+      'clear:clear a recording session'
+    )
+  fi
+
+  # LTTng-tools 2.13+
+  if ((minor_version >= 13)); then
+    cmd_names+=(
+      'add-trigger:add a trigger'
+      'list-triggers:list triggers'
+      'remove-trigger:remove a trigger'
+    )
+  fi
+
+  # Add completions
+  local expl
+
+  _describe -t commands command cmd_names
+}
+
+# Adds completions for the name of an `lttng snapshot` action.
+__lttng_complete_snapshot_action_name() {
+  local -r action_names=(
+    'add-output:add a snapshot output'
+    'del-output:remove a snapshot output'
+    'list-output:show the snapshot output'
+    'record:take a snapshot'
+  )
+
+  # Add completions
+  local expl
+
+  _describe -t actions 'snapshot action' action_names
+}
+
+# Adds user ID completions.
+#
+# The added completions are displayed as user names, but the actual
+# completions are corresponding user IDs.
+__lttng_complete_uid() {
+  if [[ ! -f /etc/passwd ]]; then
+    # Weird flex but ok
+    _message -e descriptions 'user ID'
+    return
+  fi
+
+  # Read user names and IDs from `/etc/passwd`
+  local line
+  local -a uids names fields
+
+  while read -r line; do
+    if [[ -z ${line// } ]]; then
+      # Skip empty line
+      continue
+    fi
+
+    # Extract user ID and name
+    fields=("${(@s/:/)line}")
+    uids+=($fields[3])
+    names+=("$fields[1]")
+  done < /etc/passwd
+
+  # Add completions
+  local expl
+
+  _wanted users expl 'user ID' compadd -d names -a uids
+}
+
+# Adds completions for a context field type (for the `--type` option of
+# the `add-context` command).
+#
+# This function replaces the argument field of the current context with
+# `type-option`.
+#
+# This function relies on the tracing domain options of `$opt_args` to
+# restrict the offered completions. Without a tracing domain option,
+# this function adds all the possible context field type completions.
+#
+# This function runs `lttng add-context --list` to get the list of
+# available context field types.
+#
+# This function adds completions with both the `static-context-types`
+# and `perf-context-types` tags so that the Zsh user can hide a group or
+# select them with the `group-order` and `tag-order` style.
+__lttng_complete_context_type() {
+  # Statically-known context field types
+  local kernel_types=(
+    pid procname prio nice vpid tid vtid ppid vppid hostname
+    interruptible preemptible need_reschedule migratable
+    callstack-kernel callstack-user cgroup_ns ipc_ns mnt_ns net_ns
+    pid_ns time_ns user_ns uts_ns uid euid suid gid egid sgid vuid veuid
+    vsuid vgid vegid vsgid
+  )
+  local user_types=(
+    vpid pthread_id procname ip cgroup_ns ipc_ns mnt_ns net_ns pid_ns
+    time_ns user_ns uts_ns vuid veuid vsuid vgid vegid vsgid
+  )
+
+  # Set `types` and `domain` depending on the selected tracing domain
+  local -a types
+  local domain descr_suffix
+
+  if __lttng_kernel_domain_opt_is_set; then
+    # Kernel context field types
+    types=($kernel_types)
+    domain=k
+  elif __lttng_user_domain_opt_is_set; then
+    # User space context field types
+    types=($user_types)
+    domain=u
+  else
+    # No supported tracing domain: offer all context field types
+    types=($user_types $kernel_types)
+    descr_suffix=' (all tracing domains)'
+  fi
+
+  # Get XML list of available context field types
+  local -r msg='context type'
+  local list_xml
+
+  list_xml=$(__lttng_mi_run $msg add-context --list)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Convert to one context field type per line
+  local lines
+
+  lines=$(__lttng_xmllint_xpath $list_xml '//*[local-name()="symbol"]/text()')
+
+  if (($? != 0)); then
+    _guard '^-*' $msg
+    return
+  fi
+
+  # Filter context field types depending on the selected tracing domain
+  local -a static_items perf_items
+  local line
+
+  while read -r line; do
+    if (($types[(Ie)$line])); then
+      # Statically-known context field type
+      static_items+=$line
+    elif [[ $line = perf:cpu:* && $domain != u ]]; then
+      # Per-CPU perf counter
+      perf_items+=$line
+    elif [[ $line = perf:thread:* && $domain != k ]]; then
+      # Per-thread perf counter
+      perf_items+=$line
+    elif [[ $line = perf:* && $domain != u ]]; then
+      # Other perf counter (Linux kernel tracing domain or none)
+      perf_items+=$line
+    fi
+  done <<< $lines
+
+  # Add completions
+  _alternative -C type-option \
+    "static-context-types:statically-known context type${descr_suffix}:compadd -a static_items" \
+    "perf-context-types:perf counter context type${descr_suffix}:compadd -a perf_items"
+}
+
+# Adds completions for a trigger name.
+#
+# Relies on `$opt_args[--owner-uid]` to restrict the offered
+# completions.
+__lttng_complete_trigger_name() {
+  # Get XML list of available triggers
+  local msg='trigger name'
+  local list_xml
+
+  list_xml=$(__lttng_mi_run $msg list-triggers)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Create the owner UID predicate XPath part
+  local owner_uid_xpath
+
+  if (($+opt_args[--owner-uid])); then
+    owner_uid_xpath="[./*[local-name()='owner_uid'] = ${opt_args[--owner-uid]}]"
+  fi
+
+  # Convert to one trigger name per line
+  local lines
+
+  lines=$(__lttng_xmllint_xpath $list_xml "//*[local-name()='trigger']$owner_uid_xpath/*[local-name()='name']/text()")
+
+  if (($? != 0)); then
+    _guard '^-*' $msg
+    return
+  fi
+
+  local -a trigger_names
+
+  while read -r line; do
+    trigger_names+=$line
+  done <<< $lines
+
+  # Add completions
+  local expl
+
+  _wanted triggers expl $msg compadd -a trigger_names
+}
+
+# Runs `xmllint` with:
+#
+# `$1`:
+#     An XML document to parse.
+#
+# `$2`:
+#     An XPath to extract data.
+__lttng_xmllint_xpath() {
+  local -r xml=$1 xpath=$2
+
+  xmllint --xpath $xpath - <<< $xml 2>/dev/null
+}
+
+# Prints the equivalent recording session status adjective (`active` or
+# `inactive`) for an `enabled` XML property, or `unknown` on error.
+__lttng_session_status_from_enabled_prop() {
+  local -r prop=$1
+
+  case $prop in
+    true) echo -n active;;
+    false) echo -n inactive;;
+    *) echo -n unknown;;
+  esac
+}
+
+# Prints the value of the immediate XML property named `$3` of the child
+# node named `$2` within the parent node `$1`.
+__lttng_immediate_prop_from_xml() {
+  local -r node_xml=$1 node_name=$2 prop_name=$3
+
+  __lttng_xmllint_xpath $node_xml "/*[local-name()='$node_name']/*[local-name()='$prop_name']/text()"
+}
+
+# Prints the value of the immediate XML `name` property of the child
+# node named `$2` within the parent node `$1`.
+__lttng_name_prop_from_xml() {
+  local -r node_xml=$1 node_name=$2
+
+  __lttng_immediate_prop_from_xml $node_xml $node_name name
+}
+
+# Prints the value of the immediate XML `enabled` property of the child
+# node named `$2` within the parent node `$1`.
+__lttng_enabled_prop_from_xml() {
+  local -r node_xml=$1 node_name=$2
+
+  __lttng_immediate_prop_from_xml $node_xml $node_name enabled
+}
+
+# Adds completions for a recording session name.
+#
+# Arguments:
+#
+# `$1`:
+#     One of:
+#
+#     `all`:
+#         Add completions for active and inactive recording sessions.
+#
+#     `active`:
+#         Only add completions for active recording sessions.
+#
+#     `inactive`:
+#         Only add completions for inactive recording sessions.
+#
+# `$2`:
+#     One of:
+#
+#     `all`:
+#         Add completions for recording sessions regardless of their
+#         mode.
+#
+#     `snapshot`:
+#         Only add completions for snapshot recording sessions.
+#
+#     `live`:
+#         Only add completions for LTTng live recording sessions.
+__lttng_complete_session_name() {
+  local -r req_status=$1 req_mode=$2
+
+  # Get XML document (summary of recording sessions)
+  local session_summaries_xml
+
+  session_summaries_xml=$(__lttng_mi_run 'recording session name' list)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Count recording sessions
+  local -i session_count
+
+  session_count=$(__lttng_xmllint_xpath $session_summaries_xml 'count(//*[local-name()="session"])')
+
+  if (($? != 0 || session_count == 0)); then
+    _guard '^-*' 'recording session name'
+    return
+  fi
+
+  # Append the name and info of one recording session at a time
+  local -a session_names session_infos
+  local -i index iprop
+  local session_name session_summary_xml snapshot_mode session_status session_info
+
+  # For each recording session summary
+  for index in {1..$session_count}; do
+    # Get recording session summary XML node
+    session_summary_xml=$(__lttng_xmllint_xpath $session_summaries_xml "//*[local-name()='session'][$index]")
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Get recording session name
+    session_name=$(__lttng_name_prop_from_xml $session_summary_xml session)
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Get recording session status
+    session_status=$(__lttng_enabled_prop_from_xml $session_summary_xml session)
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    session_status=$(__lttng_session_status_from_enabled_prop $session_status)
+
+    if [[ $req_status != all && $req_status != $session_status ]]; then
+      # Skip recording session with unexpected status
+      continue
+    fi
+
+    # Get recording session mode
+    session_mode=
+    iprop=$(__lttng_immediate_prop_from_xml $session_summary_xml session snapshot_mode)
+
+    if (($? == 0 && iprop)); then
+      session_mode=snapshot
+    else
+      iprop=$(__lttng_immediate_prop_from_xml $session_summary_xml session live_timer_interval)
+
+      if (($? == 0 && iprop)); then
+        session_mode=live
+      fi
+    fi
+
+    if [[ $req_mode != all && $req_mode != $session_mode ]]; then
+      # Skip recording session with unexpected mode
+      continue
+    fi
+
+    session_info=$session_status
+
+    if [[ -n $session_mode ]]; then
+      session_info+=", $session_mode mode"
+    fi
+
+    session_names+=("$session_name")
+    session_infos+=($session_info)
+  done
+
+  # No recording sessions: show message
+  if (($#session_names == 0)); then
+    _guard '^-*' 'recording session name'
+    return
+  fi
+
+  # Compute maximum session info length
+  local -i max_info_len=0 len
+
+  for session_info in $session_infos; do
+    len=$#session_info
+
+    if ((len > max_info_len)); then
+      max_info_len=$len
+    fi
+  done
+
+  # Compute maximum session name length
+  local -i max_name_len=0
+
+  for session_name in $session_names; do
+    len=$#session_name
+
+    if ((len > max_name_len)); then
+      max_name_len=$len
+    fi
+  done
+
+  # Some room for the longest info string, two spaces, and two brackets
+  local -ir max_possible_name_len=$((COLUMNS - max_info_len - 5))
+
+  if ((max_name_len > max_possible_name_len)); then
+    # Clamp
+    max_name_len=$max_possible_name_len
+  fi
+
+  # Create the dislay strings (name, status, mode)
+  local -a disps
+
+  for index in {1..${#session_names}}; do
+    disps+=("${(r:$max_name_len:: :)session_names[$index]}  [$session_infos[$index]]")
+  done
+
+  # Add completions
+  local expl
+
+  if __lttng_style_is_verbose session sessions; then
+    # Verbose mode (list with infos)
+    _wanted -C session sessions expl 'recording session name' \
+      compadd -d disps -l -a session_names
+  else
+    # Just the recording session names
+    _wanted -C session sessions expl 'recording session name' \
+      compadd -a session_names
+  fi
+}
+
+# Prints the name of the Unix user's current recording session, if any.
+__lttng_cur_session_name() {
+  local -r lttngrc_path=${LTTNG_HOME:-$HOME}/.lttngrc
+
+  if [[ ! -f $lttngrc_path ]]; then
+    return 1
+  fi
+
+  local cur_session_name
+  local -a match
+
+  while read -r line; do
+    if [[ $line =~ 'session=([^[:blank:]]+)' ]]; then
+      cur_session_name=$match[1]
+      break
+    fi
+  done < $lttngrc_path
+
+  if [[ -z $cur_session_name ]]; then
+    return 1
+  fi
+
+  echo -n $cur_session_name
+}
+
+# Prints the equivalent status adjective (`enabled` or `disabled`) for
+# an `enabled` XML property, or `unknown` on error.
+__lttng_status_from_enabled_prop() {
+  local -r prop=$1
+
+  case $prop in
+    true) echo -n enabled;;
+    false) echo -n disabled;;
+    *) echo -n unknown;;
+  esac
+}
+
+# Prints the XML document of `lttng list $2` (specifics of a single
+# recording session).
+#
+# `$1` is a message of what's expected to show on error.
+__lttng_session_xml() {
+  local -r msg=$1 session_name=$2
+
+  __lttng_mi_run $msg list $session_name
+}
+
+# Adds completions for a channel name.
+#
+# This function relies on the tracing domain options of `$opt_args`,
+# `$opt_args[-s]`, `$opt_args[--session]`, and the first non-option
+# argument to restrict the offered completions.
+#
+# Arguments:
+#
+# `$1`:
+#     One of:
+#
+#     `all`:
+#         Add completions for enabled and disabled channels.
+#
+#     `enabled`:
+#         Only add completions for enabled channels.
+#
+#     `disabled`:
+#         Only add completions for disabled channels.
+#
+# `$2`:
+#     `opt`:
+#         Use `$opt_args[-s]` and `$opt_args[--session]` to find the
+#         name of the selected recording session.
+#
+#     `arg`:
+#         Use `$line[1]` to find the name of the selected recording
+#         session.
+__lttng_complete_channel_name() {
+  local -r req_status=$1 session_name_src=$2
+
+  shift 2
+
+  # Find the recording session name to use
+  local session_name
+
+  if [[ $session_name_src = opt ]]; then
+    if (($+opt_args[-s])); then
+      session_name=$opt_args[-s]
+    elif (($+opt_args[--session])); then
+      session_name=$opt_args[--session]
+    fi
+  elif [[ $session_name_src = arg ]]; then
+    session_name=$line[1]
+  fi
+
+  if [[ -z $session_name ]]; then
+    # Fall back to current recording session
+    session_name=$(__lttng_cur_session_name)
+
+    if (($? != 0)); then
+      _guard '^-*' 'channel name'
+      return
+    fi
+  fi
+
+  # Get XML document (detailed recording session)
+  local session_xml
+
+  session_xml=$(__lttng_session_xml 'channel name' $session_name)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Count tracing domains
+  local -i domain_count
+
+  domain_count=$(__lttng_xmllint_xpath $session_xml 'count(//*[local-name()="domain"])')
+
+  if (($? != 0 || domain_count == 0)); then
+    _guard '^-*' 'channel name'
+    return
+  fi
+
+  # Append the name and info of one channel at a time
+  local domain_xml domain prop
+  local channel_xml channel_name channel_status channel_erl_mode
+  local -a channel_names channel_infos
+  local -i channel_count domain_index channel_index
+
+  # For each tracing domain
+  for domain_index in {1..$domain_count}; do
+    # Get tracing domain XML node
+    domain_xml=$(__lttng_xmllint_xpath $session_xml "//*[local-name()='domain'][$domain_index]")
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Get tracing domain type
+    domain=$(__lttng_xmllint_xpath $domain_xml '/*/*[local-name()="type"]/text()')
+
+    if (($? != 0)); then
+      continue
+    fi
+
+    # Skip unexpected tracing domains
+    if [[ $domain = KERNEL ]]; then
+      if __lttng_user_domain_opt_is_set; then
+        # Skip unexpected Linux kernel tracing domain
+        continue
+      fi
+
+      domain='Linux kernel'
+    fi
+
+    if [[ $domain = UST ]]; then
+      if __lttng_kernel_domain_opt_is_set; then
+        # Skip unexpected user space tracing domain
+        continue
+      fi
+
+      domain='user space'
+    fi
+
+    # Count channels within tracing domain
+    channel_count=$(__lttng_xmllint_xpath $domain_xml 'count(//*[local-name()="channel"])')
+
+    if (($? != 0 || channel_count == 0)); then
+      continue
+    fi
+
+    # For each channel
+    for channel_index in {1..$channel_count}; do
+      # Get channel XML node
+      channel_xml=$(__lttng_xmllint_xpath $domain_xml "//*[local-name()='channel'][$channel_index]")
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      # Get channel name
+      channel_name=$(__lttng_name_prop_from_xml $channel_xml channel)
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      # Get channel status
+      channel_status=$(__lttng_enabled_prop_from_xml $channel_xml channel)
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      channel_status=$(__lttng_status_from_enabled_prop $channel_status)
+
+      if [[ $req_status != all && $req_status != $channel_status ]]; then
+        # Skip channel with unexpected status
+        continue
+      fi
+
+      # Get channel event record loss mode
+      channel_erl_mode=$(__lttng_xmllint_xpath $channel_xml '//*[local-name()="attributes"]/*[local-name()="overwrite_mode"]/text()')
+
+      if (($? != 0)); then
+        continue
+      fi
+
+      if [[ $channel_erl_mode = DISCARD ]]; then
+        channel_erl_mode=discard
+      elif [[ $channel_erl_mode = OVERWRITE ]]; then
+        channel_erl_mode=overwrite
+      fi
+
+      channel_names+=("$channel_name")
+      channel_infos+=("$channel_status, $domain, $channel_erl_mode mode")
+    done
+  done
+
+  # No channels: show message
+  if (($#channel_names == 0)); then
+    _guard '^-*' 'channel name'
+    return
+  fi
+
+  # Compute maximum channel info length
+  local channel_info
+  local -i max_info_len=0 len
+
+  for channel_info in $channel_infos; do
+    len=$#channel_info
+
+    if ((len > max_info_len)); then
+      max_info_len=$len
+    fi
+  done
+
+  # Compute maximum channel name length
+  local -i max_name_len=0
+
+  for channel_name in $channel_names; do
+    len=$#channel_name
+
+    if ((len > max_name_len)); then
+      max_name_len=$len
+    fi
+  done
+
+  # Some room for the longest info string, two spaces, and two brackets
+  local -ir max_possible_name_len=$((COLUMNS - max_info_len - 5))
+
+  if ((max_name_len > max_possible_name_len)); then
+    # Clamp
+    max_name_len=$max_possible_name_len
+  fi
+
+  # Create the dislay strings (name, status, tracing domain, mode)
+  local -a disps
+
+  for channel_index in {1..${#channel_names}}; do
+    disps+=("${(r:$max_name_len:: :)channel_names[$channel_index]}  [$channel_infos[$channel_index]]")
+  done
+
+  # Add completions
+  local expl
+
+  if __lttng_style_is_verbose channel channels; then
+    # Verbose mode (list with infos).
+    #
+    # Using `-2` as Linux kernel and user space channels may have the
+    # same name, but we want to show the different infos.
+    _wanted -C channel channels expl 'channel name' \
+      compadd "$@" -2 -d disps -l -a channel_names
+  else
+    # Just the channel names, no duplicates
+    _wanted -C channel channels expl 'channel name' \
+      compadd "$@" -a channel_names
+  fi
+}
+
+# Add completions for instrumentation point names.
+#
+# This function relies on the tracing domain options of `$opt_args` and
+# `$opt_args[ip---syscall]` to restrict the offered completions.
+__lttng_complete_ip_name() {
+  local msg
+  local -a list_opts
+
+  if __lttng_kernel_domain_opt_is_set; then
+    list_opts=(-k)
+
+    if (($+opt_args[ip---syscall])); then
+      msg='system call name (no `sys_` prefix)'
+      list_opts+=(--syscall)
+    else
+      msg='Linux kernel tracepoint name'
+    fi
+  elif __lttng_user_domain_opt_is_set; then
+    msg='user space tracepoint name'
+    list_opts=(-u)
+  elif __lttng_jul_domain_opt_is_set; then
+    msg='`java.util.logging` logger name'
+    list_opts=(-j)
+  elif __lttng_log4j_domain_opt_is_set; then
+    msg='Apache log4j logger name'
+    list_opts=(-l)
+  elif __lttng_python_domain_opt_is_set; then
+    msg='Python logger name'
+    list_opts=(-p)
+  else
+    # No tracing domain option
+    _guard '^-*' 'instrumentation point or recording event rule name'
+    return
+  fi
+
+  # Get XML list of available instrumentation point names
+  local list_xml
+
+  list_xml=$(__lttng_mi_run $msg list $list_opts)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Convert to one instrumentation point name per line
+  local ip_names
+
+  ip_names=$(__lttng_xmllint_xpath $list_xml '//*[local-name()="event"]//*[local-name()="name"]/text()')
+
+  if (($? != 0)) || [[ -z $ip_names ]]; then
+    # `xmllint` error or no instrumentation points
+    _guard '^-*' $msg
+    return
+  fi
+
+  local ip_name
+  local -a items
+
+  while read -r ip_name; do
+    if [[ -z $ip_name ]]; then
+      continue
+    fi
+
+    items+=($ip_name)
+  done <<< $ip_names
+
+  # Add completions
+  local expl
+
+  _wanted instrumentation-points expl $msg compadd "$@" -a items
+}
+
+# Adds completions for the arguments of the `add-context` command.
+__lttng_complete_add_context_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(- : *)--list[list the available context field types]'
+    '(--list -s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name inactive all'
+    '(--list -c --channel)'{-c+,--channel=}'[select a specific channel]: : __lttng_complete_channel_name enabled opt'
+    '(--list)*'{-t+,--type=}'[add a context field to be recorded]: : __lttng_complete_context_type'
+    + '(domain)'
+    '(--list)'{-k,--kernel}'[select the Linux kernel tracing domain]'
+    '(--list)'{-u,--userspace}'[select the user space tracing domain]'
+  )
+
+  # The Java tracing domain options require LTTng-tools ≥ 2.8 (for
+  # application-specific context field types).
+  if ((minor_version >= 8)); then
+    specs+=(
+      '(--list)'{-j,--jul}'[select the `java.util.logging` tracing domain]'
+      '(--list)'{-l,--log4j}'[select the Apache log4j tracing domain]'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for log level names.
+#
+# This function relies on the tracing domain options of `$opt_args` to
+# restrict the offered completions.
+__lttng_complete_log_level() {
+  local -a log_levels
+
+  # Fill the `log_levels` array depending on the tracing domain option
+  if __lttng_user_domain_opt_is_set; then
+    log_levels=(
+      EMERG
+      ALERT
+      CRIT
+      ERR
+      WARNING
+      NOTICE
+      INFO
+      DEBUG_SYSTEM
+      DEBUG_PROGRAM
+      DEBUG_PROCESS
+      DEBUG_MODULE
+      DEBUG_UNIT
+      DEBUG_FUNCTION
+      DEBUG_LINE
+      DEBUG
+    )
+  elif __lttng_jul_domain_opt_is_set; then
+    log_levels=(
+      OFF
+      SEVERE
+      WARNING
+      INFO
+      CONFIG
+      FINE
+      FINER
+      FINEST
+      ALL
+    )
+  elif __lttng_log4j_domain_opt_is_set; then
+    log_levels=(
+      OFF
+      FATAL
+      ERROR
+      WARN
+      INFO
+      DEBUG
+      TRACE
+      ALL
+    )
+  elif __lttng_python_domain_opt_is_set; then
+    log_levels=(
+      CRITICAL
+      ERROR
+      WARNING
+      INFO
+      DEBUG
+      NOTSET
+    )
+  else
+    # No tracing domain option
+    _guard '^-*' 'log level name'
+  fi
+
+  # Add completions
+  local expl
+
+  _wanted log-levels expl 'log level name' compadd -a log_levels
+}
+
+# Adds completions for a trigger condition type.
+__lttng_complete_trigger_condition_type() {
+  local -r types=(
+    'event-rule-matches:an event rule matches an event'
+  )
+
+  # Add completions
+  local expl
+
+  _describe 'trigger condition type' types
+}
+
+# Adds completions for a trigger action type.
+__lttng_complete_trigger_action_type() {
+  local -r types=(
+    'notify:send a notification through the notification mechanism'
+    'start-session:start a recording session'
+    'stop-session:stop a recording session'
+    'rotate-session:archive the current trace chunk of a recording session'
+    'snapshot-session:take a recording session snapshot'
+  )
+
+  # Add completions
+  local expl
+
+  _describe 'trigger action type' types
+}
+
+# Adds completions for the arguments of the `add-trigger` command.
+#
+# Note that those completions are incomplete, in that:
+#
+# • A valid event rule specification, as per lttng-event-rule(7),
+#   must follow `--condition=event-rule-matches`.
+#
+# • `--capture` options are possible within an `event-rule-matches`
+#   condition specifier.
+#
+# • The `--rate-policy` option and other arguments, sometimes mandatory,
+#   are possible within an action specifier.
+#
+# Having full completion for condition and action specifiers require
+# more Zsh magic as _arguments(), like most command-line argument
+# parsers, doesn't take option positions into account.
+__lttng_complete_add_trigger_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-n --name)'{-n+,--name=}'[set the trigger name]:new trigger name:'
+    '--owner-uid=[add the trigger as another Unix user]: : __lttng_complete_uid'
+    '--condition=[set the condition type and arguments]: : __lttng_complete_trigger_condition_type'
+    '*--action=[set the action type and arguments]: : __lttng_complete_trigger_action_type'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `clear` command.
+__lttng_complete_clear_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-a --all):: : __lttng_complete_session_name all all'
+    '(1 -a --all)'{-a,--all}'[clear all recording sessions]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `create` command.
+__lttng_complete_create_cmd() {
+  local specs=(
+    $help_opt_specs
+    ':: :_guard "^-*" "new recording session name"'
+    '(-C --ctrl-url output)'{-C+,--ctrl-url=}'[set the control URL]:control URL:'
+    '(-D --data-url output)'{-D+,--data-url=}'[set the trace data output URL]:trace data output URL:'
+  )
+
+  # The `--shm-path` option LTTng-tools ≥ 2.7
+  if ((minor_version >= 7)); then
+    specs+=(
+      '--shm-path=[write shared memory files to a specific directory]:shared memory file directory:_files -/'
+    )
+  fi
+
+  # Add the remaining option groups
+  specs+=(
+    + '(output)'
+    '(-D --data-url -C --ctrl-url --live)--no-output[disable trace data output]'
+    '(-D --data-url -C --ctrl-url --live)'{-o+,--output=}'[set the local trace data output directory]:trace data output directory:_files -/'
+    '(-D --data-url -C --ctrl-url)'{-U+,--set-url=}'[set the trace data output and control URL]:trace data output and control URL:'
+    + '(mode)'
+    '(-o --output --no-output)--live=[create an LTTng live recording session]:live timer period (µs):'
+    '--snapshot[create a snapshot recording session]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `destroy` command.
+__lttng_complete_destroy_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-a --all):: : __lttng_complete_session_name all all'
+    '(1 -a --all)'{-a,--all}'[destroy all recording sessions]'
+  )
+
+  # The `--no-wait` option requires LTTng-tools ≥ 2.8
+  if ((minor_version >= 8)); then
+    specs+=(
+      '(-n --no-wait)'{-n,--no-wait}'[exit immediately]'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `disable-channel` command.
+__lttng_complete_disable_channel_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    ': : _sequence __lttng_complete_channel_name enabled opt'
+    + '(domain)'
+    {-k,--kernel}'[select the Linux kernel tracing domain]'
+    {-u,--userspace}'[select the user space tracing domain]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Prints the XML tracing domain name value depending on the tracing
+# domain option (in `$opt_args`), or prints nothing and returns 1 when
+# not available.
+__lttng_xml_domain_name_from_opt() {
+  if __lttng_kernel_domain_opt_is_set; then
+    echo -n KERNEL
+  elif __lttng_user_domain_opt_is_set; then
+    echo -n UST
+  elif __lttng_jul_domain_opt_is_set; then
+    echo -n JUL
+  elif __lttng_log4j_domain_opt_is_set; then
+    echo -n LOG4J
+  elif __lttng_python_domain_opt_is_set; then
+    echo -n PYTHON
+  else
+    return 1
+  fi
+}
+
+# Prints the XML instrumentation point type value depending on the
+# instrumentation point option (in `$opt_args`).
+__lttng_xml_ip_type_from_opt() {
+  if (($+opt_args[--syscall] || $+opt_args[ip---syscall])); then
+    echo -n SYSCALL
+  elif (($+opt_args[--probe] || $+opt_args[ip---probe])); then
+    echo -n PROBE
+  elif (($+opt_args[--function] || $+opt_args[ip---function])); then
+    echo -n FUNCTION
+  else
+    echo -n TRACEPOINT
+  fi
+}
+
+# Adds completions for an old, enabled recording event rule name
+# condition (for the `disable-event` command).
+__lttng_complete_old_enabled_er_name_cond() {
+  local -r msg='recording event rule name condition'
+
+  # Find the recording session name to use
+  local session_name
+
+  if (($+opt_args[-s])); then
+    session_name=$opt_args[-s]
+  elif (($+opt_args[--session])); then
+    session_name=$opt_args[--session]
+  else
+    # Fall back to current recording session
+    session_name=$(__lttng_cur_session_name)
+
+    if (($? != 0)); then
+      _guard '^-*' $msg
+    fi
+  fi
+
+  # Find the channel name to use (`channel0` is the default name)
+  local channel_name=channel0
+
+  if (($+opt_args[-c])); then
+    channel_name=$opt_args[-c]
+  elif (($+opt_args[--channel])); then
+    channel_name=$opt_args[--channel]
+  fi
+
+  # Create tracing domain XPath part
+  local domain_xpath
+  local xml_domain_val
+
+  xml_domain_val=$(__lttng_xml_domain_name_from_opt)
+
+  if (($? == 0)); then
+    domain_xpath="*[local-name() = 'domain'][*[local-name() = 'type'] = '$xml_domain_val']//"
+  fi
+
+  # Create channel XPath part
+  local -r channel_xpath="*[local-name() = 'channel'][*[local-name() = 'name'] = '$channel_name']//"
+
+  # Create instrumentation point type XPath part
+  local -r xml_ip_type_val=$(__lttng_xml_ip_type_from_opt)
+  local -r ip_type_xpath="[*[local-name() = 'type'] = '$xml_ip_type_val']"
+
+  # Get XML document (detailed recording session)
+  local session_xml
+
+  session_xml=$(__lttng_session_xml $msg $session_name)
+
+  if (($? != 0)); then
+    return 1
+  fi
+
+  # Convert to one recording event rule name per line
+  local lines
+
+  lines=$(__lttng_xmllint_xpath $session_xml "//$domain_xpath${channel_xpath}*[local-name() = 'event']${ip_type_xpath}[*[local-name() = 'enabled'] = 'true']/*[local-name() = 'name']/text()")
+
+  if (($? != 0)); then
+    _guard '^-*' $msg
+    return
+  fi
+
+  local -a er_names
+
+  while read -r line; do
+    if [[ -z ${line// } ]]; then
+      # Skip empty line
+      continue
+    fi
+
+    er_names+=$line
+  done <<< $lines
+
+  # Add completions
+  local expl
+
+  _wanted -C event events expl $msg compadd "$@" -a er_names
+}
+
+# Adds completions for the arguments of the `disable-event` command.
+__lttng_complete_disable_event_cmd() {
+  local -r kernel_ip_opt_excl=(--syscall --probe --function)
+  local specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '(-c --channel)'{-c+,--channel=}'[select a specific channel]: : __lttng_complete_channel_name all opt'
+    + '(names)'
+    {-a,--all-events}'[disable all recording event rules]'
+    ': :_sequence __lttng_complete_old_enabled_er_name_cond'
+    + '(domain)'
+    {-k,--kernel}'[select the Linux kernel tracing domain]'
+    "($kernel_ip_opt_excl)"{-u,--userspace}'[select the user space tracing domain]'
+    "($kernel_ip_opt_excl)"{-j,--jul}'[select the `java.util.logging` tracing domain]'
+  )
+
+  # Add tracing domain option specifications based on the minor version
+  # of LTTng-tools.
+  if ((minor_version >= 6)); then
+    specs+=(
+      "($kernel_ip_opt_excl)"{-l,--log4j}'[select the Apache log4j tracing domain]'
+    )
+  fi
+
+  if ((minor_version >= 7)); then
+    specs+=(
+      "($kernel_ip_opt_excl)"{-p,--python}'[select the Python tracing domain]'
+    )
+  fi
+
+  # Add instrumentation point type option specifications based on the
+  # minor version of LTTng-tools.
+  if ((minor_version >= 6)); then
+    specs+=(
+      + '(ip)'
+      "($non_kernel_domain_opt_excl)--syscall[disable recording ER matching Linux system call events]"
+    )
+  fi
+
+  if ((minor_version >= 7)); then
+    specs+=(
+      '--tracepoint[disable recording ER matching tracepoint events]'
+      "($non_kernel_domain_opt_excl)--probe[disable recording ER matching kprobe events]"
+      "($non_kernel_domain_opt_excl)--function[disable recording ER matching kretprobe events]"
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `disable-rotation` command.
+__lttng_complete_disable_rotation_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '--timer[disable the periodic rotation schedule]'
+    '--size[disable the size-based rotation schedule]'
+  )
+
+  __lttng_arguments $specs
+}
+
+# Adds completions for a channel output type (`mmap` and, possibly,
+# `splice`) (for the `--output` option of the `enable-channel` command).
+#
+# This function replaces the argument field of the current context with
+# `output-opt`.
+#
+# This function relies on the user space tracing domain options of
+# `$opt_args` to restrict the offered completions. Without the user
+# space tracing domain option, this function adds the `splice`
+# completion too.
+__lttng_complete_channel_output_type() {
+  local output_types=(mmap)
+
+  if ! __lttng_user_domain_opt_is_set; then
+    # Linux kernel tracing domain or none
+    output_types+=(splice)
+  fi
+
+  local expl
+
+  _wanted -C 'output-opt' values expl 'output type' compadd -a output_types
+}
+
+# Adds completions for the non-option argument of the `enable-channel`
+# command.
+#
+# This function either, depending on the keys of `$opt_args`:
+#
+# At least one creation option:
+#     Shows a message to enter the new channel name.
+#
+# Otherwise:
+#     Adds completions for a comma-separated list of known channel names
+#     using __lttng_complete_channel_name().
+__lttng_complete_enable_channel_cmd_names() {
+  local key
+  local -r enable_opts=(
+    -s --session
+    domain---kernel domain--k
+    domain---userspace domain--u
+  )
+
+  # For each key of `$opt_args`
+  for key in "${(@k)opt_args}"; do
+    if (($enable_opts[(Ie)$key])); then
+      # Enabling option exists: skip
+      continue
+    fi
+
+    # Creation option exists: single name
+    _guard '^-*' 'new channel name'
+    return
+  done
+
+  # Comma-separated list of existing channel names
+  _sequence __lttng_complete_channel_name disabled opt
+}
+
+# Adds completions for the arguments of the `enable-channel` command.
+__lttng_complete_enable_channel_cmd() {
+  local specs=(
+    $help_opt_specs
+    '--switch-timer=[set the switch timer period]:switch timer period (µs):'
+    '--read-timer=[set the read timer period]:read timer period (µs):'
+    '--subbuf-size=[set the size of each sub-buffer]:sub-buffer size (bytes; `k`/`M`/`G` suffixes supported):'
+    '--num-subbuf=[set the number of sub-buffers per ring buffer]:sub-buffer count:'
+    '--tracefile-size=[set the maximum size of each trace file]:trace file size (bytes; `k`/`M`/`G` suffixes supported):'
+    '--tracefile-count=[set the maximum number of trace files]:maximum trace file count:'
+    '--output=[set the output type]: : __lttng_complete_channel_output_type'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    ': : __lttng_complete_enable_channel_cmd_names'
+  )
+
+  # The `--blocking-timeout` and `--monitor-timer` options require
+  # LTTng-tools ≥ 2.10.
+  if ((minor_version >= 10)); then
+    specs+=(
+      '(--kernel --overwrite --buffers-global)--blocking-timeout=[set the blocking timeout]:blocking timeout (µs):'
+      '--monitor-timer=[set the monitor timer period]:monitor timer period (µs):'
+    )
+  fi
+
+  # Add the remaining option groups
+  specs+=(
+    + '(domain)'
+    '(--blocking-timeout --buffers-uid --buffers-pid)'{-k,--kernel}'[select the Linux kernel tracing domain]'
+    '(--buffers-global)'{-u,--userspace}'[select the user space tracing domain]'
+    + '(loss-mode)'
+    '--discard[discard event records with no available sub-buffer]'
+    '(--blocking-timeout)--overwrite[overwrite oldest sub-buffer with no available sub-buffer]'
+    + '(buffering)'
+    '(-k --kernel)--buffers-uid[use per-user ring buffers]'
+    '(-k --kernel)--buffers-pid[use per-process ring buffers]'
+    '(-u --userspace --blocking-timeout)--buffers-global[use global ring buffers]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `enable-event` command.
+__lttng_complete_enable_event_cmd() {
+  local -r kernel_opts_excl=(
+    -k --kernel
+    --syscall
+    --probe
+    --userspace-probe
+    --function
+  )
+  local -r non_kernel_opts_excl=(
+    $non_kernel_domain_opt_excl
+    -x --exclude
+    log-level
+  )
+  local -r exclude_opt_excl=(
+    $kernel_opts_excl
+    -j --jul
+    -l --log4j
+    -p --python
+    -x --exclude
+  )
+  local ip_specs=(
+    '--tracepoint[only match LTTng tracepoint events]'
+    "($non_kernel_opts_excl)--syscall[only match Linux system call events]"
+    "($non_kernel_opts_excl)--probe=[only match kprobe events]:kprobe location:"
+    "($non_kernel_opts_excl)--function=[only match kretprobe events]:kretprobe location:"
+  )
+  local domain_specs=(
+    "($non_kernel_opts_excl)"{-k,--kernel}'[select the Linux kernel tracing domain]'
+    "($kernel_opts_excl)"{-u,--userspace}'[select the user space tracing domain]'
+    "($kernel_opts_excl -x --exclude)"{-j,--jul}'[select the `java.util.logging` tracing domain]'
+  )
+
+  # The Apache log4j tracing domain options require LTTng-tools ≥ 2.6
+  if ((minor_version >= 6)); then
+    domain_specs+=(
+      "($kernel_opts_excl -x --exclude)"{-l,--log4j}'[select the Apache log4j tracing domain]'
+    )
+  fi
+
+  # The Python tracing domain options require LTTng-tools 2.7
+  if ((minor_version >= 7)); then
+    domain_specs+=(
+      "($kernel_opts_excl -x --exclude)"{-p,--python}'[select the Python tracing domain]'
+    )
+  fi
+
+  # The Linux user space probe instrumentation options require LTTng-tools 2.11
+  if ((minor_version >= 11)); then
+    ip_specs+=(
+      "($non_kernel_opts_excl)--userspace-probe=[only match Linux user space probe events]:user space probe location:"
+    )
+  fi
+
+  # Add completions.
+  #
+  # There's no way, based on the command-line arguments, to distinguish
+  # between creating a new recording event rule and enabling an
+  # existing, disabled recording event rule here.
+  #
+  # For example, given this:
+  #
+  #     $ lttng enable-event --kernel --syscall <TAB>
+  #
+  # At this point, the user might want the list of existing, disabled
+  # kernel system call recording event rule names (current recording
+  # session, default channel name), or the full list of available system
+  # call instrumentation point names.
+  #
+  # This function makes the arbitrary choice to provide the available
+  # instrumentation point names (__lttng_complete_ip_name()) because,
+  # interactively, it seems to be more common/useful than disabling
+  # existing recording event rules.
+  local -r specs=(
+    $help_opt_specs
+    '(--probe --userspace-probe --function -f --filter)'{-f+,--filter=}'[only match events which satisfy an expression]:filter expression:'
+    "($exclude_opt_excl)"{-x+,--exclude=}'[exclude event name patterns]:comma-separated list of patterns:'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '(-c --channel)'{-c+,--channel=}'[select a specific channel]: : __lttng_complete_channel_name all opt'
+    + '(log-level)'
+    "($kernel_opts_excl)--loglevel=[only match events with specific log levels]: : __lttng_complete_log_level"
+    "($kernel_opts_excl)--loglevel-only=[only match events with an exact log level]: : __lttng_complete_log_level"
+    + '(names)'
+    {-a,--all}'[match events regardless of their name]'
+    ': :_sequence __lttng_complete_ip_name'
+    + '(ip)' $ip_specs
+    + '(domain)' $domain_specs
+  )
+
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `enable-rotation` command.
+__lttng_complete_enable_rotation_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '--timer=[rotate periodically]:period (µs; `ms`/`s`/`m`/`h` suffixes supported):'
+    '--size=[rotate based on flushed size of current trace chunk]:size (bytes; `k`/`M`/`G` suffixes supported):'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `help` command.
+__lttng_complete_help_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ': : __lttng_complete_cmd_name'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `list` command.
+__lttng_complete_list_cmd() {
+  local -r domain_opt_excl=(
+    -d --domain
+    -f --fields
+    -c --channel
+    -k --kernel
+    -u --userspace
+    -j --jul
+    -l --log4j
+    -p --python
+    --syscall
+  )
+  local specs=(
+    $help_opt_specs
+    '(-d --domain -f --fields --syscall -c --channel 1)'{-f,--fields}'[show instrumentation point fields]'
+    "($domain_opt_excl)"{-d,--domain}'[show tracing domains with at least one channel]'
+    '(-d --domain -f --fields --syscall -c --channel)'{-c+,--channel=}'[list the objects of a specific channel]: : __lttng_complete_channel_name all arg'
+    '(-d --domain -f --fields --syscall):recording session name: __lttng_complete_session_name all all'
+    '(-d --domain -k --kernel)'{-k,--kernel}'[list Linux kernel tracing domain objects]'
+    '(-d --domain -u --userspace)'{-u,--userspace}'[list user space tracing domain objects]'
+    '(-d --domain -j --jul)'{-j,--jul}'[list `java.util.logging` tracing domain objects]'
+  )
+
+  # The Apache log4j tracing domain and `--syscall` options require
+  # LTTng-tools ≥ 2.6.
+  if ((minor_version >= 6)); then
+    specs+=(
+      '(-d --domain -l --log4j)'{-l,--log4j}'[list Apache log4j tracing domain objects]'
+      '(-d --domain)--syscall[list Linux kernel system calls]'
+    )
+  fi
+
+  # The Python tracing domain options require LTTng-tools 2.7
+  if ((minor_version >= 7)); then
+    specs+=(
+      '(-d --domain -p --python)'{-p,--python}'[list Python tracing domain objects]'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `list-triggers` command.
+__lttng_complete_list_triggers_cmd() {
+  __lttng_arguments $help_opt_specs
+}
+
+# Adds completions for the arguments of the `load` command.
+__lttng_complete_load_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-f --force)'{-f,--force}'[overwrite existing recording sessions]'
+    '(-i --input-path)'{-i+,--input-path=}'[load recording session configurations from a specific path]:recording session configuration path:_files'
+    '(-a --all --override-name 1)'{-a,--all}'[load all recording session configurations]'
+    '(-a --all):recording session configuration name:_guard "^-*" "recording session name"'
+  )
+
+  if ((minor_version >= 9)); then
+    specs+=(
+      '--override-url=[override the loaded recording session output URL]:output URL:'
+      '(-a --all)--override-name=[override the loaded recording session name]:recording session name:'
+    )
+  fi
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `metadata` command
+# (deprecated).
+__lttng_complete_metadata_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ':action:(regenerate)'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `regenerate` command.
+__lttng_complete_regenerate_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ':trace data type:(metadata statedump)'
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `remove-trigger` command.
+__lttng_complete_remove_trigger_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '--owner-uid=[remove the trigger as another Unix user]: : __lttng_complete_uid'
+    ': : __lttng_complete_trigger_name'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `rotate` command.
+__lttng_complete_rotate_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-n --no-wait)'{-n,--no-wait}'[exit immediately]'
+    ': : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `save` command.
+__lttng_complete_save_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-f --force)'{-f,--force}'[overwrite existing recording session configuration files]'
+    '(-o --output-path)'{-o+,--output-path=}'[save recording session configuration files to a specific directory]:recording session configuration directory:_files -/'
+    '(-a --all 1)'{-a,--all}'[save all recording session configurations]'
+    '(-a --all): : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `set-session` command.
+__lttng_complete_set_session_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ': : __lttng_complete_session_name all all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `snapshot` command.
+__lttng_complete_snapshot_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-): : __lttng_complete_snapshot_action_name' \
+    '(-)*:: :->action-args' \
+  )
+
+  # Add action name completions
+  local curcontext=$curcontext state state_descr line
+  local -A opt_args
+
+  _arguments -C -s -W : $specs
+
+  if (($? == 0)); then
+    # Completions added: we're done
+    return
+  fi
+
+  # Add action-specific completions
+  local -r common_session_specs=(
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all snapshot'
+  )
+  local -r common_output_specs=(
+    '(-m --max-size)'{-m+,--max-size=}'[set the maximum total size of all snapshot files]:maximum size (bytes; `k`/`M`/`G` suffixes supported):'
+    '(-n --name)'{-n+,--name=}'[set the snapshot output name]:snapshot output name:'
+    '(1 -C --ctrl-url output)'{-C+,--ctrl-url=}'[set the control URL]:control URL:'
+    '(1 -D --data-url output)'{-D+,--data-url=}'[set the trace data output URL]:trace data output URL:'
+    '(-C --ctrl-url -D --data-url): :_guard "^-*" "snapshot output URL"'
+  )
+
+  if [[ $state[1] = action-args ]]; then
+    # Add completions for the arguments of the specific snapshot action
+    curcontext=${curcontext%:*:*}:lttng-snapshot-$line[1]:
+
+    case $line[1] in
+      add-output | record)
+        specs=($common_session_specs $common_output_specs);;
+      del-output)
+        specs=($common_session_specs ':snapshot output index:(1)');;
+      list-output)
+        specs=($common_session_specs);;
+      *)
+        _message "unknown snapshot action \`$line[1]\`"
+        return 1
+        ;;
+    esac
+
+    # Add completions
+    __lttng_arguments $specs
+    return
+  fi
+
+  return 1
+}
+
+# Adds completions for the arguments of the `start` command.
+__lttng_complete_start_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    ': : __lttng_complete_session_name inactive all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `stop` command.
+__lttng_complete_stop_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-n --no-wait)'{-n,--no-wait}'[exit immediately]'
+    ': : __lttng_complete_session_name active all'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `status` command.
+__lttng_complete_status_cmd() {
+  __lttng_arguments $help_opt_specs
+}
+
+# Adds completions for the arguments of the `track` command.
+__lttng_complete_track_cmd() {
+  local specs=(
+    $help_opt_specs
+    '(-s --session)'{-s+,--session=}'[select a specific recording session]: : __lttng_complete_session_name all all'
+    '(-a --all)'{-a,--all}'[add all possible values to the selected inclusion sets]'
+    '(-p --pid)'{-p+,--pid=}'[add values to the process ID inclusion set]:process ID(s):_sequence _pids'
+  )
+
+  # Virtual PID and user/group inclusion sets require LTTng-tools ≥ 2.12
+  if ((minor_version >= 12)); then
+    specs+=(
+      '--vpid=[add values to the virtual process ID inclusion set]:virtual process ID(s):_sequence _pids'
+      '(-u --userspace)--uid=[add values to the user ID inclusion set]:user(s):_sequence _users'
+      '--vuid=[add values to the virtual user ID inclusion set]:virtual user(s):_sequence _users'
+      '(-u --userspace)--gid=[add values to the group ID inclusion set]:group(s):_sequence _groups'
+      '--vgid=[add values to the virtual group ID inclusion set]:virtual group(s):_sequence _groups'
+    )
+  fi
+
+  # Append tracing domain specifications
+  specs+=(
+    + '(domain)'
+    {-k,--kernel}'[select the Linux kernel tracing domain]'
+    "(--uid --gid)"{-u,--userspace}'[select the user space tracing domain]'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Adds completions for the arguments of the `untrack` command.
+__lttng_complete_untrack_cmd() {
+  # As of LTTng-tools 2.13, the `track` and `untrack` commands expect
+  # the same arguments.
+  __lttng_complete_track_cmd
+}
+
+# Adds completions for the arguments of the `version` command.
+__lttng_complete_version_cmd() {
+  __lttng_arguments $help_opt_specs
+}
+
+# Adds completions for the arguments of the `view` command.
+__lttng_complete_view_cmd() {
+  local -r specs=(
+    $help_opt_specs
+    '(-e --viewer)'{-e+,--viewer=}'[set the trace reader path]:trace reader path:_files'
+    '(-t --trace-path): : __lttng_complete_session_name all all'
+    '(1 -t --trace-path)'{-t+,--trace-path=}'[set the trace directory to pass to the reader]:trace directory:_files -/'
+  )
+
+  # Add completions
+  __lttng_arguments $specs
+}
+
+# Add completions for the specific `lttng` command named `$line[1]`.
+__lttng_complete_cmd() {
+  # An lttng(1) command: replace `lttng` with `lttng-$line[1]` (for
+  # example, `lttng-add-trigger`).
+  curcontext=${curcontext%:*:*}:lttng-$line[1]:
+
+  # Keep the tracing group: we need to execute `lttng` for some
+  # completions and use the required tracing group to connect to the
+  # same session daemon.
+  #
+  # The default tracing group is `tracing`.
+  local tracing_group=tracing
+
+  if (($+opt_args[-g])); then
+    tracing_group=$opt_args[-g]
+  elif (($+opt_args[--group])); then
+    tracing_group=$opt_args[--group]
+  fi
+
+  # Add command completions: dispatch to a dedicated function
+  local -r func_name=__lttng_complete_${line[1]//-/_}_cmd
+
+  if ! typeset -f $func_name >/dev/null; then
+    _message "unknown command \`$line[1]\`"
+    return 1
+  fi
+
+  local -A opt_args
+
+  $func_name
+}
+
+# Save program name
+local -r prog_name=$words[1]
+
+# First, set the `minor_version` variable to the minor version of
+# LTTng-tools. Some features depend on a specific version and this
+# completion function supports many versions from LTTng-tools 2.5.
+local -i minor_version
+
+__lttng_set_minor_version
+
+# Exit now with LTTng-tools < 2.5 or LTTng-tools > 2.14
+local -r ignore_version_limit=${LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT:-0}
+
+if ((minor_version < 5 || (minor_version > 14 && !ignore_version_limit))); then
+  _message "completion not available for LTTng-tools 2.$minor_version; please update the completion files or set \`LTTNG_ZSH_COMP_IGNORE_VERSION_LIMIT=1\`"
+  return 1
+fi
+
+# Common help option specifications
+local -r help_opt_specs=(
+  '(- : *)'{-h,--help}'[show help]'
+)
+
+# Common non Linux kernel tracing domain option exclusions
+local -r non_kernel_domain_opt_excl=(-u --userspace -j --jul -l --log4j -p --python)
+
+# General option specifications
+local gen_opt_specs=(
+  $help_opt_specs
+  '(- : *)--list-commands[list the available commands and quit]'
+  '--relayd-path=[set the relay daemon path]:relay daemon path:_files -g \*lttng-relayd'
+  '--group=[set the tracing group]:tracing group:_groups'
+  '(-q --quiet)*'{-v,--verbose}'[increase verbosity]'
+  '(-q --quiet -v --verbose)'{-q,--quiet}'[suppress all messages, including warnings and errors]'
+  '(- : *)'{-V,--version}'[show version and quit]'
+)
+
+# MI output requires LTTng-tools ≥ 2.6
+if ((minor_version >= 6)); then
+  gen_opt_specs+=(
+    '(-m --mi)'{-m+,--mi=}'[use the machine interface output]:machine interface type:(xml)'
+  )
+fi
+
+# Append session daemon option specifications
+gen_opt_specs+=(
+  + '(sessiond)'
+  {-n,--no-sessiond}'[do not spawn a session daemon]'
+  '--sessiond-path=[set the session daemon path]:session daemon path:_files -g \*lttng-sessiond'
+)
+
+# Add general option and command name completions
+local curcontext=$curcontext state state_descr line
+local -A opt_args
+
+_arguments -C -s -W : \
+  '(-): : __lttng_complete_cmd_name' \
+  '(-)*:: :->cmd-args' \
+  $gen_opt_specs
+
+local -ir main_ret=$?
+
+if ((main_ret == 0)); then
+  # Completions added: we're done
+  return
+fi
+
+if [[ $state[1] = cmd-args ]]; then
+  # Add completions for the arguments of the specific command
+  __lttng_complete_cmd
+  return
+fi
+
+return $main_ret
This page took 0.040674 seconds and 4 git commands to generate.