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

Support for newlines #214

Merged
merged 10 commits into from
Oct 17, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## formatters 0.5.3.9002
* Fixed a bug in `paginate_to_mpfs()` so that formatting in listings key columns is retained with pagination [`insightsengineering/rlistings#155`](https://github.com/insightsengineering/rlistings/issues/155).
* Added full support of newline characters in any part of `rtables` objects.

## formatters 0.5.3
* Decimal alignment now throws informative error if scientific notation is used.
Expand Down
71 changes: 41 additions & 30 deletions R/matrix_form.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,49 +15,62 @@ mform_handle_newlines <- function(matform) {
has_topleft <- mf_has_topleft(matform)
strmat <- mf_strings(matform)
frmmat <- mf_formats(matform)
nr_header <- mf_nrheader(matform)
hdr_inds <- 1:nr_header

# hack that is necessary only if bottom aligned
topleft_has_nl_char <- FALSE
if (has_topleft) {
tl <- strmat[hdr_inds, 1, drop = TRUE]
strmat[hdr_inds, 1] <- ""
tl <- tl[nzchar(tl)] # we are not interested in initial "" but we cover initial \n
topleft_has_nl_char <- any(grepl("\n", tl))
tl_to_add_back <- strsplit(paste0(tl, collapse = "\n"), split = "\n", fixed = TRUE)[[1]]
how_many_nl <- length(tl_to_add_back)
}
Comment on lines +21 to +30
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would not be necessary if it is aligned top, and it is a bit of a hack

# nlines detects if there is a newline character
row_nlines <- apply(strmat, 1, function(x) max(vapply(x, nlines, 1L), 1L))
nr_header <- mf_nrheader(matform)

if (has_topleft && (sum(row_nlines[hdr_inds]) < how_many_nl)) {
row_nlines[1] <- row_nlines[1] + how_many_nl - sum(row_nlines[hdr_inds])
}

# There is something to change
if (any(row_nlines > 1)) {
# Header indices
hdr_inds <- 1:nr_header
## groundwork for sad haxx to get tl to not be messed up
if (has_topleft) {
tl <- strmat[hdr_inds, 1]
strmat[hdr_inds, 1] <- ""
## recalc them without topleft cause thats handled separately
row_nlines <- apply(strmat, 1, function(x) max(vapply(x, nlines, 1L), 1L))
} else {
tl <- character()
}
## used below even though we don't store it on the resulting object
new_nlines_hdr <- sum(row_nlines[hdr_inds])
if (any(row_nlines > 1) || topleft_has_nl_char) {

# False: Padder should be bottom aligned if no topleft (case of rlistings)
# It is always bottom: tl_padder <- ifelse(has_topleft, pad_vert_top, pad_vert_bottom)

newstrmat <- rbind(
expand_mat_rows(strmat[hdr_inds, , drop = FALSE],
row_nlines[hdr_inds],
cpadder = pad_vert_bottom
cbind(
expand_mat_rows(strmat[hdr_inds, 1, drop = FALSE],
row_nlines[hdr_inds],
cpadder = pad_vert_bottom # topleft info is NOT top aligned
),
expand_mat_rows(strmat[hdr_inds, -1, drop = FALSE],
row_nlines[hdr_inds],
cpadder = pad_vert_bottom # colnames are bottom aligned
)
),
expand_mat_rows(strmat[-1 * hdr_inds, , drop = FALSE], row_nlines[-hdr_inds])
)

newfrmmat <- rbind(
expand_mat_rows(frmmat[hdr_inds, , drop = FALSE],
row_nlines[hdr_inds],
cpadder = pad_vert_bottom
),
row_nlines[hdr_inds],
cpadder = pad_vert_bottom),
expand_mat_rows(frmmat[-1 * hdr_inds, , drop = FALSE], row_nlines[-hdr_inds])
)
## sad haxx :(

if (has_topleft) {
newtl <- unlist(strsplit(tl, "\n"))
if (length(newtl) > new_nlines_hdr) {
stop("Expanding top-left material resulted in more lines (", length(newtl), # nocov
"than fit in the header.") # nocov
starts_from_ind <- if (sum(row_nlines[hdr_inds]) - how_many_nl > 0){
sum(row_nlines[hdr_inds]) - how_many_nl
} else {
0
}
newstrmat[1:new_nlines_hdr, 1] <- c(newtl, rep("", new_nlines_hdr - length(newtl)))
newfrmmat[1:new_nlines_hdr, 1] <- "xx"
newstrmat[starts_from_ind + seq_along(tl_to_add_back), 1] <- tl_to_add_back
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similar as before, but I tried so many other ways, if we leave it bottom this is the only way that actually works

}

mf_strings(matform) <- newstrmat
mf_formats(matform) <- newfrmmat
mf_spans(matform) <- expand_mat_rows(mf_spans(matform), row_nlines, rep_vec_to_len)
Expand Down Expand Up @@ -211,7 +224,6 @@ MatrixPrintForm <- function(strings = NULL,
indent_size = 2) {
display <- disp_from_spans(spans)


ncs <- if (has_rowlabs) ncol(strings) - 1 else ncol(strings)
ret <- structure(
list(
Expand Down Expand Up @@ -239,7 +251,6 @@ MatrixPrintForm <- function(strings = NULL,
class = c("MatrixPrintForm", "list")
)


## .do_mat_expand(ret)
if (expand_newlines) {
ret <- mform_handle_newlines(ret)
Expand Down
20 changes: 14 additions & 6 deletions R/tostring.R
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,11 @@ do_cell_fnotes_wrap <- function(mat, widths, max_width, tf_wrap) {
correct_indentation <- vapply(seq_along(mf_lgrp), function(xx) {
grouping <- mf_lgrp[xx]
if (nzchar(real_indent[grouping])) {
return(stringi::stri_detect(mf_str[xx, 1], regex = paste0("^", real_indent[grouping])))
has_correct_indentation <- stringi::stri_detect(
mf_str[xx, 1],
regex = paste0("^", real_indent[grouping])
)
return(has_correct_indentation || !nzchar(mf_str[xx, 1])) # "" is still an ok indentation
}
# Cases where no indent are true by definition
return(TRUE)
Expand Down Expand Up @@ -750,8 +754,12 @@ wrap_string <- function(str, width, collapse = NULL, smart = TRUE) {
paste0(ret[we_interval], collapse = " "),
width
)
# Taking out repetitions if there are more than one
if (length(we_interval) > 1) {
ret <- ret[-we_interval[-1]]
}
# Paste together and rerun
ret <- paste0(unique(ret), collapse = " ")
ret <- paste0(ret, collapse = " ")
return(wrap_string(str = ret, width = width, collapse = collapse, smart = smart))
}
} else {
Expand Down Expand Up @@ -800,12 +808,12 @@ wrap_txt <- function(str, width, collapse = NULL) {
unlist(wrap_string(str, width, collapse), use.names = FALSE)
}

pad_vert_top <- function(x, len) {
c(x, rep("", len - length(x)))
pad_vert_top <- function(x, len, default = "") {
c(x, rep(default, len - length(x)))
}

pad_vert_bottom <- function(x, len) {
c(rep("", len - length(x)), x)
pad_vert_bottom <- function(x, len, default = "") {
c(rep(default, len - length(x)), x)
}

pad_vec_to_len <- function(vec, len, cpadder = pad_vert_top, rlpadder = cpadder) {
Expand Down
4 changes: 2 additions & 2 deletions tests/testthat/test-pagination.R
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ test_that("pagination works", {
strs <- mf_strings(dfmf_sillytopleft)
strs[1,1] <- "ha\nha\nha\nha\nha\nha\n"
mf_strings(dfmf_sillytopleft) <- strs
expect_error(formatters:::mform_handle_newlines(dfmf_sillytopleft))
expect_silent(formatters:::mform_handle_newlines(dfmf_sillytopleft))

dfmf_cont <- dfmf
mf_rinfo(dfmf_cont)$node_class <- "ContentRow"
Expand All @@ -70,7 +70,7 @@ test_that("pagination works", {
dfmf2 <- formatters:::mform_handle_newlines(dfmf2)
expect_identical(
dfmf2$strings[1:2, 1:2],
matrix(c("tleft mats", "", "m", "pg"), nrow = 2, ncol = 2)
matrix(c("", "tleft mats", "m", "pg"), nrow = 2, ncol = 2)
)


Expand Down