Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Throw informative error for Windows style EOL (mainly for atom users) #400

Merged
merged 4 commits into from Jun 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 59 additions & 2 deletions R/parse.R
@@ -1,3 +1,60 @@
#' Save parsing from text
#'
#' Parses text safely, i.e. throws an informative error if EOL style does not
#' match LF or indicates the exact position where the parsing failed. Note
#' that we can only detect wrong EOL style if it occurs on the first line
#' already.
#' @param text Text to parse.
#' @param ... Parameters passed to [base::parse()]
#' @keywords internal
#' @examples
#' \dontrun{
#' styler:::parse_safely("a + 3 -4 -> x\r\n glück + 1")
#' # This cannot be detected as a EOL style problem because the first
#' # line ends as expected with \n
#' styler:::parse_safely("a + 3 -4 -> x\nx + 2\r\n glück + 1")
#' }
#' styler:::parse_safely("a + 3 -4 -> \n glück + 1")
parse_safely <- function(text, ...) {
tried_parsing <- tryCatch(parse(text = text, ...),
error = function(e) e,
warning = function(w) w
)
if (inherits(tried_parsing, "error")) {
if (has_crlf_as_first_line_sep(tried_parsing$message, text)) {
stop(
"The code to style seems to use Windows style line endings (CRLF). " ,
"styler currently only supports Unix style line endings (LF). ",
"Please change the EOL character in your editor to Unix style and try again.",
"\nThe parsing error was:\n", tried_parsing$message,
call. = FALSE
)
} else {
stop(tried_parsing)
}
} else if (inherits(tried_parsing, "warning")) {
warning(tried_parsing$message, call. = FALSE)
}
tried_parsing
}

#' Check if a string uses CRLF EOLs
#'
#' @param message A message returned with `tryCatch()`.
#' @param initial_text The inital text to style.
has_crlf_as_first_line_sep <- function(message, initial_text) {
split <- strsplit(message, ":", fixed = TRUE)[[1]]
if (length(split) > 1L && split[1] == "<text>") {
start_char <- as.numeric(split[3])
offending_line <- initial_text[as.integer(split[2])]
if (!is.na(offending_line)) {
if (substr(offending_line, start_char, start_char + 1) == "\r\n") {
return(TRUE)
}
}
}
FALSE
}
#' Obtain token table from text
#'
#' [utils::getParseData()] is used to obtain a flat parse table from `text`.
Expand Down Expand Up @@ -31,8 +88,8 @@ tokenize <- function(text) {
#' @keywords internal
get_parse_data <- function(text, include_text = TRUE, ...) {
# avoid https://bugs.r-project.org/bugzilla3/show_bug.cgi?id=16041
parse(text = text, keep.source = TRUE)
parsed <- parse(text = text, keep.source = TRUE)
parse_safely(text, keep.source = TRUE)
parsed <- parse_safely(text, keep.source = TRUE)
as_tibble(utils::getParseData(parsed, includeText = include_text)) %>%
add_id_and_short()
}
Expand Down
4 changes: 2 additions & 2 deletions R/transform-files.R
Expand Up @@ -217,7 +217,7 @@ verify_roundtrip <- function(old_text, new_text) {
#' @keywords internal
expressions_are_identical <- function(old_text, new_text) {
identical(
parse(text = old_text, keep.source = FALSE),
parse(text = new_text, keep.source = FALSE)
parse_safely(old_text, keep.source = FALSE),
parse_safely(new_text, keep.source = FALSE)
)
}
2 changes: 1 addition & 1 deletion R/utils.R
@@ -1,4 +1,4 @@
parse_text <- function(x) parse(text = x)[[1L]]
parse_text <- function(x) parse_safely(x)[[1L]]

line_col_names <- function() {
c("line1", "line2", "col1", "col2")
Expand Down
16 changes: 16 additions & 0 deletions man/has_crlf_as_first_line_sep.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 29 additions & 0 deletions man/parse_safely.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions tests/testthat/test-parsing.R
Expand Up @@ -42,3 +42,21 @@ test_that("issues with parsing long strings on R 3.1 can be detected", {
"install R .* 3.2"
)
})


test_that("CRLF EOLs fail with informative error", {

expect_error(
style_text("glück <- 3\r\n glück + 1"),
"Please change the EOL character in your editor to Unix style and try again."
)
expect_error(
style_text(c("glück <- 3", "glück + 1\r\n 3")),
"Please change the EOL character in your editor to Unix style and try again."
)

expect_error(
style_text("a + 3 -4 -> x\nx + 2\r\n glück + 1"),
"unexpected input"
)
})