pat-s pat-s - 3 months ago 17
LaTeX Question

knitr syntax highlighting in .Rnw files (LaTeX)

I am using .Rnw files to produce a report with LaTeX and knitr.

My

knitr_setup
looks as follows:

<<knitr_setup, echo=FALSE>>=
library(knitr)
opts_chunk$set(highlight = TRUE, cache = TRUE, eval = FALSE, size = "small")
options(width = 60)
opts_knit$set(out.format = "latex")
@
<<theme, cache=FALSE, echo=FALSE>>=
thm = knit_theme$get("olive")
knit_theme$set(thm)
@


I tested several syntax highlighting themes. Previews are provided here.
However, changing the themes in
knit_theme$get()
only results in a different background (for some) in the final pdf. Syntax highlighting stays with the default colors.

R-Version: 3.3.1

RStudio Version: 0.99.1280 (Preview)

knitr-Version: 1.13

What is wrong in my setup?

CL. CL.
Answer

The problem: You have a document with several calls to knit_theme$set() and expect syntax highlighting to change accordingly, on a per-chunk basis.

Syntax highlighting stays with the default colors.

Each call to knit_theme$set() supersedes the previous call. This is because the colors for syntax highlighting are defined just once, in the LaTeX preamble (e.g. \newcommand{\hlnum}[1]{\textcolor[rgb]{0.529,0.875,0.443}{#1}}).

However, changing the themes in knit_theme$get() only results in a different background (for some) in the final pdf.

Unlike highlighting of keywords, the background color is defined for each chunk (look for \definecolor{shadecolor}{rgb}{0.961, 0.961, 0.961}). (Exception: Chunks with results = "asis".)

The solution (concept): Using \renewcommand, the syntax highlighting commands can be "updated" mid-document. We can therefore set a new theme, extract its syntax highlighting definitions, replace newcommand by renewcommand and write the definitions to the document. All subsequent chunks will use the new theme. At the end of the document, restore the default theme; otherwise, all chunks before the first change of theme will use the last theme set.

Implementation:

setThemeInline <- function(theme) {
  knit_theme$set(knit_theme$get(theme))
  header <- opts_knit$get("header")["highlight"]
  header <- gsub(pattern = "newcommand",
                 replacement = "renewcommand",
                 x = header)
  cat(header)
}

Usage:

Note that setThemeInline must be called in an asis chunk. Don't forget to restore the theme (see last chunk). Only chunks after the chunk where setThemeInline was called will be affected.

\documentclass{article}
\begin{document}
<<setup>>=
library(knitr)

setThemeInline <- function(theme) {
  knit_theme$set(knit_theme$get(theme))
  header <- opts_knit$get("header")["highlight"]
  header <- gsub(pattern = "newcommand",
                 replacement = "renewcommand",
                 x = header)
  cat(header)

  # for chunks with results = "asis"
  shadecolor <- col2rgb(opts_chunk$get("background")) / 255
  cat(sprintf("\\definecolor{shadecolor}{rgb}{%s, %s, %s}",
              shadecolor[1, 1], shadecolor[2, 1], shadecolor[3, 1]))
}

@


<<theme, results='asis'>>=
setThemeInline("denim")
@

<<>>=
getAnswer <- function(question) {
  if (missing(question)) {
    stop("Ask something!")
  }
  return(42)
}
@

<<results='asis'>>=
setThemeInline("vampire")
@

<<>>=
getAnswer <- function(question) {
  if (missing(question)) {
    stop("Ask something!")
  }
  return(42)
}
@

<<restore>>=
knit_theme$set(knit_theme$get("default"))
@

\end{document}

Output:

Output

Comments