Skip to content

Format with {styler} after rpp::rpp_to_prod() #12

Open
@lorenzwalthert

Description

@lorenzwalthert

In this blog post, you explain how to go to prod with rpp::rpp_to_prod():

foo <-              function(x               ) { # !q foo <- Character()? function(x = ?Character()) {
  out <- paste("foo:", x)                        # !q   Character()? out <- paste("foo:", x)
  out
}

I suggest to give the user the opportunity use {styler} with scope = I("spaces") (if they want) to style this text and since the line count should not change, replace all lines that have a comment with # q! with the styled code. Here is a quick implementation:

library(magrittr)

#' Style prod code 
style_prod <- function(text) {
  text <- ensure_last_empty(convert_newlines_to_linebreaks(text))
  text_new <- c(
    as.character(styler::style_text(text, scope = I("spaces"))),
    ""
  )
  if (length(text) != length(text_new)) {
    # TODO EOF
    rlang::warn("You hit a bug in {styler}, not formatting prod code. [more instrucitons]")
    return(text)
  }
  pd <- getParseData(parse(text = text))
  active_tokens <- grepl("^# !q", pd$text) & pd$token == 'COMMENT'
  active_lines <- unique(c(pd$line1[active_tokens], pd$line2[active_tokens]))
  text[active_lines] <- text_new[active_lines]
  text
}



# From {styler}, ensure input has a traling newline so formatting with scope = 'spaces'
# has same line count
ensure_last_empty <- function(x) {
  if (all(x == "")) {
    return("")
  }
  x <- c(x, "", "")
  x <- x[seq(1, length(x) - which(rev(x) != "")[1] + 1L)]
  c(x, rep("", 1))
}

# from {styler}, turn text into a character vector where every element is one
# line, i.e. convert_newlines_to_linebreaks('x\n2') -> c('x', '2')
convert_newlines_to_linebreaks <- function(text) {
  split <- strsplit(text, "\n", fixed = TRUE)
  purrr::map(split, ~ if (identical(.x, character(0))) {
    ""
  } else {
    .x
  }) %>%
    unlist()
}


text <- 'foo <-              function(x               ) { # !q foo <- Character()? function(x = ?Character()) {
  out <- paste("foo:", x)                        # !q   Character()? out <- paste("foo:", x)
  out
}
'
style_prod(text)
#> [1] "foo <- function(x) { # !q foo <- Character()? function(x = ?Character()) {"
#> [2] "  out <- paste(\"foo:\", x) # !q   Character()? out <- paste(\"foo:\", x)" 
#> [3] "  out"                                                                     
#> [4] "}"                                                                         
#> [5] ""

Created on 2021-10-19 by the reprex package (v2.0.1)

Only drawback is that {styler} is slow (but the cache helps in 2nd styling). You could also remove certain elements in the code, e.g. Character()? from the parse data and then collapse it together similar to how styler does it.

getParseData(parse(text = "Character()? x <- 'hi'"))

Anyways, not sure how often rpp::rpp_to_prod() is called, probably not often.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions