elves / elvish

Powerful scripting language & versatile interactive shell
https://elv.sh/
BSD 2-Clause "Simplified" License
5.53k stars 297 forks source link

Augment `file:open` to allow cloning a file object #1729

Open krader1961 opened 8 months ago

krader1961 commented 8 months ago

A discussion earlier today on the chat channel caused me to notice there isn't a way to clone a file object. In particular you can't capture the current stdout file object doing this:

var log-file = (file:open /dev/stdout)

That is because the output capture changes what /dev/stdout refers to and isn't portable.

The original context was an Elvish user who has a function which outputs values they want to capture and log messages to the byte stream they do not want to capture. Here is a stylized example of what they were trying to do using I/O redirection to make it work:

> try { var v = (put 1; echo test >&3) 3>&1 } catch e { }
test

There are problems with using I/O redirection to make that work. First, it's clumsy and hard to discover how to do correctly. Second, they sometimes want the logged output to go to a file so now you have to change all the 3>&1 expressions to 3>log-file. Third, having to do it everywhere you use commands that write log messages to stdout you don't want to capture is very annoying. My proposal is to enhance file:open to accept a literal special source syntax. For example:

> var log-out = (file:open &3) 3>&1
> try { var v = (put 1; echo test >$log-out) } catch e { }
test

That example can also be improved further by defining a log function that captures the log-out variable then using that rather than echo. See also #247.