Skip to content

Commit

Permalink
Better strategy for replacing text
Browse files Browse the repository at this point in the history
Fixes #34
  • Loading branch information
hadley committed Aug 26, 2020
1 parent 57f789d commit 3254d19
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 16 deletions.
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Imports:
brio,
fansi,
rlang,
vctrs,
yaml
Suggests:
rmarkdown,
Expand Down
35 changes: 19 additions & 16 deletions R/highlight.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
#' @examples
#' cat(highlight("1 + 1"))
highlight <- function(text, classes = classes_chroma(), pre_class = NULL) {
text <- gsub("\t", " ", text)
text <- gsub("\t", " ", text, fixed = TRUE)
text <- gsub("\r", "", text, fixed = TRUE)
parsed <- parse_data(text)
if (is.null(parsed)) {
return(NA_character_)
Expand All @@ -39,21 +40,13 @@ highlight <- function(text, classes = classes_chroma(), pre_class = NULL) {
# Update input - basic idea from prettycode
changed <- !is.na(out$href) | !is.na(out$class) | out$text != out$escaped
changes <- out[changed, , drop = FALSE]
changes_by_line <- split(changes, changes$line1)
lines <- strsplit(text, "\r?\n")[[1]]

for (change in changes_by_line) {
i <- change$line1[[1]]
new <- style_token(change$escaped, change$href, change$class)

lines[[i]] <- replace_in_place(
lines[[i]],
start = change$col1,
end = change$col2,
replacement = new
)
}
out <- paste0(lines, collapse = "\n")

loc <- line_col(text)
start <- vctrs::vec_match(data.frame(line = changes$line1, col = changes$col1), loc)
end <- vctrs::vec_match(data.frame(line = changes$line2, col = changes$col2), loc)

new <- style_token(changes$escaped, changes$href, changes$class)
out <- replace_in_place(text, start, end, replacement = new)

if (is.null(pre_class)) {
return(out)
Expand Down Expand Up @@ -88,6 +81,16 @@ replace_in_place <- function(str, start, end, replacement) {
paste0(pieces, collapse = "")
}

line_col <- function(x) {
char <- strsplit(x, "")[[1]]

nl <- char == "\n"
line <- cumsum(c(TRUE, nl[-length(char)]))
col <- sequence(rle(line)$lengths)

data.frame(line, col)
}

parse_data <- function(text) {
stopifnot(is.character(text), length(text) == 1)

Expand Down
1 change: 1 addition & 0 deletions tests/testthat/test-downlit-html.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<span class="co"># This is a comment</span>

<span class="kw">stats</span>::<span class="fu"><a href="https://rdrr.io/r/stats/median.html">median</a></span>()

</pre>
<p><code><a href="https://rdrr.io/r/stats/median.html">stats::median()</a></code></p>

Expand Down
1 change: 1 addition & 0 deletions tests/testthat/test-downlit-md.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
> cat(downlit_md_string("```\nbase::t(1)\n```"))
<pre class='chroma'>
<span class='k'>base</span>::<span class='nf'><a href='https://rdrr.io/r/base/t.html'>t</a></span>(<span class='m'>1</span>)

</pre>

> # No transforms
Expand Down
5 changes: 5 additions & 0 deletions tests/testthat/test-highlight.R
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ test_that("can parse code with carriage returns", {
expect_equal(lines[[2]], "<span class='m'>2</span>")
})

test_that("syntax can span multiple lines", {
expect_equal(highlight("f(\n\n)"), "<span class='nf'>f</span>(\n\n)")
expect_equal(highlight("'\n\n'"), "<span class='s'>'\n\n'</span>")
})

test_that("unparsable code returns NULL", {
expect_equal(highlight("<"), NA_character_)
# but pure comments still highlighted
Expand Down

0 comments on commit 3254d19

Please sign in to comment.