Richie Cotton - 8 months ago 43
LaTeX Question

# How to autogenerate LaTeX \index entries for functions with knitr

I'm trying to create an index for a long

Rnw
document. I'd like each function called in the code chunks to have an index entry of the form

\index{*functionname* function (*packagecontainingthatfunction*)}


Rather than manually inspecting each code chunk and adding these index entries, it would be nice if knitr autogenerated these for me.

How do I do this?

I guess I need to override the behaviour of
knitr::render_latex
, but it isn't obvious to me what needs to change.

A sample
Rnw
file to play with:

\documentclass{article}

\usepackage[]{imakeidx}
\makeindex

\begin{document}

<<>>=
y <- log(sqrt(1:10))
@

\printindex

\end{document}


Use a hook.

This function will walk recursively through an expression, and whenever it finds a function, it returns \index{functionname function (packagename)}.

create_index_entry_from_expressions <- function(exprs)
{
lapply(
as.list(exprs),
function(li)
{
# Load packages of functions accessed by :: or :::
if(is.call(li) && grepl("^:{2,3}$", deparse(li[[1]]))) { library(deparse(li[[2]]), character.only = TRUE) } if(is.name(li)) { name_of_obj <- deparse(li) obj <- mget( name_of_obj, mode = "function", ifnotfound = NA_character_, inherits = TRUE )[[1]] location <- find(name_of_obj) if(!is.na(name_of_obj) && is.function(obj) && grepl("^[[:alpha:]]", name_of_obj) && grepl("^package:", location)) { return( paste0( "\\index{", knitr:::escape_latex(name_of_obj), " function (", substring(location, 9), ")}" ) ) } return(NULL) } if(!is.language(li)) return(NULL) create_index_entry_from_expressions(li) } ) }  This hook will add the index entries text into the .tex file, for any chunk that has indexit = TRUE as a chunk option. Define it early in the document. knitr::knit_hooks$set(indexit = function(before, options, envir) {
if (before) {
exprs <- parse(text = options\$code)
result <- create_index_entry_from_expressions(exprs)
unlist(result, use.names = FALSE)
}
})