Code chunk collapse=TRUE adds unwanted line to code block output

Working with bookdown, and I was hoping to put code chunks and their output in the same code block upon compiling, so I set the code chunk option collapse = TRUE globally. However, this added a line at the beginning of the compiled code chunk.

For example, this code chunk:

```{r, collapse = TRUE}

# unwanted line above this comment

```

produces this code block:


# unwanted line above this comment

Desired result is

# unwanted line above this comment

I tried strip.white = TRUE, but that didn't work. I'm aware that I can remove the spacing from the r code chunk like so

```{r, collapse = TRUE}
# unwanted line above this comment
```

but, I find the code chunk with extra spacing easier to read, especially when working on long, complicated documents. So, if there's a solution that doesn't involved compact r code chunks, I'd be grateful to know what it is.

This is currently the current behavior of knitr. The line of code for this behavior is here :

strip_white() is not run when collapse = TRUE.

Here is the minimal reprex with knitr

> text <- "
+ ```{r}
+ 
+ # unwanted line above this comment
+ 
+ ```"
> 
> # with collapse FALSE by default
> xfun::raw_string(knitr::knit(text = text, quiet = TRUE))


```r

# unwanted line above this comment

```
> 
> # with collapse TRUE, spaces are not stripe
> withr::with_options(list(knitr.chunk.collapse = TRUE),
+                     xfun::raw_string(knitr::knit(text = text, quiet = TRUE))
+ )


```r

# unwanted line above this comment

```
> 
> # Same as when strip.white is FALSE
> withr::with_options(list(knitr.chunk.strip.white = FALSE),
+                     xfun::raw_string(knitr::knit(text = text, quiet = TRUE))
+ )


```r

# unwanted line above this comment

```

You can open an issue in knitr repo if you want to discuss a change in that.

1 Like

Hi, thanks @cderv . That's really helpful. Before submitting an issue to the knitr repo, I tried pushing the strip_white() function into the knit_hook for 'source' using knitr::knit_hook$set(...) following these instructions from the Markdown Cookbook and it seemed to work for a regular html_document.

---
title: Force strip white when collapse = TRUE
output: html_document
---

```{r, include=FALSE}
local({
  hook_source <- knitr::knit_hooks$get('source')
  knitr::knit_hooks$set(source = function(x, options) {
    
    is_blank2 = function(x) {
      if (length(x)) all(grepl('^\\s*$', x)) else TRUE
    }
    
    strip_white2 = function(x, test_strip = is_blank2) {
      if (!length(x)) return(x)
      while (test_strip(x[1])) {
        x = x[-1]; if (!length(x)) return(x)
      }
      while (test_strip(x[(n <- length(x))])) {
        x = x[-n]; if (n < 2) return(x)
      }
      x
    }
    
    x <- xfun::split_lines(x)
    x <- strip_white2(x)
    x <- paste(x, sep = '', collapse = '\n')
    hook_source(x, options)
  })
})
```

```{r, collapse = TRUE}

# unwanted line above this comment

```

```{r, collapse = TRUE}

mean(1:5)

```

I have no idea if this has catastrophic, unintended consequences for more complex documents, but it seems to be working for this simple example.

Unfortunately, it does not appear to be working when used in an R script and called before each chapter is compiled in bookdown . Any thoughts?

You can indeed rewrite the hook source object to do what you want for your project. This is advanced trick but it is useful on a per project basis.

It should work ok in a bookdown project too. It does when I try on a small example with bookdown demo.

Awesome! Are there guidelines for creating a small bookdown reprex? Because something is not working for me.

I put the knit_hook code in an R script "R/before_script.R," which looks like this:

library(dplyr)
library(ggplot2)
library(here)
library(knitr)
library(kableExtra)

# force knitr to strip white space at begin and end of code block
# even when collapse = TRUE
local({
  hook_source <- knitr::knit_hooks$get('source')
  knitr::knit_hooks$set(source = function(x, options) {
    
    is_blank2 = function(x) {
      
      if (length(x)) all(grepl('^\\s*$', x)) else TRUE
      
    }
    
    strip_white2 = function(x, test_strip = is_blank2) {
      if (!length(x)) return(x)
      while (test_strip(x[1])) {
        x = x[-1]; if (!length(x)) return(x)
      }
      while (test_strip(x[(n <- length(x))])) {
        x = x[-n]; if (n < 2) return(x)
      }
      x
    }
    
    x <- xfun::split_lines(x)
    x <- strip_white2(x)
    x <- paste(x, sep = '', collapse = '\n')
    hook_source(x, options)
  })
})

knitr::opts_chunk$set(echo = TRUE,
                      warning = FALSE,
                      message = FALSE,
                      collapse = TRUE, # code and output in same block
                      fig.align = "center")

And then I add the following parameter to "_bookdown.yml,"

before_chapter_script: "R/before_script.R"

but, that does not seem to work.

You can fork bookdown-demo project on github and share your fork here so that I can have a look.

Hi @cderv. It took me a minute to recreate the problem. Looks like it has something to do with using

bookdown::html_chapters:
  css: [css/style.css, css/toc.css]

in "_output.yml." Though it maybe also has to do with me overwriting some high level css filters for class = sourceCode in my style.css?

Here is the github repo: https://github.com/kbvernon/bookdown-demo

You can see I added two chapters to the demo "test chapter one" and "test chapter two." In the second one, I added the knit_hook directly to the Rmd file, not just "R/before_script.R," and got the desired result, unlike in the first test chapter.

Thoughts/suggestions welcome. Thanks for your help!

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.