Skip to content

cli: aliases: support multi-word alias names#9577

Open
avamsi wants to merge 1 commit into
jj-vcs:mainfrom
avamsi:av/jj_utnvqomlvwvz
Open

cli: aliases: support multi-word alias names#9577
avamsi wants to merge 1 commit into
jj-vcs:mainfrom
avamsi:av/jj_utnvqomlvwvz

Conversation

@avamsi
Copy link
Copy Markdown
Member

@avamsi avamsi commented May 30, 2026

#6611

Checklist

If applicable:

  • I have updated CHANGELOG.md
  • I have updated the documentation (README.md, docs/, demos/)
  • I have updated the config schema (cli/src/config-schema.json)
  • I have added/updated tests to cover my changes
  • I fully understand the code that I am submitting (what it does,
    how it works, how it's organized), including any code drafted by an LLM.
  • For any prose generated by an LLM, I have proof-read and copy-edited with
    an eye towards deleting anything that is irrelevant, clarifying anything
    that is confusing, and adding details that are relevant. This includes,
    for example, commit descriptions, PR descriptions, and code comments.

Alias names containing spaces (e.g. `aliases."ws rm"`) could previously
only be invoked as a single quoted argument (`jj "ws rm"`).
Resolve them from the external subcommand plus its leading positional
arguments instead, so they can be invoked as space-separated words
(`jj ws rm`) like real subcommands.

When several alias names share a prefix, the longest match wins, and the
remaining arguments are forwarded to the alias definition.

Recursion detection is reworked accordingly: an alias is flagged as
recursive only when it resolves again without consuming any arguments,
so a multi-word alias resolved repeatedly on a shrinking argument list
(`a b b` -> `a b` -> `a`) still terminates.

Addresses jj-vcs#6611.

Change-Id: Id000000056c49bde4340301ff7de763dff332da8
@avamsi avamsi requested a review from a team as a code owner May 30, 2026 07:11
Copy link
Copy Markdown
Contributor

@josephlou5 josephlou5 left a comment

Choose a reason for hiding this comment

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

Thanks for working on this! I'm pretty excited for this feature :)

Comment thread docs/config.md

When alias names share a prefix, the longest match wins, so `l` and `"l all"`
can resolve to different commands. Don't start a multi-word alias with a
built-in command name: `jj log mine` is always parsed as the built-in `log`
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this hard to handle? For example I personally would like a jj git sync alias that implements #/1039 until it's merged upstream, but does that mean that I'll always get a jj git: unrecognized subcommand 'sync' error?

Given that your test examples have shown that foo bar is chosen over foo, I think it makes intuitive sense that log mine should resolve an alias if present, and then fall back to log (with args) if not. But also, your example was when foo bar and foo are both defined as aliases, and maybe it's harder to check all the built-in commands?

Anyway, if this is possible, that'd be cool :) And if it's not, then I guess nothing needs to change here.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Perhaps we'll need to set allow_external_subcommands(true) recursively to all subcommands. See hide_short_subcommand_aliases() for a recursion example.

Then, we can probably substitute arguments normally based on prefix matching. For example, ws rm would be substituted to workspace rm by "ws" = ["workspace"], and then by "workspace rm" = [...]. Aliases like "ws rm" = [...] will never match. A warning can be added if needed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I intentionally wanted to avoid overlap with the builtin commands, at least for the initial version -- I think this has some overlap with #1509, on letting users redefine the behaviour of builtin commands.

Basically, should users be able to define aliases like jj log mine? I'm inclined to say no. That doesn't mean we couldn't still let people define jj git sync, of course (as git is a pure "container" command).

What do you guys think?

Copy link
Copy Markdown
Contributor

@yuja yuja Jun 1, 2026

Choose a reason for hiding this comment

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

should users be able to define aliases like jj log mine? I'm inclined to say no. That doesn't mean we couldn't still let people define jj git sync, of course (as git is a pure "container" command).

No and yes. The latter will allow us to move 1-char jj bookmark subcommands to predefined aliases.

[aliases]
b = ["bookmark"]
"bookmark a" = ["bookmark", "advance"]

EDIT: Oh, it's unclear whether jj b --quiet a should be expanded.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

That doesn't mean we couldn't still let people define jj git sync, of course (as git is a pure "container" command).

That makes sense to me. A follow-up question I have then is: Is it necessarily the case that if jj git has subcommands, then jj git will never have its own behavior? If clap enforces this, then allowing aliases of sub-sub-commands sounds good (e.g., jj git sync as an alias), but if not then we're left with the same problem as jj log my-alias.

I also really like being able to move the single-character built-in aliases to the default config (or being able to define your own).

Comment thread cli/src/cli_util.rs
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How does this feature interact with completions? I described some ideas in #9047 (closed as a duplicate of the issue that you linked). Might help to also add some tests so that the behavior is clear.

Comment thread cli/tests/test_alias.rs
}

#[test]
fn test_alias_multi_word_name() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you also add a test with .run_jj(["ws ls"]) to ensure that the quoted versions still work for backward compatibility? I think they should but just want to make sure. (It's probably not a huge deal since I wouldn't imagine many people are depending on quoted alias names, but good to be thorough.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants