From 3b4c6009c00e6b7a7dd9dd54ead5669e0988e1a9 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 17 Jul 2023 14:44:09 -0700 Subject: [PATCH 1/7] zsh: typo in systemctl completions --- shell-completion/zsh/_systemctl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 425ae54157..d533734d8d 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -165,7 +165,7 @@ __systemctl() ! _retrieve_cache SYS_ALL_UNITS$_sys_service_mgr; then _sys_all_units=( ${${(f)"$(__systemctl list-units --all)"}%% *} ) - _store_cache SYS_ALL_UNITS$_sys_service_mgr _sys_all_unis + _store_cache SYS_ALL_UNITS$_sys_service_mgr _sys_all_units fi } From d0fc94a19258030fad433eb4091479bba5ef043e Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 17 Jul 2023 16:17:20 -0700 Subject: [PATCH 2/7] zsh: suppress aliases and shell functions when calling systemctl This prevents any errors in case the user had aliased some arguments following systemctl. --- shell-completion/zsh/_systemctl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index d533734d8d..666649e858 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -153,7 +153,7 @@ # @todo _systemd-run has a helper with the same name, so we must redefine __systemctl() { - systemctl $_sys_service_mgr --full --legend=no --no-pager --plain "$@" 2>/dev/null + command systemctl $_sys_service_mgr --full --legend=no --no-pager --plain "$@" 2>/dev/null } From 087f777a1cd946b91ae4013f0a3b0b6e3c333d97 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 17 Jul 2023 14:47:23 -0700 Subject: [PATCH 3/7] zsh: default to system manager when not specified This used to work correctly, before the change was reverted in e09d0d46c297. In fact it is important to specify the manager explicity in the completion because the argument is reused in the caching policies. An empty argument here caused the completion to create separate caches with and without the --system parameter. We can simplify the given pattern a little here too. --- shell-completion/zsh/_systemctl.in | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 666649e858..98b4d2eb65 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -491,9 +491,8 @@ done } # Build arguments for "systemctl" to be used in completion. -local -a _modes; _modes=("--user" "--system") -# Use the last mode (they are exclusive and the last one is used). -local _sys_service_mgr=${${words:*_modes}[(R)(${(j.|.)_modes})]} +# Use the last mode, or --system (they are exclusive and the last one is used). +local _sys_service_mgr=${words[(R)(--user|--system)]:---system} _arguments -s \ {-h,--help}'[Show help]' \ '--version[Show package version]' \ From 8a8caeccb27a375913b9d1787664656dce1f4511 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 17 Jul 2023 16:06:59 -0700 Subject: [PATCH 4/7] zsh: stop forcing unit file cache rebuilds Rebuilding whenever the cached parameter is not set forces each new shell to rebuild the cache, which often defeates the purpose of caching in the first place. --- shell-completion/zsh/_systemctl.in | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 98b4d2eb65..5a6e7d391d 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -161,8 +161,7 @@ __systemctl() (( $+functions[_systemctl_all_units] )) || _systemctl_all_units() { - if ( [[ ${+_sys_all_units} -eq 0 ]] || _cache_invalid SYS_ALL_UNITS$_sys_service_mgr ) || - ! _retrieve_cache SYS_ALL_UNITS$_sys_service_mgr; + if _cache_invalid SYS_ALL_UNITS$_sys_service_mgr || ! _retrieve_cache SYS_ALL_UNITS$_sys_service_mgr; then _sys_all_units=( ${${(f)"$(__systemctl list-units --all)"}%% *} ) _store_cache SYS_ALL_UNITS$_sys_service_mgr _sys_all_units @@ -175,8 +174,7 @@ __systemctl() { local -a all_unit_files; local -a really_all_units; - if ( [[ ${+_sys_really_all_units} -eq 0 ]] || _cache_invalid SYS_REALLY_ALL_UNITS$_sys_service_mgr ) || - ! _retrieve_cache SYS_REALLY_ALL_UNITS$_sys_service_mgr; + if _cache_invalid SYS_REALLY_ALL_UNITS$_sys_service_mgr || ! _retrieve_cache SYS_REALLY_ALL_UNITS$_sys_service_mgr; then all_unit_files=( ${${(f)"$(__systemctl list-unit-files)"}%% *} ) _systemctl_all_units From 110ba0ccf9b9e93fe6f26d19c4b578100fd9757c Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Mon, 17 Jul 2023 16:24:36 -0700 Subject: [PATCH 5/7] zsh: update default caching policy for units MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The existing caching policy was completely bogus. In the first stanza, despite the comment, the pattern given would consider the cache invalid if it was more than 1 hour old. The second stanza was also incorrect, since the output of `systemctl --all` is not unit file paths, but unit names. When they were being tested against the cachefile mtime, the test would always fail becuase of the nonexistant file (hopefully). In fact it's not very useful to test if the unit files have newer mtime in this case anyway, since we are only caching their names. Also, `systemctl --all` is an unfortunately slow operation to be used in testing for the cache validity — we want this operation to at least be faster than rebuilding the cache. I've rewritten this stanza with my best guess at its original intent. It now checks against the mtime of the parent directories in the search path, which should be updated and cause the cache to rebuild when we add, remove, or rename any unit files. --- shell-completion/zsh/_systemctl.in | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 5a6e7d391d..8c004c3bb1 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -424,20 +424,13 @@ done (( $+functions[_systemctl_caching_policy] )) || _systemctl_caching_policy() { - local _sysunits - local -a oldcache - # rebuild if cache is more than a day old - oldcache=( "$1"(mh+1) ) - (( $#oldcache )) && return 0 + [[ -n $1(#qNmd+1) ]] && return 0 - _sysunits=(${${(f)"$(__systemctl --all)"}%% *}) - - if (( $#_sysunits )); then - for unit in $_sysunits; do - [[ "$unit" -nt "$1" ]] && return 0 - done - fi + local pathkind=systemd-search-${1##*--}-unit + for dir in ${(s-:-)^$(_call_program $pathkind systemd-path $pathkind)}; do + [[ $dir -nt $1 ]] && return 0 + done return 1 } From ae6fb82cd9b7d6cd5410fc670fd3c7f2eb22eae9 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Tue, 18 Jul 2023 16:52:18 -0700 Subject: [PATCH 6/7] zsh: remove unit property caching The existing caching policy isn't very sensible for this cache. We could write a different policy, but I don't think there is much value in caching these values, as in my experience the command used to generate them is quick. --- shell-completion/zsh/_systemctl.in | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 8c004c3bb1..85ea6d28f5 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -451,13 +451,9 @@ done (( $+functions[_systemctl_unit_properties] )) || _systemctl_unit_properties() { - if ( [[ ${+_sys_all_properties} -eq 0 ]] || _cache_invalid SYS_ALL_PROPERTIES$_sys_service_mgr ) || - ! _retrieve_cache SYS_ALL_PROPERTIES$_sys_service_mgr; - then - _sys_all_properties=( ${${(M)${(f)"$({{ROOTLIBEXECDIR}}/systemd --dump-bus-properties)"}}} ) - _store_cache SYS_ALL_PROPERTIES$_sys_service_mgr _sys_all_properties - fi - _values -s , "${_sys_all_properties[@]}" + local -a _sys_all_properties=( ${(f)"$({{ROOTLIBEXECDIR}}/systemd --no-pager --dump-bus-properties 2>/dev/null)"} ) + _wanted systemd-unit-properties expl 'unit property' \ + _values -s , "${_sys_all_properties[@]}" } (( $+functions[_systemctl_job_modes] )) || From 9ec0808370c7c1b020871d4a9a352166c46a6d92 Mon Sep 17 00:00:00 2001 From: Ronan Pigott Date: Wed, 19 Jul 2023 14:26:14 -0700 Subject: [PATCH 7/7] zsh: use glob matching for template names Template names can be learned from the filesystem, so there isn't a need to parse the output of systemctl list-unit-files in this case. This should accelerate the completion of some verbs like enable. --- shell-completion/zsh/_systemctl.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 85ea6d28f5..7ce7c4c015 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -200,7 +200,10 @@ __systemctl() )"}:#*@.*}%%[[:space:]]*} } (( $+functions[_systemctl_get_template_names] )) || - _systemctl_get_template_names() { echo -E - ${^${(M)${(f)"$(__systemctl list-unit-files)"}##*@.[^[:space:]]##}%%@.*}\@ } + _systemctl_get_template_names() { + local pathkind=systemd-search-${_sys_service_mgr##*--}-unit + print -r - ${(s-:-)^$(_call_program $pathkind systemd-path $pathkind)}/*@.(${(~j.|.)$(__systemctl --type=help)})(N:t:r) + } (( $+functions[_systemctl_active_units] )) || _systemctl_active_units() {_sys_active_units=( ${${(f)"$(__systemctl list-units)"}%% *} )}