Coder Social home page Coder Social logo

Comments (15)

vspinu avatar vspinu commented on July 1, 2024 4

This part has been finally done. There are now two fully featured exporters (M-n e) one for ESS and one for Rscript standalone. Thanks for your patience.

from polymode.

malcook avatar malcook commented on July 1, 2024 1

@biocyberman - I think would be satisfied if the snippet ran Rscript ... not on localhost but rather on the host associated with tramp session through which you are editing the file.

Try this:

(defun rmarkdown-render ()
  "Reformat the current (presumed) markdown formatted buffer into
another format (i.e. html) by running rmarkdown::render() on
it (which in turn calls pandoc and friends).  

Display trace or error results in buffer *rmarkdown-render Output*

When underlying file is remote (i.e. tramp), perform conversion
on remote host (where Rscript must be on path and rmarkdown must
be installed/configured (i.e. including pandoc)).
"
;; TODO: recover when assumptions not met (e.g. RStudio offers to
;; install rmarkdown if needed).
(interactive)
  (let ((render-command (read-string "render command:" 
                     (format "render('%s',%s);"
                         (shell-quote-argument  (file-name-nondirectory (buffer-file-name)))
                         "'all'"
                         ))))
    (get-buffer-create "*rmarkdown-render Output*")
    (start-file-process
     "rmarkdown-render" "*rmarkdown-render Output*"
     "Rscript"
      "-e" (message "withCallingHandlers({library(rmarkdown); %s}, clean=FALSE, error = function(e) {print(sys.calls())})"
               render-command)
      )))

from polymode.

r2evans avatar r2evans commented on July 1, 2024

I have implemented a temporary workaround, with the assumption that it will be done more formally and more correctly later.

I initially tried to create a custom pm-weaver/rmarkdown, but I had trouble getting it to work, so I just modified pm-weaver/knitR in-place. Since I am using render() instead of knit(), this does not pose a problem for me.

I have tested it weakly (it works on the two files I've tested so far), and only knitR-ESS (I haven't played with dynamically putting Rscript.exe in my path, similar to how ESS finds all versions of R.) Perhaps somebody better at lisp could improve on this.

--- modes/poly-R.el.orig        2014-08-07 09:10:51.835450100 -0700
+++ modes/poly-R.el     2014-08-07 09:10:19.166581500 -0700
@@ -301,13 +301,13 @@
 (defcustom pm-weaver/knitR-ESS
   (pm-callback-weaver "knitR-ESS"
                       :from-to
-                      '(("latex" "\\.\\(tex\\|rnw\\)\\'" "tex" "LaTeX" "library(knitr); knit('%i', output='%o')")
-                        ("html" "\\.x?html?\\'" "html" "HTML" "library(knitr); knit('%i', output='%o')")
-                        ("markdown" "\\.r?md\\'" "md" "Markdown" "library(knitr); knit('%i', output='%o')")
-                        ("rst" "\\.rst\\'" "rst" "ReStructuredText" "library(knitr); knit('%i', output='%o')")
-                        ("brew" "\\.r?brew\\'" "brew" "Brew" "library(knitr); knit('%i', output='%o')")
-                        ("asciidoc" "\\.asciidoc\\'" "txt" "AsciiDoc" "library(knitr); knit('%i', output='%o')")
-                        ("textile" "\\.textile\\'" "textile" "Textile" "library(knitr); knit('%i', output='%o')"))
+                      '(("latex" "\\.\\(tex\\|rnw\\)\\'" "tex" "LaTeX" "library(rmarkdown); render('%i')")
+                        ("html" "\\.x?html?\\'" "html" "HTML" "library(rmarkdown); render('%i')")
+                        ("markdown" "\\.r?md\\'" "md" "Markdown" "library(rmarkdown); render('%i')")
+                        ("rst" "\\.rst\\'" "rst" "ReStructuredText" "library(rmarkdown); render('%i')")
+                        ("brew" "\\.r?brew\\'" "brew" "Brew" "library(rmarkdown); render('%i')")
+                        ("asciidoc" "\\.asciidoc\\'" "txt" "AsciiDoc" "library(rmarkdown); render('%i')")
+                        ("textile" "\\.textile\\'" "textile" "Textile" "library(rmarkdown); render('%i')"))
                       :function 'pm--run-command-in-ESS
                       :callback 'pm--ESS-callback)
   "ESS knitR weaver."

NB: I chose to remove the output argument, instead relying on render() to infer the output document from the YAML header instead of relying on polymode to force it, mostly because I do not consistently tell polymode what format to weave/export and prefer to just hit M-n w to knit/compile into a PDF or HTML in one step.

from polymode.

vspinu avatar vspinu commented on July 1, 2024

I will get around to this and other issued at the end of this week. Sorry for the delays.

from polymode.

r2evans avatar r2evans commented on July 1, 2024

No need to apologize! It's your effort helping us. Thank you!

from polymode.

malcook avatar malcook commented on July 1, 2024

What do you think about simply:

(defun rmarkdown-render ()
  "run rmarkdown::render on the current file"
  (interactive)
  (shell-command
   (format "Rscript -e 'library(rmarkdown); render(\"%s\")'"
       (shell-quote-argument (buffer-file-name)))))
