Làm thế nào để thiết lập quy trình công việc của Đan trong Emacs?


18

RStudio cung cấp một cách một nút để sản xuất tệp PDF từ nguồn LaTeX + R với Đan. Nó trông tuyệt vời để làm nghiên cứu tái sản xuất. Và tôi đang cố gắng định cấu hình Emacs của mình cho:

  • ở bộ đệm trái mã LaTeX + R theo cách Đan;
  • ở bộ đệm xem trước đầu ra PDF;
  • một tổ hợp phím để biên dịch.

Nếu có thể: tôi nên cài đặt cái này như thế nào?

(ESS hoạt động tốt, nhưng tôi không biết cách thiết lập Chế độ đan và một nút để biên dịch.)


Tôi khá chắc chắn rằng có một cách tốt hơn để làm điều đó, nhưng tôi có một chức năng Elisp ngắn với một ràng buộc chính đang chạy rmarkdown::render(thông qua shell-command) trên hiện tại buffer-file-name, nó sẽ cập nhật pdf trong cửa sổ khác.
daroczig

1
@daroczig sẽ làm việc cho LaTeX, hay chỉ đánh dấu?
Tyler

@daroczig: trong câu trả lời của tôi, tôi có thể đã cố gắng làm điều này chỉ cho các tệp Rnw (LaTeX + R). Đối với các tệp Rmd ​​(Rmd + R), đơn giản hơn, vui lòng bắt đầu một bài riêng.
antonio

