]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
completion: add zsh
authorJörg Behrmann <behrmann@physik.fu-berlin.de>
Sun, 16 Jun 2024 13:11:14 +0000 (15:11 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Mon, 22 Jul 2024 09:16:14 +0000 (11:16 +0200)
This completion of verbs is based on _timedatectl in systemd repo.
Completion for short options doesn't work. It also doesn't work for
timedatectl, so this needs to be fixed in both places.

Co-authored-by: Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
mkosi/__init__.py
mkosi/config.py
mkosi/resources/completion.zsh [new file with mode: 0644]

index b610f25d6ef6739a86ae6e5ffc9506de852c7c27..9146bd6a8c7522c1f12d807fd36464352a137a4e 100644 (file)
@@ -51,6 +51,7 @@ from mkosi.config import (
     collect_completion_arguments,
     finalize_completion_bash,
     finalize_completion_fish,
+    finalize_completion_zsh,
     format_bytes,
     parse_config,
     summary,
@@ -4425,6 +4426,8 @@ def print_completion(args: Args, *, resources: Path) -> None:
         print(finalize_completion_bash(completion_args, resources))
     elif args.shell_completion == ShellCompletion.fish:
         print(finalize_completion_fish(completion_args, resources))
+    elif args.shell_completion == ShellCompletion.zsh:
+        print(finalize_completion_zsh(completion_args, resources))
 
 
 def expand_specifier(s: str) -> str:
index c39d882c735444c648c8b7c9dc2278a172f8852b..761ef14b6ae2ba74f636948301c44d7f3b010704 100644 (file)
@@ -244,6 +244,7 @@ class ShellCompletion(StrEnum):
     none = enum.auto()
     bash = enum.auto()
     fish = enum.auto()
+    zsh  = enum.auto()
 
     def __bool__(self) -> bool:
         return self != ShellCompletion.none
@@ -1205,6 +1206,15 @@ class CompGen(StrEnum):
         else:
             return "-f"
 
+    def to_zsh(self) -> str:
+        if self == CompGen.files:
+            return ":path:_files -/"
+        elif self == CompGen.dirs:
+            return ":directory:_files -f"
+        else:
+            return ""
+
+
 @dataclasses.dataclass(frozen=True)
 class ConfigSetting:
     dest: str
@@ -4601,3 +4611,51 @@ def finalize_completion_fish(options: list[CompletionItem], resources: Path) ->
             c.write(option.compgen.to_fish())
             c.write("\n")
         return c.getvalue()
+
+
+def finalize_completion_zsh(options: list[CompletionItem], resources: Path) -> str:
+    def to_zsh_array(name: str, entries: Iterable[str]) -> str:
+        return f"declare -a {name.replace('-', '_')}=(" + " ".join(shlex.quote(str(e)) for e in entries) + ")"
+
+    completion = resources / "completion.zsh"
+
+    with io.StringIO() as c:
+        c.write("#compdef mkosi\n")
+        c.write("# SPDX-License-Identifier: LGPL-2.1-or-later\n\n")
+
+        c.write(to_zsh_array("_mkosi_verbs", [str(v) for v in Verb]))
+        c.write("\n\n")
+
+
+        c.write(completion.read_text())
+        c.write("\n")
+
+        c.write("_arguments -s \\\n")
+        c.write("    '(- *)'{-h,--help}'[Show this help]' \\\n")
+        c.write("    '(- *)--version[Show package version]' \\\n")
+
+        for option in options:
+            if not option.short and not option.long:
+                continue
+
+            posix = option.help and "'" in option.help
+            open_quote = "$'" if posix else "'"
+            if option.short and option.long:
+                c.write(f"    '({option.short} {option.long})'{{{option.short},{option.long}}}{open_quote}")
+            else:
+                c.write(f"    {open_quote}{option.short or option.long}")
+
+            if option.help:
+                help = option.help.replace("'", r"\'")
+                c.write(f"[{help}]")
+            if option.choices:
+                # TODO: maybe use metavar here? At least for me it's not shown, though
+                c.write(":arg:(")
+                c.write(" ".join(option.choices))
+                c.write(")")
+            c.write(option.compgen.to_zsh())
+            c.write("' \\\n")
+
+        c.write("    '*::mkosi verb:_mkosi_verb'\n\n")
+
+        return c.getvalue()
diff --git a/mkosi/resources/completion.zsh b/mkosi/resources/completion.zsh
new file mode 100644 (file)
index 0000000..e9cd3b5
--- /dev/null
@@ -0,0 +1,17 @@
+_mkosi_verb(){
+    if (( CURRENT == 1 )); then
+        _describe -t commands 'mkosi verb' _mkosi_verbs
+    else
+        local curcontext="$curcontext"
+        cmd="${${_mkosi_verbs[(r)$words[1]:*]%%:*}}"
+        if (( $#cmd )); then
+            if (( $+functions[_mkosi_$cmd] )); then
+                _mkosi_$cmd
+            else
+                _message "no more options"
+            fi
+        else
+            _message "unknown mkosi verb: $words[1]"
+        fi
+    fi
+}