Steve Powell Steve Powell - 12 days ago 5
Markdown Question

Create index of definitions / theorems at end of bookdown book

For reader convenience, I'd like to include, at the end of my bookdown book, written in markdown, a simple list or index of definitions from the body of the book. i.e. ones created using custom blocks, like this:

```{definition, bar, echo=T}
A bar is defined here as a foo-like thing.
```


(My need is for definitions, but others might like lists of theorems, etc. Don't know if lists of figures and tables could be covered in the same way?)

Thanks to @yihui I know that
knitr::all_labels(engine == 'definition')
is my friend.

So I can do this anywhere in the end of the book, usually at the end:

```{r comment="",results="asis",echo=FALSE}
knitr::all_labels(engine == 'definition') %>% unlist %>% paste0("\n\n","\\@ref(def:",.,"): ",.,"\n\n",collapse="\n\n") %>% cat

```


Which prints this:

1: bar

2: foobar


With clickable numbers. Which is OK. But wouldn't it be nice if, after each label, the actual definition could be printed too? (The content of the blocks is not available in knitr::all_labels(engine == 'definition'))

Answer

Here is an example using the output format bookdown::html_document2, and it should also work for any other book output formats:

---
title: "Test Definitions"
output: bookdown::html_document2
---

```{r setup, include=FALSE}
def_list = list()
knitr::knit_hooks$set(engine = function(before, options) {
  if (before && options$engine == 'definition') {
    # collect definition terms from options$name
    def_list[[options$label]] <<- options$name
  }
  NULL
})
```

```{definition, d1, name='Foo'}
Foo is defined as ...
```

```{definition, d2, name='Bar'}
Bar is defined as ...
```

All definitions in this document:

```{r echo=FALSE, results='asis'}
def_list = unlist(def_list)
cat(sprintf('- \\@ref(def:%s) %s', names(def_list), def_list), sep = '\n')
```

Output:

definition list

The basic idea is to use a chunk hook to collect definition labels and names, and print them at the end. You do not have to use the chunk option name. It can be an arbitrary option, e.g., term. The option name is special because the name of the definition will be printed in the output. If you don't like that, you can use, for example, term:

```{definition, d2, term='Bar'}
Bar is defined as ...
```