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

feat: Add support for *args to AliasMap #4605

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

matts1
Copy link
Collaborator

@matts1 matts1 commented Oct 8, 2024

This is required in order to support command aliases as functions, because they will require the following to be supported:

'upload()' = ["upload", "@"]
'upload(r)' = [["fix", "$r"], ["git", "push", "--change", "$r"]]

Here, jj upload would need to map to the first, jj upload foo would need to map to the second, and jj upload foo --bar would also need to map to the second.

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 tests to cover my changes

This is required in order to support command aliases as functions, because they will require the following to be supported:
```toml
'upload()' = ["upload", "@"]
'upload(r)' = [["fix", "$r"], ["git", "push", "--change", "$r"]]
```

Here, `jj upload` would need to map to the first, `jj upload foo` would need to map to the second, and `jj upload foo --bar` would also need to map to the second.
@yuja
Copy link
Collaborator

yuja commented Oct 8, 2024

This is required in order to support command aliases as functions, because they will require the following to be supported:

'upload()' = ["upload", "@"]
'upload(r)' = [["fix", "$r"], ["git", "push", "--change", "$r"]]

Here, jj upload would need to map to the first, jj upload foo would need to map to the second, and jj upload foo --bar would also need to map to the second.

These examples don't look like *args. (If they were, upload(*args) should conflict with upload(r, *args).)

Perhaps, we'll need a public API to get AliasFunctionOverloads?

let overloads = map.get_function_overloads("upload")?;
// for `jj upload foo --bar`, max_parameters = ["foo"].len()
// XXX should we pick upload/1 for `jj upload foo bar`?? It might be rather confusing.
let arity = min(overloads.max_arity(), max_parameters);
// If there were upload/0, /1, /3, and max_parameters is 2, I think it's better
// to error out (as ambiguous alias definitions) than falling back to upload/1.
let function = overloads.find_by_arity(arity)?;

@yuja
Copy link
Collaborator

yuja commented Oct 8, 2024

'upload()' = ["upload", "@"]
'upload(r)' = [["fix", "$r"], ["git", "push", "--change", "$r"]]

Here, jj upload would need to map to the first, jj upload foo would need to map to the second, and jj upload foo --bar would also need to map to the second.

Oh, but jj upload foo --bar will have to be rewritten to [["fix", "foo"], ["git", "push", "--change", "foo", "--bar"]]? Then, we'll need an explicit *args syntax to specify which command list to copy the remainder arguments to, and only one of the overloads should have *args.

@PhilipMetzger
Copy link
Collaborator

just a minor nit from my side, "feature" is not a known topic, it could be dsl_util: or aliases:.

@matts1
Copy link
Collaborator Author

matts1 commented Oct 8, 2024

Oh, but jj upload foo --bar will have to be rewritten to [["fix", "foo"], ["git", "push", "--change", "foo", "--bar"]]? Then, we'll need an explicit *args syntax to specify which command list to copy the remainder arguments to, and only one of the overloads should have *args.

My original intention was that every overload would have an implicit *args and we perform a longest prefix match, so given, and:

'upload()' = ["upload", "@"]
'upload(r, blah)' = [["fix", "$r"], ["git", "push", "--change", "$r", "$blah", "$args"]]
upload() ==> upload/0(args=[])
upload(first) ==> upload/0(args=[first])
upload(first, second) ==> upload/2(first, second, args=[])
upload(first, second, third) ==> upload/2(first, second, args=[third])

My logic was going to be:

  • If the overload goes to a single command, add an implicit $args at the end if it doesn't exist
  • If the overload goes to multiple commands, $args was non-empty, and none of the commands ended with $args, then error out.

Your proposal does work as well, I mostly wanted to avoid the *args in the interest of slimming down the syntax since concern was expressed over making the DSL more complex. However, if we're ok with it, then I can implement it in the following way:

'upload()' = ["upload", "@"]
'upload(r, *args)' = [["fix", "$r"], ["git", "push", "--change", "$r" "$args"]]

This would generate an upload/0 and an upload/1+.

@yuja
Copy link
Collaborator

yuja commented Oct 9, 2024

My original intention was that every overload would have an implicit *args and we perform a longest prefix match, so given, and:

'upload()' = ["upload", "@"]
'upload(r, blah)' = [["fix", "$r"], ["git", "push", "--change", "$r", "$blah", "$args"]]
upload() ==> upload/0(args=[])
upload(first) ==> upload/0(args=[first])
upload(first, second) ==> upload/2(first, second, args=[])
upload(first, second, third) ==> upload/2(first, second, args=[third])

My feeling is that choosing a prefix match would lead to random unexpected result. I would rather want to see an error if overloads set is somewhat inconsistent.

BTW, the example above has recursion? upload/0 -> (upload/1 ->) upload/0
(["upload"] might be substituted to ["upload", "@", "@"], but I'm not sure.)

Your proposal does work as well, I mostly wanted to avoid the *args in the interest of slimming down the syntax since concern was expressed over making the DSL more complex. However, if we're ok with it, then I can implement it in the following way:

'upload()' = ["upload", "@"]
'upload(r, *args)' = [["fix", "$r"], ["git", "push", "--change", "$r" "$args"]]

This would generate an upload/0 and an upload/1+.

I don't have a strong feeling about whether *args can be implicit or not, but if it can, I would add it only to the function having the maximum arity.

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