yihui / knitr

A general-purpose tool for dynamic report generation in R
https://yihui.org/knitr/
2.36k stars 873 forks source link

Add a powershell engine #1932

Open cderv opened 3 years ago

cderv commented 3 years ago

Why :

This could be made easier after working on a generic engine https://github.com/yihui/knitr/pull/1829

Maybe usefull command : xfun:::powershell()

Use case :

znmeb commented 3 years ago

Is there documentation on how to add a language engine for arbitrary compiled or interpreted languages? I'm interested in learning Rust and there doesn't seem to be a language engine for it.

cderv commented 3 years ago

There is already a PR for a Rust engine. See https://github.com/yihui/knitr/pull/1823

However, we are waiting before adding more engine as we plan on adding a feature for a Generic engine (based on proposal #1829).

You can try the Rust PR though in the meantime!

About registering a custom engine, you can see about it in the R Markdown Cookbook https://bookdown.org/yihui/rmarkdown-cookbook/custom-engine.html

yihui commented 2 years ago

@cderv Does ```{exec, command="powershell"} work now? If it works, we can add register the powershell engine (or ps for short).

Is there documentation on how to add a language engine for arbitrary compiled or interpreted languages?

@znmeb Please see https://github.com/yihui/knitr/pull/1829#issuecomment-1011801414

cderv commented 2 years ago

If it works, we can add register the powershell engine (or ps for short).

I believe we'll need to register an engine to bring a few tweaks.

powershell expect file with extension .ps1. Example with pwsh (newer powershell) gives this error

Processing -File 'pwsh24c04384463d.pwsh' failed because the file does not have a '.ps1' extension. Specify a valid PowerShell script file name, and then try again.

powershell will also error but differently.

This works


```{exec, command = "pwsh"}
#| engine.opts:
#|    ext: ps1
$env:PATH -split ";"

However, with `powershell` it seems it require explicit relative path

* Works: `powershell.exe .\powershell24c01c3480a.ps1`
* Does not work: 

This works though
````markdown
```{exec, command = "powershell"}
#| engine.opts:
#|    args1: -File
#|    ext: ps1
$env:PATH -split ";"


So we could add a `ps` engine with those tweaks probably. I can make a PR
Shaunson26 commented 2 years ago

I am curious about this. I've had to do learn some basic powershell stuff for work. I thought of keeping my notes with Rmarkdown document. I just copied code from 15.1 of the Rmarkdown cookbook. I'm curious about

  1. inline code vs -file argument (from above posts)
  2. keeping the environment across chunks
```{r}
# Allow stderr chunk option
knitr::knit_engines$set(ps = function(options) {
  code <- paste(options$code, collapse = '\n')
  out  <- system2(
    'powershell', c('-c', shQuote(code)), 
    stdout = TRUE, stderr = if (is.null(options$stderr)) TRUE
  )
  knitr::engine_output(options, code, out)
})
write-output "Hello"
$this = "that"
write-output "this equals $this"
$this

Hello

this equals that

that

# each chunk runs in it's own environment, $this from above is not available (expected)
$this
# R warning + PS stderr
write-error "An error"
Warning in system2("powershell", c("-c", shQuote(code)), stdout = TRUE,  :
  running command '"powershell" -c "write-error \"An error\""' had status 1
## write-error "An error" : An error
##     + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException
##     + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException
##
# Hide both
write-error "An error"
cderv commented 2 years ago

inline code vs -file argument (from above posts)

What do you mean by inline code ?

keeping the environment across chunks

Each chunk calls system2 to execute a powershell command. It is not like sending code to terminal. I don't know of a way to do that.

Shaunson26 commented 2 years ago

when you wrote powershell.exe .\powershell24c01c3480a.ps1 above, is that file something created from knitr i.e. the code chunk being saved to file and then executed? or something the user is providing? I'm likely missing some intricacies of knitr here..

cderv commented 2 years ago

is that file something created from knitr i.e. the code chunk being saved to file and then executed?

Yes - knitr will put the content of a chunk to a file and execute it. That is how the exec engine is working.

Full details of how this works is in the code https://github.com/yihui/knitr/blob/88c52131b071de7381a3da25533d574da1cd9631/R/engine.R#L174-L237