├── .gitignore ├── LICENSE ├── README.md ├── appveyor.yml ├── compile.R ├── latex-pass.R ├── latex-pass.Rproj ├── test.Rmd ├── test.log └── test.tex /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Yihui Xie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LaTeX Pass 2 | 3 | [![Build status](https://ci.appveyor.com/api/projects/status/0g8vduvn8aw58k4x/branch/master?svg=true)](https://ci.appveyor.com/project/yihui/latex-pass/branch/master) 4 | 5 | Upload a LaTeX error log file, or a LaTeX document, or an R Markdown document to this repository, and I will tell you which LaTeX packages you need to install in your local LaTeX distribution so you can compile your documents to PDF. You will no longer be confused by LaTeX error messages like this: 6 | 7 | ```latex 8 | ! LaTeX Error: File `inconsolata.sty' not found. 9 | 10 | Type X to quit or to proceed, 11 | or enter new name. (Default extension: sty) 12 | 13 | ! Emergency stop. 14 | 15 | 16 | l.276 ^^M 17 | 18 | ! ==> Fatal error occurred, no output PDF file produced! 19 | ``` 20 | 21 | Note that if you use both the R package [**tinytex**](https://github.com/yihui/tinytex) and the LaTeX distribution [TinyTeX](https://yihui.org/tinytex/), you should not need to use this repository, because **tinytex** will automatically install missing LaTeX packages by default. This repository may only be useful to those who do not use R or TinyTeX. 22 | 23 | ## How does it work? 24 | 25 | Depending on if you have a LaTeX error `.log` file, or a `.tex` document, or an `.Rmd` document, you may click one of the links below to edit the file in this repo, and follow the Github instructions to send a pull request. 26 | 27 | - [`test.log`](https://github.com/yihui/latex-pass/edit/master/test.log): copy and paste your LaTeX error log into here (see [example in PR #3](https://github.com/yihui/latex-pass/pull/3)). 28 | - [`test.tex`](https://github.com/yihui/latex-pass/edit/master/test.tex): copy and paste your `.tex` file here (see [example in PR #1](https://github.com/yihui/latex-pass/pull/1)). 29 | - [`test.Rmd`](https://github.com/yihui/latex-pass/edit/master/test.Rmd): copy and paste your `.Rmd` file here; its output format should be PDF (see [example in PR #4](https://github.com/yihui/latex-pass/pull/4)). 30 | 31 | After you send the pull request, wait for about 2 minutes for [AppVeyor](https://ci.appveyor.com/project/yihui/latex-pass) to finish. Then it should tell you the list of LaTeX packages required to compile your document in a comment (you may also get an email notification from Github if you have subscribed to notifications), e.g., 32 | 33 | ``` 34 | The missing packages identified from the LaTeX log are: 35 | 36 | inconsolata 37 | 38 | If you are an R user using TinyTeX, you may install these packages via: 39 | 40 | tinytex::tlmgr_install(c("inconsolata")) 41 | 42 | If you use TinyTeX but are not an R user, you may install these packages via command line: 43 | 44 | tlmgr install inconsolata 45 | ``` 46 | 47 | If you are familiar with GIT and Github, you can add or edit more than one file (e.g., multiple `.tex` and/or `.Rmd` files) to the repo and send a pull request. 48 | 49 | By default, the LaTeX engine to compile `.tex` documents is `pdflatex`. If the document requires a different engine to compile, you may name your file with the engine name, e.g., `xelatex.tex` or `lualatex.tex`, or add a comment of the form `% !TeX program = ENGINE` to your document, e.g., `% !TeX program = xelatex`. The bibliography may be processed by either `bibtex` (default) or `biber`. You may add the bibliography engine name to the filename if you want to use one specifically, e.g., `test-biber.tex`. 50 | 51 | If you are compiling an Rmd document, please see [Section 3.3.7.1 of the _R Markdown Definitive Guide_](https://bookdown.org/yihui/rmarkdown/pdf-document.html#latex-engine) for how to specify the LaTeX engine in the Rmd document. 52 | 53 | ## How to reproduce what this repo does locally 54 | 55 | If you do not want to wait for 2 minutes, you can find out the missing LaTeX packages by yourself locally via the R function `tinytex::parse_packages()`, which requires you to install TeX Live or TinyTeX. See more information at https://bookdown.org/yihui/rmarkdown-cookbook/install-latex-pkgs.html. 56 | 57 | BTW, [Colin Fay was correct](https://twitter.com/_ColinFay/status/1309415115922509824) that this service was created [because of him](https://twitter.com/_ColinFay/status/1308061202938032138). That "fresh hell" could be easily avoided with TinyTeX. 58 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: macOS 2 | 3 | cache: 4 | - $HOME/R 5 | 6 | install: 7 | - brew install --cask r > /dev/null 8 | 9 | build: off 10 | 11 | test_script: 12 | - Rscript 'compile.R' 13 | - Rscript 'latex-pass.R' 14 | - appveyor AddMessage "$(cat message.txt)" -Details "$(cat details.txt)" 15 | -------------------------------------------------------------------------------- /compile.R: -------------------------------------------------------------------------------- 1 | options(repos = "https://cran.rstudio.com") 2 | dir.create('~/R', showWarnings = FALSE) 3 | .libPaths('~/R') 4 | 5 | # install xfun and tinytex 6 | pkg_install = function(...) install.packages(..., quiet = TRUE) 7 | pkg_install('xfun') 8 | options(xfun.install.package = pkg_install) 9 | xfun::pkg_load2(c('tinytex', 'rmarkdown')) 10 | 11 | # install TinyTeX 12 | suppressMessages(suppressWarnings(if (!tinytex:::is_tinytex()) tinytex::install_tinytex())) 13 | 14 | p0 = tinytex::tl_pkgs() # the initial set of LaTeX packages installed 15 | p1 = NULL # missing packages identified from the LaTeX log 16 | 17 | # parse LaTeX errors from .log files, or compile .Rmd/.tex files to figure out 18 | # missing LaTeX packages 19 | for (f in list.files('.', '[.](Rmd|tex|log)$')) { 20 | if (!file.exists(f)) next # the file might have been deleted 21 | # different actions according to filenames extensions 22 | switch( 23 | xfun::file_ext(f), 24 | Rmd = if (length(grep('^---\\s*$', readLines(f, n = 1)))) { 25 | # the first line needs to be ---, in case it's a child Rmd file 26 | xfun::pkg_load2('rmarkdown') 27 | # make sure pandoc and pandoc-citeproc are installed 28 | for (i in c('pandoc', 'pandoc-citeproc')) { 29 | if (Sys.which(i) == '') system(paste('brew install', i)) 30 | } 31 | rmarkdown::render(f) 32 | }, 33 | tex = { 34 | x = xfun::read_utf8(f) 35 | # need to find \documentclass or \begin{document} in the .tex file 36 | if (length(grep('\\\\documentclass', x)) == 0) next 37 | n1 = length(i1 <- grep('\\\\begin\\{document\\}', x)) 38 | n2 = length(i2 <- grep('\\\\end\\{document\\}', x)) 39 | if (n1 * n2 == 0) next 40 | if (n1 > 1 || n2 > 1) { 41 | warning('More than one line of code contains \\begin{document} or \\end{document}') 42 | next 43 | } 44 | # clear the document body, because it may have references to files that 45 | # users forgot or didn't want to upload to this repo; this approach won't 46 | # work for bibliography, but users can upload their LaTeX log in this case 47 | xfun::write_utf8(c(x[1:i1], 'Hello world!', x[i2]), f) 48 | r = '.*?((?:pdf|xe|lua)latex).*' 49 | engine = if (length(grep(r, f))) gsub(r, '\\1', f) 50 | # also try to infer engine from the comment like "% !TeX program = xelatex" 51 | r = '^(?:% !TeX program\\s*=\\s*)([[:alnum:]-]+).*' 52 | if (length(i <- grep(r, x))) engine = gsub(r, '\\1', x[i][1]) 53 | # if I can't infer the engine, use pdflatex by default 54 | if (is.null(engine)) engine = 'pdflatex' 55 | r = '.*?(bibtex|biber).*' 56 | bib_engine = if (length(grep(r, f))) gsub(r, '\\1', f) 57 | if (is.null(bib_engine)) bib_engine = 'bibtex' 58 | tinytex::latexmk(f, engine = engine, bib_engine = bib_engine) 59 | }, 60 | log = { 61 | if (file.size(f) == 0) next 62 | p1 = c(p1, tinytex::parse_packages(f)) 63 | } 64 | ) 65 | } 66 | p2 = setdiff(tinytex::tl_pkgs(), p0) # newly installed packages after compiling Rmd/tex files 67 | saveRDS(list(p1, p2), file = 'packages.rds') 68 | -------------------------------------------------------------------------------- /latex-pass.R: -------------------------------------------------------------------------------- 1 | .libPaths('~/R') 2 | 3 | pp = readRDS('packages.rds') 4 | p1 = pp[[1]]; p2 = pp[[2]] 5 | one_string = function(..., s = ' ') paste(..., collapse = s) 6 | 7 | msg = c( 8 | if (length(p1)) c('The missing packages identified from the LaTeX log are:\n\n ', one_string(p1)), 9 | if (length(p2)) c('\n\nAdditional packages required to compile your documents are:\n\n ', one_string(p2)) 10 | ) 11 | msg2 = if (length(msg)) { 12 | p = sort(unique(c(p1, p2))) 13 | c( 14 | sprintf( 15 | '\n\nIf you are an R user using TinyTeX, you may install these packages via:\n\n tinytex::tlmgr_install(c(%s))', 16 | one_string(sprintf("'%s'", p), s = ', ') 17 | ), 18 | '\n\nIf you use TinyTeX, including LaTeX for Manim (https://chocolatey.org/packages/manim-latex), you may install these packages via command line:\n\n tlmgr install ', 19 | one_string(p), 20 | '\n\nIf you do not use TinyTeX (https://yihui.org/tinytex/), you need to figure out how to install them by yourself.' 21 | ) 22 | } else { 23 | msg = 'I did not figure out which LaTeX packages you need to install. Sorry.' 24 | "" 25 | } 26 | message(msg, msg2) 27 | writeLines(one_string(msg, s = ''), 'message.txt') 28 | writeLines(one_string(msg2, s = ''), 'details.txt') 29 | -------------------------------------------------------------------------------- /latex-pass.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: knitr 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | -------------------------------------------------------------------------------- /test.Rmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/latex-pass/a243ff5bd65c2729f394e9e8a07ca9d0f8f0f3d3/test.Rmd -------------------------------------------------------------------------------- /test.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/latex-pass/a243ff5bd65c2729f394e9e8a07ca9d0f8f0f3d3/test.log -------------------------------------------------------------------------------- /test.tex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yihui/latex-pass/a243ff5bd65c2729f394e9e8a07ca9d0f8f0f3d3/test.tex --------------------------------------------------------------------------------