devlog 14

🐢 Now, let’s return clap and its dynamic completions: Last time you said,

🐇 The examples are only found in the tests. https://github.com/clap-rs/clap/blob/master/clap_complete/tests/testsuite/engine.rs#L604

and we can try to create those random strings this way.

🦊 The issue is that we may not use derive method to add these custom completers. All examples are using the builder API.

🐢 We should be able to obtain the end result from derives and modify them to use these custom completers, but let’s try to use add=ArgValueCompleter first.

🐇 It looks we have another problem. We need to add a rust-toolchain.toml file to the project, you know, to keep it in the stable.

🐢 Ah, yeah, we now use multiple channels. Let’s do that.

🐇 I found an example actually

#[derive(Debug, Parser)]
struct Cli {
    #[arg(long, add = ArgValueCompleter::new(custom_completer))]
    custom: Option<String>,
}

🐢 I’m trying to add this to --from-ref option of Xvc. It doesn’t run anything. The custom completer should return a random string but it doesn’t.

🦊 Maybe test with constant first.

🐢 It didn’t work that way either.

🐇 Let’s do a cargo clean.

🐢 Nothing has changed.

🐇 Let’s take a look at the output of xvc completions

xvc completions
...
'(--skip-git)--from-ref=[Checkout the given Git reference (branch, tag, commit etc.) before performing the Xvc operation. This runs \`git checkout <given-value>\` before running the command]:FROM_REF:_default' \
...

🐢 This is the only place –from-ref is mentioned and as far as I can see there is nothing that calls a dynamic command here.

🐇 Umm, right, There is something weird here. Maybe we lack the ArgExt trait or something.

🐢 It should be turned on by clap-complete with its unstable-dynamic feature but who knows.

🐇 It didn’t work.

🐢 ArgExt is available but it isn’t used.

🐇 I think I found the answer in https://jj-vcs.github.io/jj/latest/install-and-setup/#command-line-completion

source <(COMPLETE=zsh xvc)

is the command we should use.

🐢 It doesn’t produce a completion script though.

🐇 We have this in jj/cli/src/cli_util.rs

        if env::var_os("COMPLETE").is_some() {
            return handle_shell_completion(ui, &self.app, &config, &cwd);
        }

🐢 I think the whole set handle_shell_completion is written by them. I’d like to see what jj with COMPLETE=zsh outputs.

🐇 Building it to see now.

🐢 As expected, it calls a function

❯ COMPLETE=zsh target/debug/jj
#compdef jj
function _clap_dynamic_completer_jj() {
    local _CLAP_COMPLETE_INDEX=$(expr $CURRENT - 1)
    local _CLAP_IFS=$'\n'

    local completions=("${(@f)$( \
        _CLAP_IFS="$_CLAP_IFS" \
        _CLAP_COMPLETE_INDEX="$_CLAP_COMPLETE_INDEX" \
        COMPLETE="zsh" \
        /Users/iex/github.com/etc/jj/target/debug/jj -- ${words} 2>/dev/null \
    )}")

    if [[ -n $completions ]]; then
        _describe 'values' completions
    fi
}

compdef _clap_dynamic_completer_jj jj

🐇 Now we should make it the same, shell must call xvc to get the completions. That’s how all these will work.

🐢 Our goal now is to make a random string output from --from-ref completion.

🐇 The plan is making completions work as quickly as possible.

🐢 We have done it. 🎉🥳

🐇 Cool. Now we need to fill up all those completion methods.

🦊 Yeah. We can start with basic ones and move from there.

🐢 There will probably architecture changes as well. We cannot just run xvc functions directly. We need to run internal functions but not through commands. At that point, when the user hits tab, we don’t know which command to run.

🐇 Maybe it’s time to move to a git library. “What is the best Git library for Rust?”

🐲 Should we use a Git library?

🐢 It looks Gitoxide is the default Rust way to interact with Git repositories. We can keep our way of using Git binary and use this as an experimental way to learn.

🦊 Yep. That’s a good idea. We can include in the lib, for the time being and start to use it in completions.

/jj/ /clap/ /clap-complete/ /zsh/ /gitoxide/ /git/