murex icon indicating copy to clipboard operation
murex copied to clipboard

`command(parameters...)` behaves differently to `command parameters...`

Open orefalo opened this issue 2 years ago • 9 comments

Describe the bug: From a visual standpoint, I see a difference between cmd param and cmd(param)

For a given function

function hello (name: str) {
    out "Hello $name, pleased to meet you."
}
CleanShot 2023-09-03 at 22 12 09

vs

CleanShot 2023-09-03 at 22 12 31

note the cursor positions,

Was wondering if it was expected.

orefalo avatar Sep 03 '23 18:09 orefalo

function(params...) trims the trailing carriage return and line feed whereas command params... does not.

The reason for that is because subshells do, because you generally only use subshells (and functions() syntax) for inlining commands as parameters or expressions. Having a trailing "[\r]?\n" would cause issues. eg rm ${ out "foobar.txt" } would fail because it would be trying to delete "foobar\n".

When you're running function(parameters...) you're basically running an expression. So it drops the training \r\n. Frankly function(parameters...) should be used very sparingly. It's handy syntactic sugar for ${ command parameters... } but its not intended for use as the primary way to invoke commands.


that all said, the cursor still should have wrapped round. Murex does a little trick to ensure that if commands finish without a trailing line feed in the interactive prompt, then the cursor still wraps around to the start of a new line, otherwise the prompt would be written halfway across the line, like it does in Bash.

That either isn't happening or Starship is doing something weird to break Murex's little hack.

What happens when you start typing with the cursor in that weird place?

lmorg avatar Sep 03 '23 19:09 lmorg

Noted, thank you I personally find the function(parameters...) syntax convenient, because it brings the shell closer to a standard language.

What happens when you start typing with the cursor in that weird place?

It gets back in place, in the right spot. The issue above is purely cosmetics.

orefalo avatar Sep 04 '23 05:09 orefalo

closing

orefalo avatar Sep 04 '23 19:09 orefalo

I personally find the function(parameters...) syntax convenient, because it brings the shell closer to a standard language.

A word of warning, you're going to run into all sorts of weird behaviours if you do use that as you're primary way of writing "statements" because the function(parameters...) syntax doesn't, at least not at this point in time, attach STDIN to a pipe nor STDOUT to a TTY. It's intended literally only as an inlined function, not as a statement nor method. So things like top() would behave weirdly (no TTY) and commands like cat(file) -> grep(example) would hang (grep reading from TTY but not outputting to a TTY).

Maybe in time i can iron out these edge cases but that's not going to happen in v5.0.

lmorg avatar Sep 05 '23 07:09 lmorg

thanks for the note, will change my recent habits and ensure it's capture in the docs

orefalo avatar Sep 05 '23 09:09 orefalo

Thinking a little more about this. It is counter intuitive that command(parameters...) style syntax should behave so differently to command parameters.... I will have a think about how this could be resolved in a sensible way.

lmorg avatar Sep 05 '23 11:09 lmorg

won't document it then, I also believe they should behave the same.

Maybe you can play some magic, like what you are doing with pipes.

orefalo avatar Sep 08 '23 15:09 orefalo

Yeah its definitely doable. There's already a lot of magic around expressions anyway so a little more here isn't going to do any harm.

In the guts of Murex, technically everything in the shell is statements. While expressions are parsed as an expression, they're then executed as a statement. So the expression 3 + 3 is literally ran as expr '3 + 3'. The problem is that command(parameters...) is basically syntactic sugar for ${command parameters...} so the whole thing unrolls basically as:

expr '${command parameters...}'

which is fine 99% of the time because thats the expected behaviour. I just need to detect if command(parameters...) is the only symbol in the expression, and if so, link the STDIN et al pipes of command directly to expr. This would still result in a little bit of computational overhead compared with command parameters... but pragmatically speaking it shouldn't affect overall performance since reading and writing from streams and fork() is where the real bottlenecks exist and this wouldn't add anything to that.

lmorg avatar Sep 09 '23 22:09 lmorg

@orefalo I've had a few attempts to solve this and it's proven to be much more complicated than I'd assumed. The problem being it's hard to trace if the parent caller is nesting the function or not.

I'm tempted to scrap my plan of implementing this and go back to your original suggestion of documenting that command(parameters) doesn't provide a TTY.

lmorg avatar Jul 15 '24 20:07 lmorg