'R markdown results='hold' but for messages?

I have functions outputting multiple messages in my code and I can't get these messages to be in the same output chunk, like with results='hold'.

As of now, the only option that kind of emulates what I want is the collapse=T option, but this sticks the output and the code together, which I don't want.

This code illustrates the situation :

---
title: "Example"
author: "Me"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```



```{r}
a <- function(){
  print("hello")
  print("world")
  message("hello again")
  message("world")
}
```

### default
```{r}
a()
```


### with `results='hold'`
```{r results='hold'}
a()
```


### with `collapse=T`
```{r collapse=T}
a()
```

Output : rmd

I also think It's interesting how the messages get outputted before the results/prints with results='hold'.



Solution 1:[1]

Here is a different version that may fit better with what OP wanted.

This version will mingle the messages and output together as they would be observed had they been sent to the console.

This is done by overriding three hooks: message, output, and chunk.

Contents of Rmd

---
title: "Knitr As Console Output Hook Implementation"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)

# global store for output and messages
asconsole_output <- NULL

# override message hook
# if output option is 'asconsole', append message to global
# otherwise let knitr do its thing
knitr::knit_hooks$set(message = function(x, options) {
  if(!is.null(options$output)) {
    if(options$output == 'asconsole') {
      asconsole_output <<- c(asconsole_output, x)
      return(NULL)
    }
  }
  
  knitr::hooks_html()$message(x, options)
})
  
# override output hook
# if output option is 'asconsole', append output to global
# otherwise let knitr do its thing
knitr::knit_hooks$set(output = function(x, options) {
  if(!is.null(options$output)) {
    if(options$output == 'asconsole') {
      asconsole_output <<- c(asconsole_output, x)
      return(NULL)
    }
  }
  
  knitr::hooks_html()$output(x, options)
})

# override chunk hook
# if output option is 'asconsole', clear global and append formatted contents
# otherwise let knitr do its thing
knitr::knit_hooks$set(chunk = function(x, options) {
  if(!is.null(options$output)) {
    if(options$output == 'asconsole') {
      y <- paste(asconsole_output, collapse = "")
      y <- knitr::hooks_html()$output(y, options)
      asconsole_output <<- NULL
      y <- paste(x, y, collapse = "")
      return(y)
    }
  }
  
  knitr::hooks_html()$chunk(x, options)
})

# test function with results and messages
a <- function() {
  print("a out 1")
  message("a msg 1")
  print("a out 2")
  message("a msg 2")
}
```

# Default Behavior

```{r}
a()
```

# Output As Console

```{r, output='asconsole'}
a()
```

Output HTML

enter image description here

Solution 2:[2]

An option to hold messages similar to how results are holdable, can be implemented by overriding the default knitr output hooks message and chunk.

This approach still allows results to be held should one wish to collate results that would otherwise be split by the occurrence of a message.

Contents of Rmd

---
title: "Knitr Message Hold Hook Implementation"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)

# global store for current chunk messages
current_messages <- NULL

# override default message hook
# if message option is hold, copy messages to the global store and print nothing
# otherwise let knitr do its thing
knitr::knit_hooks$set(message = function(x, options) {
  if (options$message == "hold") {
    current_messages <<- c(current_messages, x)
    return(NULL)
  } else {
    return(knitr::hooks_html()$message(x, options))
  }
})

# override chunk hook
# if message option is hold, clear global store, and append prepared messages
# otherwise let knitr do its thing
knitr::knit_hooks$set(chunk = function(x, options) {
  if (options$message == "hold") {
    collapsed_messages <- paste(current_messages, collapse = "")
    options$message <- TRUE
    messages <- knitr::hooks_html()$message(collapsed_messages, options)
    current_messages <<- NULL
    paste(x, messages, collapse = "")
  } else {
    knitr::hooks_html()$chunk(x, options)
  }
})

# test function with results and messages
a <- function() {
  print("a out 1")
  message("a msg 1")
  print("a out 2")
  message("a msg 2")
}
```

# Default Behavior

```{r}
a()
```

# Holding Messages

```{r, message='hold'}
a()
```

# Holding Results

```{r, results='hold'}
a()
```

# Holding Messages and Results

```{r, message='hold', results='hold'}
a()
```

Output HTML

enter image description here

Solution 3:[3]

I cannot find any solution using chunks option docs1 docs2

The only thing that comes to my mind is to have two chunks - one for displaying the code without evaluation and second one collapsing outputs but without code:

### Two blocs
```{r eval=FALSE}
a()
```
```{r collapse=TRUE, echo=FALSE}
a()
```

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 the-mad-statter
Solution 2
Solution 3 pawelru