mirror of
https://github.com/fish-shell/fish-shell
synced 2025-01-12 21:18:53 +00:00
Rewrite systemctl completion with argparse
This - Offers more candidates - Is more reactive (it'll always incorporate "--state=" and "--type=" - Is faster (about 800ms to about 120ms) - Needs fewer function files All __fish_systemctl_* functions except __fish_systemctl_services have been removed.
This commit is contained in:
parent
fd33e3e2c6
commit
281d468285
13 changed files with 101 additions and 171 deletions
|
@ -1,5 +1,9 @@
|
||||||
set -l systemd_version (systemctl --version | string match "systemd*" | string replace -r "\D*(\d+)" '$1')
|
set -l systemd_version (systemctl --version | string match "systemd*" | string replace -r "\D*(\d+)" '$1')
|
||||||
set -l commands list-units list-sockets start stop reload restart try-restart reload-or-restart reload-or-try-restart isolate kill is-active is-failed status show get-cgroup-attr set-cgroup-attr unset-cgroup-attr set-cgroup help reset-failed list-unit-files enable disable is-enabled reenable preset mask unmask link load list-jobs cancel dump list-dependencies snapshot delete daemon-reload daemon-reexec show-environment set-environment unset-environment default rescue emergency halt poweroff reboot kexec exit suspend hibernate hybrid-sleep switch-root
|
set -l commands list-units list-sockets start stop reload restart try-restart reload-or-restart reload-or-try-restart \
|
||||||
|
isolate kill is-active is-failed status show get-cgroup-attr set-cgroup-attr unset-cgroup-attr set-cgroup help \
|
||||||
|
reset-failed list-unit-files enable disable is-enabled reenable preset mask unmask link load list-jobs cancel dump \
|
||||||
|
list-dependencies snapshot delete daemon-reload daemon-reexec show-environment set-environment unset-environment \
|
||||||
|
default rescue emergency halt poweroff reboot kexec exit suspend hibernate hybrid-sleep switch-root
|
||||||
if test $systemd_version -gt 208
|
if test $systemd_version -gt 208
|
||||||
set commands $commands cat
|
set commands $commands cat
|
||||||
if test $systemd_version -gt 217
|
if test $systemd_version -gt 217
|
||||||
|
@ -9,29 +13,15 @@ end
|
||||||
set -l types services sockets mounts service_paths targets automounts timers
|
set -l types services sockets mounts service_paths targets automounts timers
|
||||||
|
|
||||||
function __fish_systemd_properties
|
function __fish_systemd_properties
|
||||||
if type -q /usr/lib/systemd/systemd
|
# We need to call the main systemd binary (the thing that is run as PID1).
|
||||||
/usr/lib/systemd/systemd --dump-configuration-items | string split -m1 = | while read key value
|
# Unfortunately, it's usually not in $PATH.
|
||||||
test -n "$value"
|
if test -f /usr/lib/systemd/systemd
|
||||||
and echo $key
|
/usr/lib/systemd/systemd --dump-configuration-items | string replace -rf '(.+)=(.+)$' '$1\t$2'
|
||||||
end
|
else if test -f /lib/systemd/systemd # Debian has not merged /lib and /usr/lib
|
||||||
else if type -q /lib/systemd/systemd # Debian has not merged /lib and /usr/lib
|
/lib/systemd/systemd --dump-configuration-items | string replace -rf '(.+)=(.+)$' '$1\t$2'
|
||||||
/lib/systemd/systemd --dump-configuration-items | string split -m1 = | while read key value
|
|
||||||
test -n "$value"
|
|
||||||
and echo $key
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function __fish_systemctl_failed
|
|
||||||
if __fish_contains_opt user
|
|
||||||
# Without arguments, no "--type=" will be passed
|
|
||||||
systemctl --user list-units --state=failed --no-legend --type=$argv ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-units --state=failed --no-legend --type=$argv ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
complete -f -e -c systemctl
|
|
||||||
# All systemctl commands
|
# All systemctl commands
|
||||||
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a "$commands"
|
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a "$commands"
|
||||||
|
|
||||||
|
@ -45,49 +35,13 @@ complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a disab
|
||||||
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a isolate -d 'Start a unit and dependencies and disable all others'
|
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a isolate -d 'Start a unit and dependencies and disable all others'
|
||||||
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a set-default -d 'Set the default target to boot into'
|
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a set-default -d 'Set the default target to boot into'
|
||||||
|
|
||||||
set -l commands_types start stop restart try-restart reload-or-restart reload-or-try-restart is-active is-failed is-enabled reenable mask loaded link list-dependencies show status
|
# Command completion done via argparse.
|
||||||
|
complete -c systemctl -a '(_fish_systemctl)' -f
|
||||||
|
|
||||||
if test $systemd_version -gt 208
|
# These "--x=help" outputs always have lines like "Available unit types:". We use the fact that they end in a ":" to filter them out.
|
||||||
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a cat -d 'Show a unit'
|
complete -f -c systemctl -s t -l type -d 'List of unit types' -xa '(systemctl --type=help --no-legend --no-pager | string match -v "*:")'
|
||||||
set commands_types $commands_types cat
|
complete -f -c systemctl -l state -d 'List of unit states' -xa '(systemctl --state=help --no-legend --no-pager | string match -v "*:")'
|
||||||
if test $systemd_version -gt 217
|
complete -f -c systemctl -s p -l property -a '(__fish_systemd_properties)'
|
||||||
complete -f -c systemctl -n "not __fish_seen_subcommand_from $commands" -a edit -d 'Edit a unit'
|
|
||||||
set commands_types $commands_types edit
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
for command in $commands_types
|
|
||||||
for t in $types
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from $command" -a "(eval __fish_systemctl_$t)"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Handle reset-failed specially because it doesn't apply to unit-files (only units that have been tried can have failed) and a second "--state=" argument doesn't override the earlier one.
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from reset-failed" -a "(__fish_systemctl_failed)"
|
|
||||||
|
|
||||||
# Enable/Disable: Only show units with matching state
|
|
||||||
for t in services sockets timers service_paths
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from enable" -a "(eval __fish_systemctl_$t --state=disabled)"
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from disable" -a "(eval __fish_systemctl_$t --state=enabled)"
|
|
||||||
end
|
|
||||||
|
|
||||||
# These are useless for the other commands
|
|
||||||
# .device in particular creates too much noise
|
|
||||||
for t in devices slices scopes swaps
|
|
||||||
for command in status show list-dependencies
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from $command" -a "(eval __fish_systemctl_$t)"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from isolate" -a '(__fish_systemctl_targets)' -d 'Target'
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from isolate" -a '(__fish_systemctl_snapshots)' -d 'Snapshot'
|
|
||||||
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from set-default" -a '(__fish_systemctl_targets)' -d 'Target'
|
|
||||||
complete -f -c systemctl -n "__fish_seen_subcommand_from set-default" -a '(__fish_systemctl_services)' -d 'Service'
|
|
||||||
|
|
||||||
complete -f -c systemctl -s t -l type -d 'List of unit types' -xa 'service mount socket target slice scope swap snapshot automount timer path'
|
|
||||||
complete -f -c systemctl -l state -d 'List of unit states' -xa 'LOAD, SUB, ACTIVE,'
|
|
||||||
complete -f -c systemctl -s p -l property -d 'Properties displayed in the "show" command' -a '(__fish_systemd_properties)'
|
|
||||||
complete -f -c systemctl -s a -l all -d 'Show all units or properties'
|
complete -f -c systemctl -s a -l all -d 'Show all units or properties'
|
||||||
complete -f -c systemctl -s r -l recursive -d 'Show also units of local containers'
|
complete -f -c systemctl -s r -l recursive -d 'Show also units of local containers'
|
||||||
complete -f -c systemctl -l reverse -d 'Show reverse dependencies between units'
|
complete -f -c systemctl -l reverse -d 'Show reverse dependencies between units'
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
function __fish_systemctl_automounts
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
systemctl --user list-unit-files --no-legend --type=automount ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-unit-files --no-legend --type=automount ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
function __fish_systemctl_devices
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
# Devices are usually generated at runtime
|
|
||||||
# Therefore show known _units_, not unit-files
|
|
||||||
systemctl --user list-units --no-legend --type=device ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-units --no-legend --type=device ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
function __fish_systemctl_mounts
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
systemctl --user list-unit-files --no-legend --type=mount ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-unit-files --no-legend --type=mount ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
function __fish_systemctl_scopes
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
# Scopes are usually generated at runtime
|
|
||||||
# Therefore show known _units_, not unit-files
|
|
||||||
systemctl --user list-units --no-legend --type=scope ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-units --no-legend --type=scope ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
function __fish_systemctl_service_paths
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
systemctl --user list-unit-files --no-legend --type=path ^/dev/null $argv | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-unit-files --no-legend --type=path ^/dev/null $argv | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,11 +0,0 @@
|
||||||
function __fish_systemctl_slices
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
# Slices are usually generated at runtime
|
|
||||||
# Therefore show known _units_, not unit-files
|
|
||||||
systemctl --user list-units --no-legend --type=slice ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-units --no-legend --type=slice ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,12 +0,0 @@
|
||||||
function __fish_systemctl_snapshots
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
# Snapshots are usually generated at runtime
|
|
||||||
# Therefore show known _units_, not unit-files
|
|
||||||
# They are also often not loaded, so add "--all"
|
|
||||||
systemctl --user list-units --all --no-legend --type=snapshot ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-units --all --no-legend --type=snapshot ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
function __fish_systemctl_sockets
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
systemctl --user list-unit-files --no-legend --type=socket ^/dev/null $argv | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-unit-files --no-legend --type=socket ^/dev/null $argv | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
function __fish_systemctl_swaps
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
systemctl --user list-unit-files --no-legend --type=swap ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-unit-files --no-legend --type=swap ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
function __fish_systemctl_targets
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
systemctl --user list-unit-files --no-legend --type=target ^/dev/null | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-unit-files --no-legend --type=target ^/dev/null | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +0,0 @@
|
||||||
function __fish_systemctl_timers
|
|
||||||
if type -q systemctl
|
|
||||||
if __fish_contains_opt user
|
|
||||||
systemctl --user list-unit-files --no-legend --type=timer ^/dev/null $argv | cut -f 1 -d ' '
|
|
||||||
else
|
|
||||||
systemctl list-unit-files --no-legend --type=timer ^/dev/null $argv | cut -f 1 -d ' '
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
84
share/functions/_fish_systemctl.fish
Normal file
84
share/functions/_fish_systemctl.fish
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
function _fish_systemctl --description 'Call systemctl with some options from the current commandline'
|
||||||
|
# These options are all global - before or after subcommand/arguments.
|
||||||
|
# There's a bunch of long-only options in here, so we need to be creative with the mandatory short version.
|
||||||
|
set -l opts t/type= s-state= p/property= a/all
|
||||||
|
set opts $opts r/recursive R-reverse A-after B-before
|
||||||
|
set opts $opts l/full V-value S-show-types J-job-mode=
|
||||||
|
set opts $opts F-fail i/ignore-inhibitors q/quiet N-no-block
|
||||||
|
set opts $opts W-wait U-user Y-system I-failed O-no-wall
|
||||||
|
set opts $opts G-global E-reload K-no-ask-password 4-kill-who
|
||||||
|
set opts $opts ü-signal f-force 5-message ö-now ä-root
|
||||||
|
set opts $opts Ü-runtime Ö-preset-mode= n/lines= o/output=
|
||||||
|
set opts $opts Ä-firmware-setup ß-plain H/host= M/machine=
|
||||||
|
set opts $opts 1-no-pager 2-no-legend h/help 3-version
|
||||||
|
|
||||||
|
set -l args $argv
|
||||||
|
set -l cmdline (commandline -opc) (commandline -ct)
|
||||||
|
set -e cmdline[1]
|
||||||
|
argparse $opts -- $cmdline ^/dev/null
|
||||||
|
or return
|
||||||
|
|
||||||
|
# If no subcommand has been given, return so this can be used as a condition.
|
||||||
|
test -n "$argv[1]"
|
||||||
|
or return
|
||||||
|
set -l cmd $argv[1]
|
||||||
|
set -e argv[1]
|
||||||
|
|
||||||
|
# Flags we want to pass on.
|
||||||
|
set -l passflags $_flag_user $_flag_system $_flag_failed
|
||||||
|
switch "$cmd"
|
||||||
|
# These are the normal commands, so just complete all units.
|
||||||
|
# For "restart" et al, also complete non-running ones, since it can be used regardless of state.
|
||||||
|
case reenable status reload {try-,}{reload-or-,}restart is-{active,enabled,failed} show cat \
|
||||||
|
help reset-failed list-dependencies list-units revert add-{wants,requires} edit
|
||||||
|
case enable
|
||||||
|
# This will only work for "list-unit-files", but won't print an error for "list-units".
|
||||||
|
set -q _flag_state; or set _flag_state disabled
|
||||||
|
case disable
|
||||||
|
set -q _flag_state; or set _flag_state enabled
|
||||||
|
case start
|
||||||
|
# Running `start` on an already started unit isn't an _error_, but useless.
|
||||||
|
set -q _flag_state; or set _flag_state dead,failed
|
||||||
|
case mask
|
||||||
|
set -q _flag_state; or set _flag_state loaded
|
||||||
|
case unmask
|
||||||
|
set -q _flag_state; or set _flag_state masked
|
||||||
|
case stop kill
|
||||||
|
# TODO: Is "kill" useful on other unit types?
|
||||||
|
# Running as the catch-all, "mounted" for .mount units, "active" for .target.
|
||||||
|
set -q _flag_state; or set _flag_state running,mounted,active
|
||||||
|
case isolate set-default
|
||||||
|
# These only take one unit.
|
||||||
|
set -q argv[1]; and return
|
||||||
|
case list-sockets
|
||||||
|
set _flag_type socket
|
||||||
|
case list-timers
|
||||||
|
set _flag_type timer
|
||||||
|
case get-default show-environment daemon-{reload,reexec} is-system-running default rescue emergency halt poweroff kexec \
|
||||||
|
suspend hibernate hybrid-sleep
|
||||||
|
# Accept no arguments.
|
||||||
|
return
|
||||||
|
case '*'
|
||||||
|
# Unknown subcommand. Since we don't want to execute just anything, return.
|
||||||
|
# Note that this could also be a partial token, which is completed elsewhere.
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
# Add the flags back so we can pass them to our systemctl invocations.
|
||||||
|
set -q _flag_type; and set passflags $passflags --type=$_flag_type
|
||||||
|
set -q _flag_state; and set passflags $passflags --state=$_flag_state
|
||||||
|
set -q _flag_property; and set passflags $passflags --property=$_flag_property
|
||||||
|
set -q _flag_machine; and set passflags $passflags --machine=$_flag_machine
|
||||||
|
set -q _flag_host; and set passflags $passflags --host=$_flag_host
|
||||||
|
|
||||||
|
# Output looks like
|
||||||
|
# systemd-tmpfiles-clean.timer [more whitespace] loaded active waiting Daily Cleanup[...]
|
||||||
|
# Use the last part as the description.
|
||||||
|
systemctl --no-legend --no-pager --all list-units $passflags | string replace -r "(?: +(\S+)){4}" \t'$1'
|
||||||
|
# We need this for disabled/static units. Also instance units without an active instance.
|
||||||
|
# Output looks like
|
||||||
|
# systemd-tmpfiles-clean.timer static
|
||||||
|
# Just use the state as the description, since we won't get it here.
|
||||||
|
# This is an issue for units that appear in both.
|
||||||
|
systemctl --no-legend --no-pager --all list-unit-files $passflags | string replace -r "(?: +(\S+)){1}" \t'$1'
|
||||||
|
end
|
Loading…
Reference in a new issue