як налаштувати Knitr робочий процес у Emacs?


18

RStudio пропонує спосіб за допомогою однієї кнопки для отримання PDF-файлу з джерела LaTeX + R за допомогою Knitr. Це чудово виглядає для проведення відтворюваних досліджень. І я намагаюся налаштувати свій Emacs для:

  • у лівому буфері LaTeX + R код Knitr;
  • у правому буфері попереднього перегляду виводу PDF;
  • одна комбінація клавіш для складання.

Якщо можливо: як мені це налаштувати, будь ласка?

(ESS працює чудово, але я не знаю, як налаштувати Knitr-шлях та одну-кнопку для компіляції.)


Я впевнений, що є кращий спосіб зробити це, але у мене є коротка функція Elisp з прив'язкою клавіш, що працює rmarkdown::render(через shell-command) на поточному buffer-file-name, що оновить pdf в іншому вікні.
daroczig

1
@daroczig чи буде це працювати для LaTeX, або лише розмітка?
Тайлер

@daroczig: у своїй відповіді я, можливо, намагався зробити саме це для файлів Rnw (LaTeX + R). Що стосується файлів Rmd (Rmd + R), що простіше, будь ласка, розпочніть окрему публікацію.
антоніо

1
Я не міг отримати належне налаштування. Доводиться спочатку в'язати багатогранним плетінням. Потім виберіть експортера і все, щоб створити .tex-файл. Звідти мені доводиться бігати з латексу. Я намагався адаптувати Сценарій вище, але мій елісп просто ще не існує. Що я хочу, це в'язати .Rnw-файл, створити pdf (pdflatex) і переглянути його. Я налаштував свою систему, що якщо я ввожу "Cc Ca" (Tex-Command-run-all) у файлі латексу, pdf створюється та переглядається, але я не можу викликати цю функцію у текстовому файлі з my_knitr () . Допомога буде вдячна. (defun my_knitr () "Запустити Knitr у режимі R-Poly та створити та переглянути pdf" (interacti
Krisselack

@Krisselack, схоже, функції, які я описую у своїй відповіді нижче, були видалені з ESS. Мені доведеться оновити його, щоб відобразити новий підхід, який вони використовують
Тайлер

Відповіді:


12

ОНОВЛЕННЯ

У СЗС 19.04, то ess-nowebі ess-swvбібліотеки застаріли:

  • Бібліотеки для грамотного аналізу даних застаріли і не завантажуються за замовчуванням. Сюди входять 'ess-noweb', 'ess-swv' та пов'язані з ними функції, такі як 'Rnw-режим'. Користувачам рекомендується перейти на один з декількох інших пакетів, які стосуються цих режимів. Наприклад, полімод https://github.com/polymode/poly-R/ , https://polymode.github.io/ або режим розмітки з редагуванням-непрямим https://jblevins.org/projects/markdown- режим .

Отже, моя оригінальна відповідь (нижче) вже не застосовується. Функції, які ці бібліотеки раніше використовували, надаються полімодом, а конфігурація - простішою. Щоб отримати мінімальну підтримку, все , що вам потрібно , це встановити ess, polymodeі poly-Rпакети (від MELPA, або з джерела , якщо це, як ви рулон).

Це воно! Тепер, якщо ви відкриєте Rnwфайл, ви повинні побачити PM-Rnwпрапор у моделі, а вгорі буде Polymodeменю. Ви можете переплести файл у .texфайл через M-n w(або меню полімоду) та експортувати його .pdfчерез M-n e(або меню). Вам буде запропоновано експортеру вперше зробити це; Я щойно вибрав knitr.

ПРИМІТКА. Експорт ( M-n e) автоматично запускає ваш код, генерує pdf та відображає його все за один раз. Я не зміг домогтися такої поведінки в один клік зі старою версією, описаною нижче.

Згенеровані файли матимуть слово -wovenта -exportedдодаються. Якщо вам це не подобається, ви можете налаштувати параметри polymode-weaver-output-file-formatта polymode-exporter-output-file-format.

Процес схожий на файли RMarkdown ( .Rmd).

Повна інформація представлена ​​в посібнику з полімоду

Оригінальний відповідь (застарілий після ESS 19.04)

Потрібно встановити три змінні:

  1. ess-swv-pdflatex-commands, в групі налаштування ess-sweaveпотрібно мати "pdflatex" в якості першої команди. тобто це має виглядати приблизно так:("pdflatex" "texi2pdf" "make")
  2. ess-swv-processor, у групі налаштування ess-Rмає бути значення"knitr"
  3. ess-pdf-viewer-prefв групі налаштування essдо "emacsclient". Це передбачає, що ви працюєте з сервером emacs або emacs працює в режимі --daemon. Вам також слід використовувати pdf-інструменти, якщо це можливо, оскільки це набагато краще, ніж вбудований програвач перегляду PDF-файлів Emacs.

Я використовую гачок, щоб додати дві клавіші для виклику BibTeX та 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-n sви в'яжете ваш документ, M-n bнадрукуєте його двома текстами та M-n Pобробіть його за допомогою pdflatex.

Зауважте, що Emacs не має простого способу дізнатися про завершення в'язання, тому ви не можете встановити це в'язання та латекс за один крок; ви повинні вручну запустити pdflatex після того, як ви побачили, що в'язання закінчилося.

З огляду на кілька кроків тут - Rnw -> Latex -> PDF, я не думаю, що ви можете отримати Synctex, щоб зберегти ваші файли pdf та Rnw для прокрутки разом, але я буду радий, що мене довели неправильність.

Що стосується розташування вікон, я ніколи не можу змусити їх залишитися там, де я хочу. Тож для компенсації я став досить вмілим у переміщенні вікон та буферів, як мені це потрібно;)

Yihui розмістив коротке відео на сайті pleer, де демонструє щось із цього.


Я зробив усе можливе, щоб витягнути всі потрібні конфігурації та лише необхідні конфігурації з моїх .emacs. Я, можливо, щось пропустив, там начебто волохате.
Тайлер

це дозволило мені складати в’язальні документи. Але все ж спробуйте знайти одноклавішний комбо (для Rnw -> PDF). Сподіваюсь, що це можливо, оскільки у Рстудіо це є.
drobnbobn

@Tyler: Дякую, ваше рішення працює як шарм ootb (навіть без редагування конфігурації)! Пакети: ess, polymode, poly-r
Krisselack

5

Це все-в-одному рішення. Це створить та відобразить PDF з Rnw .
Зокрема, це:

  1. Збережіть буфер Rnw і в'яжіть його,
  2. Застосувати заданий двигун LaTeX до отриманого файлу TeX,
  3. Визначте виконуваний двигун BibTeX (наприклад, biber, bibtex8),
  4. Запустіть двигун BibTeX на файл TeX, якщо файл bib новіший за файл TeX,
  5. Запустіть LaTeX ще раз, 6 Відкрийте отриманий PDF у призначеному переглядачі.

Процедура намагається вийти з інформаційними повідомленнями, якщо один з вищезазначених кроків не вдався.
При необхідності відкриється екземпляр R, або поточний використовується для показу процесу в'язання.
Вихід LaTeX надсилається в буфер "TeX-output", який також вискакується у разі помилки компіляції.

Використання

Meta- x knit-meстворити та переглянути PDF-файл.
Meta- x knit-me-clearдля видалення проміжних файлів LaTeX і knit-me.

Бібліографія вимагає пакету "biblatex", тобто:

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

Назва bib-engine (наприклад bibtex, biber) отримується для аналізу backendключового слова.
\addbibresourceКоманда аналізується, щоб отримати файл бібліографії: якщо foo.bibвона новіша, ніж файл TeX, запускається двигун bib. У зв'язку з цим враховується лише перша \addbibresourceкоманда, якщо їх багато.

Налаштувати

Щоб фактично переглядати PDF-файл, встановіть виконавчий шлях перегляду за допомогою:

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

Можливо, використовуйте такий переглядач, як SumatraPDF , який автоматично оновлює PDF при перекомпіляції та не блокує відкритий файл, запобігаючи новим компіляціям.

Двигун LaTeX за замовчуванням є pdflatex(передбачається в поточному шляху). Налаштувати за допомогою:

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

Звичайно, можливо, ви захочете прив’язати knit-meі knit-me-clearдеякі зручні клавіші.

Примітки

Тестовано у Windows MiKTeX, з biberта bibtex8backends та GNU Emacs 25.1.1.

Код Еліспа

;; (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")))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.