Skip to content

Commit 542fce2

Browse files
Merge pull request #540 from lorenzwalthert/enfore-blank-at-EOF
- Ensure styled files also have EOF line break if no tokens were changed (#540).
2 parents 8586191 + e199c64 commit 542fce2

File tree

8 files changed

+107
-3
lines changed

8 files changed

+107
-3
lines changed

R/io.R

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ transform_utf8 <- function(path, fun, write_back = TRUE) {
1515

1616
#' @importFrom rlang with_handlers warn
1717
transform_utf8_one <- function(path, fun, write_back) {
18-
old <- xfun::read_utf8(path)
1918
with_handlers({
20-
new <- fun(old)
21-
identical <- identical(unclass(old), unclass(new))
19+
file_with_info <- read_utf8(path)
20+
# only write back when changed OR when there was a missing newline
21+
new <- fun(file_with_info$text)
22+
identical_content <- identical(unclass(file_with_info$text), unclass(new))
23+
identical <- identical_content && !file_with_info$missing_EOF_line_break
2224
if (!identical && write_back) {
2325
xfun::write_utf8(new, path)
2426
}
@@ -28,3 +30,58 @@ transform_utf8_one <- function(path, fun, write_back) {
2830
NA
2931
})
3032
}
33+
34+
#' Read UTF-8
35+
#'
36+
#' Reads an UTF-8 file, returning the content and whether or not the final line
37+
#' was blank. This information is required higher up in the callstack because
38+
#' we should write back if contents changed or if there is no blank line at the
39+
#' EOF. A perfectly styled file with no EOF blank line will gain such a line
40+
#' with this implementation.
41+
#' @param path A path to a file to read.
42+
#' @keywords internal
43+
read_utf8 <- function(path) {
44+
out <- rlang::with_handlers(
45+
read_utf8_bare(path),
46+
warning = function(w) w,
47+
error = function(e) e
48+
)
49+
if (inherits(out, "character")) {
50+
list(
51+
text = out,
52+
missing_EOF_line_break = FALSE
53+
)
54+
} else if (inherits(out, "error")) {
55+
rlang::abort(out$message)
56+
} else if (inherits(out, "warning")) {
57+
list(
58+
text = read_utf8_bare(path, warn = FALSE),
59+
missing_EOF_line_break = grepl("incomplete", out$message)
60+
)
61+
}
62+
}
63+
64+
#' Drop-in replacement for [xfun::read_utf8()], with an optional `warn`
65+
#' argument.
66+
#' @keywords internal
67+
read_utf8_bare <- function(con, warn = TRUE) {
68+
x <- readLines(con, encoding = "UTF-8", warn = warn)
69+
i <- invalid_utf8(x)
70+
n <- length(i)
71+
if (n > 0) {
72+
stop(
73+
c(
74+
"The file ", con, " is not encoded in UTF-8. ",
75+
"These lines contain invalid UTF-8 characters: "
76+
),
77+
paste(c(head(i), if (n > 6) "..."), collapse = ", ")
78+
)
79+
}
80+
x
81+
}
82+
83+
#' Drop-in replacement for [xfun:::invalid_utf8()]
84+
#' @keywords internal
85+
invalid_utf8 <- function(x) {
86+
which(!is.na(x) & is.na(iconv(x, "UTF-8", "UTF-8")))
87+
}

man/read_utf8.Rd

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/read_utf8_bare.Rd

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
x
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
x
Binary file not shown.
Binary file not shown.

tests/testthat/test-utils.R

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,15 @@ test_that("non-comment-helpers", {
66
expect_equal(previous_non_comment(child, 4), 2)
77
expect_equal(next_non_comment(child, 2), 4)
88
})
9+
10+
test_that("files with and without blank EOF line are read correctly", {
11+
expect_known_value(
12+
read_utf8(test_path("reference-objects/missing-blank-at-EOF.R")),
13+
test_path("reference-objects/return-read-utf8-missing-EOF")
14+
)
15+
16+
expect_known_value(
17+
read_utf8(test_path("reference-objects/non-missing-blank-at-EOF.R")),
18+
test_path("reference-objects/return-read-utf8-non-missing-EOF")
19+
)
20+
})

0 commit comments

Comments
 (0)