(define-key polymode-mode-map [(meta n) (r)] 'rmarkdown-render)

from polymode.

r2evans avatar r2evans commented on July 1, 2024

I modified your code slightly, since generally I'm not concerned about the pandoc output:

(defun rmarkdown-render ()
  "run rmarkdown::render on the current file"
  (interactive)
  (let* ((out (shell-command-to-string
               (format "c:/R/R-3.1.1/bin/x64/Rscript.exe -e \"rmarkdown::render('%s')\""
                       (shell-quote-argument (buffer-file-name)))))
         (rstr (reverse (split-string out "\n")))
         (last3 (mapconcat 'identity (subseq rstr 0 3) "")))
    (message last3)))
(define-key polymode-mode-map [(meta n) (r)] 'rmarkdown-render)

It's not great elisp, but it's currently sufficient for my needs. If I were to extend it (and were more fluent in elisp), I'd extend it in a couple of ways:

  • capture the shell-command output into a temp buffer instead of a string;
  • search for "Output created" in the last few lines ... if found, "(message ...)" that line and delete the temp buffer, else show the temp buffer; and
  • Offer an optional argument (e.g., "C-u M-n r") to do one of the following:
    • change the current output format, where rmarkdown::render currently defaults to the first (or only) output format in the YAML section; or
    • add clean = FALSE in order to keep intermediate files created during rendering

Thanks, @malcook, that was helpful.

from polymode.

malcook avatar malcook commented on July 1, 2024

Hi - glad it helped.

In light of some of the same issues, I've slightly changed my approach as follows:

(defun rmarkdown-render ()
  "run rmarkdown::render() on the current file and display results in buffer *Shell Command Output*"
  (interactive)
  (let ((render-command (read-string "render command:"
                                     (format "render('%s',%s);"
                                             (shell-quote-argument (buffer-file-name))
                                             "'all'"
                                             ))))
    (shell-command
     (message
      "Rscript -e \"withCallingHandlers({library(rmarkdown); library(pander); %s}, error = function(e) print(sys.calls()))\""
      render-command
      ))
    ))

... which gives the chance to add additional options (like clean=FALSE) to the call to render and handles shell output better.

Also, the withCallingHandlers business gets me a backtrace in case the call to render errors out, which happens.

Anyone else improving on this snippet?

~Malcolm

from polymode.

dojeda avatar dojeda commented on July 1, 2024

Excellent snippet @malcook !
For me, however, the output is display both in the Shell Command Output buffer and the Messages buffer, which is quite annoying.
I resolved this by putting a & at the end of the shell command, which executes the rendering asynchronously and only outputs to the Async Shell Command buffer

from polymode.

r2evans avatar r2evans commented on July 1, 2024

Another technique I switched to is using smart-compile to automatically default to the correct Rscript call (instead of the default make -k), and just use compile to render the document. It does color-ify the output meaningfully, though admittedly it doesn't know enough about the output to be able to jump to the source document line for an error.

from polymode.

biocyberman avatar biocyberman commented on July 1, 2024

@malcook Could you change the function so that it works for files open through ssh connection with Tramp? I tried to render a file like that and the fuction does not understand the ssh protocol and the colons :

from polymode.

biocyberman avatar biocyberman commented on July 1, 2024

@malcook With only a typo with three additional ))) at the very end, the functions now works like a charm over tramp 👍

from polymode.

malcook avatar malcook commented on July 1, 2024

Glad it helped.

About those trailing parens, I think I lost them to an emacs core dump while coding for my master thesis over 30 years ago - glad to have 'em back - thanks for the alert!

from polymode.

kwstat avatar kwstat commented on July 1, 2024

My approach. Renders Rmd to html and opens in browser. Derived from: delhey.info/inc/ess-rmarkdown.pdf

(define-key polymode-mode-map (kbd "M-n r") 'ess-render-rmarkdown)

(defun ess-render-rmarkdown ()
  "Compile R markdown (.Rmd). Should work for any output type."
  (interactive)
  ;; Check if attached R-session
  (condition-case nil
      (ess-get-process)
    (error
     (ess-switch-process)))
  (let* ((rmd-buf (current-buffer)))
    (save-excursion
      (let* ((sprocess (ess-get-process ess-current-process-name))
             (sbuffer (process-buffer sprocess))
             (buf-coding (symbol-name buffer-file-coding-system))
             (buffer-file-name-html (concat (file-name-sans-extension buffer-file-name) ".html"))
             (R-cmd
              (format "library(rmarkdown); rmarkdown::render(\"%s\"); browseURL(\"%s\")"
                      buffer-file-name buffer-file-name-html)))
        (message "Running rmarkdown on %s" buffer-file-name)
        (ess-execute R-cmd 'buffer nil nil)
        (switch-to-buffer rmd-buf)
        (ess-show-buffer (buffer-name sbuffer) nil)))))

from polymode.

malcook avatar malcook commented on July 1, 2024

@kwstat - big difference with your approach is that it (re)-uses current R process which may have some state (i.e. variables set) which would not be present when starting a new R process, such as my approach. "You get what you asked for"

from polymode.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.