I'm attempting to create a build system for knitr/Sweave in Sublime Text 2. My current, simple (and working) build system is as follows:
{
"cmd": ["bash", "-c", "/usr/bin/R64 CMD Sweave '${file_name}' && pdflatex '${file_base_name}.tex' -interaction=nonstopmode -synctex=1 %S -f -pdf && /Applications/Skim.app/Contents/MacOS/Skim '${file_base_name}.pdf'"],
"path": "$PATH:/usr/texbin:/usr/local/bin",
"selector": "text.tex.latex.sweave","shell":false,
"file_regex": "^(...*?):([0-9]+): ([0-9]*)([^\\.]+)"
}
(The text.text.latex.sweave
context is defined in the Sweave Textmate bundle, which kind of works in Sublime Text)
The build system takes a .Rnw
file, converts it to TeX, and then runs pdflatex
on it. This build system works, but it is fairly limited in how it opens Skim (it just opens the PDF—that's all). The LaTeXTools Sublime Text package is far more robust and opens/refreshes Skim while highlighting modified lines and providing Skim's magic reverse search.
I don't want to rewrite the LaTeXTools build system, especially since it does most of the heavy lifting (and Skim magic) with a separate Python script. However, I would really like to be able to use it to build a TeX file generated from Sweave.
Ideally, I'd love to somehow nest a build system—convert an .Rnw
file to TeX and then immediately run the LaTeXTools build system that already exists. In pseudocode:
{
[CONVERT RNW TO ${file_name}.tex && RUN THE LATEXTOOLS BUILD SYSTEM ON ${file_name}.tex]
}
Is it possible to access a build system from inside another build system (or alternatively, access a build system from bash)?
This is a patch to two files in the LatexTools plugin in order to deal with Rnw files, and one patch to the Latex plugin in order to make Rnw files to behave like LaTeX files.
First the patch to the Latex plugin, in specific to the file LaTeX.tmLanguage:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>fileTypes</key>
<array>
<string>tex</string>
<string>Rnw</string>
</array>
Observe how I added an element to the array in order to deal with Rnw extensions.
Now the patch to makePDF.py
look for a a line like this
if self.tex_ext.upper() != ".TEX":
sublime.error_message("%s is not a TeX source file: cannot compile." % (os.path.basename(view.file_name()),))
return
and replace it with
if (self.tex_ext.upper() != ".TEX") and (self.tex_ext.upper() != ".RNW"):
sublime.error_message("%s is not a TeX or Rnw source file: cannot compile." % (os.path.basename(view.file_name()),))
return
Then look for a line like
os.chdir(tex_dir)
CmdThread(self).start()
print threading.active_count()
and replace it with
os.chdir(tex_dir)
if self.tex_ext.upper() == ".RNW":
# Run Rscript -e "library(knitr); knit('" + self.file_name + "')"
os.system("Rscript -e \"library(knitr); knit('"+ self.file_name +"')\"")
self.file_name = self.tex_base + ".tex"
self.tex_ext = ".tex"
CmdThread(self).start()
print threading.active_count()
The last patch is to the file jumpToPDF.py
look for a line
if texExt.upper() != ".TEX":
sublime.error_message("%s is not a TeX source file: cannot jump." % (os.path.basename(view.fileName()),))
return
and replace it with
if (texExt.upper() != ".TEX") and (texExt.upper() != ".RNW"):
sublime.error_message("%s is not a TeX or Rnw source file: cannot jump." % (os.path.basename(view.fileName()),))
return
Good luck!
Thanks for the detailed description of the required changes Herberto!
I just went ahead and changed the mentioned files. Everything works like a charm! One thing is though, not sure if it is required, but I recompiled both python files to .pyc after editing them.
python -m py_compile makePDF.py
does the job. Should anyone run into an "invalid syntax error" at the line
print threading.active_count()
while recompiling, just replace it with:
print(threading.active_count())
Also, since the log parser of LaTeXTools only displays errors from the log files, we might be interested to see the knitr output as well. You can store it in a separate log file by replacing:
os.system("Rscript -e \"library(knitr); knit('"+ self.file_name +"')\"")
with:
knitcmd = "/usr/bin/Rscript -e \"library(knitr); knit('"+ self.file_name +"')\""
process = subprocess.Popen(knitcmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
#Launch the shell command:
knit_output, knit_error = process.communicate()
#store results in a log
knit_log = open(self.tex_base + "_knitrbuild.log", "w")
knit_log.write(knit_output)
knit_log.write(knit_error)
knit_log.close()
Before I was using a simple bash script to build the documents (Mac specific):
#!/bin/bash
[ $# -eq 0 ] && { echo "Usage: $0 file.Rnw for knitting"; exit 1; }
rnw="library(knitr);knit("\'"$1.Rnw"\'")"
echo "Rscript executing:" $rnw
tex="$1.tex"
pdf="$1.pdf"
Rscript -e $rnw && pdflatex $tex && pdflatex $tex && open -a Preview $pdf
retval=$?
[ $retval -eq 0 ] && echo "$rnw knitted and $pdf ready"
but being able to customize LaTeXTools and run it directly from ST2 with Skim support is very nice.
Is there any reasons why you wouldn't want to add the changes you outlined directly into your package source? (maybe my it's only my version that's too old.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With