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

Move most of the peculiar argument handling for external calls into the parser #13089

Merged
merged 21 commits into from
Jun 20, 2024

Conversation

devyn
Copy link
Contributor

@devyn devyn commented Jun 7, 2024

Description

We've had a lot of different issues and PRs related to arg handling with externals since the rewrite of run-external in #12921:

Many of these are caused by the argument handling of external calls and run-external being very special and involving the parser handing quoted strings over to run-external so that it knows whether to expand tildes and globs and so on. This is really unusual and also makes it harder to use run-external, and also harder to understand it (and probably is part of the reason why it was rewritten in the first place).

This PR moves a lot more of that work over to the parser, so that by the time run-external gets it, it's dealing with much more normal Nushell values. In particular:

  • Unquoted strings are handled as globs with no expand
  • The unescaped-but-quoted handling of strings was removed, and the parser constructs normal looking strings instead, removing internal quotes so that run-external doesn't have to do it
  • Bare word interpolation is now supported and expansion is done in this case
    • Expressions typed as Glob containing Expr::StringInterpolation now produce Value::Glob instead, with the quoted status from the expr passed through so we know if it was a bare word
    • Bare word interpolation for values typed as glob now possible, but not implemented
  • Because expansion is now triggered by Value::Glob(_, false) instead of looking at the expr, externals now support glob types

