Skip to content

Commit

Permalink
Merge pull request #5490 from rstudio/feature/tinytex-support
Browse files Browse the repository at this point in the history
add support for installing tinytex
  • Loading branch information
kevinushey committed Oct 9, 2019
2 parents db4fdb8 + dbb6c68 commit 2d8c683
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 10 deletions.
18 changes: 12 additions & 6 deletions src/cpp/core/include/core/system/Xdg.hpp
Expand Up @@ -31,16 +31,22 @@ namespace xdg {
* All of these can be configured with environment variables as described below. * All of these can be configured with environment variables as described below.
*/ */


// Returns the RStudio XDG user config directory. On Unix-alikes, this is ~/.config/rstudio, or // Returns the RStudio XDG user config directory.
// XDG_CONFIG_HOME. //
// On Unix-alikes, this is ~/.config/rstudio, or XDG_CONFIG_HOME.
// On Windows, this is 'FOLDERID_RoamingAppData' (typically 'AppData/Roaming').
FilePath userConfigDir(); FilePath userConfigDir();


// Returns the RStudio XDG user data directory. On Unix-alikes, this is ~/.local/share/rstudio, or // Returns the RStudio XDG user data directory.
// XDG_DATA_HOME //
// On Unix-alikes, this is ~/.local/share/rstudio, or XDG_DATA_HOME.
// On Windows, this is 'FOLDERID_LocalAppData' (typically 'AppData/Local').
FilePath userDataDir(); FilePath userDataDir();


// Returns the RStudio XDG system config directory. On Unix-alikes, this is /etc/rstudio, or // Returns the RStudio XDG system config directory.
// XDG_CONFIG_DIRS //
// On Unix-alikes, this is /etc/rstudio, XDG_CONFIG_DIRS.
// On Windows, this is 'FOLDERID_ProgramData' (typically 'C:/ProgramData').
FilePath systemConfigDir(); FilePath systemConfigDir();


} // namespace xdg } // namespace xdg
Expand Down
26 changes: 26 additions & 0 deletions src/cpp/session/SessionModuleContext.cpp
Expand Up @@ -1077,9 +1077,35 @@ FilePath findProgram(const std::string& name)
} }
} }


bool addTinytexToPathIfNecessary()
{
// avoid some pathological cases where e.g. TinyTeX folder
// exists but doesn't have the pdflatex binary (don't
// attempt to re-add the folder multiple times)
static bool s_added = false;
if (s_added)
return true;

if (!module_context::findProgram("pdflatex").empty())
return false;

std::string binDir;
Error error = r::exec::RFunction(".rs.tinytexBin").call(&binDir);
if (error)
LOG_ERROR(error);

FilePath binPath = module_context::resolveAliasedPath(binDir);
if (!binPath.exists())
return false;

s_added = true;
core::system::addToSystemPath(binPath);
return true;
}


bool isPdfLatexInstalled() bool isPdfLatexInstalled()
{ {
addTinytexToPathIfNecessary();
return !module_context::findProgram("pdflatex").empty(); return !module_context::findProgram("pdflatex").empty();
} }


Expand Down
1 change: 1 addition & 0 deletions src/cpp/session/include/session/SessionModuleContext.hpp
Expand Up @@ -118,6 +118,7 @@ std::string rLibsUser();
// find out the location of a binary // find out the location of a binary
core::FilePath findProgram(const std::string& name); core::FilePath findProgram(const std::string& name);


bool addTinytexToPathIfNecessary();
bool isPdfLatexInstalled(); bool isPdfLatexInstalled();


// is the file a text file // is the file a text file
Expand Down
27 changes: 27 additions & 0 deletions src/cpp/session/modules/SessionRMarkdown.R
Expand Up @@ -462,4 +462,31 @@
FALSE FALSE
}) })


.rs.addFunction("tinytexRoot", function()
{
sysname <- Sys.info()[["sysname"]]
if (sysname == "Windows")
file.path(Sys.getenv("APPDATA"), "TinyTeX")
else if (sysname == "Darwin")
"~/Library/TinyTeX"
else
"~/.TinyTeX"
})


.rs.addFunction("tinytexBin", function()
{
root <- tryCatch(
tinytex:::tinytex_root(),
error = function(e) .rs.tinytexRoot()
)

if (!file.exists(root))
return(NULL)

# NOTE: binary directory has a single arch-specific subdir;
# rather than trying to hard-code the architecture we just
# infer it directly
bin <- file.path(root, "bin")
subbin <- list.files(bin, full.names = TRUE)
normalizePath(subbin[[1]], mustWork = TRUE)
})
3 changes: 3 additions & 0 deletions src/cpp/session/modules/tex/SessionCompilePdf.cpp
Expand Up @@ -596,6 +596,9 @@ class AsyncPdfCompiler : boost::noncopyable,
if (error) if (error)
LOG_ERROR(error); LOG_ERROR(error);


// add tinytex to the PATH if appropriate
module_context::addTinytexToPathIfNecessary();

// determine tex program path // determine tex program path
std::string userErrMsg; std::string userErrMsg;
if (!pdflatex::latexProgramForFile(magicComments_, if (!pdflatex::latexProgramForFile(magicComments_,
Expand Down
8 changes: 8 additions & 0 deletions src/gwt/src/org/rstudio/core/client/widget/InfoBar.java
Expand Up @@ -142,6 +142,14 @@ else if (n == 3)
})); }));
} }


public void showTexInstallationMissingWarning(String message,
Command onInstall)
{
setText(message);
labelRight_.clear();
labelRight_.add(label("Install TinyTeX", () -> { onInstall.execute(); }));
}

public void showReadOnlyWarning(List<String> alternatives) public void showReadOnlyWarning(List<String> alternatives)
{ {
if (alternatives.size() == 0) if (alternatives.size() == 0)
Expand Down
Expand Up @@ -484,6 +484,20 @@ public void withStan(final String progressCaption,
(Boolean success) -> { if (success) command.execute(); }); (Boolean success) -> { if (success) command.execute(); });
} }


public void withTinyTeX(final String progressCaption,
final String userPrompt,
final Command command)
{
withDependencies(
progressCaption,
userPrompt,
new Dependency[] {
Dependency.cranPackage("tinytex", "0.16")
},
true,
(Boolean success) -> { if (success) command.execute(); });
}

@Override @Override
public void onPackageStateChanged(PackageStateChangedEvent event) public void onPackageStateChanged(PackageStateChangedEvent event)
{ {
Expand Down
Expand Up @@ -315,6 +315,12 @@ public void showRequiredPackagesMissingWarning(List<String> packages)
// no-op for code browser targets // no-op for code browser targets
} }


@Override
public void showTexInstallationMissingWarning(String message)
{
// no-op for code browser targets
}

@Override @Override
public void showWarningBar(final String warning) public void showWarningBar(final String warning)
{ {
Expand Down
Expand Up @@ -1252,6 +1252,24 @@ public void showRequiredPackagesMissingWarning(List<String> packages)
view_.showRequiredPackagesMissingWarning(packages); view_.showRequiredPackagesMissingWarning(packages);
} }


public void showTexInstallationMissingWarning(String message)
{
view_.showTexInstallationMissingWarning(message);
}

public void installTinyTeX()
{
Command onInstall = () -> {
String code = "tinytex::install_tinytex()";
events_.fireEvent(new SendToConsoleEvent(code, true));
};

dependencyManager_.withTinyTeX(
"Installing tinytex",
"Installing TinyTeX",
onInstall);
}

private void jumpToPreviousFunction() private void jumpToPreviousFunction()
{ {
Scope jumpTo = scopeHelper_.getPreviousFunction( Scope jumpTo = scopeHelper_.getPreviousFunction(
Expand Down
Expand Up @@ -215,12 +215,12 @@ public void onResponseReceived(TexCapabilities response)
{ {
String warning; String warning;
if (Desktop.isDesktop()) if (Desktop.isDesktop())
warning = "No TeX installation detected. Please install " + warning = "No LaTeX installation detected. Please install " +
"TeX before compiling."; "LaTeX before compiling.";
else else
warning = "This server does not have TeX installed. You " + warning = "This server does not have LaTeX installed. You " +
"may not be able to compile."; "may not be able to compile.";
display.showWarningBar(warning); display.showTexInstallationMissingWarning(warning);
} }
else if (checkForRnwWeave && else if (checkForRnwWeave &&
!response.isRnwWeaveAvailable(fRnwWeave)) !response.isRnwWeaveAvailable(fRnwWeave))
Expand Down
Expand Up @@ -901,6 +901,19 @@ public void showRequiredPackagesMissingWarning(List<String> packages)
showWarningImpl(() -> warningBar_.showRequiredPackagesMissingWarning(packages, onInstall, onDismiss)); showWarningImpl(() -> warningBar_.showRequiredPackagesMissingWarning(packages, onInstall, onDismiss));
} }


@Override
public void showTexInstallationMissingWarning(String message)
{
final Command install = () -> {
target_.installTinyTeX();
hideWarningBar();
};

showWarningImpl(() -> {
warningBar_.showTexInstallationMissingWarning(message, install);
});
}

@Override @Override
public void showWarningBar(final String warning) public void showWarningBar(final String warning)
{ {
Expand Down
Expand Up @@ -22,6 +22,7 @@ public interface WarningBarDisplay extends IsWidget
{ {
void showReadOnlyWarning(List<String> alternatives); void showReadOnlyWarning(List<String> alternatives);
void showRequiredPackagesMissingWarning(List<String> packages); void showRequiredPackagesMissingWarning(List<String> packages);
void showTexInstallationMissingWarning(String message);
void showWarningBar(String message); void showWarningBar(String message);
void hideWarningBar(); void hideWarningBar();
} }

0 comments on commit 2d8c683

Please sign in to comment.