1
Tôi không thể có được một thiết lập thích hợp. Tôi phải đan đầu tiên với polymode-dệt. Sau đó chọn xuất và mọi thứ để tạo tệp .tex. Từ đó tôi phải chạy mủ. Tôi đã cố gắng điều chỉnh Script ở trên, nhưng elisp của tôi vẫn chưa có. Những gì tôi muốn là đan tệp .Rnw, tạo tệp pdf (pdflatex) và xem nó. Tôi thiết lập hệ thống của mình, rằng nếu tôi gõ "Cc Ca" (Tex-Command-run-all) trong tệp latex, pdf được xây dựng và xem, nhưng tôi không thể gọi chức năng đó trên tệp tex từ my_knitr () . Trợ giúp sẽ được đánh giá cao. (defun my_knitr () "Chạy Đan trong chế độ R-Poly và tạo và xem pdf" (tương tác
Krisselack

@Krisselack có vẻ như các tính năng tôi mô tả trong câu trả lời của tôi dưới đây đã bị xóa khỏi ESS. Tôi sẽ phải cập nhật nó để phản ánh cách tiếp cận mới mà họ sử dụng
Tyler

Câu trả lời:


12

CẬP NHẬT

Kể từ ESS 19.04, các thư viện ess-nowebess-swvthư viện đã lỗi thời:

Do đó, câu trả lời ban đầu của tôi (bên dưới) không còn được áp dụng. Các tính năng mà các thư viện này sử dụng để cung cấp hiện được cung cấp bởi polymode và cấu hình đơn giản hơn. Để nhận được hỗ trợ tối thiểu, tất cả bạn cần là cài đặt ess, polymodepoly-Rcác gói (từ MELPA, hoặc từ nguồn nếu đó là cách bạn cuộn).

Đó là nó! Bây giờ nếu bạn mở một Rnwtệp, bạn sẽ thấy PM-Rnwcờ trong mô hình và sẽ có một Polymodemenu ở trên cùng. Bạn có thể dệt tệp của mình thành một .textệp thông qua M-n w(hoặc menu polymode) và xuất nó sang .pdfqua M-n e(hoặc menu). Bạn sẽ được nhắc nhở cho một nhà xuất khẩu lần đầu tiên bạn làm điều này; Tôi vừa chọn knitr.

LƯU Ý: export ( M-n e) tự động chạy mã của bạn, tạo pdf và hiển thị mã, tất cả trong một lần. Tôi không thể có được hành vi "một lần nhấp" đó với phiên bản cũ được mô tả bên dưới.

Các tập tin được tạo sẽ có từ -woven-exportednối thêm. Nếu bạn không thích điều này, bạn có thể tùy chỉnh các tùy chọn polymode-weaver-output-file-formatpolymode-exporter-output-file-format.

Quá trình này tương tự đối với các tệp RMarkdown ( .Rmd).

Chi tiết đầy đủ được cung cấp trong hướng dẫn sử dụng polymode

Câu trả lời gốc (lỗi thời sau ESS 19.04)

Ba biến cần được đặt:

  1. ess-swv-pdflatex-commands, trong nhóm tùy chỉnh ess-sweavecần phải có "pdflatex" làm lệnh đầu tiên. tức là, nó sẽ trông giống như:("pdflatex" "texi2pdf" "make")
  2. ess-swv-processor, trong nhóm tùy chỉnh ess-R, phải là giá trị"knitr"
  3. ess-pdf-viewer-preftrong nhóm tùy biến essđể "emacsclient". Điều này giả sử bạn đang chạy máy chủ emacs hoặc emacs đang chạy ở chế độ --daemon. Bạn cũng nên sử dụng các công cụ pdf nếu có thể, vì nó tốt hơn nhiều so với trình xem pdf Emacs tích hợp.

Tôi sử dụng một hook để thêm hai keybindings để gọi BibTeX và texi2pdf:

(add-hook 'ess-noweb-mode-hook 'my-noweb-hook)

(defun my-noweb-hook ()
  (define-key ess-noweb-mode-prefix-map "b"
    #'(lambda () (interactive) (TeX-command "BibTeX" 'TeX-master-file)))
  (define-key ess-noweb-mode-prefix-map "P"
    #'(lambda () (interactive)
        (ess-swv-PDF "texi2pdf"))))

Một khi điều này được thực hiện, M-n ssẽ đan tài liệu của bạn, M-n bsẽ bibtex nó và M-n Psẽ xử lý nó với pdflatex.

Lưu ý rằng không có cách đơn giản nào để Emacs biết khi nào đan xong, vì vậy bạn không thể thiết lập điều này thành đan & latex trong một bước; bạn phải kích hoạt thủ công pdflatex sau khi bạn thấy đan xong.

Đưa ra nhiều bước ở đây - Rnw -> latex -> PDF, tôi không nghĩ bạn có thể có được Synctex để giữ các tệp pdf và Rnw của bạn để cuộn cùng nhau, nhưng tôi rất vui mừng khi bị chứng minh là sai.

Đối với việc sắp xếp cửa sổ, tôi không bao giờ có thể khiến họ ở lại nơi tôi muốn. Vì vậy, để bù đắp, tôi đã trở nên khá thành thạo trong việc xáo trộn các cửa sổ và bộ đệm khi tôi cần chúng;)

Yihui đã đăng một đoạn video ngắn trên trang web đan cho thấy một số điều này.


Tôi đã làm hết sức mình để trích xuất tất cả các cấu hình cần thiết và chỉ cấu hình cần thiết, từ .emacs của tôi. Tôi có thể đã bỏ lỡ một cái gì đó, đó là loại lông trong đó.
Tyler

nó làm cho tôi có thể biên dịch các tài liệu đan. Nhưng vẫn cố gắng tìm kết hợp một phím (cho Rnw -> PDF). Hy vọng là có thể, vì Rstudio có điều này.
drobnbobn

@Tyler: Cảm ơn bạn, giải pháp của bạn hoạt động như một ootb quyến rũ (ngay cả khi không chỉnh sửa cấu hình)! Gói: ess, polymode, poly-r
Krisselack

5

Đây là một giải pháp tất cả trong một. Nó sẽ tạo và hiển thị một tệp PDF từ Rnw .
Cụ thể nó sẽ:

  1. Lưu bộ đệm Rnw và đan nó,
  2. Áp dụng công cụ LaTeX đã cho vào tệp TeX kết quả,
  3. Xác định công cụ thực thi BibTeX (ví dụ: biber, bibtex8),
  4. Chạy công cụ BibTeX trên tệp TeX nếu tệp bib mới hơn tệp TeX,
  5. Chạy lại LaTeX, 6 Mở PDF kết quả trong trình xem được chỉ định.

Quy trình cố gắng thoát với thông báo thông tin nếu một trong các bước trên không thành công.
Một phiên bản R sẽ được mở, nếu cần hoặc hiện tại được sử dụng để hiển thị quá trình đan.
Đầu ra LaTeX được gửi đến bộ đệm "TeX-output", cũng xuất hiện trong trường hợp lỗi biên dịch.

Sử dụng

Meta- x knit-međể tạo và xem PDF.
Meta- x knit-me-clearđể xóa các tệp LaTeX trung gian và knit-me.

Thư mục yêu cầu gói "biblatex", nghĩa là:

\usepackage[
    options...      
    backend=ENGINE,
]{biblatex}
\addbibresource{foo.bib}

Tên của bib-engine (ví dụ bibtex, biber) được lấy để phân tích backendtừ khóa.
\addbibresourcelệnh được phân tích cú pháp để lấy tệp thư mục: nếu foo.bibmới hơn tệp TeX thì công cụ bib được chạy. Về vấn đề này, chỉ có \addbibresourcelệnh đầu tiên được tính đến nếu có nhiều.

Tùy chỉnh

Để thực sự xem PDF, hãy đặt đường dẫn thực thi của người xem bằng:

(setq pdf-viewer "path/to/pdf-viewer")

Có thể sử dụng trình xem như SumatraPDF , tự động cập nhật PDF khi được biên dịch lại và không chặn tệp đã mở ngăn chặn các phần tổng hợp mới.

Công cụ LaTeX mặc định là pdflatex(được giả định trong đường dẫn hiện tại). Tùy chỉnh với:

(setq latex-engine "newengine"
      latex-args   "--option-1 --option-2")

Tất nhiên bạn có thể muốn liên kết knit-meknit-me-clearvới một số phím thuận tiện.

Ghi chú

Đã thử nghiệm trong Windows MiKTeX, với biberbibtex8phụ trợ và GNU Emacs 25.1.1.

Mã Elisp

;; (require 'ess-site) ; assumed in your init file

(defun knit-me-clear () 
  "Delete intermediate LaTeX files and run `knkt-me'.
These are based on extensions .aux, .blg, .out, .run.xml, .bbl, .log, -blx.bib"

  (interactive)
  (check-Rnw)
  (let
      ((file)
       (stem (file-name-sans-extension (buffer-file-name))))
    (dolist (elt
         (list ".aux" ".blg" ".out" ".run.xml" ".bbl" ".log" "-blx.bib"))
      (setq file (concat stem elt))
      (if (file-exists-p file) (delete-file file))))  
  (knit-me))


(defun knit-me () 
  "Knit->LaTeX-engine->bibtex-engine->LaTeX-engine->View.
Default LaTeX engine is \"pdflatex\" and can be customised with `latex-engine';
default LaTeX arguments are set to nil and can be customised with `latex-args';
default PDF viewer is set to nil and can be customised with `pdf-viewer'.
Bibliography must be set via \"biblatex\" LaTeX package.
Bibliography engine is obtained from \"backend\" option in \"biblatex\" package.
A reference  LaTeX bib file is obtained from the first LaTeX command \"\addbibresource{foo.bib}\".
The biblatex-engine is run if the bib file is newer of the TeX file. 
If there are multiple \"\addbibresource\" only the first will be used to decide whether to run the biblatex-engine."

  (interactive)

  ;; Default values
  (defvar pdf-viewer nil)
  (defvar latex-engine "pdflatex")
  (defvar latex-args nil)

  (check-Rnw)

  ;;If 1 R-proc found, associate it with buffer;
  ;;if many found, ask to choose one; if none found, launch and associate
  (ess-force-buffer-current "Process to use: ")

  ;;Save Rnw buffer
  (save-buffer)


  (let*
      (;;Set file paths
       (pathstem (file-name-sans-extension (buffer-file-name)))
       (namestem (file-name-nondirectory pathstem))
       (cur-dir     (file-name-directory pathstem))
       (rnw-name    (concat namestem ".Rnw"))
       (tex-name    (concat namestem ".tex"))

       ;;Create LaTeX commmand
       (latex-args (concat latex-args " " namestem))
       (latex-cmd (concat latex-engine " " latex-args))

       ;;Create knit commmand
       (knit-cmd (format "require(knitr); setwd('%s'); knit('%s')"  cur-dir rnw-name))

       ;;Get R buffer proc
       (r-proc (ess-get-process))
       (r-buf (ess-get-process-buffer))

       ;;TeX executable process and bibtex engine/file
       (tex-proc)
       (tex-buf)
       (bibfile (bib-getfile))
       (bibengine (bib-getengine))
       (bibfile-updated
    (file-newer-than-file-p
     (concat cur-dir (file-name-nondirectory bibfile) ".bib") (concat pathstem ".tex")))


       ;;Command success
       (success nil)
       (error-msg "")
       )


    (setq default-directory cur-dir)

    ;; Exit on error
    (catch 'exit-func

      ;;Check bibtex file and engine
      (when (not bibfile)
    (setq error-msg (bib-getfile t))
    (throw 'exit-func nil))     
      (when (not bibengine)
    (setq error-msg (bib-getengine t))      
    (throw 'exit-func nil))

      ;; Biber wants .bib
      (let ((fail (and (string= bibengine "biber")
              (string= (file-name-nondirectory bibfile) (file-name-base bibfile)))))
    (setq success (not fail)))
      (when (not success)
    (setq error-msg
          (format "biber wants \\addbibresource{%s%s}" (file-name-base bibfile) ".bib"))
    (throw 'exit-func nil))


      ;; Knitting
      (switch-to-buffer-other-window r-buf)
      (message knit-cmd)
      (ess-eval-linewise knit-cmd nil t nil t) 
      ;; Foll. 3 lines are an alternative to ess-eval
      ;; (inferior-ess-mark-as-busy r-proc)  ; knit immediately after this line       
      ;; (process-send-string r-proc (format "cat(\"%s\");%s\n" knit-cmd knit-cmd)) ; real 
      ;; (ess-wait-for-process r-proc nil)

      ;; Check for knitting results
      (with-current-buffer r-buf
    ;; Parse last 3 lines
    (let ((beg) (end) (out))
      (goto-char (point-max))
      (setq end (point))
      (forward-line -3) 
      (setq beg (point))
      (setq out (buffer-substring-no-properties beg end))

      ;; Knitting successful?
      (setq success "output file: %s\n\n[1] \"%s\"\n> ")
      (setq success (string= (format success tex-name tex-name) out))))

      (when (not success)
    (setq error-msg (concat "Unable to knit " rnw-name))
    (throw 'exit-func nil))

      ;; First LaTeXing
      (setq tex-buf (get-buffer-create "TeX-output")) ; Create output buffer or use existing
      (with-current-buffer tex-buf                   
    (buffer-disable-undo)
    (erase-buffer))
      (message "1st latex ...")
      (send-r-mess (format "Starting LaTeX (see \"%s\")" (buffer-name tex-buf)))      
      (send-r-mess latex-cmd)
      (setq success (= 0 (call-process latex-engine nil tex-buf t latex-args)))
      (goto-char (point-max))

      ;; Check 1st LaTeX results
      (when (not success)
    (setq error-msg (concat "Unable to LaTeX " namestem))
    (switch-to-buffer-other-window tex-buf) 
    (other-window 1)
    (throw 'exit-func nil))

      ;; Run bibtex engine
      (when bibfile-updated  
    (message "biblatex ...")
    (send-r-mess (concat bibengine " "  namestem))
    (setq success (= 0 (call-process bibengine nil tex-buf t namestem)))
    (goto-char (point-max))

    ;; Check bibtex results
    (when (not success)
      (setq error-msg (concat "Unable to " bibengine " " namestem))
      (switch-to-buffer-other-window tex-buf) 
      (other-window 1)
      (throw 'exit-func nil)))

      ;; Second LaTeXing
      (message "2nd latex ...")
      (send-r-mess latex-cmd)
      (setq success (= 0 (call-process latex-engine nil tex-buf t latex-args)))
      (goto-char (point-max))

      ;; Check 2nd LaTeX results
      (when (not success)
    (setq error-msg (concat "Unable to LaTeX " pathstem))
    (switch-to-buffer-other-window tex-buf) 
    (other-window 1)
    (throw 'exit-func nil))

      ;; View   
      (if (not pdf-viewer) (throw 'exit-func nil))
      (send-r-mess  "...and now the viewer")
      (goto-char (point-max))
      (setq success (file-exists-p pdf-viewer))
      (when (not success)
    (setq error-msg (concat "Can\\'t find executable " pdf-viewer))
    (throw 'exit-func nil))

      ;; If you need viewer console output, use "(start-process "pdf-viewer" tex-buf ...";
      ;; but you block tex-buf buffer till the viewer is open
      (start-process "pdf-viewer" nil pdf-viewer (concat namestem ".pdf")))

    (if success
    (if bibfile-updated (message (concat "Updated to "  (file-name-nondirectory bibfile))))
      (message error-msg)
      (send-r-mess error-msg))))

(defun bib-getfile(&optional show-messages)
  "Check if 'addbibresource' command and related file exist. 
If found, return .bib file full path, else:
if SHOW-MESSAGES is nil return nil, if SHOW-MESSAGES is non-nil return related error."
  (save-excursion
    (goto-char (point-min))
    (re-search-forward "\\\\addbibresource{\\(.+\\)}" nil t))
  (let ((fmatch (match-string-no-properties 1)) 
    (success nil)
    mess)    
    (cond 
     ((not fmatch) (setq mess "Missing \\addbibresource command."))
     ((not (file-exists-p (concat (file-name-sans-extension fmatch) ".bib")))
      (setq mess (concat "Missing file: " fmatch ".bib")))
     ;; if no problem, sucess=message=bib-file-path
     (t (setq mess (concat (file-name-directory (buffer-file-name)) fmatch)
          success mess)))

    (if show-messages mess success)))

(defun bib-getengine(&optional show-messages)
  "Find biblatex engine.
If found,  engine name, else:
if SHOW-MESSAGES is nil return nil, if SHOW-MESSAGES is non-nil return related error."
  (save-excursion
    (goto-char (point-min))
    (let ((pack (re-search-forward "\\\\usepackage *\\(\\[[^]]*\\)\\] *{ *biblatex *}" nil t))
      (bend nil)
      mess)

      (when pack (setq pack (match-string-no-properties 1)))
      (when (and pack
         (string-match "[^[:alpha:]]+backend *= *\\([^, \n]+\\)" pack))
    (setq bend (match-string 1 pack)))
      (cond 
       ((not pack) (setq mess "Missing biblatex package command."))
       ((not bend) (setq mess "Missing biblatex backend."))
       ;; if no problem, sucess=message=bib-file-path
       (t (setq mess bend)))
      (if show-messages mess bend))))


(defun send-r-mess (mess)
  "Just send MESS at the end of R console buffer"
  (process-send-string (ess-get-process)
             (format "cat('%s\\n')\n" mess)))

(defun check-Rnw ()
  "Give error if `ess-dialect' is not \"R\""
  (if (not (string= "R" ess-dialect))
      (error "Not an Rnw buffer")))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.