tinytex/0000755000176200001440000000000013607256622011767 5ustar liggesuserstinytex/NAMESPACE0000644000176200001440000000117013607251460013200 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(copy_tinytex) export(install_tinytex) export(latexmk) export(lualatex) export(parse_packages) export(pdflatex) export(r_texmf) export(reinstall_tinytex) export(tinytex_root) export(tl_pkgs) export(tl_sizes) export(tlmgr) export(tlmgr_conf) export(tlmgr_install) export(tlmgr_path) export(tlmgr_remove) export(tlmgr_search) export(tlmgr_update) export(uninstall_tinytex) export(use_tinytex) export(xelatex) import(stats) import(tools) import(utils) importFrom(xfun,is_linux) importFrom(xfun,is_macos) importFrom(xfun,is_unix) importFrom(xfun,is_windows) importFrom(xfun,with_ext) tinytex/LICENSE0000644000176200001440000000007613607164264012777 0ustar liggesusersYEAR: 2017-2020 COPYRIGHT HOLDER: Yihui Xie and RStudio, Inc. tinytex/README.md0000644000176200001440000000423513564425227013253 0ustar liggesusers# TinyTeX [![Build Status](https://travis-ci.org/yihui/tinytex.svg)](https://travis-ci.org/yihui/tinytex) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/yihui/tinytex?svg=true&branch=master)](https://ci.appveyor.com/project/yihui/tinytex) [![Coverage status](https://codecov.io/gh/yihui/tinytex/branch/master/graph/badge.svg)](https://codecov.io/github/yihui/tinytex?branch=master) [![Downloads from the RStudio CRAN mirror](https://cranlogs.r-pkg.org/badges/tinytex)](https://cran.r-project.org/package=tinytex) tinytex logo The installation and maintenance of LaTeX have bothered me for several years. Yes, there are MiKTeX, MacTeX, and TeX Live, but the common problems are: 1. You have to either install a basic version that is relatively small (several hundred MB) but basically doesn't work, because it is very likely that certain frequently used LaTeX packages are missing; or you install the full version that is several GB, but in your whole life, you probably will only use 1% of the packages. 2. The documentation for installation and maintenance is often way too long for beginners. For example, I doubt if anyone has the courage or patience to read [the `tlmgr` manual](https://www.tug.org/texlive/doc/tlmgr.html) (yes, it is very useful). I believe these problems can be solved by TinyTeX, a custom LaTeX distribution based on TeX Live that is small in size (about 150Mb) but still functions well in most cases. Even if you run into the problem of missing LaTeX packages, it should be super clear to you what you need to do. The manual should be at most two pages long. In fact, if you are an R Markdown user, there is nothing you need to do, because missing packages will just be installed automatically. You may not even know the existence of LaTeX at all since it should rarely bother you. This repo contains the installation scripts of TinyTeX (under the `tools` directory) and the R companion package **tinytex**. Please see the full documentation at . Obviously I hope it is not too long. tinytex/man/0000755000176200001440000000000013564425227012543 5ustar liggesuserstinytex/man/tl_sizes.Rd0000644000176200001440000000106713551404710014660 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tlmgr.R \name{tl_sizes} \alias{tl_sizes} \title{Sizes of LaTeX packages in TeX Live} \usage{ tl_sizes(show_total = TRUE) } \arguments{ \item{show_total}{Whether to show the total size.} } \value{ A data frame of three columns: \code{package} is the package names, \code{size} is the sizes in bytes, and \code{size_h} is the human-readable version of sizes. } \description{ Use the command \command{tlmgr info --list --only-installed} to obtain the sizes of installed LaTeX packages. } tinytex/man/tlmgr.Rd0000644000176200001440000000763013607164632014163 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tlmgr.R \name{tlmgr} \alias{tlmgr} \alias{tlmgr_search} \alias{tlmgr_install} \alias{tlmgr_remove} \alias{tlmgr_update} \alias{tlmgr_path} \alias{tlmgr_conf} \title{Run the TeX Live Manager} \usage{ tlmgr(args = character(), usermode = FALSE, ..., .quiet = FALSE) tlmgr_search(what, file = TRUE, all = FALSE, global = TRUE, word = FALSE, ...) tlmgr_install( pkgs = character(), usermode = FALSE, path = !usermode && os != "windows", ... ) tlmgr_remove(pkgs = character(), usermode = FALSE) tlmgr_update( all = TRUE, self = TRUE, more_args = character(), usermode = FALSE, run_fmtutil = TRUE, ... ) tlmgr_path(action = c("add", "remove")) tlmgr_conf(more_args = character()) } \arguments{ \item{args}{A character vector of arguments to be passed to the command \command{tlmgr}.} \item{usermode}{(For expert users only) Whether to use TeX Live's \href{https://www.tug.org/texlive/doc/tlmgr.html#USER-MODE}{user mode}. If \code{TRUE}, you must have run \code{tlmgr('init-usertree')} once before. This option allows you to manage a user-level texmf tree, e.g., install a LaTeX package to your home directory instead of the system directory, to which you do not have write permission. This option should not be needed on personal computers, and has some limitations, so please read the \pkg{tlmgr} manual very carefully before using it.} \item{...}{For \code{tlmgr()}, additional arguments to be passed to \code{\link{system2}()} (e.g., \code{stdout = TRUE} to capture stdout). For other functions, arguments to be passed to \code{tlmgr()}.} \item{.quiet}{Whether to hide the actual command before executing it.} \item{what}{A search keyword as a (Perl) regular expression.} \item{file}{Whether to treat \code{what} as a filename (pattern).} \item{all}{For \code{tlmgr_search()}, whether to search in everything, including package names, descriptions, and filenames. For \code{tlmgr_update()}, whether to update all installed packages.} \item{global}{Whether to search the online TeX Live Database or locally.} \item{word}{Whether to restrict the search of package names and descriptions to match only full words.} \item{pkgs}{A character vector of LaTeX package names.} \item{path}{Whether to run \code{tlmgr_path('add')} after installing packages (\code{path = TRUE} is a conservative default: it is only necessary to do this after a binary package is installed, such as the \pkg{metafont} package, which contains the executable \command{mf}, but it does not hurt even if no binary packages were installed).} \item{self}{Whether to update the TeX Live Manager itself.} \item{more_args}{A character vector of more arguments to be passed to the command \command{tlmgr update} or \command{tlmgr conf}.} \item{run_fmtutil}{Whether to run \command{fmtutil-sys --all} to (re)create format and hyphenation files after updating \pkg{tlmgr}.} \item{action}{On Unix, add/remove symlinks of binaries to/from the system's \code{PATH}. On Windows, add/remove the path to the TeXLive binary directory to/from the system environment variable \code{PATH}.} } \description{ Execute the \command{tlmgr} command to search for LaTeX packages, install packages, update packages, and so on. } \details{ The \code{tlmgr()} function is a wrapper of \code{system2('tlmgr')}. All other \code{tlmgr_*()} functions are based on \code{tlmgr} for specific tasks. Please consult the \pkg{tlmgr} manual for full details. } \examples{ # search for a package that contains titling.sty tlmgr_search('titling.sty') #' to match titling.sty exactly, add a slash before the keyword, e.g. #' tlmgr_search('/titling.sty') #' use a regular expression if you want to be more precise, e.g. #' tlmgr_search('/titling\\.sty$') # list all installed LaTeX packages tlmgr(c('info', '--list', '--only-installed', '--data', 'name')) } \references{ The \pkg{tlmgr} manual: \url{https://www.tug.org/texlive/doc/tlmgr.html} } tinytex/man/copy_tinytex.Rd0000644000176200001440000000266113564425227015575 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/install.R \name{copy_tinytex} \alias{copy_tinytex} \alias{use_tinytex} \title{Copy TinyTeX to another location and use it in another system} \usage{ copy_tinytex( from = tinytex_root(), to = select_dir("Select Destination Directory") ) use_tinytex(from = select_dir("Select TinyTeX Directory")) } \arguments{ \item{from}{The root directory of the TinyTeX installation. For \code{copy_tinytex()}, the default value \code{tinytex_root()} should be a reasonable guess if you installed TinyTeX via \code{install_tinytex()}. For \code{use_tinytex()}, if \code{from} is not provided, a dialog for choosing the directory interactively will pop up.} \item{to}{The destination directory where you want to make a copy of TinyTeX. Like \code{from} in \code{use_tinytex()}, a dialog will pop up if \code{to} is not provided in \code{copy_tinytex()}.} } \description{ The function \code{copy_tinytex()} copies the existing TinyTeX installation to another directory (e.g., a portable device like a USB stick). The function \code{use_tinytex()} runs \command{tlmgr path add} to add the copy of TinyTeX in an existing folder to the \code{PATH} variable of the current system, so that you can use utilities such as \command{tlmgr} and \command{pdflatex}, etc. } \note{ You can only copy TinyTeX and use it in the same system, e.g., the Windows version of TinyTeX only works on Windows. } tinytex/man/r_texmf.Rd0000644000176200001440000000205213551414541014466 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tlmgr.R \name{r_texmf} \alias{r_texmf} \title{Add/remove R's texmf tree to/from TeX Live} \usage{ r_texmf(action = c("add", "remove")) } \arguments{ \item{action}{Add/remove R's texmf tree to/from TeX Live.} } \description{ R ships a custom texmf tree containing a few LaTeX style and class files, which are required when compiling R packages manuals (\file{Rd.sty}) or Sweave documents (\file{Sweave.sty}). This tree can be found under the directory \code{file.path(R.home('share'), 'texmf')}. This function can be used to add/remove R's texmf tree to/from TeX Live via \code{\link{tlmgr_conf}('auxtrees')}. } \examples{ r_texmf('remove') r_texmf('add') # all files under R's texmf tree list.files(file.path(R.home('share'), 'texmf'), recursive = TRUE, full.names = TRUE) } \references{ See the \pkg{tlmgr} manual for detailed information about \command{tlmgr conf auxtrees}. Check out \url{https://tex.stackexchange.com/q/77720/9128} if you don't know what \code{texmf} means. } tinytex/man/parse_packages.Rd0000644000176200001440000000260313564425227016003 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/latex.R \name{parse_packages} \alias{parse_packages} \title{Find missing LaTeX packages from a LaTeX log file} \usage{ parse_packages( log, text = readLines(log), files = detect_files(text), quiet = rep(FALSE, 3) ) } \arguments{ \item{log}{Path to the LaTeX log file (typically named \file{*.log}).} \item{text}{A character vector of the error log (read from the file provided by the \code{log} argument by default).} \item{files}{A character vector of names of the missing files (automatically detected from the \code{log} by default).} \item{quiet}{Whether to suppress messages when finding packages. It should be a logical vector of length 3: the first element indicates whether to suppress the message when no missing LaTeX packages could be detected from the log, the second element indicate whether to suppress the message when searching for packages via \code{tlmgr_search()}, and the third element indicates whether to warn if no packages could be found via \code{tlmgr_search()}.} } \value{ A character vector of LaTeX package names. } \description{ Analyze the error messages in a LaTeX log file to figure out the names of missing LaTeX packages that caused the errors. These packages can be installed via \code{\link{tlmgr_install}()}. Searching for missing packages is based on \code{\link{tlmgr_search}()}. } tinytex/man/install_tinytex.Rd0000644000176200001440000000406313564425227016267 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/install.R \name{install_tinytex} \alias{install_tinytex} \alias{uninstall_tinytex} \alias{reinstall_tinytex} \alias{tinytex_root} \title{Install/Uninstall TinyTeX} \usage{ install_tinytex( force = FALSE, dir = "auto", repository = "ctan", extra_packages = NULL ) uninstall_tinytex(force = FALSE, dir = tinytex_root()) reinstall_tinytex(packages = TRUE, dir = tinytex_root(), ...) tinytex_root() } \arguments{ \item{force}{Whether to force to install (override) or uninstall TinyTeX.} \item{dir}{The directory to install or uninstall TinyTeX (should not exist unless \code{force = TRUE}).} \item{repository}{The CTAN repository to be used. By default, a fast mirror is automatically chosen. You can manually set one if the automatic mirror is not really fast enough, e.g., if you are in China, you may consider \code{'http://mirrors.tuna.tsinghua.edu.cn/CTAN/'}, or if you are in the midwest in the US, you may use \code{'https://mirror.las.iastate.edu/tex-archive/'}. You can find the full list of mirrors at \url{https://ctan.org/mirrors}.} \item{extra_packages}{A character vector of extra LaTeX packages to be installed.} \item{packages}{Whether to reinstall all currently installed packages.} \item{...}{Other arguments to be passed to \code{install_tinytex()} (note that the \code{extra_packages} argument will be set to \code{tl_pkgs()} if \code{packages = TRUE}).} } \description{ The function \code{install_tinytex()} downloads the installation script from \url{https://github.com/yihui/tinytex} according to the platform (Unix or Windows), and executes it to install TinyTeX (a custom LaTeX distribution based on TeX Live). The function \code{uninstall_tinytex()} removes TinyTeX; \code{reinstall_tinytex()} reinstalls TinyTeX as well as previously installed LaTeX packages by default; \code{tinytex_root()} returns the root directory of TinyTeX. } \references{ See the TinyTeX documentation (\url{https://yihui.org/tinytex/}) for the default installation directories on different platforms. } tinytex/man/tl_pkgs.Rd0000644000176200001440000000076513551404710014473 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/tlmgr.R \name{tl_pkgs} \alias{tl_pkgs} \title{List the names of installed TeX Live packages} \usage{ tl_pkgs() } \value{ A character vector of package names. } \description{ Calls \command{tlmgr info --list --only-installed --data name} to obtain the names of all installed TeX Live packages. Platform-specific strings in package names are removed, e.g., \code{"tex"} is returned for the package \pkg{tex.x86_64-darwin}. } tinytex/man/latexmk.Rd0000644000176200001440000001052513564425227014502 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/latex.R \name{latexmk} \alias{latexmk} \alias{pdflatex} \alias{xelatex} \alias{lualatex} \title{Compile a LaTeX document} \usage{ latexmk( file, engine = c("pdflatex", "xelatex", "lualatex", "latex"), bib_engine = c("bibtex", "biber"), engine_args = NULL, emulation = TRUE, min_times = 1, max_times = 10, install_packages = emulation && tlmgr_available(), pdf_file = gsub("tex$", "pdf", file), clean = TRUE ) pdflatex(...) xelatex(...) lualatex(...) } \arguments{ \item{file}{A LaTeX file path.} \item{engine}{A LaTeX engine (can be set in the global option \code{tinytex.engine}, e.g., \code{options(tinytex.engine = 'xelatex')}).} \item{bib_engine}{A bibliography engine (can be set in the global option \code{tinytex.bib_engine}).} \item{engine_args}{Command-line arguments to be passed to \code{engine} (can be set in the global option \code{tinytex.engine_args}, e.g., \code{options(tinytex.engine_args = '-shell-escape'}).} \item{emulation}{Whether to emulate the executable \command{latexmk} using R.} \item{min_times, max_times}{The minimum and maximum number of times to rerun the LaTeX engine when using emulation. You can set the global options \code{tinytex.compile.min_times} or \code{tinytex.compile.max_times}, e.g., \code{options(tinytex.compile.max_times = 3)}.} \item{install_packages}{Whether to automatically install missing LaTeX packages found by \code{\link{parse_packages}()} from the LaTeX log. This argument is only for the emulation mode and TeX Live.} \item{pdf_file}{Path to the PDF output file. By default, it is under the same directory as the input \code{file} and also has the same base name. When \code{engine == 'latex'}, this will be a DVI file.} \item{clean}{Whether to clean up auxiliary files after compilation (can be set in the global option \code{tinytex.clean}, which defaults to \code{TRUE}).} \item{...}{Arguments to be passed to \code{latexmk()} (other than \code{engine} and \code{emulation}).} } \value{ A character string of the path of the output file (i.e., the value of the \code{pdf_file} argument). } \description{ The function \code{latexmk()} emulates the system command \command{latexmk} (\url{https://ctan.org/pkg/latexmk}) to compile a LaTeX document. The functions \code{pdflatex()}, \code{xelatex()}, and \code{lualatex()} are wrappers of \code{latexmk(engine =, emulation = TRUE)}. } \details{ The \command{latexmk} emulation works like this: run the LaTeX engine once (e.g., \command{pdflatex}), run \command{makeindex} to make the index if necessary (the \file{*.idx} file exists), run the bibliography engine \command{bibtex} or \command{biber} to make the bibliography if necessary (the \file{*.aux} or \file{*.bcf} file exists), and finally run the LaTeX engine a number of times (the maximum is 10 by default) to resolve all cross-references. If \code{emulation = FALSE}, you need to make sure the executable \command{latexmk} is available in your system, otherwise \code{latexmk()} will fall back to \code{emulation = TRUE}. You can set the global option \code{options(tinytex.latexmk.emulation = FALSE)} to always avoid emulation (i.e., always use the executable \command{latexmk}). The default command to generate the index (if necessary) is \command{makeindex}. To change it to a different command (e.g., \command{zhmakeindex}), you may set the global option \code{tinytex.makeindex}. To pass additional command-line arguments to the command, you may set the global option \code{tinytex.makeindex.args} (e.g., \code{options(tinytex.makeindex = 'zhmakeindex', tinytex.makeindex.args = c('-z', 'pinyin'))}). If you are using the LaTeX distribution TinyTeX, but its path is not in the \code{PATH} variable of your operating system, you may set the global option \code{tinytex.tlmgr.path} to the full path of the executable \command{tlmgr}, so that \code{latexmk()} knows where to find executables like \command{pdflatex}. For example, if you are using Windows and your TinyTeX is on an external drive \file{Z:/} under the folder \file{TinyTeX}, you may set \code{options(tinytex.tlmgr.path = "Z:/TinyTeX/bin/win32/tlmgr.bat")}. Usually you should not need to set this option because TinyTeX can add itself to the \code{PATH} variable during installation or via \code{\link{use_tinytex}()}. In case both methods fail, you can use this manual approach. } tinytex/DESCRIPTION0000644000176200001440000000243613607256622013502 0ustar liggesusersPackage: tinytex Type: Package Title: Helper Functions to Install and Maintain 'TeX Live', and Compile 'LaTeX' Documents Version: 0.19 Authors@R: c( person("Yihui", "Xie", role = c("aut", "cre", "cph"), email = "xie@yihui.name", comment = c(ORCID = "0000-0003-0645-5666")), person(family = "RStudio, Inc.", role = "cph"), person("Fernando", "Cagua", role = "ctb"), person("Ethan", "Heinzen", role = "ctb"), person() ) Description: Helper functions to install and maintain the 'LaTeX' distribution named 'TinyTeX' (), a lightweight, cross-platform, portable, and easy-to-maintain version of 'TeX Live'. This package also contains helper functions to compile 'LaTeX' documents, and install missing 'LaTeX' packages automatically. Imports: xfun (>= 0.5) Suggests: testit, rstudioapi License: MIT + file LICENSE URL: https://github.com/yihui/tinytex BugReports: https://github.com/yihui/tinytex/issues Encoding: UTF-8 LazyData: true RoxygenNote: 7.0.2 NeedsCompilation: no Packaged: 2020-01-14 05:35:47 UTC; yihui Author: Yihui Xie [aut, cre, cph] (), RStudio, Inc. [cph], Fernando Cagua [ctb], Ethan Heinzen [ctb] Maintainer: Yihui Xie Repository: CRAN Date/Publication: 2020-01-14 06:20:02 UTC tinytex/tests/0000755000176200001440000000000013357673762013143 5ustar liggesuserstinytex/tests/test-travis.R0000644000176200001440000000020413211546311015521 0ustar liggesusers# run tests on Travis (these tests depend on TeX Live) if (!is.na(Sys.getenv('CI', NA))) testit::test_pkg('tinytex', 'test-travis') tinytex/tests/test-cran.R0000644000176200001440000000005113211546267015146 0ustar liggesuserstestit::test_pkg('tinytex', 'test-cran') tinytex/tests/test-travis/0000755000176200001440000000000013607256622015416 5ustar liggesuserstinytex/tests/test-travis/test-tlmgr.R0000644000176200001440000000074013211554120017625 0ustar liggesuserslibrary(testit) assert('tlmgr is available', { tlmgr_available() }) assert('tlmgr_search() searches the online TeX Live database', { res = tlmgr_search('/framed', stdout = TRUE) ('framed:' %in% res) (any(grepl('/framed[.]sty$', res))) }) assert('`tlmgr info` can list the installed packages', { res = tlmgr(c('info', '--list', '--only-installed', '--data', 'name'), stdout = TRUE) # only check a few basic packages (c('xetex', 'luatex', 'graphics') %in% res) }) tinytex/tests/test-cran/0000755000176200001440000000000013607256622015031 5ustar liggesuserstinytex/tests/test-cran/test-latex.R0000644000176200001440000000241313607161407017242 0ustar liggesuserslibrary(testit) assert('detect_files() can detect filenames from LaTeX log', { (length(detect_files("asdf qwer")) == 0) (detect_files("! LaTeX Error: File `framed.sty' not found.") %==% 'framed.sty') (detect_files("/usr/local/bin/mktexpk: line 123: mf: command not found") %==% 'mf') (grepl('^psyr\\[\\.\\]', detect_files("! Font U/psy/m/n/10=psyr at 10.0pt not loadable: Metric (TFM) file not found"))) (grepl('^FandolSong-Regular\\[\\.\\]', detect_files('! The font "FandolSong-Regular" cannot be found.'))) (grepl('^tcrm0700\\[\\.\\]', detect_files('!pdfTeX error: /usr/local/bin/pdflatex (file tcrm0700): Font tcrm0700 at 600 not found'))) (detect_files("or the language definition file ngerman.ldf was not found") %==% 'ngerman.ldf') (detect_files("!pdfTeX error: pdflatex (file 8r.enc): cannot open encoding file for reading") %==% '8r.enc') (detect_files("! CTeX fontset `fandol' is unavailable in current mode") %==% 'fandol') (detect_files('Package widetext error: Install the flushend package which is a part of sttools') %==% 'flushend.sty') (detect_files('! Package isodate.sty Error: Package file substr.sty not found.') %==% 'substr.sty') (detect_files("! Package fontenc Error: Encoding file `t2aenc.def' not found.") %==% 't2aenc.def') }) tinytex/R/0000755000176200001440000000000013572476470012176 5ustar liggesuserstinytex/R/install.R0000644000176200001440000003702213600167077013763 0ustar liggesusers#' Install/Uninstall TinyTeX #' #' The function \code{install_tinytex()} downloads the installation script from #' \url{https://github.com/yihui/tinytex} according to the platform (Unix or #' Windows), and executes it to install TinyTeX (a custom LaTeX distribution #' based on TeX Live). The function \code{uninstall_tinytex()} removes TinyTeX; #' \code{reinstall_tinytex()} reinstalls TinyTeX as well as previously installed #' LaTeX packages by default; \code{tinytex_root()} returns the root directory #' of TinyTeX. #' @param force Whether to force to install (override) or uninstall TinyTeX. #' @param dir The directory to install or uninstall TinyTeX (should not exist #' unless \code{force = TRUE}). #' @param repository The CTAN repository to be used. By default, a fast mirror #' is automatically chosen. You can manually set one if the automatic mirror #' is not really fast enough, e.g., if you are in China, you may consider #' \code{'http://mirrors.tuna.tsinghua.edu.cn/CTAN/'}, or if you are in the #' midwest in the US, you may use #' \code{'https://mirror.las.iastate.edu/tex-archive/'}. You can find the full #' list of mirrors at \url{https://ctan.org/mirrors}. #' @param extra_packages A character vector of extra LaTeX packages to be #' installed. #' @references See the TinyTeX documentation (\url{https://yihui.org/tinytex/}) #' for the default installation directories on different platforms. #' @export install_tinytex = function( force = FALSE, dir = 'auto', repository = 'ctan', extra_packages = NULL ) { if (!is.logical(force)) stop('The argument "force" must take a logical value.') check_dir = function(dir) { if (dir_exists(dir) && !force) stop( 'The directory "', dir, '" exists. Please either delete it, ', 'or use install_tinytex(force = TRUE).' ) } user_dir = '' if (!(dir %in% c('', 'auto'))) { dir = gsub('[/\\]+$', '', dir) # remove trailing slashes check_dir(dir) unlink(dir, recursive = TRUE) user_dir = normalizePath(dir, mustWork = FALSE) } tweak_path() msg = if (tlmgr_available()) { system2('tlmgr', '--version') c( 'Detected an existing tlmgr at ', Sys.which('tlmgr'), '. ', 'It seems TeX Live has been installed (check tinytex::tinytex_root()). ' ) } else if (Sys.which('pdftex') != '') { system2('pdftex', '--version') c( 'Detected an existing LaTeX distribution (e.g., pdftex is at ', Sys.which('pdftex'), '). ' ) } if (length(msg)) warning( msg, 'You are recommended to uninstall it, although TinyTeX should work well alongside ', 'another LaTeX distribution if a LaTeX document is compiled through tinytex::latexmk().', call. = FALSE ) owd = setwd(tempdir()) on.exit({ unlink(c('install-unx.sh', 'install-tl.zip', 'pkgs-custom.txt', 'tinytex.profile')) setwd(owd) p = Sys.which('tlmgr') if (os == 'windows') message( 'Please quit and reopen your R session and IDE (if you are using one, such ', 'as RStudio or Emacs) and check if tinytex:::is_tinytex() is TRUE.' ) else if (!is_tinytex()) warning( 'TinyTeX was not successfully installed or configured.', if (p != '') c(' tlmgr was found at ', p) else { c('Your PATH variable is ', Sys.getenv('PATH')) }, '. See https://yihui.org/tinytex/faq/ for more information.' ) }, add = TRUE) add_texmf = function(bin) { system2(bin, c('conf', 'auxtrees', 'add', r_texmf_path())) } https = grepl('^https://', repository) repository = sub('/+$', '', repository) if ((not_ctan <- repository != 'ctan') && !grepl('/tlnet$', repository)) { repository = paste0(repository, '/systems/texlive/tlnet') } if ((texinput <- Sys.getenv('TEXINPUT')) != '') message( 'Your environment variable TEXINPUT is "', texinput, '". Normally you should not set this variable, because it may lead to issues like ', 'https://github.com/yihui/tinytex/issues/92.' ) switch( os, 'unix' = { macos = Sys.info()[['sysname']] == 'Darwin' downloader = if (macos) 'curl' else 'wget' if (Sys.which(downloader) == '') stop(sprintf( "'%s' is not found but required to install TinyTeX", downloader ), call. = FALSE) if (macos && file.access('/usr/local/bin', 2) != 0) { chown_cmd = 'chown -R `whoami`:admin /usr/local/bin' message( 'The directory /usr/local/bin is not writable. I recommend that you ', 'make it writable. See https://github.com/yihui/tinytex/issues/24 for more info.' ) if (system(sprintf( "/usr/bin/osascript -e 'do shell script \"%s\" with administrator privileges'", chown_cmd )) != 0) warning( "Please run this command in your Terminal (password required):\n sudo ", chown_cmd, call. = FALSE ) } if (!macos && dir_exists('~/bin')) on.exit(message( 'You may have to restart your system after installing TinyTeX to make sure ', '~/bin appears in your PATH variable (https://github.com/yihui/tinytex/issues/16).' ), add = TRUE) if (not_ctan) { Sys.setenv(CTAN_REPO = repository) on.exit(Sys.unsetenv('CTAN_REPO'), add = TRUE) } download_file('https://yihui.org/gh/tinytex/tools/install-unx.sh') res = system2('sh', c( 'install-unx.sh', if (not_ctan) c( '--no-admin', '--path', shQuote(repository), if (macos && https) 'tlgpg' ) )) if (res != 0) stop('Failed to install TinyTeX', call. = FALSE) target = normalizePath( if (macos) '~/Library/TinyTeX' else '~/.TinyTeX' ) if (!dir_exists(target)) stop('Failed to install TinyTeX.') if (!user_dir %in% c('', target)) { dir.create(dirname(user_dir), showWarnings = FALSE, recursive = TRUE) dir_rename(target, user_dir) target = user_dir } bin = file.path(list.files(file.path(target, 'bin'), full.names = TRUE), 'tlmgr') system2(bin, c('path', 'add')) if (length(extra_packages)) system2(bin, c('install', extra_packages)) add_texmf(bin) message('TinyTeX installed to ', target) }, 'windows' = { target = if (user_dir == '') win_app_dir('TinyTeX') else user_dir unlink('install-tl-*', recursive = TRUE) download_file(paste0( if (repository == 'ctan') 'http://mirror.ctan.org/systems/texlive/tlnet' else repository, '/install-tl.zip' ), mode = 'wb') download_file('https://yihui.org/gh/tinytex/tools/pkgs-custom.txt') pkgs_custom = readLines('pkgs-custom.txt') download_file('https://yihui.org/gh/tinytex/tools/tinytex.profile') x = readLines('tinytex.profile') writeLines(gsub('./', './TinyTeX/', x, fixed = TRUE), 'tinytex.profile') unzip('install-tl.zip') in_dir(list.files('.', '^install-tl-.*'), { message('Starting to install TinyTeX to ', target, '. It will take a few minutes.') (if (interactive()) function(msg) utils::winDialog('ok', msg) else message)(paste0( 'Next you may see two error dialog boxes about the missing luatex.dll, ', 'and an error message like "Use of uninitialized value in bitwise or (|)..." in the end. ', 'These messages can be ignored.' )) bat = readLines('install-tl-windows.bat') # never PAUSE (no way to interact with the Windows shell from R) writeLines( grep('^pause\\s*$', bat, ignore.case = TRUE, invert = TRUE, value = TRUE), 'install-tl-windows.bat' ) shell('install-tl-windows.bat -no-gui -profile=../tinytex.profile', invisible = FALSE) file.remove('TinyTeX/install-tl.log') dir.create(target, showWarnings = FALSE, recursive = TRUE) file.copy(list.files('TinyTeX', full.names = TRUE), target, recursive = TRUE) }) unlink('install-tl-*', recursive = TRUE) in_dir(target, { bin_tlmgr = file.path('bin', 'win32', 'tlmgr') tlmgr = function(...) system2(bin_tlmgr, ...) if (not_ctan) { tlmgr(c('option', 'repository', shQuote(repository))) if (https) tlmgr(c('--repository', 'http://www.preining.info/tlgpg/', 'install', 'tlgpg')) if (tlmgr(c('update', '--list')) != 0) { warning('The repository ', repository, ' does not seem to be accessible. Reverting to the default CTAN mirror.') tlmgr(c('option', 'repository', 'ctan')) } } tlmgr(c('install', 'latex-bin', 'xetex', pkgs_custom, extra_packages)) tlmgr(c('path', 'add')) add_texmf(bin_tlmgr) }) message('TinyTeX installed to ', target) }, stop('This platform is not supported.') ) } #' @rdname install_tinytex #' @export uninstall_tinytex = function(force = FALSE, dir = tinytex_root()) { tweak_path() if (dir == '') stop('TinyTeX does not seem to be installed.') if (!is_tinytex() && !force) stop( 'Detected TeX Live at "', dir, '", but it appears to be TeX Live instead of TinyTeX. ', 'To uninstall TeX Live, use the argument force = TRUE.' ) r_texmf('remove') tlmgr_path('remove') unlink(dir, recursive = TRUE) } #' @param packages Whether to reinstall all currently installed packages. #' @param ... Other arguments to be passed to \code{install_tinytex()} (note #' that the \code{extra_packages} argument will be set to \code{tl_pkgs()} if #' \code{packages = TRUE}). #' @rdname install_tinytex #' @export reinstall_tinytex = function(packages = TRUE, dir = tinytex_root(), ...) { pkgs = if (packages) tl_pkgs() if (length(pkgs)) message( 'If reinstallation fails, try install_tinytex() again. Then ', 'install the following packages:\n\ntinytex::tlmgr_install(c(', paste('"', pkgs, '"', sep = '', collapse = ', '), '))\n' ) # in theory, users should not touch the texmf-local dir; if they did, I'll try # to preserve it during reinstall: https://github.com/yihui/tinytex/issues/117 if (length(list.files(texmf <- file.path(dir, 'texmf-local'), recursive = TRUE)) > 0) { dir.create(texmf_tmp <- tempfile(), recursive = TRUE) message( 'The directory ', texmf, ' is not empty. It will be backed up to ', texmf_tmp, ' and restored later.\n' ) file.copy(texmf, texmf_tmp, recursive = TRUE) on.exit( file.copy(file.path(texmf_tmp, basename(texmf)), dirname(texmf), recursive = TRUE), add = TRUE ) } uninstall_tinytex() install_tinytex(extra_packages = pkgs, dir = dir, ...) } win_app_dir = function(..., error = TRUE) { d = Sys.getenv('APPDATA') if (d == '') { if (error) stop('Environment variable "APPDATA" not set.') return(d) } file.path(d, ...) } #' @rdname install_tinytex #' @export tinytex_root = function() { tweak_path() path = Sys.which('tlmgr') if (path == '') return('') root_dir = function(path, ...) { dir = normalizePath(file.path(dirname(path), ...), mustWork = TRUE) if (!'bin' %in% list.files(dir)) stop( dir, ' does not seem to be the root directory of TeX Live (no "bin/" dir under it)' ) dir } if (os == 'windows') return(root_dir(path, '..', '..')) if (Sys.readlink(path) == '') stop( 'Cannot figure out the root directory of TeX Live from ', path, ' (not a symlink on ', os, ')' ) path = symlink_root(path) root_dir(normalizePath(path), '..', '..', '..') } # trace a symlink to its final destination symlink_root = function(path) { path = normalizePath(path, mustWork = TRUE) path2 = Sys.readlink(path) if (path2 == '') return(path) # no longer a symlink; must be resolved now # path2 may still be a _relative_ symlink in_dir(dirname(path), symlink_root(path2)) } is_tinytex = function() { gsub('^[.]', '', tolower(basename(tinytex_root()))) == 'tinytex' } in_dir = function(dir, expr) { owd = setwd(dir); on.exit(setwd(owd), add = TRUE) expr } dir_exists = function(path) file_test('-d', path) dir_rename = function(from, to) { # cannot rename '/foo' to '/bar' because of 'Invalid cross-device link' suppressWarnings(file.rename(from, to)) || dir_copy(from, to) } dir_copy = function(from, to) { dir.create(to, showWarnings = FALSE, recursive = TRUE) all(file.copy(list.files(from, full.names = TRUE), to, recursive = TRUE)) && unlink(from, recursive = TRUE) == 0 } download_file = function(...) { xfun::download_file(..., quiet = Sys.getenv('APPVEYOR') != '') } # LaTeX packages that I use install_yihui_pkgs = function() { pkgs = readLines('https://yihui.org/gh/tinytex/tools/pkgs-yihui.txt') tlmgr_install(pkgs) } # install a prebuilt version of TinyTeX install_prebuilt = function() { if (is_windows()) { installer = 'TinyTeX.zip' download_file('https://ci.appveyor.com/api/projects/yihui/tinytex/artifacts/TinyTeX.zip', installer) install_windows_zip(installer) } else if (is_linux()) { system('wget -qO- https://yihui.org/gh/tinytex/tools/download-travis-linux.sh | sh') } else { stop('TinyTeX was not prebuilt for this platform.') } } # if you have already downloaded the zip archive, use this function to install it install_windows_zip = function(path = 'TinyTeX.zip') { unzip(path, exdir = win_app_dir()) tlmgr_path(); texhash(); fmtutil(); updmap(); fc_cache() } #' Copy TinyTeX to another location and use it in another system #' #' The function \code{copy_tinytex()} copies the existing TinyTeX installation #' to another directory (e.g., a portable device like a USB stick). The function #' \code{use_tinytex()} runs \command{tlmgr path add} to add the copy of TinyTeX #' in an existing folder to the \code{PATH} variable of the current system, so #' that you can use utilities such as \command{tlmgr} and \command{pdflatex}, #' etc. #' @param from The root directory of the TinyTeX installation. For #' \code{copy_tinytex()}, the default value \code{tinytex_root()} should be a #' reasonable guess if you installed TinyTeX via \code{install_tinytex()}. For #' \code{use_tinytex()}, if \code{from} is not provided, a dialog for choosing #' the directory interactively will pop up. #' @param to The destination directory where you want to make a copy of TinyTeX. #' Like \code{from} in \code{use_tinytex()}, a dialog will pop up if \code{to} #' is not provided in \code{copy_tinytex()}. #' @note You can only copy TinyTeX and use it in the same system, e.g., the #' Windows version of TinyTeX only works on Windows. #' @export copy_tinytex = function(from = tinytex_root(), to = select_dir('Select Destination Directory')) { if (!dir_exists(from)) stop('TinyTeX does not seem to be installed.') if (length(to) != 1 || !dir_exists(to)) stop("The destination directory '", to, "' does not exist.") file.copy(from, to, recursive = TRUE) } #' @rdname copy_tinytex #' @export use_tinytex = function(from = select_dir('Select TinyTeX Directory')) { if (length(from) != 1) stop('Please provide a valid path to the TinyTeX directory.') d = list.files(file.path(from, 'bin'), full.names = TRUE) d = d[dir_exists(d)] if (length(d) != 1) stop("The directory '", from, "' does not contain TinyTeX.") p = file.path(d, 'tlmgr') if (os == 'windows') p = paste0(p, '.bat') if (system2(p, c('path', 'add')) != 0) stop( "Failed to add '", d, "' to your system's environment variable PATH. You may ", "consider the fallback approach, i.e., set options(tinytex.tlmgr.path = '", p, "')." ) message('Restart R and your editor and check if tinytex::tinytex_root() points to ', from) } select_dir = function(caption = 'Select Directory') { d = tryCatch(rstudioapi::selectDirectory(caption), error = function(e) { if (os == 'windows') utils::choose.dir(caption = caption) else { tcltk::tk_choose.dir(caption = caption) } }) if (!is.null(d) && !is.na(d)) d } tinytex/R/latex.R0000644000176200001440000005610013607166605013433 0ustar liggesusers#' Compile a LaTeX document #' #' The function \code{latexmk()} emulates the system command \command{latexmk} #' (\url{https://ctan.org/pkg/latexmk}) to compile a LaTeX document. The #' functions \code{pdflatex()}, \code{xelatex()}, and \code{lualatex()} are #' wrappers of \code{latexmk(engine =, emulation = TRUE)}. #' #' The \command{latexmk} emulation works like this: run the LaTeX engine once #' (e.g., \command{pdflatex}), run \command{makeindex} to make the index if #' necessary (the \file{*.idx} file exists), run the bibliography engine #' \command{bibtex} or \command{biber} to make the bibliography if necessary #' (the \file{*.aux} or \file{*.bcf} file exists), and finally run the LaTeX #' engine a number of times (the maximum is 10 by default) to resolve all #' cross-references. #' #' If \code{emulation = FALSE}, you need to make sure the executable #' \command{latexmk} is available in your system, otherwise \code{latexmk()} #' will fall back to \code{emulation = TRUE}. You can set the global option #' \code{options(tinytex.latexmk.emulation = FALSE)} to always avoid emulation #' (i.e., always use the executable \command{latexmk}). #' #' The default command to generate the index (if necessary) is #' \command{makeindex}. To change it to a different command (e.g., #' \command{zhmakeindex}), you may set the global option #' \code{tinytex.makeindex}. To pass additional command-line arguments to the #' command, you may set the global option \code{tinytex.makeindex.args} (e.g., #' \code{options(tinytex.makeindex = 'zhmakeindex', tinytex.makeindex.args = #' c('-z', 'pinyin'))}). #' #' If you are using the LaTeX distribution TinyTeX, but its path is not in the #' \code{PATH} variable of your operating system, you may set the global option #' \code{tinytex.tlmgr.path} to the full path of the executable \command{tlmgr}, #' so that \code{latexmk()} knows where to find executables like #' \command{pdflatex}. For example, if you are using Windows and your TinyTeX is #' on an external drive \file{Z:/} under the folder \file{TinyTeX}, you may set #' \code{options(tinytex.tlmgr.path = "Z:/TinyTeX/bin/win32/tlmgr.bat")}. #' Usually you should not need to set this option because TinyTeX can add itself #' to the \code{PATH} variable during installation or via #' \code{\link{use_tinytex}()}. In case both methods fail, you can use this #' manual approach. #' @param file A LaTeX file path. #' @param engine A LaTeX engine (can be set in the global option #' \code{tinytex.engine}, e.g., \code{options(tinytex.engine = 'xelatex')}). #' @param bib_engine A bibliography engine (can be set in the global option #' \code{tinytex.bib_engine}). #' @param engine_args Command-line arguments to be passed to \code{engine} (can #' be set in the global option \code{tinytex.engine_args}, e.g., #' \code{options(tinytex.engine_args = '-shell-escape'}). #' @param emulation Whether to emulate the executable \command{latexmk} using R. #' @param min_times,max_times The minimum and maximum number of times to rerun #' the LaTeX engine when using emulation. You can set the global options #' \code{tinytex.compile.min_times} or \code{tinytex.compile.max_times}, e.g., #' \code{options(tinytex.compile.max_times = 3)}. #' @param install_packages Whether to automatically install missing LaTeX #' packages found by \code{\link{parse_packages}()} from the LaTeX log. This #' argument is only for the emulation mode and TeX Live. #' @param pdf_file Path to the PDF output file. By default, it is under the same #' directory as the input \code{file} and also has the same base name. When #' \code{engine == 'latex'}, this will be a DVI file. #' @param clean Whether to clean up auxiliary files after compilation (can be #' set in the global option \code{tinytex.clean}, which defaults to #' \code{TRUE}). #' @export #' @return A character string of the path of the output file (i.e., the value of #' the \code{pdf_file} argument). latexmk = function( file, engine = c('pdflatex', 'xelatex', 'lualatex', 'latex'), bib_engine = c('bibtex', 'biber'), engine_args = NULL, emulation = TRUE, min_times = 1, max_times = 10, install_packages = emulation && tlmgr_available(), pdf_file = gsub('tex$', 'pdf', file), clean = TRUE ) { if (!grepl('[.]tex$', file)) stop("The input file '", file, "' does not have the .tex extension") file = path.expand(file) if (missing(engine)) engine = getOption('tinytex.engine', engine) engine = gsub('^(pdf|xe|lua)(tex)$', '\\1la\\2', engine) # normalize *tex to *latex engine = match.arg(engine) is_latex = engine == 'latex' tweak_path() if (missing(emulation)) emulation = getOption('tinytex.latexmk.emulation', emulation) if (!emulation) { if (Sys.which('latexmk') == '') { warning('The executable "latexmk" not found in your system') emulation = TRUE } else if (system2_quiet('latexmk', '-v') != 0) { warning('The executable "latexmk" was found but does not work') emulation = TRUE } } if (missing(min_times)) min_times = getOption('tinytex.compile.min_times', min_times) if (missing(max_times)) max_times = getOption('tinytex.compile.max_times', max_times) if (missing(bib_engine)) bib_engine = getOption('tinytex.bib_engine', bib_engine) if (missing(engine_args)) engine_args = getOption('tinytex.engine_args', engine_args) if (missing(clean)) clean = getOption('tinytex.clean', TRUE) pdf = gsub('tex$', if (is_latex) 'dvi' else 'pdf', basename(file)) if (!is.null(output_dir <- getOption('tinytex.output_dir'))) { output_dir_arg = shQuote(paste0(if (emulation) '-', '-output-directory=', output_dir)) if (length(grep(output_dir_arg, engine_args, fixed = TRUE)) == 0) stop( "When you set the global option 'tinytex.output_dir', the argument 'engine_args' ", "must contain this value: ", capture.output(dput(output_dir_arg)) ) pdf = file.path(output_dir, pdf) if (missing(pdf_file)) pdf_file = file.path(output_dir, basename(pdf_file)) } if (is_latex) pdf_file = with_ext(pdf_file, 'dvi') check_pdf = function() { if (!file.exists(pdf)) show_latex_error(file, with_ext(pdf, 'log'), TRUE) file_rename(pdf, pdf_file) pdf_file } if (emulation) { latexmk_emu( file, engine, bib_engine, engine_args, min_times, max_times, install_packages, clean ) return(check_pdf()) } system2_quiet('latexmk', c( '-latexoption=-halt-on-error -interaction=batchmode', if (is_latex) '-latex=latex' else paste0('-pdf -pdflatex=', engine), engine_args, shQuote(file) ), error = { if (install_packages) warning( 'latexmk(install_packages = TRUE) does not work when emulation = FALSE' ) check_latexmk_version() }) if (clean) system2('latexmk', c('-c', engine_args), stdout = FALSE) check_pdf() } #' @param ... Arguments to be passed to \code{latexmk()} (other than #' \code{engine} and \code{emulation}). #' @rdname latexmk #' @export pdflatex = function(...) latexmk(engine = 'pdflatex', emulation = TRUE, ...) #' @rdname latexmk #' @export xelatex = function(...) latexmk(engine = 'xelatex', emulation = TRUE, ...) #' @rdname latexmk #' @export lualatex = function(...) latexmk(engine = 'lualatex', emulation = TRUE, ...) # a quick and dirty version of latexmk (should work reasonably well unless the # LaTeX document is extremely complicated) latexmk_emu = function( file, engine, bib_engine = c('bibtex', 'biber'), engine_args = NULL, min_times = 1, max_times = 10, install_packages = FALSE, clean ) { aux = c( 'log', 'idx', 'aux', 'bcf', 'blg', 'bbl', 'fls', 'out', 'lof', 'lot', 'toc', 'nav', 'snm', 'vrb', 'ilg', 'ind', 'xwm', 'brf', 'run.xml' ) base = gsub('[.]tex$', '', basename(file)) aux_files = setNames(paste(base, aux, sep = '.'), aux) aux_files = c(aux_files, 'preview.aux') # generated by the preview package if (!is.null(output_dir <- getOption('tinytex.output_dir'))) aux_files = file.path(output_dir, aux_files) logfile = aux_files['log']; unlink(logfile) # clean up the log before compilation # clean up aux files from LaTeX compilation files1 = exist_files(aux_files) keep_log = FALSE on.exit({ files2 = exist_files(aux_files) files3 = setdiff(files2, files1) if (keep_log || length(latex_warning(logfile, TRUE))) files3 = setdiff(files3, logfile) if (clean) unlink(files3) }, add = TRUE) pkgs_last = character() filep = sub('.log$', if (engine == 'latex') '.dvi' else '.pdf', logfile) verbose = getOption('tinytex.verbose', FALSE) run_engine = function() { on_error = function() { if (install_packages && file.exists(logfile)) { pkgs = parse_packages(logfile, quiet = !verbose) if (length(pkgs) && !identical(pkgs, pkgs_last)) { if (verbose) message('Trying to automatically install missing LaTeX packages...') if (tlmgr_install(pkgs, .quiet = !verbose) == 0) { pkgs_last <<- pkgs return(run_engine()) } } } keep_log <<- TRUE show_latex_error(file, logfile) } res = system2_quiet( engine, c('-halt-on-error', '-interaction=batchmode', engine_args, shQuote(file)), error = { if (install_packages) tlmgr_update( run_fmtutil = FALSE, .quiet = TRUE, stdout = FALSE, stderr = FALSE ) on_error() }, logfile = logfile, fail_rerun = verbose ) # PNAS you are the worst! Why don't you singal an error in case of missing packages? if (res == 0 && !file.exists(filep)) on_error() invisible(res) } run_engine() if (install_packages) check_babel(logfile) # generate index if (file.exists(idx <- aux_files['idx'])) { idx_engine = getOption('tinytex.makeindex', 'makeindex') system2_quiet(idx_engine, c(getOption('tinytex.makeindex.args'), shQuote(idx)), error = { stop("Failed to build the index via ", idx_engine, call. = FALSE) }) } # generate bibliography bib_engine = match.arg(bib_engine) if (install_packages && bib_engine == 'biber' && Sys.which('biber') == '') tlmgr_install('biber') aux = aux_files[if ((biber <- bib_engine == 'biber')) 'bcf' else 'aux'] if (file.exists(aux)) { if (biber || require_bibtex(aux)) { blg = aux_files['blg'] # bibliography log file build_bib = function() system2_quiet(bib_engine, shQuote(aux), error = { stop("Failed to build the bibliography via ", bib_engine, call. = FALSE) }) build_bib() check_blg = function() { if (!file.exists(blg)) return(TRUE) x = readLines(blg) if (length(grep('error message', x)) == 0) return(TRUE) warn = function() { warning( bib_engine, ' seems to have failed:\n\n', paste(x, collapse = '\n'), call. = FALSE ) TRUE } if (!tlmgr_available() || !install_packages) return(warn()) # install the possibly missing .bst package and rebuild bib r = '.* open style file ([^ ]+).*' pkgs = parse_packages(files = gsub(r, '\\1', grep(r, x, value = TRUE))) if (length(pkgs) == 0) return(warn()) tlmgr_install(pkgs); build_bib() FALSE } # check .blg at most 3 times for missing packages for (i in 1:3) if (check_blg()) break } } for (i in seq_len(max_times)) { if (i > min_times) { if (file.exists(logfile)) { if (!needs_rerun(logfile)) break } else warning('The LaTeX log file "', logfile, '" is not found') } run_engine() } } require_bibtex = function(aux) { x = readLines(aux) r = length(grep('^\\\\citation\\{', x)) && length(grep('^\\\\bibdata\\{', x)) && length(grep('^\\\\bibstyle\\{', x)) if (r && !tlmgr_available() && os == 'windows') tweak_aux(aux, x) r } # remove the .bib extension in \bibdata{} in the .aux file, because bibtex on # Windows requires no .bib extension (sigh) tweak_aux = function(aux, x = readLines(aux)) { r = '^\\\\bibdata\\{.+\\}\\s*$' if (length(i <- grep(r, x)) == 0) return() x[i] = gsub('[.]bib([,}])', '\\1', x[i]) writeLines(x, aux) } needs_rerun = function(log) { any(grepl( '(Rerun to get |Please \\(re\\)run | Rerun LaTeX\\.)', readLines(log), useBytes = TRUE )) } system2_quiet = function(..., error = NULL, logfile = NULL, fail_rerun = TRUE) { # system2(stdout = FALSE) fails on Windows with MiKTeX's pdflatex in the R # console in RStudio: https://github.com/rstudio/rstudio/issues/2446 so I have # to redirect stdout and stderr to files instead f1 = tempfile('stdout'); f2 = tempfile('stderr') on.exit(unlink(c(f1, f2)), add = TRUE) # run the command quietly if possible res = system2(..., stdout = if (use_file_stdout()) f1 else FALSE, stderr = f2) if (is.character(logfile) && file.exists(f2) && length(e <- xfun::read_utf8(f2))) { i = grep('^\\s*$', e, invert = TRUE) e[i] = paste('!', e[i]) # prepend ! to non-empty error messages cat('', e, file = logfile, sep = '\n', append = TRUE) } # if failed, use the normal mode if (fail_rerun && res != 0) res = system2(...) # if still fails, run the error callback if (res != 0) error # lazy evaluation invisible(res) } use_file_stdout = function() { getOption('tinytex.stdout.file', { os == 'windows' && interactive() && !is.na(Sys.getenv('RSTUDIO', NA)) }) } # parse the LaTeX log and show error messages show_latex_error = function( file, logfile = gsub('[.]tex$', '.log', basename(file)), force = FALSE ) { e = c('LaTeX failed to compile ', file, '. See https://yihui.org/tinytex/r/#debugging for debugging tips.') if (!file.exists(logfile)) stop(e, call. = FALSE) x = readLines(logfile, warn = FALSE) b = grep('^\\s*$', x) # blank lines b = c(b, which(x == "Here is how much of TeX's memory you used:")) m = NULL for (i in grep('^! ', x)) { # ignore the last error message about the fatal error if (grepl('==> Fatal error occurred', x[i], fixed = TRUE)) next n = b[b > i] n = if (length(n) == 0) i else min(n) - 1L m = c(m, x[i:n], '') } if (length(m)) { message(paste(m, collapse = '\n')) latex_hints(m, file) stop(e, ' See ', logfile, ' for more info.', call. = FALSE) } else if (force) stop(e, call. = FALSE) } latex_hints = function(x, f) { check_inline_math(x, f) check_unicode(x) } check_inline_math = function(x, f) { r = 'l[.][0-9]+\\s*|\\s*[0-9.]+\\\\times.*' if (!any('! Missing $ inserted.' == x) || !length(i <- grep(r, x))) return() m = gsub(r, '', x[i]); m = m[m != ''] s = xfun::with_ext(f, 'Rmd') if (file.exists(s)) message( if (length(m)) c('Try to find the following text in ', s, ':\n', paste(' ', m, '\n'), '\n'), 'You may need to add $ $ around a certain inline R expression `r ` in ', s, if (length(m)) ' (see the above hint)', '. See https://github.com/rstudio/rmarkdown/issues/385 for more info.' ) } check_unicode = function(x) { if (length(grep('! Package inputenc Error: Unicode character', x))) message( 'Try other LaTeX engines instead (e.g., xelatex) if you are using pdflatex. ', 'For R Markdown users, see https://bookdown.org/yihui/rmarkdown/pdf-document.html' ) } # whether a LaTeX log file contains LaTeX or package (e.g. babel) warnings latex_warning = function(file, show = FALSE) { if (!file.exists(file)) return() x = readLines(file, warn = FALSE) if (length(i <- grep('^(LaTeX|Package [[:alnum:]]+) Warning:', x)) == 0) return() # these warnings may be okay (our Pandoc LaTeX template in rmarkdown may need an update) i = i[grep('^Package (fixltx2e|caption|hyperref) Warning:', x[i], invert = TRUE)] if (length(i) == 0) return() b = grep('^\\s*$', x) i = unlist(lapply(i, function(j) { n = b[b > j] n = if (length(n) == 0) i else min(n) - 1L j:n })) i = sort(unique(i)) if (show) warning(paste(x[i], collapse = '\n'), call. = FALSE) x[i] } # check if any babel packages are missing check_babel = function(file) { if (length(m <- latex_warning(file)) == 0 || length(grep('^Package babel Warning:', m)) == 0) return() r = "^\\(babel).* language `([[:alpha:]]+)'.*$" if (length(i <- grep(r, m)) == 0) return() tlmgr_install(paste0('hyphen-', tolower(gsub(r, '\\1', m[i])))) } # check the version of latexmk check_latexmk_version = function() { out = system2('latexmk', '-v', stdout = TRUE) reg = '^.*Version (\\d+[.]\\d+).*$' out = grep(reg, out, value = TRUE) if (length(out) == 0) return() ver = as.numeric_version(gsub(reg, '\\1', out[1])) if (ver >= '4.43') return() system2('latexmk', '-v') warning( 'Your latexmk version seems to be too low. ', 'You may need to update the latexmk package or your LaTeX distribution.', call. = FALSE ) } # return file paths that exist exist_files = function(files) { files[utils::file_test('-f', files)] } # use file.copy() if file.rename() fails file_rename = function(from, to) { if (from == to) return(TRUE) if (!suppressWarnings(file.rename(from, to))) { if (file.copy(from, to, overwrite = TRUE)) file.remove(from) } } #' Find missing LaTeX packages from a LaTeX log file #' #' Analyze the error messages in a LaTeX log file to figure out the names of #' missing LaTeX packages that caused the errors. These packages can be #' installed via \code{\link{tlmgr_install}()}. Searching for missing packages #' is based on \code{\link{tlmgr_search}()}. #' @param log Path to the LaTeX log file (typically named \file{*.log}). #' @param text A character vector of the error log (read from the file provided #' by the \code{log} argument by default). #' @param files A character vector of names of the missing files (automatically #' detected from the \code{log} by default). #' @param quiet Whether to suppress messages when finding packages. It should be #' a logical vector of length 3: the first element indicates whether to #' suppress the message when no missing LaTeX packages could be detected from #' the log, the second element indicate whether to suppress the message when #' searching for packages via \code{tlmgr_search()}, and the third element #' indicates whether to warn if no packages could be found via #' \code{tlmgr_search()}. #' @return A character vector of LaTeX package names. #' @export parse_packages = function( log, text = readLines(log), files = detect_files(text), quiet = rep(FALSE, 3) ) { pkgs = character(); quiet = rep_len(quiet, length.out = 3) x = unique(c(files, miss_font())) if (length(x) == 0) { if (!quiet[1]) message( 'I was unable to find any missing LaTeX packages from the error log', if (missing(log)) '.' else c(' ', log, '.') ) return(invisible(pkgs)) } for (j in seq_along(x)) { l = tlmgr_search(paste0('/', x[j]), stdout = TRUE, .quiet = quiet[2]) if (length(l) == 0) next if (x[j] == 'fandol') return(x[j]) # a known package # why $? e.g. searching for mf returns a list like this # metafont.x86_64-darwin: # bin/x86_64-darwin/mf <- what we want # metapost.x86_64-darwin: # bin/x86_64-darwin/mfplain <- but this also matches /mf k = grep(paste0('/', x[j], '$'), l) # only match /mf exactly if (length(k) == 0) { if (!quiet[3]) warning('Failed to find a package that contains ', x[j]) next } k = k[k > 2] p = grep(':$', l) if (length(p) == 0) next for (i in k) { pkg = gsub(':$', '', l[max(p[p < i])]) # find the package name pkgs = c(pkgs, setNames(pkg, x[j])) } } pkgs = gsub('[.].*', '', pkgs) # e.g., 'metafont.x86_64-darwin' unique(pkgs) } # find filenames (could also be font names) from LaTeX error logs detect_files = function(text) { # possible errors are like: # ! LaTeX Error: File `framed.sty' not found. # /usr/local/bin/mktexpk: line 123: mf: command not found # ! Font U/psy/m/n/10=psyr at 10.0pt not loadable: Metric (TFM) file not found # !pdfTeX error: /usr/local/bin/pdflatex (file tcrm0700): Font tcrm0700 at 600 not found # xdvipdfmx:fatal: Unable to find TFM file "rsfs10" # ! The font "FandolSong-Regular" cannot be found. # ! Package babel Error: Unknown option `ngerman'. Either you misspelled it # (babel) or the language definition file ngerman.ldf was not found. # !pdfTeX error: pdflatex (file 8r.enc): cannot open encoding file for reading # ! CTeX fontset `fandol' is unavailable in current mode # Package widetext error: Install the flushend package which is a part of sttools # Package biblatex Info: ... file 'trad-abbrv.bbx' not found # ! Package pdftex.def Error: File `logo-mdpi-eps-converted-to.pdf' not found # ! xdvipdfmx:fatal: pdf_ref_obj(): passed invalid object. # ! Package tikz Error: I did not find the tikz library 'hobby'... named tikzlibraryhobby.code.tex # support file `supp-pdf.mkii' (supp-pdf.tex) is missing r = c( ".*! Font [^=]+=([^ ]+).+ not loadable.*", '.*! .*The font "([^"]+)" cannot be found.*', '.*!.+ error:.+\\(file ([^)]+)\\): .*', '.*Package widetext error: Install the ([^ ]+) package.*', '.*Unable to find TFM file "([^"]+)".*', # the above are messages about missing fonts; below are typically missing .sty or commands ".* File `(.+eps-converted-to.pdf)'.*", ".*xdvipdfmx:fatal: pdf_ref_obj.*", '.* (tikzlibrary[^.]+[.]code[.]tex).*', ".*! LaTeX Error: File `([^']+)' not found.*", ".* file ['`]?([^' ]+)'? not found.*", '.*the language definition file ([^ ]+) .*', '.* \\(file ([^)]+)\\): cannot open .*', ".*file `([^']+)' .*is missing.*", ".*! CTeX fontset `([^']+)' is unavailable.*", ".*: ([^:]+): command not found.*" ) x = grep(paste(r, collapse = '|'), text, value = TRUE) if (length(x) > 0) unique(unlist(lapply(r, function(p) { z = grep(p, x, value = TRUE) v = gsub(p, '\\1', z) if (length(v) == 0) return(v) if (p == r[8] && length(grep('! Package tikz Error:', text)) == 0) return() if (!(p %in% r[1:5])) return(if (p %in% r[6:7]) 'epstopdf' else v) if (p == r[4]) paste0(v, '.sty') else font_ext(v) }))) } # a helper function that combines parse_packages() and tlmgr_install() parse_install = function(...) { tlmgr_install(parse_packages(...)) } # check missfont.log and detect the missing font packages; missfont.log # typically looks like this: # mktexpk --mfmode / --bdpi 600 --mag 1+0/600 --dpi 600 ecrm0900 miss_font = function() { if (!file.exists(f <- 'missfont.log')) return() on.exit(unlink(f), add = TRUE) x = gsub('\\s*$', '', readLines(f)) x = grep('.+\\s+.+', x, value = TRUE) if (length(x) == 0) return() x1 = gsub('.+\\s+', '', x) # possibly missing fonts x2 = gsub('\\s+.+', '', x) # the command to make fonts unique(c(font_ext(x1), x2)) } font_ext = function(x) { i = !grepl('[.]', x) x[i] = paste0(x[i], '[.](tfm|afm|mf|otf)') x } # it should be rare that we need to manually run texhash texhash = function() { tweak_path() system2('texhash') } updmap = function(usermode = FALSE) { tweak_path() system2(if (usermode) 'updmap-user' else 'updmap-sys') } fmtutil = function(usermode = FALSE, ...) { tweak_path() system2(if (usermode) 'fmtutil-user' else 'fmtutil-sys', '--all', ...) } fc_cache = function(args = c('-v', '-r')) { tweak_path() system2('fc-cache', args) } # look up files in the Kpathsea library, e.g., kpsewhich('Sweave.sty') kpsewhich = function(filename, options = character()) { tweak_path() system2('kpsewhich', c(options, shQuote(filename))) } tinytex/R/package.R0000644000176200001440000000007213311741767013706 0ustar liggesusers#' @import stats utils tools NULL os = .Platform$OS.type tinytex/R/tlmgr.R0000644000176200001440000002352013607164243013437 0ustar liggesusers#' Run the TeX Live Manager #' #' Execute the \command{tlmgr} command to search for LaTeX packages, install #' packages, update packages, and so on. #' #' The \code{tlmgr()} function is a wrapper of \code{system2('tlmgr')}. All #' other \code{tlmgr_*()} functions are based on \code{tlmgr} for specific #' tasks. Please consult the \pkg{tlmgr} manual for full details. #' @param args A character vector of arguments to be passed to the command #' \command{tlmgr}. #' @param usermode (For expert users only) Whether to use TeX Live's #' \href{https://www.tug.org/texlive/doc/tlmgr.html#USER-MODE}{user mode}. If #' \code{TRUE}, you must have run \code{tlmgr('init-usertree')} once before. #' This option allows you to manage a user-level texmf tree, e.g., install a #' LaTeX package to your home directory instead of the system directory, to #' which you do not have write permission. This option should not be needed on #' personal computers, and has some limitations, so please read the #' \pkg{tlmgr} manual very carefully before using it. #' @param ... For \code{tlmgr()}, additional arguments to be passed to #' \code{\link{system2}()} (e.g., \code{stdout = TRUE} to capture stdout). For #' other functions, arguments to be passed to \code{tlmgr()}. #' @param .quiet Whether to hide the actual command before executing it. #' @references The \pkg{tlmgr} manual: #' \url{https://www.tug.org/texlive/doc/tlmgr.html} #' @export #' @examples #' # search for a package that contains titling.sty #' tlmgr_search('titling.sty') #' #' #' to match titling.sty exactly, add a slash before the keyword, e.g. #' #' tlmgr_search('/titling.sty') #' #' #' use a regular expression if you want to be more precise, e.g. #' #' tlmgr_search('/titling\\.sty$') #' #' # list all installed LaTeX packages #' tlmgr(c('info', '--list', '--only-installed', '--data', 'name')) tlmgr = function(args = character(), usermode = FALSE, ..., .quiet = FALSE) { tweak_path() if (!.quiet && !tlmgr_available()) { warning('TeX Live does not seem to be installed. See https://yihui.org/tinytex/.') } if (usermode) args = c('--usermode', args) if (!.quiet) message(paste(c('tlmgr', args), collapse = ' ')) system2('tlmgr', args, ...) } # add ~/bin to PATH if necessary on Linux, because sometimes PATH may not be # inherited (https://github.com/rstudio/rstudio/issues/1878), and TinyTeX is # installed to ~/bin by default; on Windows, prioritize win_app_dir('TinyTeX') # if it exists (so TinyTeX can be used even when MiKTeX is installed); on macOS, # check if it is necessary to add ~/Library/TinyTeX/bin/*/ to PATH #' @importFrom xfun is_linux is_unix is_macos is_windows with_ext tweak_path = function() { # check if ~/bin/tlmgr exists (created by TinyTeX by default) f = if (is_linux()) '~/bin/tlmgr' else if (is_windows()) { win_app_dir('TinyTeX', 'bin', 'win32', 'tlmgr.bat', error = FALSE) } else if (is_macos()) '~/Library/TinyTeX/bin/x86_64-darwin/tlmgr' else return() if (!file_test('-x', f)) f = getOption('tinytex.tlmgr.path', '') if (!file_test('-x', f)) return() bin = normalizePath(dirname(f)) # if the pdftex from TinyTeX is already on PATH, no need to adjust the PATH if ((p <- Sys.which('pdftex')) != '') { p2 = xfun::with_ext(file.path(bin, 'pdftex'), xfun::file_ext(p)) if (xfun::same_path(p, p2)) return() } old = Sys.getenv('PATH') one = unlist(strsplit(old, s <- .Platform$path.sep, fixed = TRUE)) Sys.setenv(PATH = paste(c(bin, setdiff(one, bin)), collapse = s)) do.call( on.exit, list(substitute(Sys.setenv(PATH = x), list(x = old)), add = TRUE), envir = parent.frame() ) } tlmgr_available = function() Sys.which('tlmgr') != '' #' @param what A search keyword as a (Perl) regular expression. #' @param file Whether to treat \code{what} as a filename (pattern). #' @param all For \code{tlmgr_search()}, whether to search in everything, #' including package names, descriptions, and filenames. For #' \code{tlmgr_update()}, whether to update all installed packages. #' @param global Whether to search the online TeX Live Database or locally. #' @param word Whether to restrict the search of package names and descriptions #' to match only full words. #' @rdname tlmgr #' @export tlmgr_search = function(what, file = TRUE, all = FALSE, global = TRUE, word = FALSE, ...) { tlmgr(c( 'search', if (file) '--file', if (all) '--all', if (global) '--global', if (word) '--word', shQuote(what) ), ...) } #' @param pkgs A character vector of LaTeX package names. #' @param path Whether to run \code{tlmgr_path('add')} after installing packages #' (\code{path = TRUE} is a conservative default: it is only necessary to do #' this after a binary package is installed, such as the \pkg{metafont} #' package, which contains the executable \command{mf}, but it does not hurt #' even if no binary packages were installed). #' @rdname tlmgr #' @export tlmgr_install = function(pkgs = character(), usermode = FALSE, path = !usermode && os != 'windows', ...) { res = 0L if (length(pkgs)) { res = tlmgr(c('install', pkgs), usermode, ...) if (res != 0 || tl_list(pkgs, stdout = FALSE, stderr = FALSE, .quiet = TRUE) != 0) { tlmgr_update(all = FALSE, usermode = usermode) res = tlmgr(c('install', pkgs), usermode, ...) } if ('epstopdf' %in% pkgs && is_unix() && Sys.which('gs') == '') { if (is_macos() && Sys.which('brew') != '') { message('Trying to install GhostScript via Homebrew for the epstopdf package.') system('brew install ghostscript') } if (Sys.which('gs') == '') warning('GhostScript is required for the epstopdf package.') } if (path) tlmgr_path('add') } invisible(res) } #' @rdname tlmgr #' @export tlmgr_remove = function(pkgs = character(), usermode = FALSE) { if (length(pkgs)) tlmgr(c('remove', pkgs), usermode) } #' @param self Whether to update the TeX Live Manager itself. #' @param more_args A character vector of more arguments to be passed to the #' command \command{tlmgr update} or \command{tlmgr conf}. #' @param run_fmtutil Whether to run \command{fmtutil-sys --all} to (re)create #' format and hyphenation files after updating \pkg{tlmgr}. #' @rdname tlmgr #' @export tlmgr_update = function( all = TRUE, self = TRUE, more_args = character(), usermode = FALSE, run_fmtutil = TRUE, ... ) { tlmgr(c('update', if (all) '--all', if (self && !usermode) '--self', more_args), usermode, ...) if (run_fmtutil) fmtutil(usermode, stdout = FALSE) } #' @param action On Unix, add/remove symlinks of binaries to/from the system's #' \code{PATH}. On Windows, add/remove the path to the TeXLive binary #' directory to/from the system environment variable \code{PATH}. #' @rdname tlmgr #' @export tlmgr_path = function(action = c('add', 'remove')) tlmgr(c('path', match.arg(action)), .quiet = TRUE) #' @rdname tlmgr #' @export tlmgr_conf = function(more_args = character()) { tlmgr(c('conf', more_args)) } #' Add/remove R's texmf tree to/from TeX Live #' #' R ships a custom texmf tree containing a few LaTeX style and class files, #' which are required when compiling R packages manuals (\file{Rd.sty}) or #' Sweave documents (\file{Sweave.sty}). This tree can be found under the #' directory \code{file.path(R.home('share'), 'texmf')}. This function can be #' used to add/remove R's texmf tree to/from TeX Live via #' \code{\link{tlmgr_conf}('auxtrees')}. #' @param action Add/remove R's texmf tree to/from TeX Live. #' @references See the \pkg{tlmgr} manual for detailed information about #' \command{tlmgr conf auxtrees}. Check out #' \url{https://tex.stackexchange.com/q/77720/9128} if you don't know what #' \code{texmf} means. #' @export #' @examples #' r_texmf('remove') #' r_texmf('add') #' #' # all files under R's texmf tree #' list.files(file.path(R.home('share'), 'texmf'), recursive = TRUE, full.names = TRUE) r_texmf = function(action = c('add', 'remove')) { tlmgr_conf(c('auxtrees', match.arg(action), shQuote(r_texmf_path()))) } r_texmf_path = function() { d = file.path(R.home('share'), 'texmf') if (dir_exists(d)) return(d) # retry another directory: https://github.com/yihui/tinytex/issues/60 if ('Rd.sty' %in% basename(list.files(d2 <- '/usr/share/texmf', recursive = TRUE))) { return(d2) } warning("Cannot find R's texmf tree; returning '", d, "'") d } #' Sizes of LaTeX packages in TeX Live #' #' Use the command \command{tlmgr info --list --only-installed} to obtain the #' sizes of installed LaTeX packages. #' @param show_total Whether to show the total size. #' @export #' @return A data frame of three columns: \code{package} is the package names, #' \code{size} is the sizes in bytes, and \code{size_h} is the human-readable #' version of sizes. tl_sizes = function(show_total = TRUE) { info = tl_list(NULL, 'name,size', stdout = TRUE) info = read.table(sep = ',', text = info, stringsAsFactors = FALSE, col.names = c('package', 'size')) info = info[order(info[, 'size'], decreasing = TRUE), , drop = FALSE] info$size_h = sapply(info[, 'size'], auto_size) rownames(info) = NULL if (show_total) message('The total size is ', auto_size(sum(info$size))) info } # human-readable size from bytes auto_size = function(bytes) format(structure(bytes, class = 'object_size'), 'auto') #' List the names of installed TeX Live packages #' #' Calls \command{tlmgr info --list --only-installed --data name} to obtain the #' names of all installed TeX Live packages. Platform-specific strings in #' package names are removed, e.g., \code{"tex"} is returned for the package #' \pkg{tex.x86_64-darwin}. #' @export #' @return A character vector of package names. tl_pkgs = function() { x = tl_list(stdout = TRUE, .quiet = TRUE) unique(sub(paste0('.', tl_platform()), '', x)) } tl_list = function(pkgs = NULL, field = 'name', ...) { tlmgr(c('info', '--list', '--only-installed', '--data', field, pkgs), ...) } tl_platform = function() tlmgr('print-platform', stdout = TRUE, .quiet = TRUE) tinytex/MD50000644000176200001440000000211013607256622012271 0ustar liggesusers928b115f25d9a5c4a48a11083b04ac6a *DESCRIPTION 65cabda422fb305eff1b0312980aee19 *LICENSE 709903beb6c916e2e0eefb377265d801 *NAMESPACE 029b43c4df38b6711589a4fd4e8a509c *R/install.R 39cb056508494e2b2c556533700c9307 *R/latex.R 97e5cb1da23125629a9ed4bbeea18a4a *R/package.R 177254313462d3b4b41ce0d7a511a0b3 *R/tlmgr.R 23a4d616e4e8a66fa1321a52f135e05b *README.md 07b1d67fc7523f46f234d2a78056943d *inst/CITATION a4aa863437c27133719365ac8a3fc840 *inst/NEWS.Rd d7dac0f18e52934ac844f0e2836eb115 *man/copy_tinytex.Rd 7e129d7e0c50b19399adf51e32e70e65 *man/install_tinytex.Rd 32349417dacf86c9dbd1610288764faa *man/latexmk.Rd 27ce3b3274be741515a8edbe8dcf3223 *man/parse_packages.Rd 4082537f550f6232e84e907689d7d8de *man/r_texmf.Rd 4be97b58b32eefa02aef1e68f3a3376a *man/tl_pkgs.Rd 2ed377a2bbbd6ccb27b243484e77e2b8 *man/tl_sizes.Rd a487fb23889624ab4a14c99db7f30da6 *man/tlmgr.Rd adafda5ea0b62571a6766d4c95aaa065 *tests/test-cran.R 325d0dd9770190bf9ff783f6d3caf13f *tests/test-cran/test-latex.R c31f780b68534a35399588ede74709d8 *tests/test-travis.R 58f9287cb2885d14c642355da92d22e0 *tests/test-travis/test-tlmgr.R tinytex/inst/0000755000176200001440000000000013551414516012740 5ustar liggesuserstinytex/inst/CITATION0000644000176200001440000000201413551414516014072 0ustar liggesuserscitHeader("To cite the 'tinytex' package in publications use:") year = sub('.*(2[[:digit:]]{3})-.*', '\\1', meta$Date, perl = TRUE) vers = paste('R package version', meta$Version) citEntry( entry = 'manual', title = paste('tinytex:', meta$Title), author = Filter(function(p) 'aut' %in% p$role, as.person(meta$Author)), year = year, note = vers, url = meta$URL, textVersion = paste('Yihui Xie (', year, '). tinytex: ', meta$Title, '. ', vers, '.', sep = '') ) citEntry( entry = 'article', title = 'TinyTeX: A lightweight, cross-platform, and easy-to-maintain LaTeX distribution based on TeX Live', author = 'Yihui Xie', journal = 'TUGboat', year = '2019', volumne = '40', number = '1', pages = '30--32', url = 'http://tug.org/TUGboat/Contents/contents40-1.html', textVersion = paste( 'Yihui Xie (2019)', 'TinyTeX: A lightweight, cross-platform, and easy-to-maintain LaTeX distribution based on TeX Live.', 'TUGboat 40 (1): 30--32. http://tug.org/TUGboat/Contents/contents40-1.html' ) ) tinytex/inst/NEWS.Rd0000644000176200001440000000043713462664410014010 0ustar liggesusers\name{NEWS} \title{News for Package 'tinytex'} \section{CHANGES IN tinytex VERSION 999.999}{ \itemize{ \item This NEWS file is only a placeholder. The version 999.999 does not really exist. Please read the NEWS on Github: \url{https://github.com/yihui/tinytex/releases} } }