User-Facing Changes

  • Bare word interpolation works for external command options, and otherwise embedded in other strings:

    ^echo --foo=(2 + 2) # prints --foo=4
    ^echo -foo=$"(2 + 2)" # prints -foo=4
    ^echo foo="(2 + 2)" # prints (no interpolation!) foo=(2 + 2)
    ^echo foo,(2 + 2),bar # prints foo,4,bar
  • Bare word interpolation expands for external command head/args:

    let name = "exa"
    ~/.cargo/bin/($name) # this works, and expands the tilde
    ^$"~/.cargo/bin/($name)" # this doesn't expand the tilde
    ^echo ~/($name)/* # this glob is expanded
    ^echo $"~/($name)/*" # this isn't expanded
  • Ndots are now supported for the head of an external command (^.../foo works)

  • Glob values are now supported for head/args of an external command, and expanded appropriately:

    ^("~/.cargo/bin/exa" | into glob) # the tilde is expanded
    ^echo ("*.txt" | into glob) # this glob is expanded
  • run-external now works more like any other command, without expecting a special call convention
    for its args:

    run-external echo "'foo'"
    # before PR: 'foo'
    # after PR:  foo
    run-external echo "*.txt"
    # before PR: (glob is expanded)
    # after PR:  *.txt

Tests + Formatting

Lots of tests added and cleaned up. Some tests that weren't active on Windows changed to use nu --testbin cococo so that they can work. Added a test for Linux only to make sure tilde expansion of commands works, because changing HOME there causes ~ to reliably change.

  • 🟢 toolkit fmt
  • 🟢 toolkit clippy
  • 🟢 toolkit test
  • 🟢 toolkit test stdlib

After Submitting

  • release notes: make sure to mention the new syntaxes that are supported

@kubouch
Copy link
Contributor

kubouch commented Jun 7, 2024

Awesome! I was going to suggest that we probably shouldn't be doing the external arg parsing in run-external, but it should be done in the parser.

@devyn
Copy link
Contributor Author

devyn commented Jun 7, 2024

Great! There are a few things I'd appreciate a review on. One in particular is how I handled string interpolations that should turn into globs - I just made them Expr::StringInterpolation with Type::Glob. I didn't really see any other expressions out there that turn into different values depending on their Expression type, so I'm wondering if this would ever cause a problem or if it's too weird and I should just add an Expr::GlobInterpolation or something like that instead.

This is my first time really digging into the nushell parser code and... well, it's not bad, it's easy enough to understand for me, but I can understand why we're trying to push forward the new parser. There are a lot of special cases and it's not as much based on building up smaller parsers as I would have hoped, and there aren't really a lot of parser combinator type helper functions either.

But I'm also probably not as familiar with general patterns there as I could be, so some more review of those changes would be appreciated too.

@devyn devyn marked this pull request as ready for review June 7, 2024 10:10
@fdncred
Copy link
Collaborator

fdncred commented Jun 7, 2024

This bare word string interpolation seems pretty epic to me 🚀. Reduces some typing.

What about single quotes and backtick quotes? I haven't tried this PR yet.

^$'~/.cargo/bin/($name)' # does this expand the tilde? assume no
^$`~/.cargo/bin/($name)` # does this expand the tiled? or maybe this isn't even possible. Not sure we have backtick interpolation yet. assume no or not even supported

@kubouch
Copy link
Contributor

kubouch commented Jun 8, 2024

@fdncred IMO,

^$`~/.cargo/bin/($name)`

should expand tilde because it's a bareword. The first one shouldn't, I agree.

@devyn
Copy link
Contributor Author

devyn commented Jun 8, 2024

^$'~/.cargo/bin/($name)' # does this expand the tilde? assume no

Nope

^$`~/.cargo/bin/($name)` # does this expand the tiled? or maybe this isn't even possible. Not sure we have backtick interpolation yet. assume no or not even supported

We don't have that syntax yet I think but if we did it probably should.

@kubouch
Copy link
Contributor

kubouch commented Jun 8, 2024

We don't have that syntax yet I think but if we did it probably should.

Then I don't understand when is the Expr::StringInterpolation(..., false) or the proposed Expr::GlobInterpolation used, I thought these are for

$`~/.cargo/bin/($name)`

@devyn devyn merged commit bdc3234 into nushell:main Jun 20, 2024
13 checks passed
@devyn devyn deleted the fix-run-external-quoting branch June 20, 2024 04:00
@hustcer hustcer added this to the v0.95.0 milestone Jun 20, 2024
@fdncred
Copy link
Collaborator

fdncred commented Jun 20, 2024

@devyn It would be good to change the default_config.nu since you added shape_glob_interpolation. The themes should have the default color in them for light and dark.

I realize this is mostly a run-external PR but I'm wondering if some internal commands need to be updated to support bare word string interpolation? Or maybe echo is the only one that is supposed to work (but without expansion) - not sure exactly.
For instance, this doesn't work, but I'm not sure if it's supposed to.

 let bin_name = "bin"
 ls ~/.cargo/($bin_name)
Error: nu::shell::directory_not_found

  × Directory not found
   ╭─[entry #2:1:4]
 1  ls ~/.cargo/($bin_name)
   ·    ──────────┬─────────
   ·              ╰── directory not found
   ╰────
  help: /Users/fdncred/.cargo/($bin_name) does not exist

but these work

 echo ~/.cargo/($bin_name)
~/.cargo/bin
 ^echo ~/.cargo/($bin_name)
/Users/fdncred/.cargo/bin
 ^ls ~/.cargo/($bin_name)
... all my bins ...

@kubouch kubouch added pr:release-note-mention Addition/Improvement to be mentioned in the release notes pr:language This PR makes some language changes labels Jun 20, 2024
@devyn
Copy link
Contributor Author

devyn commented Jun 20, 2024

It would be good to change the default_config.nu since you added shape_glob_interpolation. The themes should have the default color in them for light and dark.

Sure, I'll do that.

I realize this is mostly a run-external PR but I'm wondering if some internal commands need to be updated to support bare word string interpolation? Or maybe echo is the only one that is supposed to work (but without expansion) - not sure exactly.

I didn't really do anything to make this work with internal commands yet. The complicated bit is that there are a bunch of different syntax shapes that are used. I think I can add it for SyntaxShape::Glob quite easily now that I've added GlobInterpolation, but it would probably take interpolation types for Filepath and Directory too.

Overall I'm not very satisfied with how this is currently designed and it feels like it should be more compositional, so we don't need many variants of the same expressions just to support interpolation

fdncred pushed a commit that referenced this pull request Jun 21, 2024
# Description

Just missed this during #13089. Adds `shape_glob_interpolation` to the
config.

This actually isn't really going to be seen at all yet, so I debated
whether it's really needed at all. It's only used to highlight the
quotes themselves, and we don't have any quoted glob interpolations at
the moment.
devyn added a commit that referenced this pull request Jun 24, 2024
…rings (#13218)

# Description

@hustcer reported that slashes were disappearing from external args
since #13089:

```
$> ossutil ls oss:https://abc/b/c
Error: invalid cloud url: "oss:/abc/b/c", please make sure the url starts with: "oss:https://"

$> ossutil ls 'oss:https://abc/b/c'
Error: oss: service returned error: StatusCode=403, ErrorCode=UserDisable, ErrorMessage="UserDisable", RequestId=66791EDEFE87B73537120838, Ec=0003-00000801, Bucket=abc, Object=
```

I narrowed this down to the ndots handling, since that does path parsing
and path reconstruction in every case. I decided to change that so that
it only activates if the string contains at least `...`, since that
would be the minimum trigger for ndots, and also to not activate it if
the string contains `:https://`, since it's probably undesirable for a URL.

Kind of a hack, but I'm not really sure how else we decide whether
someone wants ndots or not.

# User-Facing Changes
- bare strings not containing ndots are not modified
- bare strings containing `:https://` are not modified

# Tests + Formatting
Added tests to prevent regression.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr:language This PR makes some language changes pr:release-note-mention Addition/Improvement to be mentioned in the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants