我正在将我的工具链从 R + TeXShop 改造成我希望通过 emacs(Aquamacs,具体而言)更高效的 Sweave -> LaTeX -> SyncteX -> pdfview (skim) AUCTeX-mode (with emacs-speaks- statsitics 的 sweave 次要模式)。AUCTeX -> pdfview 链中的 SyncteX 一切正常,从 Sweave 编译为 .pdf 一切正常。
当我添加 Sweave 作为第一步时,麻烦就来了。.Rnw 文件现在成为主要的原始文档,它生成的 .tex 文件只是一个中间步骤。当然,SyncteX 锁定的是 .tex 文件。
我对 .emacs 文件所做的唯一更改是注册两个新命令以从 .Rnw 构建 .pdf。
谁能提供有关如何让 emacs 使用 SyncteX 将输出 .pdf 同步到 .Rnw 而不是 .tex 的建议?
谢谢!
编辑1: 警告:这最终成为我整个下午摸索的总结。我非常接近解决方案,但最后却被一个我找不到文档的错误所挫败。警告 2:今天是我第一次深入了解 emacs 的内部工作原理。肯定会出现错误或效率低下。
VitoshKa 的回答让我大部分时间都在那里。将他的建议添加到我的 .emacs(好吧,Preferences.el,但功能相同)文件中会导致Symbol’s value as variable is void: noweb-minor-mode-map
启动时出错,因为 Aquamacs 似乎在其其余 init 文件之前加载 .emacs 文件。
我通过(require 'ess-site) (require 'ess-eldoc)
在 VitoshKa 的(define-key noweb-minor-mode-map (kbd "\C-c \C-c") 'Rnw-command-master)
. 不幸的是,Aquamacs 附带的 ess-swv.elc 文件已经是二进制文件,并强制 Mn P 阅读器使用 acroread。因此,我将 ess-swv.el 文件的一部分的以下编辑添加到我自己的 .emacs 的底部:
(defun ess-makePDFandView ()
(interactive)
(setq namestem (substring (buffer-name) 0 (search ".Rnw" (buffer-name))))
(setq tex-filename (concat "\"" namestem "\".tex"))
(setq my-command-string (concat "pdflatex -synctex=1" tex-filename))
(shell-command my-command-string)
(setq my-command-string (concat "/Applications/Skim.app/Contents/MacOS/Skim \"" namestem ".pdf\" &"))
(shell-command my-command-string))
(define-key noweb-minor-mode-map "\M-nv" 'ess-makePDFandView)
现在 emacs 将使用Mn v或Cc Cc View RET从 emacs 以正确的 pdf 名称启动skim 。还有一个障碍要克服...
emacs 中的 Command-Shift-Click 尝试同步到 filename.Rnw.pdf(但丢弃错误消息至少仍会导致 pdfviewer 中的正确同步)。pdfviewer 中的 Command-Shift-Click 以搜索回源强制 emacs 打开 filename.tex 文件并同步到该文件。幸运的是,Cameron Bracken 对此进行了修复。他只是没有完全走上 emacs 集成的道路。
所以我在我的 .emacs 中添加了 ess-swv.el 的进一步破解:
(defun ess-swv-latex-rnw-sync ()
"Run LaTeX on the product of Sweave()ing the current file."
(interactive)
(save-excursion
(let* ((namestem (file-name-sans-extension (buffer-file-name)))
(latex-filename (concat namestem ".tex"))
(synctex-filename (concat namestem ".synctex.gz"))
(tex-buf (get-buffer-create " *ESS-tex-output*"))
(patchDVI-command-string (concat "Rscript -e \"library('patchDVI');patchSynctex('" synctex-filename "')\"")))
(message "synctex string: %s" patchDVI-command-string)
(message "Running LaTeX on '%s' ..." latex-filename)
(switch-to-buffer tex-buf)
(call-process "latex" nil tex-buf 1 "-synctex=1 " latex-filename)
(switch-to-buffer (buffer-name))
(display-buffer tex-buf)
(message "Finished running LaTeX" )
(message "Running patchDVI...")
(shell-command patchDVI-command-string))))
(define-key noweb-minor-mode-map "\M-nq" 'ess-swv-latex-rnw-sync)
认为这是缺少修补 DVI 并将其同步...但没有!Command-Shift-Click 上的行为与上面相同...回到破解 ess-swv。我删除了 ess-makePDFandView 函数,而是将以下内容添加到我的 .emacs 中:
(defun ess-swv-PDF-rnw-sync (&optional pdflatex-cmd)
"From LaTeX file, create a PDF (via 'texi2pdf' or 'pdflatex', ...), by
default using the first entry of `ess-swv-pdflatex-commands' and display it."
(interactive
(list
(let ((def (elt ess-swv-pdflatex-commands 0)))
(completing-read (format "pdf latex command (%s): " def)
ess-swv-pdflatex-commands ; <- collection to choose from
nil 'confirm ; or 'confirm-after-completion
nil nil def))))
(let* ((buf (buffer-name))
(namestem (file-name-sans-extension (buffer-file-name)))
(latex-filename (concat namestem ".tex"))
(tex-buf (get-buffer-create " *ESS-tex-output*"))
(pdfviewer (ess-get-pdf-viewer))
(pdf-status)
(cmdstr-win (format "start \"%s\" \"%s.pdf\""
pdfviewer namestem))
(cmdstr (format "\"%s\" \"%s.pdf\" &" pdfviewer namestem)))
;;(shell-command (concat "pdflatex " latex-filename))
(message "Running '%s' on '%s' ..." pdflatex-cmd latex-filename)
(switch-to-buffer tex-buf)
(setq pdf-status
(call-process pdflatex-cmd nil tex-buf 1 "-synctex=1 "
(if (string= "texi2" (substring pdflatex-cmd 0 5))
;; workaround (bug?): texi2pdf or texi2dvi *fail* to work with full path:
(file-name-nondirectory latex-filename)
latex-filename)))
(if (not (= 0 pdf-status))
(message "** OOPS: error in '%s' (%d)!" pdflatex-cmd pdf-status)
;; else: pdflatex probably ok
(shell-command
(concat (if (and ess-microsoft-p (w32-shell-dos-semantics))
cmdstr-win
cmdstr))))
(switch-to-buffer buf)
(display-buffer tex-buf)))
(define-key noweb-minor-mode-map "\M-nv" 'ess-swv-PDF-rnw-sync)
越来越近了,但我们仍然需要告诉 auctex 要通过哪些文件名进行浏览。所以我硬着头皮编辑了 auctex-config.el。我注释掉了现有的 aquamacs-call-viewer 函数定义并将其替换为我自己的:
(defun aquamacs-call-viewer (line source)
"Display current output file as PDF at LINE (as in file SOURCE).
Calls `aquamacs-tex-pdf-viewer' to display the PDF file using the
Skim AppleScript protocol."
(cond
((string= (file-name-extension (TeX-active-master)) "Rnw")
(let* ((full-file-name
(expand-file-name
;; as in TeX-view
;; C-c C-c view uses %o (from TeX-expand-list), which
;; is the same.
(concat (file-name-sans-extension (TeX-active-master)) "." (TeX-output-extension))
default-directory))
(full-source-name
(expand-file-name
(concat (file-name-sans-extension (source)) ".Rnw") ;; this is relative to the master
(file-name-directory (full-file-name)))))
(message "full pdf name: %s" full-file-name)
(message "full rnw sournce name: %s" full-source-name)
(do-applescript
(format
"
set theSink to POSIX file \"%s\"
set theSource to POSIX file \"%s\"
tell application \"%s\"
activate
open theSink
tell front document to go to TeX line %d from theSource%s
end tell
"
full-file-name full-source-name aquamacs-tex-pdf-viewer line
;; do not say "showing reading bar false" so users can override in future
(cond ((eq t aquamacs-skim-show-reading-bar)
" showing reading bar true")
((eq nil aquamacs-skim-show-reading-bar)
" showing reading bar false")
(t ""))))))
(t
(let* ((full-file-name
(expand-file-name
;; as in TeX-view
;; C-c C-c view uses %o (from TeX-expand-list), which
;; is the same.
(TeX-active-master (TeX-output-extension))
default-directory))
(full-source-name
(expand-file-name
source ;; this is relative to the master
(file-name-directory full-file-name))))
(message "IN OTHERWISE!! WAT: %s" (file-name-extension (TeX-active-master)))
(do-applescript
(format
"
set theSink to POSIX file \"%s\"
set theSource to POSIX file \"%s\"
tell application \"%s\"
activate
open theSink
tell front document to go to TeX line %d from theSource%s
end tell
"
full-file-name full-source-name aquamacs-tex-pdf-viewer line
;; do not say "showing reading bar false" so users can override in future
(cond ((eq t aquamacs-skim-show-reading-bar)
" showing reading bar true")
((eq nil aquamacs-skim-show-reading-bar)
" showing reading bar false")
(t ""))))))))
还有一个最终测试(请注意,我将工具链的键绑定更改为:Mn s -> Mn q -> Mn v 按 sweave -> latex -> view 的顺序[注意,对于最后一步,您必须使用 pdflatex 和不是texi2pdf]),一切都建立起来,没有错误,启动查看器......
"Skim" "/Users/myname/text/testing/myfile.pdf": exited abnormally with code 127.
现在我又完全迷路了。有人对Skim足够熟悉吗?
编辑 2:好吧,错误 127 只是在二进制文件中找不到文件。在那里的某个地方,我一定把路弄坏了。所以我(setenv "PATH" (concat (getenv "PATH") ":" "/Applications/Skim.app/Contents/MacOS"))
在我的 auctex-config.el 顶部附近添加了。现在一切都编译并启动,没有错误......但是emacs上的Command-Shift-Click没有让Skim做出响应(至少它没有给出错误)。在 Skim 上的 Command-Shift-Click 仍然强制 emacs 打开 .tex 文件。
我想这现在已经成为一个非常 Aquamacs + Skim 的特定问题,因为其余的大部分交互都在 applescript 中,除非我在上面指出的 lisp 的关键行中遗漏了一些明显的东西。