Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Zsh completions #34

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -882,7 +882,15 @@ You can enable auto-completion in Bash with these commands:
```bash
completions_dir="${BASH_COMPLETION_USER_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/bash-completion}/completions"
mkdir -p "${completions_dir}"
duty --completion > "${completions_dir}/duty"
duty --completion=bash > "${completions_dir}/duty"
```

Only Bash is supported for now.
Or in Zsh with:
j-g00da marked this conversation as resolved.
Show resolved Hide resolved

```zsh
completions_dir="$HOME/.duty"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand you may have taken inspiration from the Bash example above, but this doesn't seem right to me. The Bash example uses standard locations that Bash immediately understands. This location would require users to fiddle with the Zsh configuration to load the completion from ~/.duty I believe. Furthermore, not using standard locations is generally frowned-upon by users (me included 😄) as that leads to a cluttered HOME directory 🙂

In short, could you try to see if there's a standard location we could write the file in, so that Zsh's completion system natively finds it?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In short, could you try to see if there's a standard location we could write the file in, so that Zsh's completion system natively finds it?

From what I understand, zsh doesn't have any "standard" location for completions other than /usr/local/share/zsh/site-functions, which is in fpath by default, but I don't think we want to install it system-wide. I based my approach on oh my zsh, which puts completions under ~/.oh-my-zsh/completions and adds it to fpath. Still, I think cluttered HOME is a good point. Let me know what you think.

One thing I'd like to see for Zsh completions is actual description of the completion words

Good point, I will work on this later today.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! We could then document that and let the user decide. I found https://github.com/zsh-users/zsh-completions/blob/master/zsh-completions-howto.org#telling-zsh-which-function-to-use-for-completing-a-command to be very readable, maybe we could link to it.

Copy link
Author

@j-g00da j-g00da Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've modified the docs yestarday and changed the completions.zsh to use compdef (rich completions) instead of old compctl. Still no descriptions, but now it will be possible to add them. Will work on adding descriptions later today or tomorrow. You can take a look at the docs and let me know if it's enough information (I will polish the text later).
Sources: this answer on stackoverflow, and ofc the zsh-completions-howto.org.

Copy link
Author

@j-g00da j-g00da Feb 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also - completions.zsh is WIP, it's just a minimal example for now, but it works, and I know opts.complete parsing as of now breaks the bash complete implementation.
Also 2 - We can make it compatible with old zsh versions, but I don't know if this is that important since user can always use bash completions in zsh if native approach doesn't work (explained in the docs).

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much! Don't bother about supporting old Zsh versions, latest is fine 🙂

mkdir -p "${completions_dir}"
echo "source ${completions_dir}/completion" >> $HOME/.zshrc
duty --completion=zsh > "${completions_dir}/completion"
exec zsh
```
20 changes: 17 additions & 3 deletions src/duty/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import argparse
import inspect
import sys
import os
import textwrap
from pathlib import Path
from typing import Any
Expand Down Expand Up @@ -73,8 +74,10 @@ def get_parser() -> ArgParser:
parser.add_argument(
"--completion",
dest="completion",
action="store_true",
help=argparse.SUPPRESS,
nargs="?",
const=True,
metavar="SHELL",
help="Prints completion script for selected shell. If no value is provided, $SHELL is used.",
)
parser.add_argument(
"--complete",
Expand Down Expand Up @@ -275,7 +278,18 @@ def main(args: list[str] | None = None) -> int:
collection.load()

if opts.completion:
print(Path(__file__).parent.joinpath("completions.bash").read_text())
if opts.completion is True:
shell = os.path.basename(os.environ.get('SHELL'))
else:
shell = opts.completion.lower()

if shell == 'zsh':
print(Path(__file__).parent.joinpath("completions.zsh").read_text())
elif shell == 'bash':
print(Path(__file__).parent.joinpath("completions.bash").read_text())
else:
raise NotImplementedError(f"Completion is only supported on Bash and Zsh, got '{shell}'.")
j-g00da marked this conversation as resolved.
Show resolved Hide resolved

return 0

if opts.complete:
Expand Down
6 changes: 6 additions & 0 deletions src/duty/completions.zsh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Based on pyinvoke implementation of zsh completion
_complete_duty() {
reply=( $(duty --complete -- ${words}) )
}

compctl -K _complete_duty + -f duty
j-g00da marked this conversation as resolved.
Show resolved Hide resolved