diff --git a/DESCRIPTION b/DESCRIPTION index 97546004..d9411de0 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -2,7 +2,7 @@ Package: tinytable Type: Package Title: Simple and Configurable Tables in 'HTML', 'LaTeX', 'Markdown', 'Word', 'PNG', 'PDF', and 'Typst' Formats Description: Create highly customized tables with this simple and dependency-free package. Data frames can be converted to 'HTML', 'LaTeX', 'Markdown', 'Word', 'PNG', 'PDF', or 'Typst' tables. The user interface is minimalist and easy to learn. The syntax is concise. 'HTML' tables can be customized using the flexible 'Bootstrap' framework, and 'LaTeX' code with the 'tabularray' package. -Version: 0.5.0.1 +Version: 0.5.0.2 Imports: methods Depends: diff --git a/Makefile b/Makefile index 5f60d8bc..e74c85be 100644 --- a/Makefile +++ b/Makefile @@ -22,4 +22,6 @@ test: install ## test Rscript -e "library(tinytable);tinytest::run_test_dir()" website: install ## render vignettes and website + rm -rf _quarto + rm -rf docs Rscript -e "altdoc::render_docs(verbose = TRUE, freeze = TRUE, autolink = TRUE)" diff --git a/NEWS.md b/NEWS.md index 2ecbca45..383c706d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,10 +2,17 @@ ## Development + +Misc: + +* Major refactor of the style internals. HTML, LaTeX, and Typst documents should be much more concise and efficient. +* `style_tt()`: the `i` and `j` indices are now consistent in all formats. They refer to rows *after* the insertion of row groups. + Bugs: * Typst notes returned an error since the last release. Thanks to @DominikVogel for report #357. + ## 0.5.0 New: diff --git a/R/build_tt.R b/R/build_tt.R index 47efd39a..d014457d 100644 --- a/R/build_tt.R +++ b/R/build_tt.R @@ -17,6 +17,13 @@ build_tt <- function(x, output = NULL) { x@output <- output + for (th in x@lazy_theme) { + fn <- th[[1]] + args <- th[[2]] + args[["x"]] <- x + x <- do.call(fn, args) + } + # groups must increment indices here for (idx in seq_along(x@lazy_group)) { l <- x@lazy_group[[idx]] @@ -66,10 +73,7 @@ build_tt <- function(x, output = NULL) { # markdown styles need to be applied before creating the table, otherwise there's annoying parsing, etc. if (x@output %in% c("markdown", "gfm", "dataframe")) { - for (l in x@lazy_style) { - l[["x"]] <- x - x <- eval(l) - } + x <- style_eval(x) } # draw the table @@ -86,20 +90,6 @@ build_tt <- function(x, output = NULL) { x <- eval(l) } - if (x@output == "typst") { - if (is.null(x@theme[[1]]) || is.function(x@theme[[1]]) || isTRUE(x@theme[[1]] %in% c("default", "striped"))) { - # reverse the order of the lines to allow overwriting defaults - ls <- x@lazy_style - x <- style_tt(x, i = nrow(x), line = "b", line_width = 0.1) - if (x@nhead > 0) { - x <- style_tt(x, i = -x@nhead + 1, line = "t", line_width = 0.1) - x <- style_tt(x, i = 1, line = "t", line_width = 0.05) - } else { - x <- style_tt(x, i = 1, line = "t", line_width = 0.1) - } - } - } - if (!x@output %in% c("markdown", "gfm", "dataframe")) { for (l in x@lazy_style) { l[["x"]] <- x @@ -110,8 +100,9 @@ build_tt <- function(x, output = NULL) { } } - if (x@output == "typst") { - x <- style_apply_typst(x) + # markdown styles are applied earlier + if (!x@output %in% c("markdown", "gfm", "dataframe")) { + x <- style_eval(x) } x <- finalize(x) diff --git a/R/class.R b/R/class.R index d5458381..48b283f9 100644 --- a/R/class.R +++ b/R/class.R @@ -35,11 +35,13 @@ setClass( ncol = "numeric", nhead = "numeric", ngroupi = "numeric", + group_i_idx = "numeric", names = "NULLorCharacter", output = "character", output_dir = "character", id = "character", bootstrap_class = "character", + bootstrap_css_rule = "character", css = "data.frame", style = "data.frame", lazy_format = "list", @@ -47,6 +49,8 @@ setClass( lazy_style = "list", lazy_plot = "list", lazy_finalize = "list", + lazy_theme = "list", + group_tt_i = "logical", portable = "logical" ) ) @@ -80,6 +84,8 @@ setMethod("initialize", "tinytable", function( .Object@css <- data.frame(i = NA, j = NA, bootstrap = NA, id = NA) .Object@portable <- FALSE .Object@style <- data.frame() + .Object@group_tt_i <- FALSE + .Object@lazy_theme <- list() # conditional: allows NULL user input if (!is.null(placement)) .Object@placement <- placement if (!is.null(caption)) .Object@caption <- caption diff --git a/R/format_numeric.R b/R/format_numeric.R index e3b97880..aaff0cad 100644 --- a/R/format_numeric.R +++ b/R/format_numeric.R @@ -30,6 +30,7 @@ format_numeric <- function(value, num_suffix, digits, num_mark_big, num_mark_dec } else { out <- NULL } + if (is.character(out)) out <- trimws(out) return(out) } diff --git a/R/format_tt.R b/R/format_tt.R index d5356cc1..ffc6c419 100644 --- a/R/format_tt.R +++ b/R/format_tt.R @@ -122,7 +122,9 @@ format_tt <- function(x, escape = escape, markdown = markdown, quarto = quarto, - other = other) + other = other, + inull = is.null(i), + jnull = is.null(j)) out@lazy_format <- c(out@lazy_format, list(cal)) } else { @@ -145,7 +147,9 @@ format_tt <- function(x, other = other, escape = escape, quarto = quarto, - markdown = markdown) + markdown = markdown, + inull = is.null(i), + jnull = is.null(j)) } return(out) @@ -170,7 +174,9 @@ format_tt_lazy <- function(x, escape = FALSE, markdown = FALSE, quarto = quarto, - other = as.character + other = as.character, + inull = FALSE, + jnull = FALSE ) { # format_tt() supports vectors @@ -207,11 +213,8 @@ format_tt_lazy <- function(x, replace <- sanitize_replace(replace) sanity_num_mark(digits, num_mark_big, num_mark_dec) - i <- sanitize_i(i, x, pre_group_i = TRUE) + i <- sanitize_i(i, x, lazy = FALSE) j <- sanitize_j(j, x) - ibody <- attr(i, "body") - inull <- isTRUE(attr(i, "null")) - jnull <- isTRUE(attr(j, "null")) # In sanity_tt(), we fill in missing NULL `j` in the format-specific versions, # because tabularray can do whole column styling. Here, we need to fill in @@ -223,37 +226,37 @@ format_tt_lazy <- function(x, for (col in j) { # sprintf() is self-contained if (!is.null(sprintf)) { - out[ibody, col] <- base::sprintf(sprintf, ori[ibody, col, drop = TRUE]) + out[i, col] <- base::sprintf(sprintf, ori[i, col, drop = TRUE]) } else { # logical - if (is.logical(ori[ibody, col])) { - out[ibody, col] <- bool(ori[ibody, col, drop = TRUE]) + if (is.logical(ori[i, col])) { + out[i, col] <- bool(ori[i, col, drop = TRUE]) # date - } else if (inherits(ori[ibody, col], "Date")) { - out[ibody, col] <- format(ori[ibody, col, drop = TRUE], date) + } else if (inherits(ori[i, col], "Date")) { + out[i, col] <- format(ori[i, col, drop = TRUE], date) # numeric - } else if (is.numeric(ori[ibody, col, drop = TRUE])) { - tmp <- format_numeric(ori[ibody, col], + } else if (is.numeric(ori[i, col, drop = TRUE])) { + tmp <- format_numeric(ori[i, col], num_suffix = num_suffix, digits = digits, num_mark_big = num_mark_big, num_mark_dec = num_mark_dec, num_zero = num_zero, num_fmt = num_fmt) - if (!is.null(tmp)) out[ibody, col] <- tmp + if (!is.null(tmp)) out[i, col] <- tmp # other } else { - out[ibody, col] <- other(ori[ibody, col, drop = TRUE]) + out[i, col] <- other(ori[i, col, drop = TRUE]) } } for (k in seq_along(replace)) { - idx <- ori[ibody, col, drop = TRUE] %in% replace[[k]] - out[ibody, col][idx] <- names(replace)[[k]] + idx <- ori[i, col, drop = TRUE] %in% replace[[k]] + out[i, col][idx] <- names(replace)[[k]] } } # loop over columns @@ -262,12 +265,12 @@ format_tt_lazy <- function(x, # before escaping if (is.function(fn)) { for (col in j) { - out[ibody, col] <- fn(ori[ibody, col, drop = TRUE]) + out[i, col] <- fn(ori[i, col, drop = TRUE]) } } if (isTRUE(math)) { - for (row in ibody) { + for (row in i) { for (col in j) { out[row, col] <- format_math(out[row, col], math) } @@ -312,18 +315,6 @@ format_tt_lazy <- function(x, o <- FALSE } - # body - for (row in ibody) { - for (col in j) { - out[row, col] <- escape_text(out[row, col], output = o) - } - } - - # column names - if (0 %in% i) { - colnames(x) <- escape_text(colnames(x), output = o) - } - # caption & groups: if i and j are both null if (inull && jnull) { if (inherits(x, "tinytable")) { @@ -350,7 +341,25 @@ format_tt_lazy <- function(x, x@lazy_group[[idx]] <- g } } + colnames(x) <- escape_text(colnames(x), output = o) + for (col in seq_len(ncol(out))) { + out[, col] <- escape_text(out[, col], output = o) + } + + } else { + # body + for (row in i) { + for (col in j) { + out[row, col] <- escape_text(out[row, col], output = o) + } + } + + # column names + if (0 %in% i) { + colnames(x) <- escape_text(colnames(x), output = o) + } } + } # markdown and quarto at the very end diff --git a/R/group_bootstrap.R b/R/group_bootstrap.R index 76cab062..015d4f53 100644 --- a/R/group_bootstrap.R +++ b/R/group_bootstrap.R @@ -45,12 +45,12 @@ group_bootstrap_col <- function(x, j, ihead, ...) { x@table_string <- out - x <- style_eval(x, i = ihead, align = "c") + x <- style_tt(x, i = ihead, align = "c") # midrule on numbered spans (not full columns of body) jnames <- names(j) jnames <- seq_along(jnames)[trimws(jnames) != ""] - x <- style_eval(x, i = ihead, j = jnames, line = "b", line_width = 0.05, line_color = "#d3d8dc") + x <- style_tt(x, i = ihead, j = jnames, line = "b", line_width = 0.05, line_color = "#d3d8dc") return(x) } @@ -59,16 +59,8 @@ group_bootstrap_col <- function(x, j, ihead, ...) { group_bootstrap_row <- function(x, i, j, indent = 1, ...) { label <- names(i) - # reverse order is important - i <- rev(sort(i)) - - # # i = list("a" = 2, "b" = 3, "c" = 4) should be displayed consecutively - # i <- i - (rev(seq_along(i)) - 1) - out <- x@table_string - tab <- strsplit(out, "\\n")[[1]] - for (g in seq_along(i)) { js <- sprintf( "window.addEventListener('load', function () { insertSpanRow(%s, %s, '%s') });", @@ -76,7 +68,8 @@ group_bootstrap_row <- function(x, i, j, indent = 1, ...) { i[g] + x@nhead - 1, ncol(x), names(i)[g]) - out <- bootstrap_setting(out, new = js, component = "cell") + out <- lines_insert(out, js, "tinytable span after", "after") + # out <- bootstrap_setting(out, new = js, component = "cell") } # need unique function names in case there are @@ -88,26 +81,11 @@ group_bootstrap_row <- function(x, i, j, indent = 1, ...) { fixed = TRUE) idx <- insert_values(seq_len(nrow(x)), rep(NA, length(i)), i) - idx_old <- idx$new[!is.na(idx$old)] - idx_new <- idx$new[is.na(idx$old)] - - # limit index ot number of rows to avoid styling header or footer - idx_old <- idx_old[idx_old <= nrow(x)] x@table_string <- out - # should not be style_tt, because we already have a string bootstrap table at this stage - x <- style_eval(x, i = idx_old, j = 1, indent = indent) - # if there's a two-level header column multi-span, we want it centered. - x <- style_eval(x, i = -1, align = "c") - - dots <- list(...) - dots[["j"]] <- NULL - if (length(dots) > 0) { - args <- c(list(x = x, i = idx$new[is.na(idx$old)]), dots) - x <- do.call(style_tt, args) - } + x <- style_tt(x, i = -1, align = "c") # do not override meta since we modified it here above return(x) diff --git a/R/group_tabularray.R b/R/group_tabularray.R index 60027cd0..188ad571 100644 --- a/R/group_tabularray.R +++ b/R/group_tabularray.R @@ -46,14 +46,16 @@ group_tabularray_col <- function(x, j, ihead, ...) { for (k in seq_along(j)) { z <- min(j[[k]]) + cs <- max(j[[k]]) - min(j[[k]]) + 1 + if (cs == 1) cs <- NULL args <- list( tt_build_now = TRUE, x = x, i = ihead, j = z, align = "c", - colspan = max(j[[k]]) - min(j[[k]]) + 1) - x <- do.call(style_eval, args) + colspan = cs) + x <- do.call(style_tt, args) } return(x) @@ -95,6 +97,8 @@ group_tabularray_row <- function(x, i, indent) { tab <- c(top, idx$vec, bot) tab <- paste(tab, collapse = "\n") + # colspan for row groups + # can't figure out how to use style_tt() here. Maybe build order? cellspec <- sprintf( "cell{%s}{%s}={%s}{%s},", idx$new[is.na(idx$old)] + x@nhead, @@ -105,12 +109,6 @@ group_tabularray_row <- function(x, i, indent) { cellspec <- paste(cellspec, collapse = "") tab <- tabularray_insert(tab, content = cellspec, type = "inner") - # we also want to indent the header - i <- idx$new[!is.na(idx$old)] + x@nhead - cellspec <- sprintf("cell{%s}{%s}={%s},\n", i, 1, sprintf("preto={\\hspace{%sem}}", indent)) - cellspec <- paste(cellspec, collapse = "") - tab <- tabularray_insert(tab, content = cellspec, type = "inner") - x@table_string <- tab return(x) diff --git a/R/group_tt.R b/R/group_tt.R index 8c65ca58..c3492f2a 100644 --- a/R/group_tt.R +++ b/R/group_tt.R @@ -70,13 +70,28 @@ group_tt <- function(x, i = NULL, j = NULL, indent = 1, ...) { # we don't need this as a list, and we use some sorting later i <- unlist(i) - x@ngroupi <- x@ngroupi + length(i) + if (!is.null(i)) { + if (isTRUE(x@group_tt_i)) { + stop("Only one row-wise `group_tt(i = ...)` call is allowed.", call. = FALSE) + } + x@group_tt_i <- TRUE + if (isTRUE(indent > 0)) { + idx_indent <- setdiff( + seq_len(nrow(x) + length(i)), + i + seq_along(i) - 1) + x <- style_tt(x, i = idx_indent, j = 1, indent = indent) + } + } + + if (!is.null(i)) { + x@ngroupi <- x@ngroupi + length(i) + x@group_i_idx <- as.numeric(unlist(i)) + } cal <- call("group_eval", i = i, j = j, indent = indent) x@lazy_group <- c(x@lazy_group, list(cal)) - return(x) } diff --git a/R/group_typst.R b/R/group_typst.R index 4e758dc4..d651f5df 100644 --- a/R/group_typst.R +++ b/R/group_typst.R @@ -40,7 +40,7 @@ group_typst_row <- function(x, i, indent, ...) { idx_new <- i + seq_along(i) - 1 idx_all <- seq_len(nrow(x) + length(i)) idx <- setdiff(idx_all, idx_new) - x <- style_tt(x, idx, indent = indent) + # x <- style_tt(x, idx, indent = indent) return(x) } @@ -67,13 +67,5 @@ group_typst_col <- function(x, j, ihead, ...) { x@table_string <- out - # # midrule - # jrule <- lapply(names(j), function(n) if (trimws(n) != "") j[[n]]) - # jrule <- Filter(function(k) !is.null(k), jrule) - # for (jr in jrule) { - # # 0 indexing - # x <- style_eval(x, i = ihead, j = jr, line = "b", line_width = .05, midrule = TRUE) - # } - return(x) } diff --git a/R/last_style.R b/R/last_style.R new file mode 100644 index 00000000..d132560e --- /dev/null +++ b/R/last_style.R @@ -0,0 +1,25 @@ +last_valid <- function(x) { + x <- x[!is.na(x)] + if (length(x) == 0) return(NA) + return(utils::tail(x, 1)) +} + +last_style_vec <- function(x) { + if (is.factor(x)) { + x <- as.character(x) + } + if (is.logical(x) && !all(is.na(x))) { + x <- any(sapply(x, isTRUE)) + } else { + x <- last_valid(x) + } + return(x) +} + + +last_style <- function(sty) { + sty <- split(sty, list(sty$i, sty$j)) + sty <- lapply(sty, function(k) lapply(k, last_style_vec)) + sty <- do.call(rbind, lapply(sty, data.frame)) + return(sty) +} diff --git a/R/sanity.R b/R/sanity.R index f721aab0..cf267bb4 100644 --- a/R/sanity.R +++ b/R/sanity.R @@ -1,99 +1,108 @@ usepackage_latex <- function(name, options = NULL, extra_lines = NULL) { - assert_dependency("rmarkdown") - invisible(knitr::knit_meta_add(list(rmarkdown::latex_dependency(name, options, extra_lines)))) + assert_dependency("rmarkdown") + invisible(knitr::knit_meta_add(list(rmarkdown::latex_dependency(name, options, extra_lines)))) } -sanitize_i <- function(i, x, pre_group_i = FALSE) { - if (is.null(i)) { - if (pre_group_i && inherits(x, "tinytable")) { - out <- seq_len(nrow(x) - x@ngroupi) - } else { - out <- seq_len(nrow(x)) +sanity_align <- function(align, i) { + if (any(grepl("d", align)) && !is.null(i)) { + msg <- "d column alignment can only be applied to entire columns. `i` must be `NULL`." + stop(msg, call. = FALSE) } - if (inherits(x, "tinytable") && x@nhead > 0) { - out <- c(-1 * (1:x@nhead - 1), out) +} + + +sanitize_i <- function(i, x, pre_group_i = FALSE, lazy = TRUE) { + out <- seq_len(nrow(x)) + if (is.null(i) && isTRUE(lazy)) { + out <- NA + attr(out, "null") <- TRUE + attr(out, "body") <- seq_len(nrow(x)) + attr(out, "head") <- integer() + } else { + if (!is.null(i)) { + out <- i + } else if (inherits(x, "tinytable")) { + out <- seq_len(nrow(x@table_dataframe)) + } + attr(out, "null") <- FALSE + attr(out, "body") <- out[out > 0] + attr(out, "head") <- out[out < 1] } - } else { - out <- i - } - attr(out, "null") <- is.null(i) - attr(out, "body") <- out[out > 0] - attr(out, "head") <- out[out < 1] - return(out) + return(out) } sanitize_j <- function(j, x) { - # regex - if (is.character(j) && length(j) == 1 && !is.null(colnames(x))) { - out <- grep(j, colnames(x), perl = TRUE) - # full names - } else if (is.character(j) && length(j) > 1 && !is.null(colnames(x))) { - bad <- setdiff(j, colnames(x)) - if (length(bad) > 0) { - msg <- sprintf("Missing columns: %s", paste(bad, collapse = ", ")) - stop(msg, call. = FALSE) - } - out <- which(colnames(x) %in% j) - } else { - assert_integerish(j, lower = 1, upper = ncol(x), null.ok = TRUE) - if (is.null(j)) { - out <- seq_len(ncol(x)) + # regex + if (is.character(j) && length(j) == 1 && !is.null(colnames(x))) { + out <- grep(j, colnames(x), perl = TRUE) + # full names + } else if (is.character(j) && length(j) > 1 && !is.null(colnames(x))) { + bad <- setdiff(j, colnames(x)) + if (length(bad) > 0) { + msg <- sprintf("Missing columns: %s", paste(bad, collapse = ", ")) + stop(msg, call. = FALSE) + } + out <- which(colnames(x) %in% j) } else { - out <- j + assert_integerish(j, lower = 1, upper = ncol(x), null.ok = TRUE) + if (is.null(j)) { + out <- seq_len(ncol(x)) + } else { + out <- j + } } - } - attr(out, "null") <- is.null(j) - return(out) + attr(out, "null") <- is.null(j) + return(out) } sanitize_output <- function(output) { - assert_choice(output, choice = c("tinytable", "markdown", "latex", "html", "typst", "dataframe", "gfm"), null.ok = TRUE) - - # default output format - if (is.null(output) || isTRUE(output == "tinytable")) { - has_viewer <- interactive() && !is.null(getOption("viewer")) - out <- if (has_viewer) "html" else "markdown" - } else { - out <- output - } - - if (isTRUE(check_dependency("knitr"))) { - if (isTRUE(knitr::pandoc_to() %in% c("latex", "beamer"))) { - flag <- getOption("tinytable_latex_preamble", default = TRUE) - if (isTRUE(flag)) { - usepackage_latex("float") - usepackage_latex("tabularray", extra_lines = c( - "\\usepackage[normalem]{ulem}", - "\\usepackage{graphicx}", - "\\UseTblrLibrary{booktabs}", - "\\UseTblrLibrary{rotating}", - "\\UseTblrLibrary{siunitx}", - "\\NewTableCommand{\\tinytableDefineColor}[3]{\\definecolor{#1}{#2}{#3}}", - "\\newcommand{\\tinytableTabularrayUnderline}[1]{\\underline{#1}}", - "\\newcommand{\\tinytableTabularrayStrikeout}[1]{\\sout{#1}}" - )) - } - if (is.null(output)) out <- "latex" - } else if (isTRUE(knitr::pandoc_to() %in% c("html", "revealjs"))) { - if (is.null(output)) out <- "html" - } else if (isTRUE(knitr::pandoc_to() == "typst")) { - if (is.null(output)) out <- "typst" - if (isTRUE(check_dependency("quarto"))) { - if (isTRUE(quarto::quarto_version() < "1.5.29")) { - msg <- "Typst tables require version 1.5.29 or later of Quarto and version 0.11.0 or later of Typst. This software may (or may not) only be available in pre-release builds: https://quarto.org/docs/download" - stop(msg, call. = FALSE) - } - } - } else if (isTRUE(knitr::pandoc_to() == "docx")) { - if (is.null(output)) out <- "markdown" + assert_choice(output, choice = c("tinytable", "markdown", "latex", "html", "typst", "dataframe", "gfm"), null.ok = TRUE) + + # default output format + if (is.null(output) || isTRUE(output == "tinytable")) { + has_viewer <- interactive() && !is.null(getOption("viewer")) + out <- if (has_viewer) "html" else "markdown" } else { - if (is.null(output)) out <- "markdown" + out <- output + } + + if (isTRUE(check_dependency("knitr"))) { + if (isTRUE(knitr::pandoc_to() %in% c("latex", "beamer"))) { + flag <- getOption("tinytable_latex_preamble", default = TRUE) + if (isTRUE(flag)) { + usepackage_latex("float") + usepackage_latex("tabularray", extra_lines = c( + "\\usepackage[normalem]{ulem}", + "\\usepackage{graphicx}", + "\\UseTblrLibrary{booktabs}", + "\\UseTblrLibrary{rotating}", + "\\UseTblrLibrary{siunitx}", + "\\NewTableCommand{\\tinytableDefineColor}[3]{\\definecolor{#1}{#2}{#3}}", + "\\newcommand{\\tinytableTabularrayUnderline}[1]{\\underline{#1}}", + "\\newcommand{\\tinytableTabularrayStrikeout}[1]{\\sout{#1}}" + )) + } + if (is.null(output)) out <- "latex" + } else if (isTRUE(knitr::pandoc_to() %in% c("html", "revealjs"))) { + if (is.null(output)) out <- "html" + } else if (isTRUE(knitr::pandoc_to() == "typst")) { + if (is.null(output)) out <- "typst" + if (isTRUE(check_dependency("quarto"))) { + if (isTRUE(quarto::quarto_version() < "1.5.29")) { + msg <- "Typst tables require version 1.5.29 or later of Quarto and version 0.11.0 or later of Typst. This software may (or may not) only be available in pre-release builds: https://quarto.org/docs/download" + stop(msg, call. = FALSE) + } + } + } else if (isTRUE(knitr::pandoc_to() == "docx")) { + if (is.null(output)) out <- "markdown" + } else { + if (is.null(output)) out <- "markdown" + } } - } - return(out) + return(out) } @@ -101,298 +110,315 @@ sanitize_output <- function(output) { #' #' @noRd check_dependency <- function(library_name) { - flag <- requireNamespace(library_name, quietly = TRUE) - if (isFALSE(flag)) { - msg <- sprintf("Please install the `%s` package.", library_name) - return(msg) - } else { - return(TRUE) - } + flag <- requireNamespace(library_name, quietly = TRUE) + if (isFALSE(flag)) { + msg <- sprintf("Please install the `%s` package.", library_name) + return(msg) + } else { + return(TRUE) + } } assert_dependency <- function(library_name) { - flag <- check_dependency(library_name) - if (!isTRUE(flag)) stop(flag, call. = FALSE) - return(invisible()) + flag <- check_dependency(library_name) + if (!isTRUE(flag)) stop(flag, call. = FALSE) + return(invisible()) } assert_choice <- function(x, choice, null.ok = FALSE, name = as.character(substitute(x))) { - if (is.null(x) && isTRUE(null.ok)) { - return(TRUE) - } - if (is.character(x) && length(x) == 1 && x %in% choice) { - return(TRUE) - } - msg <- sprintf( - "`%s` must be one of: %s", - name, - paste(choice, collapse = ", ") - ) - stop(msg, call. = FALSE) + if (is.null(x) && isTRUE(null.ok)) { + return(TRUE) + } + if (is.character(x) && length(x) == 1 && x %in% choice) { + return(TRUE) + } + msg <- sprintf( + "`%s` must be one of: %s", + name, + paste(choice, collapse = ", ") + ) + stop(msg, call. = FALSE) } check_string <- function(x, null.ok = FALSE) { - if (is.null(x) && isTRUE(null.ok)) { - return(invisible(TRUE)) - } - if (is.character(x) && length(x) == 1) { - return(invisible(TRUE)) - } - return(FALSE) + if (is.null(x) && isTRUE(null.ok)) { + return(invisible(TRUE)) + } + if (is.character(x) && length(x) == 1) { + return(invisible(TRUE)) + } + return(FALSE) } assert_string <- function(x, null.ok = FALSE, name = as.character(substitute(x))) { - msg <- sprintf("`%s` must be a string.", name) - if (!isTRUE(check_string(x, null.ok = null.ok))) { - stop(msg, call. = FALSE) - } + msg <- sprintf("`%s` must be a string.", name) + if (!isTRUE(check_string(x, null.ok = null.ok))) { + stop(msg, call. = FALSE) + } } check_flag <- function(x, null.ok = FALSE) { - if (is.null(x) && isTRUE(null.ok)) { - return(TRUE) - } - if (is.logical(x) && length(x) == 1) { - return(TRUE) - } - return(FALSE) + if (is.null(x) && isTRUE(null.ok)) { + return(TRUE) + } + if (is.logical(x) && length(x) == 1) { + return(TRUE) + } + return(FALSE) } assert_flag <- function(x, null.ok = FALSE, name = as.character(substitute(x))) { - msg <- sprintf("`%s` must be a logical flag.", name) - if (!isTRUE(check_flag(x, null.ok = null.ok))) { - stop(msg, call. = FALSE) - } + msg <- sprintf("`%s` must be a logical flag.", name) + if (!isTRUE(check_flag(x, null.ok = null.ok))) { + stop(msg, call. = FALSE) + } +} + +check_function <- function(x, null.ok = FALSE) { + if (is.null(x) && isTRUE(null.ok)) { + return(TRUE) + } + if (is.function(x)) { + return(TRUE) + } + return(FALSE) +} + +assert_function <- function(x, null.ok = FALSE, name = as.character(substitute(x))) { + msg <- sprintf("`%s` must be a function.", name) + if (!isTRUE(check_function(x, null.ok = null.ok))) { + stop(msg, call. = FALSE) + } } assert_length <- function(x, len = 1, null.ok = FALSE, name = as.character(substitute(x))) { - if (is.null(x) && isTRUE(null.ok)) { - return(invisible(TRUE)) - } - msg <- sprintf("`%s` must be one of these lengths: %s", name, paste(len, collapse = ", ")) - if (!length(x) %in% len) { - stop(msg, call. = FALSE) - } + if (is.null(x) && isTRUE(null.ok)) { + return(invisible(TRUE)) + } + msg <- sprintf("`%s` must be one of these lengths: %s", name, paste(len, collapse = ", ")) + if (!length(x) %in% len) { + stop(msg, call. = FALSE) + } } assert_logical <- function(x, null.ok = FALSE, name = as.character(substitute(x))) { - if (is.null(x) && isTRUE(null.ok)) { - return(invisible(TRUE)) - } - msg <- sprintf("`%s` must be a logical vector", name) - if (!is.logical(x)) stop(msg, call. = FALSE) + if (is.null(x) && isTRUE(null.ok)) { + return(invisible(TRUE)) + } + msg <- sprintf("`%s` must be a logical vector", name) + if (!is.logical(x)) stop(msg, call. = FALSE) } check_integerish <- function(x, len = NULL, lower = NULL, upper = NULL, null.ok = TRUE) { - if (is.null(x) && isTRUE(null.ok)) { + if (is.null(x) && isTRUE(null.ok)) { + return(TRUE) + } + if (!is.numeric(x)) { + return(FALSE) + } + x <- stats::na.omit(x) + if (!is.null(len) && length(x) != len) { + return(FALSE) + } + if (!is.null(lower) && any(x < lower)) { + return(FALSE) + } + if (!is.null(upper) && any(x > upper)) { + return(FALSE) + } + if (isTRUE(any(abs(x - round(x)) > (.Machine$double.eps)^0.5))) { + return(FALSE) + } return(TRUE) - } - if (!is.numeric(x)) { - return(FALSE) - } - x <- stats::na.omit(x) - if (!is.null(len) && length(x) != len) { - return(FALSE) - } - if (!is.null(lower) && any(x < lower)) { - return(FALSE) - } - if (!is.null(upper) && any(x > upper)) { - return(FALSE) - } - if (isTRUE(any(abs(x - round(x)) > (.Machine$double.eps)^0.5))) { - return(FALSE) - } - return(TRUE) } assert_integerish <- function(x, len = NULL, lower = NULL, upper = NULL, null.ok = FALSE, name = as.character(substitute(x))) { - if (isTRUE(null.ok) && is.null(x)) { - return(invisible()) - } - msg <- sprintf("`%s` must be integer-ish", name) - if (is.null(x) && !isTRUE(null.ok)) stop(sprintf("%s should not be NULL.", name), call. = FALSE) - if (!isTRUE(check_integerish(x, len = len, lower = lower, upper = upper, null.ok = null.ok))) { - if (!is.numeric(x)) msg <- paste0(msg, "; it is not numeric") - if (!is.null(len) && length(x) != len) msg <- paste0(msg, sprintf("; its length must be %s", len)) - if (!is.null(lower) && any(x < lower)) msg <- paste0(msg, sprintf("; all values must be greater than or equal to %s", lower)) - if (!is.null(upper) && any(x > upper)) msg <- paste0(msg, sprintf("; all values must be less than or equal to %s", upper)) - if (isTRUE(any(abs(x - round(x)) > (.Machine$double.eps)^0.5))) msg <- paste0(msg, "; all values must be close to integers") - stop(msg, call. = FALSE) - } + if (isTRUE(null.ok) && is.null(x)) { + return(invisible()) + } + msg <- sprintf("`%s` must be integer-ish", name) + if (is.null(x) && !isTRUE(null.ok)) stop(sprintf("%s should not be NULL.", name), call. = FALSE) + if (!isTRUE(check_integerish(x, len = len, lower = lower, upper = upper, null.ok = null.ok))) { + if (!is.numeric(x)) msg <- paste0(msg, "; it is not numeric") + if (!is.null(len) && length(x) != len) msg <- paste0(msg, sprintf("; its length must be %s", len)) + if (!is.null(lower) && any(x < lower)) msg <- paste0(msg, sprintf("; all values must be greater than or equal to %s", lower)) + if (!is.null(upper) && any(x > upper)) msg <- paste0(msg, sprintf("; all values must be less than or equal to %s", upper)) + if (isTRUE(any(abs(x - round(x)) > (.Machine$double.eps)^0.5))) msg <- paste0(msg, "; all values must be close to integers") + stop(msg, call. = FALSE) + } } check_null <- function(x) { - is.null(x) + is.null(x) } assert_null <- function(x, name = as.character(substitute(x))) { - if (!isTRUE(check_null(x))) stop(sprintf("%s should be NULL.", name), call. = FALSE) + if (!isTRUE(check_null(x))) stop(sprintf("%s should be NULL.", name), call. = FALSE) } check_numeric <- function(x, len = NULL, lower = NULL, upper = NULL, null.ok = TRUE) { - if (is.null(x) && isTRUE(null.ok)) { + if (is.null(x) && isTRUE(null.ok)) { + return(TRUE) + } + if (!is.numeric(x)) { + return(FALSE) + } + if (!is.null(len) && length(x) != len) { + return(FALSE) + } + if (!is.null(lower) && any(x < lower)) { + return(FALSE) + } + if (!is.null(upper) && any(x > upper)) { + return(FALSE) + } return(TRUE) - } - if (!is.numeric(x)) { - return(FALSE) - } - if (!is.null(len) && length(x) != len) { - return(FALSE) - } - if (!is.null(lower) && any(x < lower)) { - return(FALSE) - } - if (!is.null(upper) && any(x > upper)) { - return(FALSE) - } - return(TRUE) } assert_numeric <- function(x, len = NULL, lower = NULL, upper = NULL, null.ok = FALSE, name = as.character(substitute(x))) { - msg <- sprintf("`%s` must be numeric", name) - if (!isTRUE(check_numeric(x, len = len, lower = lower, upper = upper, null.ok = null.ok))) { - if (!is.null(len) && length(x) != len) msg <- paste0(msg, sprintf("; its length must be %s", len)) - if (!is.null(lower) && any(x < lower)) msg <- paste0(msg, sprintf("; all values must be greater than or equal to %s", lower)) - if (!is.null(upper) && any(x > upper)) msg <- paste0(msg, sprintf("; all values must be less than or equal to %s", upper)) - stop(msg, call. = FALSE) - } + msg <- sprintf("`%s` must be numeric", name) + if (!isTRUE(check_numeric(x, len = len, lower = lower, upper = upper, null.ok = null.ok))) { + if (!is.null(len) && length(x) != len) msg <- paste0(msg, sprintf("; its length must be %s", len)) + if (!is.null(lower) && any(x < lower)) msg <- paste0(msg, sprintf("; all values must be greater than or equal to %s", lower)) + if (!is.null(upper) && any(x > upper)) msg <- paste0(msg, sprintf("; all values must be less than or equal to %s", upper)) + stop(msg, call. = FALSE) + } } assert_data_frame <- function(x, min_rows = 0, min_cols = 0, name = as.character(substitute(x))) { - msg <- sprintf("`%s` must be a data.frame.", name) - if (!is.data.frame(x)) stop(msg, call. = FALSE) - msg <- sprintf("Number of rows in `%s` must be at least `%s`", name, min_rows) - if (nrow(x) < min_rows) stop(msg, call. = FALSE) - msg <- sprintf("Number of columns in `%s` must be at least `%s`", name, min_cols) - if (ncol(x) < min_cols) stop(msg, call. = FALSE) + msg <- sprintf("`%s` must be a data.frame.", name) + if (!is.data.frame(x)) stop(msg, call. = FALSE) + msg <- sprintf("Number of rows in `%s` must be at least `%s`", name, min_rows) + if (nrow(x) < min_rows) stop(msg, call. = FALSE) + msg <- sprintf("Number of columns in `%s` must be at least `%s`", name, min_cols) + if (ncol(x) < min_cols) stop(msg, call. = FALSE) } check_character <- function(x, len = NULL, null.ok = FALSE, name = as.character(substitute(x))) { - if (isTRUE(null.ok) && is.null(x)) { + if (isTRUE(null.ok) && is.null(x)) { + return(TRUE) + } else if (!is.character(x)) { + msg <- sprintf("`%s` must be character.", name) + return(msg) + } else if (!is.null(len) && length(x) != len) { + msg <- sprintf("`%s` must have length %s.", name, len) + return(msg) + } return(TRUE) - } else if (!is.character(x)) { - msg <- sprintf("`%s` must be character.", name) - return(msg) - } else if (!is.null(len) && length(x) != len) { - msg <- sprintf("`%s` must have length %s.", name, len) - return(msg) - } - return(TRUE) } assert_character <- function(x, len = NULL, null.ok = FALSE, name = as.character(substitute(x))) { - flag <- check_character(x, len = len, null.ok = null.ok, name = name) - if (!isTRUE(flag)) { - stop(flag, call. = FALSE) - } else { - return(invisible(TRUE)) - } + flag <- check_character(x, len = len, null.ok = null.ok, name = name) + if (!isTRUE(flag)) { + stop(flag, call. = FALSE) + } else { + return(invisible(TRUE)) + } } assert_list <- function(x, named = FALSE, len = NULL, null.ok = FALSE, name = as.character(substitute(x))) { - if (isTRUE(null.ok) && is.null(x)) { - return(invisible(TRUE)) - } - if (!is.list(x)) stop("Input is not a list.", call. = FALSE) - if (isTRUE(named)) { - if (is.null(names(x))) { - stop(sprintf("`%s` should be named list.", name), call. = FALSE) + if (isTRUE(null.ok) && is.null(x)) { + return(invisible(TRUE)) + } + if (!is.list(x)) stop("Input is not a list.", call. = FALSE) + if (isTRUE(named)) { + if (is.null(names(x))) { + stop(sprintf("`%s` should be named list.", name), call. = FALSE) + } } - } - if (!is.null(len)) { - if (length(x) != len) { - stop(sprintf("`%s` must be of length %s.", name, len), call. = FALSE) + if (!is.null(len)) { + if (length(x) != len) { + stop(sprintf("`%s` must be of length %s.", name, len), call. = FALSE) + } } - } } assert_function <- function(x, null.ok = FALSE, name = as.character(substitute(x))) { - if (isTRUE(null.ok) && is.null(x)) { - return(invisible(TRUE)) - } - if (!is.function(x)) { - msg <- sprintf("`%s` must be a function.", name) - stop(msg, call. = FALSE) - } + if (isTRUE(null.ok) && is.null(x)) { + return(invisible(TRUE)) + } + if (!is.function(x)) { + msg <- sprintf("`%s` must be a function.", name) + stop(msg, call. = FALSE) + } } check_atomic_vector <- function(x, null.ok = FALSE, name = as.character(substitute(x))) { - if (isTRUE(null.ok) && is.null(x)) { - return(invisible(TRUE)) - } - # doesn't work on glue::glue() output - # flag <- is.atomic(x) && is.vector(x) && !is.list(x) - flag <- is.atomic(x) && is.null(dim(x)) && length(x) > 0 && !is.list(x) - if (flag) { - out <- TRUE - } else if (is.factor(x) && is.null(dim(x))) { - out <- TRUE - } else { - out <- sprintf("`%s` must be an atomic vector.", name) - } - return(out) + if (isTRUE(null.ok) && is.null(x)) { + return(invisible(TRUE)) + } + # doesn't work on glue::glue() output + # flag <- is.atomic(x) && is.vector(x) && !is.list(x) + flag <- is.atomic(x) && is.null(dim(x)) && length(x) > 0 && !is.list(x) + if (flag) { + out <- TRUE + } else if (is.factor(x) && is.null(dim(x))) { + out <- TRUE + } else { + out <- sprintf("`%s` must be an atomic vector.", name) + } + return(out) } assert_class <- function(x, classname) { - if (!inherits(x, classname)) { - msg <- sprintf("`x` must be of class `%s`.", classname) - stop(msg, call. = FALSE) - } + if (!inherits(x, classname)) { + msg <- sprintf("`x` must be of class `%s`.", classname) + stop(msg, call. = FALSE) + } } sanitize_notes <- function(notes) { - if (is.character(notes) && length(notes) > 0) { - notes <- as.list(notes) - } - assert_list(notes, null.ok = TRUE) - for (idx in seq_along(notes)) { - n <- notes[[idx]] - bad <- FALSE - if (is.list(n)) { - if (is.null(names(notes)[idx])) { - bad <- TRUE - } - if (!all(c("i", "j", "text") %in% names(n))) { - bad <- TRUE - } - } else if (!is.character(n) || length(n) != 1) { - bad <- TRUE - } - if (isTRUE(bad)) { - stop("`notes` includes invalid elements. Please refer to the documentation for details.", call. = FALSE) - } - } - return(notes) + if (is.character(notes) && length(notes) > 0) { + notes <- as.list(notes) + } + assert_list(notes, null.ok = TRUE) + for (idx in seq_along(notes)) { + n <- notes[[idx]] + bad <- FALSE + if (is.list(n)) { + if (is.null(names(notes)[idx])) { + bad <- TRUE + } + if (!all(c("i", "j", "text") %in% names(n))) { + bad <- TRUE + } + } else if (!is.character(n) || length(n) != 1) { + bad <- TRUE + } + if (isTRUE(bad)) { + stop("`notes` includes invalid elements. Please refer to the documentation for details.", call. = FALSE) + } + } + return(notes) } sanitize_replace <- function(replace) { - if (isTRUE(replace)) { - replace <- stats::setNames(list(NA), "") - } else if (isFALSE(replace)) { - replace <- stats::setNames(list(NULL), "") - } else if (isTRUE(check_string(replace))) { - replace <- stats::setNames(list(NA), replace) - } else if (!is.list(replace) || is.null(names(replace))) { - stop("`replace` should be TRUE/FALSE, a single string, or a named list.", call. = FALSE) - } - return(replace) + if (isTRUE(replace)) { + replace <- stats::setNames(list(NA), "") + } else if (isFALSE(replace)) { + replace <- stats::setNames(list(NULL), "") + } else if (isTRUE(check_string(replace))) { + replace <- stats::setNames(list(NA), replace) + } else if (!is.list(replace) || is.null(names(replace))) { + stop("`replace` should be TRUE/FALSE, a single string, or a named list.", call. = FALSE) + } + return(replace) } sanity_num_mark <- function(digits, num_mark_big, num_mark_dec) { - if (is.null(digits)) { - if (num_mark_big != "") stop("`num_mark_big` requires a `digits` value.", call. = FALSE) - if (num_mark_dec != ".") stop("`num_mark_dec` requires a `digits` value.", call. = FALSE) - } + if (is.null(digits)) { + if (num_mark_big != "") stop("`num_mark_big` requires a `digits` value.", call. = FALSE) + if (num_mark_dec != ".") stop("`num_mark_dec` requires a `digits` value.", call. = FALSE) + } } diff --git a/R/style_bootstrap.R b/R/style_bootstrap.R index 6ca5f336..7c0c023a 100644 --- a/R/style_bootstrap.R +++ b/R/style_bootstrap.R @@ -29,137 +29,122 @@ setMethod( bootstrap_css = NULL, bootstrap_css_rule = NULL, ...) { - out <- x@table_string - # i is a logical matrix mask - if (is.matrix(i) && is.logical(i) && nrow(i) == nrow(x) && ncol(i) == ncol(x)) { - assert_null(j) - settings <- which(i == TRUE, arr.ind = TRUE) - settings <- stats::setNames(data.frame(settings), c("i", "j")) - } else { - ival <- sanitize_i(i, x) - jval <- sanitize_j(j, x) - # order may be important for recycling - settings <- expand.grid(i = ival, j = jval, tabularray = "") - if (is.null(i) && !is.null(j)) { - settings <- settings[order(settings$i, settings$j), ] - } - } - - # JS 0-indexing - settings$j <- settings$j - 1 - settings$i <- settings$i - 1 + x@nhead - - - # settings have a different size for latex, so bootstrap breaks - vectorize_bootstrap <- function(setting, userinput, string) { - # simple cases - if (is.null(userinput) || isFALSE(userinput)) { - return(setting) - } - if (isTRUE(userinput)) { - return(paste(setting, string)) - } - - # logical vector - if (is.logical(userinput)) { - out <- paste(setting, ifelse(userinput, string, "")) - return(out) - } - - # character vector means the user inputs actual values - if (is.character(userinput)) { - out <- sprintf(string, userinput) - out <- paste(setting, out) - return(out) - } - stop("here be dragons") - } - if (!is.null(align)) { - align_bootstrap <- ifelse(align == "c", "center", align) - align_bootstrap <- ifelse(align == "d", "center", align_bootstrap) - align_bootstrap <- ifelse(align == "l", "left", align_bootstrap) - align_bootstrap <- ifelse(align == "r", "right", align_bootstrap) + if (length(x@bootstrap_css_rule) == 1) { + x@table_string <- bootstrap_setting(x@table_string, x@bootstrap_css_rule, component = "css") + } + + sty <- x@style + + + sty$alignv[which(sty$alignv == "t")] <- "top" + sty$alignv[which(sty$alignv == "b")] <- "bottom" + sty$alignv[which(sty$alignv == "m")] <- "middle" + + sty$align[which(sty$align == "l")] <- "left" + sty$align[which(sty$align == "c")] <- "center" + sty$align[which(sty$align == "d")] <- "center" + sty$align[which(sty$align == "r")] <- "right" + + rec <- expand.grid( + i = c(-(seq_len(x@nhead) - 1), seq_len(x@nrow)), + j = seq_len(x@ncol) + ) + css <- rep("", nrow(rec)) + + for (row in seq_len(nrow(sty))) { + + # index: sty vs rec + idx_i <- sty$i[row] + if (is.na(idx_i)) idx_i <- unique(rec$i) + idx_j <- sty$j[row] + if (is.na(idx_j)) idx_j <- unique(rec$j) + idx <- rec$i == idx_i & rec$j == idx_j + + if (isTRUE(sty[row, "bold"])) css[idx] <- paste(css[idx], "font-weight: bold;") + if (isTRUE(sty[row, "italic"])) css[idx] <- paste(css[idx], "font-style: italic;") + if (isTRUE(sty[row, "underline"])) css[idx] <- paste(css[idx], "text-decoration: underline;") + if (isTRUE(sty[row, "strikeout"])) css[idx] <- paste(css[idx], "text-decoration: line-through;") + if (isTRUE(sty[row, "monospace"])) css[idx] <- paste(css[idx], "font-family: monospace;") + if (!is.na(sty[row, "color"])) css[idx] <- paste(css[idx], paste0("color: ", sty[row, "color"], ";")) + if (!is.na(sty[row, "background"])) css[idx] <- paste(css[idx], paste0("background-color: ", sty[row, "background"], ";")) + if (!is.na(sty[row, "fontsize"])) css[idx] <- paste(css[idx], paste0("font-size: ", sty[row, "fontsize"], "em;")) + if (!is.na(sty[row, "alignv"])) css[idx] <- paste(css[idx], paste0("vertical-align: ", sty[row, "alignv"], ";")) + if (!is.na(sty[row, "align"])) css[idx] <- paste(css[idx], paste0("text-align: ", sty[row, "align"], ";")) + if (!is.na(sty[row, "indent"])) css[idx] <- paste(css[idx], paste0("padding-left: ", sty[row, "indent"], "em;")) + if (!is.na(sty[row, "bootstrap_css"])) css[idx] <- paste(css[idx], sty[row, "bootstrap_css"]) + + lin <- "" + line <- sty$line[row] + line_width <- sty$line_width[row] + line_color <- sty$line_color[row] + line_color <- if (is.na(line_color)) "black" else line_color + line_width <- if (is.na(line_width)) 0.1 else line_width + left <- grepl("l", line) + right <- grepl("r",line) + top <- grepl("t", line) + bottom <- grepl("b", line) + if (all(c(left, right, top, bottom))) { + template <- "border: solid %s %sem;" + } else if (any(c(left, right, top, bottom))) { + template <- "border: solid %s %sem;" + if (left) template <- "border-left: solid %s %sem;" + if (right) template <- "border-right: solid %s %sem;" + if (top) template <- "border-top: solid %s %sem;" + if (bottom) template <- "border-bottom: solid %s %sem;" } else { - align_bootstrap <- align - } - - if (!is.null(alignv)) { - alignv_bootstrap <- switch(alignv, - "t" = "top", - "m" = "middle", - "b" = "bottom" - ) - } else { - alignv_bootstrap <- alignv - } - - if (!is.null(fontsize)) { - fontsize_bootstrap <- sprintf("%sem", fontsize) - } else { - fontsize_bootstrap <- fontsize - } - - settings$bootstrap <- "" - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, bold, "font-weight: bold;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, italic, "font-style: italic;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, underline, "text-decoration: underline;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, strikeout, "text-decoration: line-through;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, monospace, "font-family: monospace;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, fontsize_bootstrap, "font-size: %s;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, align_bootstrap, "text-align: %s;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, alignv_bootstrap, "vertical-align: %s;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, color, "color: %s;") - settings$bootstrap <- vectorize_bootstrap(settings$bootstrap, background, "background-color: %s;") - if (indent > 0) { - settings$bootstrap <- paste(settings$bootstrap, sprintf("padding-left: %sem;", indent), sep = "") + template <- "" } - - if (!is.null(line)) { - tmp <- sprintf(": solid %s %s;", paste0(line_width, "em"), line_color) - if (grepl("t", line)) settings$bootstrap <- paste0(settings$bootstrap, " border-top", tmp) - if (grepl("b", line)) settings$bootstrap <- paste0(settings$bootstrap, " border-bottom", tmp) - if (grepl("l", line)) settings$bootstrap <- paste0(settings$bootstrap, " border-left", tmp) - if (grepl("r", line)) settings$bootstrap <- paste0(settings$bootstrap, " border-right", tmp) + if (template != "") { + lin <- paste(lin, sprintf(template, line_color, line_width)) } - - # unique IDs for each CSS style combination - id <- sapply(unique(settings$bootstrap), function(k) get_id(stem = "tinytable_css_")) - settings$id <- id[match(settings$bootstrap, names(id))] - - if (is.null(rowspan)) rowspan <- 1 - if (is.null(colspan)) colspan <- 1 - - # CSS style for cell - css_done <- NULL - - x@css <- rbind(x@css, settings[, c("i", "j", "bootstrap", "id")]) - - if (!is.null(bootstrap_css)) { - tmp <- settings[, c("i", "j", "bootstrap", "id")] - tmp$bootstrap <- bootstrap_css - x@css <- rbind(x@css, tmp) + css[idx] <- paste(css[idx], lin) + } + + css <- gsub(" +", " ", trimws(css)) + + # JS 0-indexing + rec$i <- rec$i - 1 + x@nhead + rec$j <- rec$j - 1 + + + # spans: before styles because we return(x) if there is no style + for (row in seq_len(nrow(sty))) { + rowspan <- if (!is.na(sty$rowspan[row])) sty$rowspan[row] else 1 + colspan <- if (!is.na(sty$colspan[row])) sty$colspan[row] else 1 + if (rowspan > 1 || colspan > 1) { + id <- get_id(stem = "spanCell_") + listener <- " window.addEventListener('load', function () { %s(%s, %s, %s, %s) })" + listener <- sprintf(listener, id, sty$i[row], sty$j[row] - 1, rowspan, colspan) + x@table_string <- lines_insert(x@table_string, listener, "tinytable span after", "after") + # x@table_string <- bootstrap_setting(x@table_string, listener, component = "cell") } - - # spans - for (row in seq_len(nrow(settings))) { - if (rowspan != 1 || colspan != 1) { - listener <- "window.addEventListener('load', function () { spanCell_%s(%s, %s, %s, %s) })" - listener <- sprintf(listener, settings$id[row], settings$i[row], settings$j[row], rowspan, colspan) - out <- bootstrap_setting(out, listener, component = "cell") - } + } + + + rec$css_arguments <- css + rec <- rec[rec$css_arguments != "", , drop = FALSE] + if (nrow(rec) == 0) return(x) + + # Unique CSS arguments assigne by arrays + css_table <- unique(rec[, c("css_arguments"), drop = FALSE]) + css_table$id_css <- sapply(seq_len(nrow(css_table)), function(i) get_id(stem = "tinytable_css_")) + idx <- merge(rec[, c("i", "j", "css_arguments")], css_table, all.x = TRUE) + if (nrow(idx) > 0) { + idx <- split(idx, idx$id) + for (i in seq_along(idx)) { + id_css <- idx[[i]]$id[1] + arr <- sprintf("{ i: %s, j: %s }, ", idx[[i]]$i, idx[[i]]$j) + arr <- c(" {", " positions: [ ", arr, " ],", " css_id: '", id_css, "',", "}, ") + arr <- paste(arr, collapse = "") + x@table_string <- lines_insert(x@table_string, arr, "tinytable style arrays after", "after") + entry <- sprintf(" .table td.%s, .table th.%s { %s }", id_css, id_css, idx[[i]]$css_arguments[1]) + x@table_string <- lines_insert(x@table_string, entry, "tinytable css entries after", "after") } + } - if (!is.null(bootstrap_css_rule)) { - out <- bootstrap_setting(out, bootstrap_css_rule, component = "css") - } + return(x) +}) - x@table_string <- out - - if (!is.null(bootstrap_class)) { - x@bootstrap_class <- bootstrap_class - } - return(x) - }) diff --git a/R/style_grid.R b/R/style_grid.R index 0c81ed3a..ab213ee2 100644 --- a/R/style_grid.R +++ b/R/style_grid.R @@ -1,58 +1,56 @@ +style_eval_grid <- function(x) { + out <- x@table_dataframe + sty <- x@style -#' tinytable S4 method -#' -#' @keywords internal -style_grid_internal <- function(x, - i = NULL, - j = NULL, - bold = FALSE, - italic = FALSE, - monospace = FALSE, - underline = FALSE, - strikeout = FALSE, - rowspan = NULL, - colspan = NULL, - ...) { + if (nrow(sty) == 0) return(x) - out <- x@table_dataframe + all_i <- seq_len(nrow(x)) + idx_g <- x@group_i_idx + cumsum(rep(1, length(x@group_i_idx))) - 1 + idx_d <- setdiff(all_i, idx_g) - # i is a logical matrix mask - if (is.matrix(i) && is.logical(i) && nrow(i) == nrow(x) && ncol(i) == ncol(x)) { - assert_null(j) - settings <- which(i == TRUE, arr.ind = TRUE) - settings <- stats::setNames(data.frame(settings), c("i", "j")) - } else { - jval <- sanitize_j(j, x) - ival <- sanitize_i(i, x) - settings <- expand.grid(i = ival, j = jval) + # expand i to full rows + if (any(is.na(sty$i))) { + alli <- data.frame(i = seq_len(nrow(x))) + alli <- merge(alli, sty[is.na(sty$i), colnames(sty) != "i"], all = TRUE) + sty <- rbind(sty, alli) + sty <- sty[!is.na(sty$i),] + sty <- sty[order(sty$i, sty$j),] + } + + last <- function(k) { + if (all(is.na(k))) return(NA) + if (is.logical(k)) return(as.logical(max(k, na.rm = TRUE))) + return(utils::tail(stats::na.omit(k), 1)) } + sty <- do.call(rbind, by(sty, list(sty$i, sty$j), function(k) { + data.frame(lapply(k, last)) + })) - # we only format the body, not headers - settings <- settings[settings$i > 0,] + # TODO: style groups + sty <- sty[which(!sty$i %in% idx_g),] - # Unlike other formats, Markdown inserts `group_tt()` row labels after styling. This aligns the `i` index to the full columns. - gr <- x@lazy_group - gr <- Filter(function(k) !is.null(k$i), gr) - # do not style spanning row labels - lab_idx <- drop(unlist(lapply(gr, function(k) k$i))) - lab_idx <- lab_idx + cumsum(rep(1, length(lab_idx))) - 1 - settings <- settings[!settings$i %in% lab_idx,] - for (g in gr) { - for (lab in g$i) { - settings$i[settings$i > lab - 1] <- settings$i[settings$i > lab - 1] - 1 - } - lab_idx <- c(lab_idx, g$i) + if (nrow(sty) == 0) return(x) + + # user-supplied indices are post-groups + # adjust indices to match original data rows since we only operate on those + for (g in rev(idx_g)) { + sty[sty$i > g, "i"] <- sty[sty$i > g, "i"] - 1 } for (col in seq_along(out)) { out[[col]] <- as.character(out[[col]]) } - for (idx in seq_len(nrow(settings))) { - row <- settings[idx, "i"] - col <- settings[idx, "j"] + for (idx in seq_len(nrow(sty))) { + row <- sty[idx, "i"] + col <- sty[idx, "j"] + bold <- sty[which(sty$i == row & sty$j == col), "bold"] + italic <- sty[which(sty$i == row & sty$j == col), "italic"] + strikeout <- sty[which(sty$i == row & sty$j == col), "strikeout"] + rowspan <- sty[which(sty$i == row & sty$j == col), "rowspan"] + colspan <- sty[which(sty$i == row & sty$j == col), "colspan"] if (isTRUE(bold)) { out[row, col] <- sprintf("**%s**", out[row, col]) } @@ -90,5 +88,5 @@ style_grid_internal <- function(x, setMethod( f = "style_eval", signature = "tinytable_grid", - definition = style_grid_internal + definition = style_eval_grid ) diff --git a/R/style_grid_dataframe.R b/R/style_grid_dataframe.R index 432c6b45..7e59d869 100644 --- a/R/style_grid_dataframe.R +++ b/R/style_grid_dataframe.R @@ -3,7 +3,7 @@ #' @keywords internal setMethod(f = "style_eval", signature = "tinytable_dataframe", - definition = style_grid_internal + definition = style_eval_grid ) diff --git a/R/style_tabularray.R b/R/style_tabularray.R index 196d03ed..d6ec2932 100644 --- a/R/style_tabularray.R +++ b/R/style_tabularray.R @@ -2,239 +2,237 @@ setMethod( f = "style_eval", signature = "tinytable_tabularray", definition = function(x, - i = NULL, - j = NULL, - bold = FALSE, - italic = FALSE, - monospace = FALSE, - underline = FALSE, - strikeout = FALSE, - color = NULL, - background = NULL, - fontsize = NULL, - align = NULL, - alignv = NULL, - line = NULL, - line_color = "black", - line_width = 0.1, - colspan = NULL, - rowspan = NULL, - indent = 0, - tabularray_inner = NULL, - tabularray_outer = NULL, - ...) { - - out <- x@table_string - - # i is a logical matrix mask - if (is.matrix(i) && is.logical(i) && nrow(i) == nrow(x) && ncol(i) == ncol(x)) { - assert_null(j) - settings <- which(i == TRUE, arr.ind = TRUE) - settings <- stats::setNames(data.frame(settings), c("i", "j")) - settings$tabularray <- "" - inull <- jnull <- FALSE - - } else { - ival <- sanitize_i(i, x) - jval <- sanitize_j(j, x) - # order may be important for recycling - settings <- expand.grid(i = ival, j = jval, tabularray = "", stringsAsFactors = FALSE) - inull <- isTRUE(attr(ival, "null")) - jnull <- isTRUE(attr(jval, "null")) - if (inull && !jnull) { - settings <- settings[order(settings$i, settings$j), ] - } - } + i = NULL, + j = NULL, + bold = FALSE, + italic = FALSE, + monospace = FALSE, + underline = FALSE, + strikeout = FALSE, + color = NULL, + background = NULL, + fontsize = NULL, + align = NULL, + alignv = NULL, + line = NULL, + line_color = "black", + line_width = 0.1, + colspan = NULL, + rowspan = NULL, + indent = 0, + tabularray_inner = NULL, + tabularray_outer = NULL, + ...) { + sty <- x@style + sty$i <- sty$i + x@nhead - # header index - if ("i" %in% names(settings)) { - settings$i <- settings$i + x@nhead - } + rec <- expand.grid( + i = c(seq_len(x@nrow + x@nhead)), + j = seq_len(x@ncol), + line = NA, + line_color = NA, + line_width = NA + ) - # colspan and rowspan require cell level, so we keep the full settings DF, even - # in tabularray, where we can sometimes use rowspec or colspec when one is empty - if (is.null(colspan) && is.null(rowspan)) { - if (inull && jnull) { - settings <- unique(settings[, c("i", "tabularray"), drop = FALSE]) - } else if (inull) { - settings <- unique(settings[, c("j", "tabularray"), drop = FALSE]) - } else if (jnull) { - settings <- unique(settings[, c("i", "tabularray"), drop = FALSE]) - } + sty$alignv[which(sty$alignv == "b")] <- "f" + sty$alignv[which(sty$alignv == "t")] <- "h" + sty$alignv[which(sty$alignv == "m")] <- "m" + + for (spec in stats::na.omit(sty$tabularray_inner)) { + x@table_string <- tabularray_insert(x@table_string, content = spec, type = "inner") } - span <- "" - span <- if (!is.null(colspan)) paste0(span, "c=", colspan, ",") else span - span <- if (!is.null(rowspan)) paste0(span, "r=", rowspan, ",") else span - - if (!is.null(alignv)) { - alignv_tabularray <- switch(alignv, - "b" = "f", - "t" = "h", - "m" = "m" - ) - settings$tabularray <- sprintf("%s valign=%s,", settings$tabularray, alignv_tabularray) + for (spec in stats::na.omit(sty$tabularray_outer)) { + x@table_string <- tabularray_insert(x@table_string, content = spec, type = "inner") } - # convert to tabularray now that we've filled the bootstrap settings - if (is.numeric(fontsize)) settings$tabularray <- sprintf("%s font=\\fontsize{%sem}{%sem}\\selectfont,", settings$tabularray, fontsize, fontsize + 0.3) - if (indent > 0) settings$tabularray <- sprintf("%s preto={\\hspace{%sem}},", settings$tabularray, indent) + set <- span <- rep("", nrow(rec)) - if (!is.null(align)) { - if (length(align) == 1) align <- rep(align, length(jval)) + for (row in seq_len(nrow(sty))) { - # explicit j input - siunitx <- get_option("tinytable_siunitx_table_format", default = "table-format=-%s.%s,table-align-text-before=false,table-align-text-after=false,input-symbols={-,\\*+()}") - if ("j" %in% colnames(settings)) { - for (idx in seq_along(jval)) { - a_tmp <- align[idx] - j_tmp <- jval[idx] - rowidx <- settings$j == j_tmp - if (a_tmp == "d") { - num <- x@table_dataframe[[j_tmp]] - num <- strsplit(num, "\\.") - num <- lapply(num, function(k) if (length(k) == 1) c(k, " ") else k) - left <- sapply(num, function(k) k[[1]]) - right <- sapply(num, function(k) k[[2]]) - left <- max(nchar(gsub("\\D", "", left))) - right <- max(nchar(gsub("\\D", "", right))) - tmp <- sprintf(siunitx, left, right) - settings$tabularray <- ifelse( - rowidx, - sprintf("%s si={%s},", settings$tabularray, tmp), - settings$tabularray) - } else { - settings$tabularray <- ifelse( - rowidx, - sprintf("%s halign=%s,", settings$tabularray, a_tmp), - settings$tabularray) - } - } - - # no explicit j input - } else { - a_tmp <- align[1] - if (a_tmp == "d") { - num <- unlist(x@table_dataframe[, jval]) - num <- strsplit(num, "\\.") - num <- lapply(num, function(k) if (length(k) == 1) c(k, " ") else k) - left <- sapply(num, function(k) k[[1]]) - right <- sapply(num, function(k) k[[2]]) - left <- max(nchar(gsub("\\D", "", left))) - right <- max(nchar(gsub("\\D", "", right))) - tmp <- sprintf(siunitx, left, right) - settings$tabularray <- sprintf("%s si={%s},", settings$tabularray, tmp) + # index: sty vs rec + idx_i <- sty$i[row] + if (is.na(idx_i)) idx_i <- unique(rec$i) + idx_j <- sty$j[row] + if (is.na(idx_j)) idx_j <- unique(rec$j) + idx <- rec$i == idx_i & rec$j == idx_j + + cmd <- "" + if (isTRUE(sty$bold[row])) cmd <- paste0(cmd, "\\bfseries") + if (isTRUE(sty$italic[row])) cmd <- paste0(cmd, "\\textit") + if (isTRUE(sty$underline[row])) cmd <- paste0(cmd, "\\tinytableTabularrayUnderline") + if (isTRUE(sty$strikeout[row])) cmd <- paste0(cmd, "\\tinytableTabularrayStrikeout") + if (isTRUE(sty$monospace[row])) cmd <- paste0(cmd, "\\texttt") + + col <- sty$color[row] + if (!is.na(col)) { + x <- color_to_preamble(x, col) + if (grepl("^#", col)) col <- sub("^#", "c", col) + cmd <- sprintf("%s, fg=%s", cmd, col) + } + + bg <- sty$background[row] + if (!is.na(bg)) { + x <- color_to_preamble(x, bg) + if (grepl("^#", bg)) bg <- sub("^#", "c", bg) + cmd <- sprintf("%s, bg=%s", cmd, bg) + } + + if (grepl("^,", cmd)) { + tmp <- "%s, %s, " + } else { + tmp <- "%s, cmd=%s, " + } + if (trimws(cmd) != "") set[idx] <- sprintf(tmp, set[idx], cmd) + + fontsize <- sty$fontsize[row] + if (!is.na(as.numeric(fontsize))) { + set[idx] <- sprintf( + "%s font=\\fontsize{%sem}{%sem}\\selectfont,", + set[idx], fontsize, fontsize + 0.3) + } + + halign <- sty$align[row] + if (!is.na(halign)) { + if (!identical(halign, "d")) { + set[idx] <- sprintf("%s, halign=%s,", set[idx], halign) } else { - settings$tabularray <- sprintf( - "%s halign=%s,", - settings$tabularray, a_tmp) + dcol <- get_dcolumn(rec[row, "j"], x) + set[idx] <- sprintf("%s, %s", set[idx], dcol) } - } } - vectorize_tabularray <- function(z) { - if (is.null(z)) { - return(rep(FALSE, nrow(settings))) + alignv <- sty$alignv[row] + if (!is.na(alignv)) { + set[idx] <- sprintf("%s, valign=%s,", set[idx], alignv) } - if (check_flag(z)) { - return(rep(z, nrow(settings))) + + indent <- sty$indent[row] + if (isTRUE(indent > 0)) { + set[idx] <- sprintf("%s preto={\\hspace{%sem}},", set[idx], indent) + } + + if (!is.na(sty$colspan[row])) { + span[idx] <- paste0(span[idx], "c=", sty$colspan[row], ",") + } + + if (!is.na(sty$rowspan[row])) { + span[idx] <- paste0(span[idx], "r=", sty$rowspan[row], ",") + } + + if (!is.na(sty$line[row])) { + rec$line[idx] <- sty$line[row] } - return(z) - } - bold <- vectorize_tabularray(bold) - italic <- vectorize_tabularray(italic) - underline <- vectorize_tabularray(underline) - strikeout <- vectorize_tabularray(strikeout) - monospace <- vectorize_tabularray(monospace) - cmd <- rep("", nrow(settings)) - cmd <- ifelse(bold, paste0(cmd, "\\bfseries"), cmd) - cmd <- ifelse(italic, paste0(cmd, "\\textit"), cmd) - cmd <- ifelse(underline, paste0(cmd, "\\tinytableTabularrayUnderline"), cmd) - cmd <- ifelse(strikeout, paste0(cmd, "\\tinytableTabularrayStrikeout"), cmd) - cmd <- ifelse(monospace, paste0(cmd, "\\texttt"), cmd) - settings$tabularray <- sprintf("%s, cmd=%s,", settings$tabularray, cmd) - - # hex must be treated differently in LaTeX - cols <- c(color, background, line_color) - cols_done <- NULL - if (!is.null(cols)) { - hex <- cols[grepl("^#", cols)] - for (h in hex) { - b <- sprintf( - "\\tinytableDefineColor{%s}{HTML}{%s}", - sub("^#", "c", h), sub("^#", "", h)) - if (!b %in% cols_done) { - out <- tabularray_insert(out, content = b, type = "body") - cols_done <- c(cols_done, b) - } + if (!is.na(sty$line_color[row])) { + rec$line_color[idx] <- sty$line_color[row] + } + + if (!is.na(sty$line_width[row])) { + rec$line_width[idx] <- sty$line_width[row] } } - if (!is.null(background)) { - settings$tabularray <- sprintf("%s bg=%s,", settings$tabularray, sub("^#", "c", background)) + + clean <- function(k) { + k <- gsub("\\s*", "", k) + k <- gsub(",+", ",", k) + k <- gsub("^,", "", k, perl = TRUE) + k <- gsub(",", ", ", k) + k <- trimws(k) + return(k) } - if (!is.null(color)) { - settings$tabularray <- sprintf("%s fg=%s,", settings$tabularray, sub("^#", "c", color)) + + rec$set <- clean(set) + rec$span <- clean(span) + + all_i <- seq_len(x@nrow + x@nhead) + all_j <- seq_len(x@ncol) + + # complete rows and columns + rec <- do.call(rbind, by(rec, list(rec$j, rec$set, rec$span), function(k) { + transform(k, complete_column = all(all_i %in% k$i)) + })) + rec <- do.call(rbind, by(rec, list(rec$i, rec$set, rec$span), function(k) { + transform(k, complete_row = all(all_j %in% k$j)) + })) + + idx <- rec$span != "" | rec$set != "" + + # complete columns (first because of d-column) + cols <- unique(rec[idx & rec$complete_column, c("j", "set", "span"), drop = FALSE]) + spec <- by(cols, list(cols$set, cols$span), function(k) { + sprintf("column{%s}={%s}{%s}", paste(k$j, collapse = ","), k$span, k$set) + }) + spec <- unique(as.vector(unlist(spec))) + for (s in spec) { + x@table_string <- tabularray_insert(x@table_string, content = s, type = "inner") } - settings$tabularray <- trimws(gsub("cmd=,", "", settings$tabularray)) - settings$tabularray <- trimws(gsub("\\s+", "", settings$tabularray)) - settings$tabularray <- trimws(gsub(",+", ",", settings$tabularray)) - - - if (!all(settings$tabularray == ",") || span != "") { - for (k in seq_len(nrow(settings))) { - if (all(c("i", "j") %in% colnames(settings))) { - spec <- sprintf("cell{%s}{%s}={%s}{%s},", settings$i[k], settings$j[k], span, settings$tabularray[k]) - } else if ("i" %in% colnames(settings)) { - spec <- sprintf("row{%s}={%s},", settings$i[k], settings$tabularray[k]) - } else if ("j" %in% colnames(settings)) { - spec <- sprintf("column{%s}={%s},", settings$j[k], settings$tabularray[k]) - } - out <- tabularray_insert(out, content = spec, type = "inner") - } + # complete rows + rows <- unique(rec[ + idx & rec$complete_row & !rec$complete_column, + c("i", "set", "span"), + drop = FALSE]) + spec <- by(rows, list(rows$set, rows$span), function(k) { + sprintf("row{%s}={%s}{%s}", paste(k$i, collapse = ","), k$span, k$set) + }) + spec <- unique(as.vector(unlist(spec))) + for (s in spec) { + x@table_string <- tabularray_insert(x@table_string, content = s, type = "inner") } - # Lines are not part of cellspec/rowspec/columnspec. Do this separately. - if (!is.null(line)) { - iline <- jline <- NULL - if (grepl("t", line)) iline <- c(iline, ival + x@nhead) - if (grepl("b", line)) iline <- c(iline, ival + x@nhead + 1) - if (grepl("l", line)) jline <- c(jline, jval) - if (grepl("r", line)) jline <- c(jline, jval + 1) - iline <- unique(iline) - jline <- unique(jline) - line_width <- paste0(line_width, "em") - if (!is.null(iline)) { - tmp <- sprintf( - "hline{%s}={%s}{solid, %s, %s},", - paste(iline, collapse = ","), - paste(jval, collapse = ","), - line_width, - sub("^#", "c", line_color) - ) - out <- tabularray_insert(out, content = tmp, type = "inner") - } - if (!is.null(jline)) { - tmp <- sprintf( - "vline{%s}={%s}{solid, %s, %s},", - paste(jline, collapse = ","), - paste(ival + x@nhead, collapse = ","), - line_width, - sub("^#", "c", line_color) - ) - out <- tabularray_insert(out, content = tmp, type = "inner") - } + # cells + cells <- unique(rec[idx & !rec$complete_row & !rec$complete_column, , drop = FALSE]) + spec <- sprintf("cell{%s}{%s}={%s}{%s}", cells$i, cells$j, cells$span, cells$set) + spec <- unique(as.vector(unlist(spec))) + for (s in spec) { + x@table_string <- tabularray_insert(x@table_string, content = s, type = "inner") } - out <- tabularray_insert(out, content = tabularray_inner, type = "inner") - out <- tabularray_insert(out, content = tabularray_outer, type = "outer") + # lines + rec$lin <- "solid, " + rec$lin <- ifelse(!is.na(rec$line_color), + paste0(rec$lin, rec$line_color), rec$lin) + rec$lin <- ifelse(!is.na(rec$line_width), + paste0(rec$lin, sprintf(", %sem", rec$line_width)), rec$lin) + rec$lin[is.na(rec$line)] <- NA - x@table_string <- out + # horizontal lines + horizontal <- rec[grepl("b|t", rec$line), c("i", "j", "lin", "line"), drop = FALSE] + horizontal <- rbind( + horizontal[grepl("t", horizontal$line),, drop = FALSE], + transform(horizontal[grepl("b", horizontal$line),, drop = FALSE], i = i + 1) + ) + spec <- by(horizontal, list(horizontal$i, horizontal$lin), function(k) { + jval <- paste(sort(unique(k$j)), collapse = ",") + sprintf("hline{%s}={%s}{%s}", k$i, jval, k$lin) + }) + spec <- unique(as.vector(unlist(spec))) + for (s in spec) { + x@table_string <- tabularray_insert(x@table_string, content = s, type = "inner") + } + + # vertical lines + vertical <- rec[grepl("l|r", rec$line), c("i", "j", "lin", "line"), drop = FALSE] + vertical <- rbind( + vertical[grepl("l", vertical$line),, drop = FALSE], + transform(vertical[grepl("r", vertical$line),, drop = FALSE], j = j + 1) + ) + spec <- by(vertical, list(vertical$j, vertical$lin), function(k) { + ival <- paste(sort(unique(k$i)), collapse = ",") + sprintf("vline{%s}={%s}{%s}", k$j, ival, k$lin) + }) + spec <- unique(as.vector(unlist(spec))) + for (s in spec) { + x@table_string <- tabularray_insert(x@table_string, content = s, type = "inner") + } return(x) -}) + +}) + + tabularray_insert <- function(x, content = NULL, type = "body") { @@ -265,6 +263,34 @@ tabularray_insert <- function(x, content = NULL, type = "body") { } +color_to_preamble <- function(x, col) { + if (grepl("^#", col)) { # hex color need to be defined in LaTeX + col <- sub("^#", "c", col) + regex <- sprintf("DefineColor.*%s", col) + if (!grepl(regex, x@table_string)) { + b <- sprintf("\\tinytableDefineColor{%s}{HTML}{%s}", col, sub("^c", "", col)) + x@table_string <- tabularray_insert(x@table_string, content = b, type = "body") + } + } + return(x) +} + + + +get_dcolumn <- function(j, x) { + siunitx <- get_option("tinytable_siunitx_table_format", default = "table-format=-%s.%s,table-align-text-before=false,table-align-text-after=false,input-symbols={-,\\*+()}") + num <- unlist(x@table_dataframe[, j]) + num <- strsplit(num, "\\.") + num <- lapply(num, function(k) if (length(k) == 1) c(k, " ") else k) + left <- sapply(num, function(k) k[[1]]) + right <- sapply(num, function(k) k[[2]]) + left <- max(nchar(gsub("\\D", "", left))) + right <- max(nchar(gsub("\\D", "", right))) + out <- sprintf(siunitx, left, right) + out <- sprintf("si={%s},", out) + return(out) +} + ## not longer used, but took a while to collect and might be useful in the future # out <- list( diff --git a/R/style_tt.R b/R/style_tt.R index 49ef0a9f..23adc45d 100644 --- a/R/style_tt.R +++ b/R/style_tt.R @@ -6,7 +6,7 @@ #' Note: Markdown and Word tables only support these styles: italic, bold, strikeout. Moreover, the `style_tt()` function cannot be used to style headers inserted by the `group_tt()` function; instead, you should style the headers directly in the header definition using markdown syntax: `group_tt(i = list("*italic header*" = 2))`. These limitations are due to the fact that there is no markdown syntax for the other options, and that we create Word documents by converting a markdown table to .docx via the Pandoc software. #' #' @param x A table object created by `tt()`. -#' @param i Row indices where the styling should be applied. Can be a single value, a vector, or a logical matrix with the same number of rows and columns as `x`. `i=0` is the header, and negative values are higher level headers. +#' @param i Row indices where the styling should be applied. Can be a single value, a vector, or a logical matrix with the same number of rows and columns as `x`. `i=0` is the header, and negative values are higher level headers. Row indices refer to rows *after* the insertion of row labels by `group_tt()`, when applicable. #' @param j Column indices where the styling should be applied. Can be: #' + Integer vectors indicating column positions. #' + Character vector indicating column names. @@ -135,7 +135,7 @@ style_tt <- function (x, alignv = NULL, colspan = NULL, rowspan = NULL, - indent = 0, + indent = NULL, line = NULL, line_color = "black", line_width = 0.1, @@ -148,151 +148,125 @@ style_tt <- function (x, output = NULL, ...) { - out <- x + out <- x - assert_choice(output, c("typst", "latex", "html", "markdown", "gfm"), null.ok = TRUE) + assert_choice(alignv, c("t", "m", "b"), null.ok = TRUE) - if ("width" %in% names(list(...))) { - stop("The `width` argument is now in the `tt()` function.", call. = FALSE) - } + assert_style_tt( + x = out, i = i, j = j, bold = bold, italic = italic, monospace = monospace, underline = underline, strikeout = strikeout, + color = color, background = background, fontsize = fontsize, align = align, + colspan = colspan, rowspan = rowspan, indent = indent, + line = line, line_color = line_color, line_width = line_width, + tabularray_inner = tabularray_inner, tabularray_outer = tabularray_outer, bootstrap_css = bootstrap_css, + bootstrap_css_rule = bootstrap_css_rule) - ## issue #759: reuse object with different styles across RevealJS slides requires new ID every time style_tt is called - # This is a very bad idea. Breaks a ton of things. We need unique IDs. - # out@id <- get_id("tinytable_") - cal <- call("style_tt_lazy", - # out <- style_tt_lazy( - # x should not be in here otherwise the object becomes very big - i = i, - j = j, - bold = bold, - italic = italic, - monospace = monospace, - underline = underline, - strikeout = strikeout, - color = color, - background = background, - fontsize = fontsize, - align = align, - alignv = alignv, - colspan = colspan, - rowspan = rowspan, - indent = indent, - line = line, - line_color = line_color, - line_width = line_width, - tabularray_inner = tabularray_inner, - tabularray_outer = tabularray_outer, - bootstrap_class = bootstrap_class, - bootstrap_css = bootstrap_css, - bootstrap_css_rule = bootstrap_css_rule, - output = output) - - if (isTRUE(list(...)[["tt_build_now"]])) { - out <- eval(cal) - } else { - out@lazy_style <- c(out@lazy_style, list(cal)) - } - - assert_function(finalize, null.ok = TRUE) - if (is.function(finalize)) { - out@lazy_finalize <- c(out@lazy_finalize, list(finalize)) - } - - return(out) -} - - - -style_tt_lazy <- function (x, - i, - j, - bold, - italic, - monospace, - underline, - strikeout, - color, - background, - fontsize, - align, - alignv, - colspan, - rowspan, - indent, - line, - line_color, - line_width, - tabularray_inner, - tabularray_outer, - bootstrap_class, - bootstrap_css, - bootstrap_css_rule, - output) { - - out <- x + if (!is.null(bootstrap_class)) { + out@bootstrap_class <- bootstrap_class + } + if (!is.null(bootstrap_css_rule)) { + out@bootstrap_css_rule <- bootstrap_css_rule + } - jval <- sanitize_j(j, x) - jnull <- isTRUE(attr(jval, "null")) + sanity_align(align, i) - # alignv can only be a single character for now - assert_choice(alignv, c("t", "m", "b"), null.ok = TRUE) + assert_choice(output, c("typst", "latex", "html", "markdown", "gfm"), null.ok = TRUE) - # align can be "c" or "clrrlc" takes many possible values - assert_string(align, null.ok = TRUE) + if ("width" %in% names(list(...))) { + stop("The `width` argument is now in the `tt()` function.", call. = FALSE) + } - if (!is.null(align)) { - if (nchar(align) == 1) { - assert_choice(align, c("c", "l", "r", "d")) + # i is a logical matrix mask + if (is.matrix(i) && is.logical(i) && nrow(i) == nrow(x) && ncol(i) == ncol(x)) { + assert_null(j) + settings <- which(i == TRUE, arr.ind = TRUE) + settings <- stats::setNames(data.frame(settings), c("i", "j")) } else { - align_split <- strsplit(align, split = "")[[1]] - for (align_character in align_split){ - assert_choice(align_character, c("c", "l", "r", "d")) - } - if (jnull) { - j <- seq_len(x@ncol) - } + ival <- sanitize_i(i, x) + jval <- sanitize_j(j, x) + # order may be important for recycling + settings <- expand.grid(i = ival, j = jval, tabularray = "") + if (is.null(i) && !is.null(j)) { + settings <- settings[order(settings$i, settings$j), ] + } } - } - - if (x@output == "typst") { - nalign <- x@ncol - } else { - nalign <- if (jnull) x@ncol else length(jval) - } - if (!is.null(align)) { - align <- strsplit(align, split = "")[[1]] - if (length(align) != 1 && length(align) != nalign) { - msg <- sprintf("`align` must be a single character or a string of length %s.", nalign) - stop(msg, call. = FALSE) - } - if (!all(align %in% c("c", "l", "r", "d"))) { - msg <- "`align` must be characters c, l, r, or d." - stop(msg, call. = FALSE) + settings[["color"]] <- if (is.null(color)) NA else as.vector(color) + settings[["background"]] <- if (is.null(background)) NA else as.vector(background) + settings[["fontsize"]] <- if (is.null(fontsize)) NA else as.vector(fontsize) + settings[["alignv"]] <- if (is.null(alignv)) NA else alignv + settings[["line"]] <- if (is.null(line)) NA else line + settings[["line_color"]] <- if (is.null(line)) NA else line_color + settings[["line_width"]] <- if (is.null(line)) NA else line_width + settings[["bold"]] <- bold + settings[["italic"]] <- italic + settings[["monospace"]] <- monospace + settings[["strikeout"]] <- strikeout + settings[["underline"]] <- underline + settings[["indent"]] <- if (is.null(indent)) NA else as.vector(indent) + settings[["colspan"]] <- if (is.null(colspan)) NA else colspan + settings[["rowspan"]] <- if (is.null(rowspan)) NA else rowspan + settings[["bootstrap_css_rule"]] <- if (!is.null(bootstrap_css_rule)) bootstrap_css_rule else NA + settings[["bootstrap_css"]] <- if (!is.null(bootstrap_css)) bootstrap_css else NA + settings[["tabularray_inner"]] <- if (!is.null(tabularray_inner)) tabularray_inner else NA + settings[["tabularray_outer"]] <- if (!is.null(tabularray_outer)) tabularray_outer else NA + + if (!is.null(align)) { + if (nchar(align) == length(jval)) { + align_string <- strsplit(align, "")[[1]] + if (!all(align_string %in% c("c", "l", "r", "d"))) { + msg <- "`align` must be characters c, l, r, or d." + stop(msg, call. = FALSE) + } + align_string <- data.frame(j = jval, align = align_string) + settings <- merge(settings, align_string, by = "j", all.x = TRUE) + } else if (nchar(align) == 1) { + assert_choice(align, c("c", "l", "r", "d")) + align_string <- data.frame(j = jval, align = align) + settings <- merge(settings, align_string, by = "j", all.x = TRUE) + } else { + msg <- sprintf("`align` must be a single character or a string of length %s.", length(jval)) + stop(msg, call. = FALSE) + } + } else { + settings[["align"]] <- NA } - if (any(align == "d")) { - tmp <- paste(sprintf("row{%s}={guard},", seq_len(x@nhead)), collapse = "\n") - tabularray_inner <- paste(tabularray_inner, tmp) + empty <- settings[, 4:ncol(settings)] + empty <- sapply(empty, function(x) is.na(x) | (is.logical(x) && !any(x))) + if (nrow(settings) == 1) { + empty <- all(empty) + settings <- settings[!empty, , drop = FALSE] + } else { + empty <- apply(empty, 1, all) + settings <- settings[!empty, , drop = FALSE] } - } - assert_style_tt( - x = out, i = i, j = j, bold = bold, italic = italic, monospace = monospace, underline = underline, strikeout = strikeout, - color = color, background = background, fontsize = fontsize, align = align, alignv = alignv, - colspan = colspan, rowspan = rowspan, indent = indent, - line = line, line_color = line_color, line_width = line_width, - tabularray_inner = tabularray_inner, tabularray_outer = tabularray_outer, bootstrap_css = bootstrap_css, - bootstrap_css_rule = bootstrap_css_rule, bootstrap_class = bootstrap_class) + if (nrow(out@style) > 0 && nrow(settings) > 0 && ncol(out@style) != ncol(settings)) { + a <- out@style + b <- settings + if (!"tabularray" %in% colnames(a)) a$tabularray <- "" + if (!"tabularray" %in% colnames(b)) b$tabularray <- "" + settings <- rbind(a, b[, colnames(a)]) + out@style <- unique(settings) + } else if (nrow(settings) > 0) { + out@style <- rbind(out@style, settings) + } + ## issue #759: reuse object with different styles across RevealJS slides requires new ID every time style_tt is called + # This is a very bad idea. Breaks a ton of things. We need unique IDs. + # out@id <- get_id("tinytable_") - out <- style_eval(x = out, i = i, j = j, bold = bold, italic = italic, monospace = monospace, underline = underline, strikeout = strikeout, color = color, background = background, fontsize = fontsize, align = align, alignv = alignv, colspan = colspan, rowspan = rowspan, indent = indent, tabularray_inner = tabularray_inner, tabularray_outer = tabularray_outer, bootstrap_css = bootstrap_css, bootstrap_css_rule = bootstrap_css_rule, bootstrap_class = bootstrap_class, line = line, line_color = line_color, line_width = line_width) + assert_function(finalize, null.ok = TRUE) + if (is.function(finalize)) { + out@lazy_finalize <- c(out@lazy_finalize, list(finalize)) + } - return(out) + return(out) } + assert_style_tt <- function (x, i, j, @@ -305,7 +279,6 @@ assert_style_tt <- function (x, background, fontsize, align, - alignv, colspan, rowspan, indent, @@ -318,81 +291,81 @@ assert_style_tt <- function (x, bootstrap_css = NULL, bootstrap_css_rule = NULL) { - assert_integerish(colspan, len = 1, lower = 2, null.ok = TRUE) - assert_integerish(rowspan, len = 1, lower = 2, null.ok = TRUE) - assert_numeric(indent, len = 1, lower = 0) - assert_character(background, null.ok = TRUE) - assert_character(color, null.ok = TRUE) - assert_numeric(fontsize, null.ok = TRUE) - assert_logical(bold) - assert_logical(italic) - assert_logical(monospace) - assert_logical(underline) - assert_logical(strikeout) - assert_string(line, null.ok = TRUE) - assert_string(line_color, null.ok = FALSE) # black default - assert_numeric(line_width, len = 1, lower = 0, null.ok = FALSE) # 0.1 default - assert_character(bootstrap_class, null.ok = TRUE) - assert_character(bootstrap_css, null.ok = TRUE) - assert_string(bootstrap_css_rule, null.ok = TRUE) - - if (is.character(line)) { - line <- strsplit(line, split = "")[[1]] - if (!all(line %in% c("t", "b", "l", "r"))) { - msg <- "`line` must be a string of characters t, b, l, or r." - stop(msg, call. = FALSE) + assert_integerish(colspan, len = 1, lower = 2, null.ok = TRUE) + assert_integerish(rowspan, len = 1, lower = 2, null.ok = TRUE) + assert_numeric(indent, len = 1, lower = 0, null.ok = TRUE) + assert_character(background, null.ok = TRUE) + assert_character(color, null.ok = TRUE) + assert_numeric(fontsize, null.ok = TRUE) + assert_logical(bold) + assert_logical(italic) + assert_logical(monospace) + assert_logical(underline) + assert_logical(strikeout) + assert_string(line, null.ok = TRUE) + assert_string(line_color, null.ok = FALSE) # black default + assert_numeric(line_width, len = 1, lower = 0, null.ok = FALSE) # 0.1 default + assert_character(bootstrap_class, null.ok = TRUE) + assert_character(bootstrap_css, null.ok = TRUE) + assert_string(bootstrap_css_rule, null.ok = TRUE) + + if (is.character(line)) { + line <- strsplit(line, split = "")[[1]] + if (!all(line %in% c("t", "b", "l", "r"))) { + msg <- "`line` must be a string of characters t, b, l, or r." + stop(msg, call. = FALSE) + } } - } - ival <- sanitize_i(i, x, pre_group_i = TRUE) - jval <- sanitize_j(j, x) - inull <- isTRUE(attr(ival, "null")) - jnull <- isTRUE(attr(jval, "null")) - - # 1 - if (inull && jnull) { - assert_length(color, len = 1, null.ok = TRUE) - assert_length(background, len = 1, null.ok = TRUE) - assert_length(fontsize, len = 1, null.ok = TRUE) - assert_length(bold, len = 1) - assert_length(italic, len = 1) - assert_length(monospace, len = 1) - assert_length(underline, len = 1) - assert_length(strikeout, len = 1) - - # 1 or #rows - } else if (!inull && jnull) { - assert_length(color, len = c(1, length(ival)), null.ok = TRUE) - assert_length(background, len = c(1, length(ival)), null.ok = TRUE) - assert_length(fontsize, len = c(1, length(ival)), null.ok = TRUE) - assert_length(bold, len = c(1, length(ival))) - assert_length(italic, len = c(1, length(ival))) - assert_length(monospace, len = c(1, length(ival))) - assert_length(underline, len = c(1, length(ival))) - assert_length(strikeout, len = c(1, length(ival))) - - # 1 or #cols - } else if (inull && !jnull) { - assert_length(color, len = c(1, length(jval)), null.ok = TRUE) - assert_length(background, len = c(1, length(jval)), null.ok = TRUE) - assert_length(fontsize, len = c(1, length(jval)), null.ok = TRUE) - assert_length(bold, len = c(1, length(jval))) - assert_length(italic, len = c(1, length(jval))) - assert_length(monospace, len = c(1, length(jval))) - assert_length(underline, len = c(1, length(jval))) - assert_length(strikeout, len = c(1, length(jval))) - - # 1 or #cells - } else if (!inull && !jnull) { - assert_length(color, len = c(1, length(ival) * length(jval)), null.ok = TRUE) - assert_length(background, len = c(1, length(ival) * length(jval)), null.ok = TRUE) - assert_length(fontsize, len = c(1, length(ival) * length(jval)), null.ok = TRUE) - assert_length(bold, len = c(1, length(ival) * length(jval))) - assert_length(italic, len = c(1, length(ival) * length(jval))) - assert_length(monospace, len = c(1, length(ival) * length(jval))) - assert_length(underline, len = c(1, length(ival) * length(jval))) - assert_length(strikeout, len = c(1, length(ival) * length(jval))) - } + ival <- sanitize_i(i, x) + jval <- sanitize_j(j, x) + inull <- isTRUE(attr(ival, "null")) + jnull <- isTRUE(attr(jval, "null")) + + # 1 + if (inull && jnull) { + assert_length(color, len = 1, null.ok = TRUE) + assert_length(background, len = 1, null.ok = TRUE) + assert_length(fontsize, len = 1, null.ok = TRUE) + assert_length(bold, len = 1) + assert_length(italic, len = 1) + assert_length(monospace, len = 1) + assert_length(underline, len = 1) + assert_length(strikeout, len = 1) + + # 1 or #rows + } else if (!inull && jnull) { + assert_length(color, len = c(1, length(ival)), null.ok = TRUE) + assert_length(background, len = c(1, length(ival)), null.ok = TRUE) + assert_length(fontsize, len = c(1, length(ival)), null.ok = TRUE) + assert_length(bold, len = c(1, length(ival))) + assert_length(italic, len = c(1, length(ival))) + assert_length(monospace, len = c(1, length(ival))) + assert_length(underline, len = c(1, length(ival))) + assert_length(strikeout, len = c(1, length(ival))) + + # 1 or #cols + } else if (inull && !jnull) { + assert_length(color, len = c(1, length(jval)), null.ok = TRUE) + assert_length(background, len = c(1, length(jval)), null.ok = TRUE) + assert_length(fontsize, len = c(1, length(jval)), null.ok = TRUE) + assert_length(bold, len = c(1, length(jval))) + assert_length(italic, len = c(1, length(jval))) + assert_length(monospace, len = c(1, length(jval))) + assert_length(underline, len = c(1, length(jval))) + assert_length(strikeout, len = c(1, length(jval))) + + # 1 or #cells + } else if (!inull && !jnull) { + assert_length(color, len = c(1, length(ival) * length(jval)), null.ok = TRUE) + assert_length(background, len = c(1, length(ival) * length(jval)), null.ok = TRUE) + assert_length(fontsize, len = c(1, length(ival) * length(jval)), null.ok = TRUE) + assert_length(bold, len = c(1, length(ival) * length(jval))) + assert_length(italic, len = c(1, length(ival) * length(jval))) + assert_length(monospace, len = c(1, length(ival) * length(jval))) + assert_length(underline, len = c(1, length(ival) * length(jval))) + assert_length(strikeout, len = c(1, length(ival) * length(jval))) + } } diff --git a/R/style_typst.R b/R/style_typst.R index e872a072..941b6f83 100644 --- a/R/style_typst.R +++ b/R/style_typst.R @@ -25,216 +25,177 @@ setMethod( indent = 0, midrule = FALSE, # undocumented, only used by `group_tt()` ...) { - out <- x@table_string - # gutters are used for group_tt(j) but look ugly with cell fill - if (!is.null(background)) { - x <- style_tt(x, finalize = function(x) { - x@table_string <- lines_drop( - x@table_string, - "column-gutter:", - fixed = TRUE) - return(x) - }) - } + sty <- x@style - if (is.null(line)) { - line <- NA - line_color <- NA - line_width <- NA + # gutters are used for group_tt(j) but look ugly with cell fill + if (!all(is.na(sty$background))) { + x@table_string <- lines_drop(x@table_string, "column-gutter:", fixed = TRUE) } - if (is.null(color)) color <- NA - if (is.null(background)) background <- NA - color <- ifelse(grepl("^#", color), sprintf('rgb("%s")', color), color) - line_color <- ifelse(grepl("^#", line_color), sprintf('rgb("%s")', line_color), line_color) - background <- ifelse(grepl("^#", background), sprintf('rgb("%s")', background), background) - - if (is.null(color)) color <- NA - if (is.null(fontsize)) fontsize <- NA - indent <- if (indent > 0) paste0(indent, "em") else NA - - sett <- style_settings_typst( - x = x, - i = i, - j = j, - color = color, - underline = underline, - italic = italic, - bold = bold, - monospace = monospace, - strikeout = strikeout, - fontsize = fontsize, - indent = indent, - background = background, - line = line, - line_width = line_width, - line_color = line_color, - align = align) - - x@style <- unique(rbind(x@style, sett)) - - return(x) - }) - - -style_apply_typst <- function(x) { - sty <- x@style + sty$align[which(sty$align == "l")] <- "left" + sty$align[which(sty$align == "c")] <- "center" + sty$align[which(sty$align == "d")] <- "center" + sty$align[which(sty$align == "r")] <- "right" - lin <- sty[, c("i", "j", "line", "line_color", "line_width")] - lin <- unique(lin[!is.na(lin$line),]) + sty$i <- sty$i - 1 + x@nhead + sty$j <- sty$j - 1 + if (length(x@names) == 0) sty$i <- sty$i + 1 + + rec <- expand.grid( + i = seq_len(x@nhead + x@nrow + x@ngroupi) - 1, + j = seq_len(x@ncol) - 1 + ) + css <- rep("", nrow(rec)) + + insert_field <- function(x, name = "bold", value = "true") { + old <- sprintf("%s: [^,]*,", name) + new <- sprintf("%s: %s,", name, value) + out <- ifelse(grepl(old, x), + sub(old, new, x), + sprintf("%s, %s", x, new)) + return(out) + } - sty <- sty[, !colnames(sty) %in% c("line", "line_color", "line_width")] - sty <- unique(sty) + for (row in seq_len(nrow(sty))) { + idx_i <- sty$i[row] + if (is.na(idx_i)) idx_i <- unique(rec$i) + idx_j <- sty$j[row] + if (is.na(idx_j)) idx_j <- unique(rec$j) + idx <- rec$i == idx_i & rec$j == idx_j + if (isTRUE(sty[row, "bold"])) css[idx] <- insert_field(css[idx], "bold", "true") + if (isTRUE(sty[row, "italic"])) css[idx] <- insert_field(css[idx], "italic", "true") + if (isTRUE(sty[row, "underline"])) css[idx] <- insert_field(css[idx], "underline", "true") + if (isTRUE(sty[row, "strikeout"])) css[idx] <- insert_field(css[idx], "strikeout", "true") + if (isTRUE(sty[row, "monospace"])) css[idx] <- insert_field(css[idx], "monospace", "true") + if (!is.na(sty[row, "align"])) css[idx] <- insert_field(css[idx], "align", sty[row, "align"]) + + fs <- sty[row, "indent"] + if (!is.na(fs)) { + css[idx] <- insert_field(css[idx], "indent", sprintf("%sem", fs)) + } - no_style <- apply(sty[, 3:ncol(sty)], 1, function(k) { - all(is.na(k) | k == FALSE) - }) + fs <- sty[row, "fontsize"] + if (!is.na(fs)) { + css[idx] <- insert_field(css[idx], "fontsize", sprintf("%sem", fs)) + } - sty <- sty[!no_style,, drop = FALSE] + col <- sty[row, "color"] + if (!is.na(col)) { + if (grepl("^#", col)) col <- sprintf('rgb("%s")', col) + css[idx] <- insert_field(css[idx], "color", col) + } - last_style <- function(x) { - if (all(is.na(x))) { - x <- NA - } else if (is.logical(x)) { - x <- any(x[!is.na(x)]) - } else { - x <- utils::tail(x[!is.na(x)], 1) + bg <- sty[row, "background"] + if (!is.na(bg)) { + if (grepl("^#", bg)) bg <- sprintf('rgb("%s")', bg) + css[idx] <- insert_field(css[idx], "background", bg) } - return(x) } - sty <- split(sty, list(sty$i, sty$j)) - sty <- lapply(sty, function(k) lapply(k, last_style)) - sty <- do.call(rbind, lapply(sty, data.frame)) - # Typst-specific stuff + css <- gsub(" +", " ", trimws(css)) + css <- sub("^,", "", trimws(css)) + css <- gsub(",+", ",", trimws(css)) + rec$css <- css - # 0- & header-indexing - sty$i <- sty$i + x@nhead - 1 - sty$j <- sty$j - 1 + # TODO: spans before styles, as in bootstrap - for (col in colnames(sty)) { - if (is.logical(sty[[col]])) { - sty[[col]] <- ifelse(sty[[col]] & !is.na(sty[[col]]), "true", "none") - } else { - sty[[col]][is.na(sty[[col]])] <- "none" - } + # Unique style arrays + uni <- split(rec, rec$css) + + pairs <- sapply(uni, function(x) paste(sprintf("(%s, %s),", x$j, x$i), collapse = " ")) + styles <- sapply(uni, function(x) x$css[1]) + styles <- sprintf("(pairs: (%s), %s),", pairs, styles) + + for (s in styles) { + x@table_string <- lines_insert(x@table_string, s, "tinytable cell style after", "after") + # x@table_string <- lines_insert(x@table_string, s, "tinytable cell align after", "after") } - # array representation for duplicate styles = cleaner .typ file - if (!all(no_style)) { - idx <- apply(sty[, 3:ncol(sty)], 1, paste, collapse = "|") - sty <- split(sty, idx, drop = FALSE) - sty <- lapply(sty, function(k) { - k$i <- sprintf("(%s,)", paste(unique(k$i), collapse = ", ")) - k$j <- sprintf("(%s,)", paste(unique(k$j), collapse = ", ")) - k[1,] - }) - sty <- do.call(rbind, sty) - - - for (row in seq_len(nrow(sty))) { - style <- sprintf( - " (y: %s, x: %s, color: %s, underline: %s, italic: %s, bold: %s, mono: %s, strikeout: %s, fontsize: %s, indent: %s, background: %s, align: %s),", - sty$i[row], - sty$j[row], - sty$color[row], - sty$underline[row], - sty$italic[row], - sty$bold[row], - sty$monospace[row], - sty$strikeout[row], - sty$fontsize[row], - sty$indent[row], - sty$background[row], - sty$align[row] - ) - x@table_string <- lines_insert(x@table_string, style, "tinytable cell style after", "after") + lin <- sty[grepl("b|t", sty$line),, drop = FALSE] + if (nrow(lin) > 0) { + lin <- split(lin, list(lin$i, lin$line, lin$line_color, lin$line_width)) + lin <- Filter(function(x) nrow(x) > 0, lin) + lin <- lapply(lin, hlines) + for (l in lin) { + x@table_string <- lines_insert(x@table_string, l, "tinytable lines before", "before") } } - lin$i <- lin$i + x@nhead - # not sure why, but seems necessary - if (x@nhead == 0) lin$i <- lin$i + 1 - - lin_split <- split(lin, lin[, 3:ncol(lin)]) - for (ls in lin_split) { - line_h <- "table.hline(y: %s, start: %s, end: %s, stroke: %sem + %s)," - line_v <- "table.vline(x: %s, start: %s, end: %s, stroke: %sem + %s)," - if (any(grepl("b", ls$line))) { - for (h in unique(ls$i)) { - template <- sprintf(line_h, h, min(ls$j) - 1, max(ls$j), ls$line_width[1], ls$line_color[1]) - x@table_string <- lines_insert(x@table_string, template, "tinytable lines before", "before") - } - } - if (any(grepl("t", ls$line))) { - for (h in unique(ls$i)) { - template <- sprintf(line_h, h - 1, min(ls$j) - 1, max(ls$j), ls$line_width[1], ls$line_color[1]) - x@table_string <- lines_insert(x@table_string, template, "tinytable lines before", "before") - } - } - if (any(grepl("l", ls$line))) { - for (v in unique(ls$j)) { - template <- sprintf(line_v, v - 1, min(ls$i) - 1, max(ls$i), ls$line_width[1], ls$line_color[1]) - x@table_string <- lines_insert(x@table_string, template, "tinytable lines before", "before") - } - } - if (any(grepl("r", ls$line))) { - for (v in unique(ls$j)) { - template <- sprintf(line_v, v, min(ls$i) - 1, max(ls$i), ls$line_width[1], ls$line_color[1]) - x@table_string <- lines_insert(x@table_string, template, "tinytable lines before", "before") - } + lin <- sty[grepl("l|r", sty$line),, drop = FALSE] + if (nrow(lin) > 0) { + lin <- split(lin, list(lin$j, lin$line, lin$line_color, lin$line_width)) + lin <- Filter(function(x) nrow(x) > 0, lin) + lin <- lapply(lin, vlines) + for (l in lin) { + x@table_string <- lines_insert(x@table_string, l, "tinytable lines before", "before") } } return(x) -} +}) -style_settings_typst <- function(x, i, j, color, underline, italic, bold, monospace, strikeout, fontsize, indent, background, line, line_color, line_width, align) { - if (is.matrix(i) && is.logical(i) && nrow(i) == nrow(x) && ncol(i) == ncol(x)) { - assert_null(j) - settings <- which(i == TRUE, arr.ind = TRUE) - settings <- stats::setNames(data.frame(settings), c("i", "j")) - jval <- NULL - } else { - ival <- sanitize_i(i, x) - jval <- sanitize_j(j, x) +split_chunks <- function(x) { + x <- sort(x) + breaks <- c(0, which(diff(x) != 1), length(x)) + result <- list() + for (i in seq_along(breaks)[-length(breaks)]) { + chunk <- x[(breaks[i] + 1):breaks[i + 1]] + result[[i]] <- c(min = min(chunk), max = max(chunk)) } - settings <- expand.grid(i = ival, j = jval) - settings <- settings[order(settings$i, settings$j),] - settings[["color"]] <- color - settings[["underline"]] <- underline - settings[["italic"]] <- italic - settings[["bold"]] <- bold - settings[["monospace"]] <- monospace - settings[["strikeout"]] <- strikeout - settings[["fontsize"]] <- if (!is.na(fontsize)) sprintf("%sem", fontsize) else NA - settings[["indent"]] <- indent - settings[["background"]] <- background - settings[["line"]] <- line - settings[["line_color"]] <- line_color - settings[["line_width"]] <- line_width - - if (!is.null(align)) { - settings[["align"]] <- sapply(align, - switch, - c = "center", - d = "center", - r = "right", - l = "left") - } else { - settings[["align"]] <- NA - } - return(settings) + out <- data.frame(do.call(rbind, result)) + out$max <- out$max + 1 + return(out) } - -# Lines are not part of cellspec/rowspec/columnspec. Do this separately. - - +hlines <- function(k) { + xmin <- split_chunks(k$j)$min + xmax <- split_chunks(k$j)$max + ymin <- k$i[1] + ymax <- k$i[1] + 1 + line <- k$line[1] + color <- if (is.na(k$line_color[1])) "black" else k$line_color[1] + if (grepl("^#", color)) color <- sprintf('rgb("%s")', color) + width <- if (is.na(k$line_width[1])) 0.1 else k$line_width[1] + width <- sprintf("%sem", width) + out <- "" + if (grepl("t", line)) { + tmp <- "table.hline(y: %s, start: %s, end: %s, stroke: %s + %s)," + tmp <- sprintf(tmp, ymin, xmin, xmax, width, color) + out <- paste(out, tmp) + } + if (grepl("b", line)) { + tmp <- "table.hline(y: %s, start: %s, end: %s, stroke: %s + %s)," + tmp <- sprintf(tmp, ymax, xmin, xmax, width, color) + out <- paste(out, tmp) + } + return(out) +} +vlines <- function(k) { + ymin <- split_chunks(k$i)$min + ymax <- split_chunks(k$i)$max + xmin <- k$j[1] + xmax <- xmin + 1 + line <- k$line[1] + color <- if (is.na(k$line_color[1])) "black" else k$line_color[1] + width <- if (is.na(k$line_width[1])) 0.1 else k$line_width[1] + width <- sprintf("%sem", width) + out <- "" + if (grepl("l", line)) { + tmp <- "table.vline(x: %s, start: %s, end: %s, stroke: %s + %s)," + tmp <- sprintf(tmp, xmin, ymin, ymax, width, color) + out <- paste(out, tmp) + } + if (grepl("r", line)) { + tmp <- "table.vline(x: %s, start: %s, end: %s, stroke: %s + %s)," + tmp <- sprintf(tmp, xmax, ymin, ymax, width, color) + out <- paste(out, tmp) + } + return(out) +} diff --git a/R/theme_bootstrap.R b/R/theme_bootstrap.R new file mode 100644 index 00000000..55dab118 --- /dev/null +++ b/R/theme_bootstrap.R @@ -0,0 +1,26 @@ +theme_bootstrap <- function(x, ...) { + + fn <- theme_placement_factory( + horizontal = get_option("tinytable_theme_default_horizontal", "c"), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) + x <- style_tt(x, finalize = fn) + + fn <- function(table) { + if (isTRUE(table@output == "markdown")) { + tab <- table@table_string + tab <- strsplit(tab, "\n")[[1]] + tab <- tab[!grepl("^[\\+|-]+$", tab)] + tab <- gsub("|", " ", tab, fixed = TRUE) + table@table_string <- paste(tab, collapse = "\n") + } else if (isTRUE(table@output == "typst")) { + table <- style_tt(table, i = 0:nrow(table), line = "bt", line_width = 0.05, line_color = "silver") + } + return(table) + } + x <- style_tt(x, finalize = theme_void_fn) # only affects LaTeX + x <- style_tt(x, + tabularray_inner = "hlines={gray8},", + bootstrap_class = "table", + finalize = fn) + return(x) +} diff --git a/R/theme_default.R b/R/theme_default.R new file mode 100644 index 00000000..e5b09b33 --- /dev/null +++ b/R/theme_default.R @@ -0,0 +1,24 @@ +theme_default <- function(x, ...) { + + fn <- theme_placement_factory( + horizontal = get_option("tinytable_theme_default_horizontal", "c"), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) + x <- style_tt(x, finalize = fn) + + if (isTRUE(x@output %in% c("html", "typst"))) { + bc <- if (length(x@bootstrap_class) == 0) "table table-borderless" else x@bootstrap_class + x <- style_tt(x, + bootstrap_class = bc, + i = nrow(x) + x@ngroupi, + line = "b", + line_color = "#d3d8dc", + line_width = 0.1) + x <- style_tt(x, + bootstrap_class = bc, + i = 0, + line = "bt", + line_color = "#d3d8dc", + line_width = 0.1) + } + return(x) +} diff --git a/R/theme_grid.R b/R/theme_grid.R new file mode 100644 index 00000000..dcbf3ee3 --- /dev/null +++ b/R/theme_grid.R @@ -0,0 +1,23 @@ +theme_grid <- function(x, ...) { + + fn <- theme_placement_factory( + horizontal = get_option("tinytable_theme_default_horizontal", "c"), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) + x <- style_tt(x, finalize = fn) + + fn <- function(table) { + if (isTRUE(table@output == "latex")) { + table <- theme_void_fn(table) + } else if (isTRUE(table@output == "typst")) { + table@table_string <- sub( + "stroke: none,", + "stroke: (paint: black),", + table@table_string) + } + return(table) + } + + x <- style_tt(x, tabularray_inner = "hlines, vlines,", finalize = fn, + bootstrap_class = "table table-bordered") + return(x) +} diff --git a/R/theme_multipage.R b/R/theme_multipage.R new file mode 100644 index 00000000..6d28635a --- /dev/null +++ b/R/theme_multipage.R @@ -0,0 +1,41 @@ +theme_multipage <- function(x, + rowhead = get_option("tinytable_theme_multipage_rowhead", 0L), + rowfoot = get_option("tinytable_theme_multipage_rowfoot", 0L), + ...) { + # do not change the defaul theme + if (identical(x@theme[[1]], "multipage")) x@theme <- list("default") + assert_integerish(rowhead, lower = 0, len = 1) + assert_integerish(rowfoot, lower = 0, len = 1) + # cap <- sprintf("caption={%s}", x@caption) + # x@caption <- "" + fn <- function(table) { + if (!isTRUE(table@output == "latex")) return(table) + + tab <- table@table_string + tab <- sub("\\\\begin\\{talltblr", "\\\\begin\\{longtblr", tab) + tab <- sub("\\\\end\\{talltblr", "\\\\end\\{longtblr", tab) + + tab <- strsplit(tab, "\n")[[1]] + idx <- grepl("^\\\\caption\\{|^\\\\begin\\{table|^\\\\end\\{table|^\\\\centering", trimws(tab)) + tab <- tab[!idx] + tab <- paste(tab, collapse = "\n") + + table@table_string <- tab + + # table <- style_tt(table, tabularray_outer = cap) + + if (rowhead > 0) { + table <- style_tt(table, tabularray_inner = sprintf("rowhead=%s", rowhead)) + } + + if (rowfoot > 0) { + table <- style_tt(table, tabularray_inner = sprintf("rowfoot=%s", rowfoot)) + } + + return(table) + } + x <- style_tt(x, finalize = fn) + return(x) +} + + diff --git a/R/theme_placement.R b/R/theme_placement.R new file mode 100644 index 00000000..21d17cc8 --- /dev/null +++ b/R/theme_placement.R @@ -0,0 +1,36 @@ +theme_placement_factory <- function( + horizontal = get_option("tinytable_theme_placement_horizontal", default = NULL), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) { + + function(x) { + tab <- x@table_string + if (x@output == "latex" && !is.null(latex_float)) { + assert_string(latex_float, null.ok = TRUE) + tab <- sub( + "\\\\begin\\{table\\}([^\\[])", + sprintf("\\\\begin{table}[%s]\\1", latex_float), + tab) + } else if (x@output == "typst" && !is.null(horizontal)) { + assert_choice(horizontal, c("l", "c", "r")) + if (horizontal == "l") { + tab <- sub("#align(center,", "#align(left,", tab, fixed = TRUE) + } else if (horizontal == "r") { + tab <- sub("#align(center,", "#align(right,", tab, fixed = TRUE) + } + } + x@table_string <- tab + return(x) + } +} + + +theme_placement <- function( + x, + horizontal = get_option("tinytable_theme_placement_horizontal", default = NULL), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) { + fn <- theme_placement_factory(horizontal = horizontal, latex_float = latex_float) + x <- style_tt(x, finalize = fn) + return(x) +} + + diff --git a/R/theme_resize.R b/R/theme_resize.R new file mode 100644 index 00000000..f56d2c2f --- /dev/null +++ b/R/theme_resize.R @@ -0,0 +1,44 @@ +theme_resize <- function(x, + width = get_option("tinytable_theme_resize_width", 1), + direction = get_option("tinytable_theme_resize_direction", "down"), + ...) { + + fn <- theme_placement_factory( + horizontal = get_option("tinytable_theme_default_horizontal", "c"), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) + x <- style_tt(x, finalize = fn) + + assert_numeric(width, len = 1, lower = 0.01, upper = 1) + assert_choice(direction, c("down", "up", "both")) + # do not change the default theme + if (identical(x@theme[[1]], "resize")) x@theme <- list("default") + fn <- function(table) { + if (!isTRUE(table@output == "latex")) return(table) + + tab <- table@table_string + + if (direction == "both") { + new <- sprintf("\\resizebox{%s\\linewidth}{!}{", width) + } else if (direction == "down") { + new <- sprintf("\\resizebox{\\ifdim\\width>\\linewidth %s\\linewidth\\else\\width\\fi}{!}{", width) + } else if (direction == "up") { + new <- sprintf("\\resizebox{\\ifdim\\width<\\linewidth %s\\linewidth\\else\\width\\fi}{!}{", width) + } + + reg <- "\\\\begin\\{tblr\\}|\\\\begin\\{talltblr\\}" + tab <- lines_insert(tab, regex = reg, new = new, position = "before") + + new <- "}" + reg <- "\\\\end\\{tblr\\}|\\\\end\\{talltblr\\}" + tab <- lines_insert(tab, regex = reg, new = new, position = "after") + + table@table_string <- tab + + return(table) + } + + x <- style_tt(x, finalize = fn) + return(x) +} + + diff --git a/R/theme_rotate.R b/R/theme_rotate.R new file mode 100644 index 00000000..d04ca483 --- /dev/null +++ b/R/theme_rotate.R @@ -0,0 +1,35 @@ +theme_rotate <- function(x, angle = 90, ...) { + assert_numeric(angle, len = 1, lower = 0, upper = 360) + fn <- function(table) { + if (isTRUE(table@output == "latex")) { + rot <- sprintf("\\begin{table}\n\\rotatebox{%s}{", angle) + table@table_string <- sub( + "\\begin{table}", + rot, + table@table_string, + fixed = TRUE) + table@table_string <- sub( + "\\end{table}", + "}\n\\end{table}", + table@table_string, + fixed = TRUE) + } else if (isTRUE(table@output == "typst")) { + rot <- sprintf("#rotate(-%sdeg, reflow: true, [\n #figure(", angle) + table@table_string <- sub( + "#figure(", + rot, + table@table_string, + fixed = TRUE) + table@table_string <- sub( + ") // end figure", + ") ]) // end figure", + table@table_string, + fixed = TRUE) + } + table <- style_tt(table, finalize = fn) + return(table) + } + x <- style_tt(x, finalize = fn) + return(x) +} + diff --git a/R/theme_striped.R b/R/theme_striped.R new file mode 100644 index 00000000..375ecd9a --- /dev/null +++ b/R/theme_striped.R @@ -0,0 +1,32 @@ +theme_striped <- function(x, ...) { + + fn <- theme_placement_factory( + horizontal = get_option("tinytable_theme_default_horizontal", "c"), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) + x <- style_tt(x, finalize = fn) + + x <- style_tt(x, + tabularray_inner = "row{even}={bg=black!5!white}", + bootstrap_class = "table table-striped", + output = "latex") + + x <- style_tt(x, + i = seq(1, nrow(x), by = 2), + background = "#ededed", + output = "typst") + + # theme_default + if (isTRUE(x@output %in% c("html", "typst"))) { + x <- style_tt(x, + i = nrow(x), + line = "b", + line_color = "#d3d8dc", + line_width = 0.1) + x <- style_tt(x, + i = 0, + line = "bt", + line_color = "#d3d8dc", + line_width = 0.1) + } + return(x) +} diff --git a/R/theme_tabular.R b/R/theme_tabular.R new file mode 100644 index 00000000..5e7442fb --- /dev/null +++ b/R/theme_tabular.R @@ -0,0 +1,55 @@ +theme_tabular <- function(x, + style = get_option("tinytable_theme_tabular_style", "tabular"), + ...) { + + assert_choice(style, c("tabular", "tabularray")) + + # do not change the default theme + if (identical(x@theme[[1]], "tabular")) x@theme <- list("default") + + fn <- function(table) { + tab <- table@table_string + + if (isTRUE(table@output == "latex")) { + tab <- lines_drop(tab, regex = "\\\\begin\\{table\\}", position = "before") + tab <- lines_drop(tab, regex = "\\\\begin\\{table\\}", position = "equal") + tab <- lines_drop(tab, regex = "\\\\end\\{table\\}", position = "after") + tab <- lines_drop(tab, regex = "\\\\end\\{table\\}", position = "equal") + tab <- lines_drop(tab, regex = "\\\\centering", position = "equal") + if (style == "tabular") { + tab <- lines_drop_between(tab, regex_start = "tabularray outer open", regex_end = "tabularray inner close") + tab <- lines_drop(tab, regex = "tabularray outer close", position = "equal") + tab <- lines_drop(tab, regex = "tabularray inner open", position = "equal") + tab <- lines_drop(tab, regex = "tabularray inner close", position = "equal") + tab <- lines_drop(tab, regex = "^colspec=\\{", position = "equal") + tab <- gsub("cmidrule\\[(.*?)\\]", "cmidrule(\\1)", tab) + tab <- gsub("\\{tblr\\}\\[*", "{tabular}", tab) + tab <- gsub("\\{talltblr\\}\\[", "{tabular}", tab) + tab <- gsub("\\{talltblr\\}", "{tabular}", tab) + tab <- gsub("\\{longtblr\\}\\[", "{tabular}", tab) + tab <- gsub("\\{longtblr\\}", "{tabular}", tab) + tab <- gsub("\\\\toprule|\\\\midrule|\\\\bottomrule", "\\\\hline", tab) + tab <- sub("\\s*%% tabularray outer open", "", tab) + tab <- sub("\\s*%% TinyTableHeader", "", tab) + # align + a <- sprintf("begin{tabular}{%s}", strrep("l", ncol(table))) + tab <- sub("begin{tabular}", a, tab, fixed = TRUE) + } + + } else if (isTRUE(table@output == "html")) { + tab <- lines_drop(tab, regex = "\\linewidth %s\\linewidth\\else\\width\\fi}{!}{", width) - } else if (direction == "up") { - new <- sprintf("\\resizebox{\\ifdim\\width<\\linewidth %s\\linewidth\\else\\width\\fi}{!}{", width) - } - - reg <- "\\\\begin\\{tblr\\}|\\\\begin\\{talltblr\\}" - tab <- lines_insert(tab, regex = reg, new = new, position = "before") - - new <- "}" - reg <- "\\\\end\\{tblr\\}|\\\\end\\{talltblr\\}" - tab <- lines_insert(tab, regex = reg, new = new, position = "after") - - table@table_string <- tab - - return(table) - } - - x <- style_tt(x, finalize = fn) - x <- theme_tt(x, "placement") - return(x) -} - - -theme_void <- function(x, ...) { - assert_class(x, "tinytable") - fn <- function(table) { - if (isTRUE(table@output == "latex")) { - s <- table@table_string - s <- gsub("\\\\toprule|\\\\bottomrule|\\\\midrule", "", s) - l <- strsplit(s, "\n")[[1]] - l <- l[which(trimws(l) != "")] - table@table_string <- paste(l, collapse = "\n") - } else if (isTRUE(table@output == "markdown")) { - tab <- table@table_string - tab <- strsplit(tab, "\n")[[1]] - tab <- tab[!grepl("^[\\+|-]+$", tab)] - tab <- tab[!grepl("^[\\+|=]+$", tab)] - tab <- gsub("|", " ", tab, fixed = TRUE) - table@table_string <- paste(tab, collapse = "\n") - } else if (isTRUE(table@output == "typst")) { - tab <- table@table_string - tab <- lines_drop(tab, regex = "table.hline", position = "all", fixed = TRUE) - table@table_string <- tab - } - return(table) - } - x <- style_tt(x, finalize = fn, - bootstrap_class = "table table-borderless") - x <- theme_tt(x, "placement") - return(x) -} - - -theme_grid <- function(x, ...) { - assert_class(x, "tinytable") - fn <- function(table) { - if (isTRUE(table@output == "latex")) { - s <- table@table_string - s <- lines_drop(s, regex = "\\\\bottomrule", position = "equal") - s <- lines_drop(s, regex = "\\\\midrule", position = "equal") - s <- lines_drop(s, regex = "\\\\toprule", position = "equal") - table@table_string <- s - } else if (isTRUE(table@output == "typst")) { - table@table_string <- sub( - "stroke: none,", - "stroke: (paint: black),", - table@table_string) - } - return(table) - } - x <- style_tt(x, tabularray_inner = "hlines, vlines,", finalize = fn, - bootstrap_class = "table table-bordered") - x <- theme_tt(x, "placement") - return(x) -} - - -theme_striped <- function(x, ...) { - assert_class(x, "tinytable") - x <- style_tt(x, - tabularray_inner = "row{even}={bg=black!5!white}", - bootstrap_class = "table table-striped", - output = "latex") - x <- style_tt(x, - i = seq(1, nrow(x), by = 2), - background = "#ededed", - output = "typst") - x <- theme_tt(x, "default") - return(x) -} - - -theme_bootstrap <- function(x, ...) { - assert_class(x, "tinytable") - fn <- function(table) { - if (isTRUE(table@output == "markdown")) { - tab <- table@table_string - tab <- strsplit(tab, "\n")[[1]] - tab <- tab[!grepl("^[\\+|-]+$", tab)] - tab <- gsub("|", " ", tab, fixed = TRUE) - table@table_string <- paste(tab, collapse = "\n") - } else if (isTRUE(table@output == "typst")) { - table <- style_eval(table, i = 0:nrow(table), line = "bt", line_width = 0.05, line_color = "silver") - } - return(table) - } - x <- theme_tt(x, theme = "void") # only affects LaTeX - x <- style_tt(x, tabularray_inner = "hlines={gray8},", finalize = fn) - return(x) -} - - -theme_placement <- function(x, - horizontal = get_option("tinytable_theme_placement_horizontal", default = NULL), - latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) { - # do not change the defaul theme - if (identical(x@theme[[1]], "placement")) x@theme <- list("default") - fn <- function(table) { - tab <- table@table_string - if (table@output == "latex" && !is.null(latex_float)) { - assert_string(latex_float, null.ok = TRUE) - tab <- sub( - "\\\\begin\\{table\\}([^\\[])", - sprintf("\\\\begin{table}[%s]\\1", latex_float), - tab) - } else if (table@output == "typst" && !is.null(horizontal)) { - assert_choice(horizontal, c("l", "c", "r")) - if (horizontal == "l") { - tab <- sub("#align(center,", "#align(left,", tab, fixed = TRUE) - } else if (horizontal == "r") { - tab <- sub("#align(center,", "#align(right,", tab, fixed = TRUE) - } - } - table@table_string <- tab - return(table) - } - x <- style_tt(x, finalize = fn) - return(x) -} - - -theme_multipage <- function(x, - rowhead = get_option("tinytable_theme_multipage_rowhead", 0L), - rowfoot = get_option("tinytable_theme_multipage_rowfoot", 0L), - ...) { - assert_class(x, "tinytable") - # do not change the defaul theme - if (identical(x@theme[[1]], "multipage")) x@theme <- list("default") - assert_integerish(rowhead, lower = 0, len = 1) - assert_integerish(rowfoot, lower = 0, len = 1) - cap <- sprintf("caption={%s}", x@caption) - x@caption <- "" - fn <- function(table) { - if (!isTRUE(table@output == "latex")) return(table) - - tab <- table@table_string - tab <- sub("\\\\begin\\{talltblr", "\\\\begin\\{longtblr", tab) - tab <- sub("\\\\end\\{talltblr", "\\\\end\\{longtblr", tab) - - tab <- strsplit(tab, "\n")[[1]] - idx <- grepl("^\\\\caption\\{|^\\\\begin\\{table|^\\\\end\\{table|^\\\\centering", trimws(tab)) - tab <- tab[!idx] - tab <- paste(tab, collapse = "\n") - - table@table_string <- tab - - table <- style_eval(table, tabularray_outer = cap) - - if (rowhead > 0) { - table <- style_eval(table, tabularray_inner = sprintf("rowhead=%s", rowhead)) - } - - if (rowfoot > 0) { - table <- style_eval(table, tabularray_inner = sprintf("rowfoot=%s", rowfoot)) - } - - return(table) - } - x <- style_tt(x, finalize = fn) - return(x) -} - - -theme_rotate <- function(x, angle = 90, ...) { - assert_numeric(angle, len = 1, lower = 0, upper = 360) - fn <- function(table) { - if (isTRUE(table@output == "latex")) { - rot <- sprintf("\\begin{table}\n\\rotatebox{%s}{", angle) - table@table_string <- sub( - "\\begin{table}", - rot, - table@table_string, - fixed = TRUE) - table@table_string <- sub( - "\\end{table}", - "}\n\\end{table}", - table@table_string, - fixed = TRUE) - } else if (isTRUE(table@output == "typst")) { - rot <- sprintf("#rotate(-%sdeg, reflow: true, [\n #figure(", angle) - table@table_string <- sub( - "#figure(", - rot, - table@table_string, - fixed = TRUE) - table@table_string <- sub( - ") // end figure", - ") ]) // end figure", - table@table_string, - fixed = TRUE) - } - table <- style_tt(table, finalize = fn) - return(table) - } - x <- style_tt(x, finalize = fn) - return(x) -} - - -theme_dictionary <- list( - "default" = theme_default, - "grid" = theme_grid, - "resize" = theme_resize, - "multipage" = theme_multipage, - "placement" = theme_placement, - "rotate" = theme_rotate, - "striped" = theme_striped, - "void" = theme_void, - "bootstrap" = theme_bootstrap, - "tabular" = theme_tabular -) - - - -#' Themes for `tinytable` -#' -#' @description -#' A theme is a function which applies a collection of transformations to a `tinytable` object. Whereas the other `tinytable` functions such as `format_tt()` and `style_tt()` aim to be output-agnostic, themes can be output-specific, only applying to LaTeX, HTML, or Typst, as needed. -#' -#' Each theme can have specific arguments, which are passed to the `theme_tt()` function. See the "Arguments" section below. -#' -#' @param x A `tinytable` object -#' @param theme String. Name of the theme to apply. One of: -#' + "bootstrap": Similar appearance to the default Bootstrap theme in HTML -#' + "grid": Vertical and horizontal rules around each cell. -#' + "multipage": Long tables continue on the next page (LaTeX only) -#' + "placement": Position of the table environment (LaTeX) -#' + "rotate": Rotate a LaTeX or Typst table. -#' + "resize": Scale a LaTeX `tinytable` to fit the `width` argument. -#' + "striped": Grey stripes on alternating rows -#' + "tabular": Remove table environment (LaTeX) or Javascript/CSS (HTML) -#' + "void": No rules -#' @param ... Additional arguments passed the themeing function. See the "Arguments" section below for a list of supported arguments for each theme. -#' @section Arguments: -#' -#' multipage -#' -#' + `rowhead`: Non-negative integer. The number of header rows to repeat on each page. -#' - Set globally with `options("tinytable_theme_multipage_rowhead" = 1L)` -#' + `rowfoot`: Non-negative integer. The number of footer rows to repeat on each page. -#' - Set globally with `options("tinytable_theme_multipage_rowfoot" = 1L)` -#' -#' tabular -#' -#' + `style`: -#' - "tabular": Drop all LaTeX dependencies and floating environments, except `\\begin{tabular}` -#' - "tabularray": Drop all LaTeX dependencies and floating environments, except `\\begin{tblr}` -#' - Set globally with `options("tinytable_theme_tabular_style" = "tblr")` -#' -#' placement -#' -#' + `horizontal` (Typst only): "l", "c", or "r" to align the table horizontally in the page. -#' - Set globally with `options("tinytable_theme_placement_horizontal" = "l")` -#' + `latex_float`: String to insert in square brackets after the LaTeX table environment, ex: "H", "htbp". The default value is controlled by a global option: -#' - Set globally with `options("tinytable_theme_placement_latex_float" = "H")` -#' -#' resize -#' -#' + `width`: A numeric value between 0.01 and 1, representing the proportion of the line width to use -#' - Set globally with `options("tinytable_theme_resize_width" = 0.9)` -#' + `direction`: "down", "up", "both" A string indicating if the table should be scaled in one direction. For example, "down" will only resize the table if it exceeds `\linewidth` -#' - Set globally with `options("tinytable_theme_resize_direction" = "down")` -#' -#' rotate -#' -#' + `angle`: Angle of the rotation. For example, `angle=90`` applies a half counter-clockwise turn. -#' + Caveats: -#' - LaTeX and Typst only. -#' - Typst: In Quarto documents, rotation does not work because Quarto takes over the figure environment. -#' - LaTeX: In Quarto documents, captions must be specified using the `caption` argument in `tt()` rather than via Quarto chunk options. -#' -#' @examples -#' library(tinytable) -#' -#' x <- mtcars[1:4, 1:4] -#' -#' # equivalent calls -#' tt(x, theme = "striped") -#' -#' tt(x) |> theme_tt("striped") -#' -#' # resize w/ argument -#' x <- cbind(mtcars[1:10,], mtcars[1:10,]) -#' tt(x) |> -#' theme_tt("resize", width = .9) |> -#' print("latex") -#' -#' @return A modified `tinytable` object -#' @export -theme_tt <- function(x, theme, ...) { - if (is.null(theme)) return(x) - if (is.function(theme)) return(theme(x, ...)) - td <- theme_dictionary - na <- unique(sort(names(td))) - assert_choice(theme, na) - fn <- td[[theme]] - out <- fn(x, ...) - return(out) -} - diff --git a/R/theme_void.R b/R/theme_void.R new file mode 100644 index 00000000..8ead522f --- /dev/null +++ b/R/theme_void.R @@ -0,0 +1,35 @@ +theme_void_fn <- function(table) { + + if (isTRUE(table@output == "latex")) { + s <- table@table_string + s <- gsub("\\\\toprule|\\\\bottomrule|\\\\midrule", "", s) + l <- strsplit(s, "\n")[[1]] + l <- l[which(trimws(l) != "")] + table@table_string <- paste(l, collapse = "\n") + } else if (isTRUE(table@output == "markdown")) { + tab <- table@table_string + tab <- strsplit(tab, "\n")[[1]] + tab <- tab[!grepl("^[\\+|-]+$", tab)] + tab <- tab[!grepl("^[\\+|=]+$", tab)] + tab <- gsub("|", " ", tab, fixed = TRUE) + table@table_string <- paste(tab, collapse = "\n") + } else if (isTRUE(table@output == "typst")) { + tab <- table@table_string + tab <- lines_drop(tab, regex = "table.hline", position = "all", fixed = TRUE) + table@table_string <- tab + } + return(table) +} + + +theme_void <- function(x, ...) { + fn <- theme_placement_factory( + horizontal = get_option("tinytable_theme_default_horizontal", "c"), + latex_float = get_option("tinytable_theme_placement_latex_float", default = NULL)) + x <- style_tt(x, finalize = fn) + + x <- style_tt(x, + finalize = theme_void_fn, + bootstrap_class = "table table-borderless") + return(x) +} diff --git a/R/theme_zzz.R b/R/theme_zzz.R new file mode 100644 index 00000000..48766f6f --- /dev/null +++ b/R/theme_zzz.R @@ -0,0 +1,103 @@ +theme_dictionary <- list( + "default" = theme_default, + "grid" = theme_grid, + "resize" = theme_resize, + "multipage" = theme_multipage, + "placement" = theme_placement, + "rotate" = theme_rotate, + "striped" = theme_striped, + "void" = theme_void, + "bootstrap" = theme_bootstrap, + "tabular" = theme_tabular +) + + + +#' Themes for `tinytable` +#' +#' @description +#' A theme is a function which applies a collection of transformations to a `tinytable` object. Whereas the other `tinytable` functions such as `format_tt()` and `style_tt()` aim to be output-agnostic, themes can be output-specific, only applying to LaTeX, HTML, or Typst, as needed. +#' +#' Each theme can have specific arguments, which are passed to the `theme_tt()` function. See the "Arguments" section below. +#' +#' @param x A `tinytable` object +#' @param theme String. Name of the theme to apply. One of: +#' + "bootstrap": Similar appearance to the default Bootstrap theme in HTML +#' + "grid": Vertical and horizontal rules around each cell. +#' + "multipage": Long tables continue on the next page (LaTeX only) +#' + "placement": Position of the table environment (LaTeX) +#' + "rotate": Rotate a LaTeX or Typst table. +#' + "resize": Scale a LaTeX `tinytable` to fit the `width` argument. +#' + "striped": Grey stripes on alternating rows +#' + "tabular": Remove table environment (LaTeX) or Javascript/CSS (HTML) +#' + "void": No rules +#' @param ... Additional arguments passed the themeing function. See the "Arguments" section below for a list of supported arguments for each theme. +#' @section Arguments: +#' +#' multipage +#' +#' + `rowhead`: Non-negative integer. The number of header rows to repeat on each page. +#' - Set globally with `options("tinytable_theme_multipage_rowhead" = 1L)` +#' + `rowfoot`: Non-negative integer. The number of footer rows to repeat on each page. +#' - Set globally with `options("tinytable_theme_multipage_rowfoot" = 1L)` +#' +#' tabular +#' +#' + `style`: +#' - "tabular": Drop all LaTeX dependencies and floating environments, except `\\begin{tabular}` +#' - "tabularray": Drop all LaTeX dependencies and floating environments, except `\\begin{tblr}` +#' - Set globally with `options("tinytable_theme_tabular_style" = "tblr")` +#' +#' placement +#' +#' + `horizontal` (Typst only): "l", "c", or "r" to align the table horizontally in the page. +#' - Set globally with `options("tinytable_theme_placement_horizontal" = "l")` +#' + `latex_float`: String to insert in square brackets after the LaTeX table environment, ex: "H", "htbp". The default value is controlled by a global option: +#' - Set globally with `options("tinytable_theme_placement_latex_float" = "H")` +#' +#' resize +#' +#' + `width`: A numeric value between 0.01 and 1, representing the proportion of the line width to use +#' - Set globally with `options("tinytable_theme_resize_width" = 0.9)` +#' + `direction`: "down", "up", "both" A string indicating if the table should be scaled in one direction. For example, "down" will only resize the table if it exceeds `\linewidth` +#' - Set globally with `options("tinytable_theme_resize_direction" = "down")` +#' +#' rotate +#' +#' + `angle`: Angle of the rotation. For example, `angle=90`` applies a half counter-clockwise turn. +#' + Caveats: +#' - LaTeX and Typst only. +#' - Typst: In Quarto documents, rotation does not work because Quarto takes over the figure environment. +#' - LaTeX: In Quarto documents, captions must be specified using the `caption` argument in `tt()` rather than via Quarto chunk options. +#' +#' @examples +#' library(tinytable) +#' +#' x <- mtcars[1:4, 1:4] +#' +#' # equivalent calls +#' tt(x, theme = "striped") +#' +#' tt(x) |> theme_tt("striped") +#' +#' # resize w/ argument +#' x <- cbind(mtcars[1:10,], mtcars[1:10,]) +#' tt(x) |> +#' theme_tt("resize", width = .9) |> +#' print("latex") +#' +#' @return A modified `tinytable` object +#' @export +theme_tt <- function(x, theme, ...) { + assert_class(x, "tinytable") + if (is.null(theme)) return(x) + if (is.function(theme)) return(theme(x, ...)) + td <- theme_dictionary + na <- unique(sort(names(td))) + assert_choice(theme, na) + fn <- td[[theme]] + out <- list(list(fn, list(...))) + x@lazy_theme <- c(x@lazy_theme, out) + return(x) +} + diff --git a/R/tt.R b/R/tt.R index f8b46ad8..c7487273 100644 --- a/R/tt.R +++ b/R/tt.R @@ -31,7 +31,7 @@ #' @param ... Additional arguments are ignored #' @return An object of class `tt` representing the table. #' -#' The table object has S4 slots which hold information about the structure of the table. This meta-data can be accessed with the usual `@` accessor. In general, modifying the content of these slots is not recommended, but it can be useful to some developers, such as those who want to force print to a specific output format without calling `print()`. +#' The table object has S4 slots which hold information about the structure of the table. Relying on or modifying the contents of these slots is strongly discouraged. Their names and contents could change at any time, and the `tinytable` developers do not consider changes to the internal structure of the output object to be a "breaking change" for versioning or changelog purposes. #' @template latex_preamble #' @template global_options #' @@ -61,22 +61,23 @@ tt <- function(x, caption = get_option("tinytable_tt_caption", default = NULL), notes = get_option("tinytable_tt_notes", default = NULL), width = get_option("tinytable_tt_width", default = NULL), - theme = get_option("tinytable_tt_theme", default = NULL), + theme = get_option("tinytable_tt_theme", default = "default"), rownames = get_option("tinytable_tt_rownames", default = FALSE), escape = get_option("tinytable_tt_escape", default = FALSE), ...) { dots <- list(...) - if ("placement" %in% names(dots)) { - warning("The `placement` argument in `tt()` is deprecated. Please use this instead: `theme_tt(table, 'placement')`", call. = FALSE) - } # sanity checks assert_string(caption, null.ok = TRUE) assert_integerish(digits, len = 1, null.ok = TRUE) notes <- sanitize_notes(notes) + if (!isTRUE(check_function(theme)) && !isTRUE(check_string(theme))) { + stop("The `theme` argument must be a function or a string.", call. = FALSE) + } + # x should be a data frame, not a tibble or slopes, for indexing convenience assert_data_frame(x, min_rows = 1, min_cols = 1) if (!isTRUE(identical(class(x), "data.frame"))) { diff --git a/R/tt_bootstrap.R b/R/tt_bootstrap.R index 94c1be25..4fa11522 100644 --- a/R/tt_bootstrap.R +++ b/R/tt_bootstrap.R @@ -144,17 +144,18 @@ setMethod( # before style_eval() x@table_string <- out - if (is.null(x@theme[[1]]) || is.function(x@theme[[1]]) || isTRUE("default" %in% x@theme[[1]])) { - x <- style_eval(x, bootstrap_class = "table table-borderless", - i = 0, line = "b", line_color = "#d3d8dc", line_width = 0.1) + if (length(x@bootstrap_class) == 0) { + if (is.null(x@theme[[1]]) || is.function(x@theme[[1]]) || isTRUE("default" %in% x@theme[[1]])) { + x <- theme_tt(x, "default") + } } else if ("bootstrap" %in% x@theme[[1]]) { - x <- style_eval(x, bootstrap_class = "table") + x <- style_tt(x, bootstrap_class = "table") } else if ("striped" %in% x@theme[[1]]) { - x <- style_eval(x, bootstrap_class = "table table-striped") + x <- style_tt(x, bootstrap_class = "table table-striped") } else if ("grid" %in% x@theme[[1]]) { - x <- style_eval(x, bootstrap_class = "table table-bordered") + x <- style_tt(x, bootstrap_class = "table table-bordered") } else if ("void" %in% x@theme[[1]]) { - x <- style_eval(x, bootstrap_class = "table table-borderless") + x <- style_tt(x, bootstrap_class = "table table-borderless") } if (length(x@width) > 1) { diff --git a/README.md b/README.md index 55258d6a..32116079 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ want to benefit from the latest features—showcased on the package website—you should install from R-Universe: ``` r -install.packages("tinytable", repos = "https://vincentarelbundock.r-universe.dev") +install.packages("tinytable") ``` Alternatively, you can install it from CRAN: @@ -131,7 +131,7 @@ tt(x, ## Tutorial -The `tinytable` 0.5.0 tutorial will take you much further. It is +The `tinytable` 0.5.0.1 tutorial will take you much further. It is available in two formats: - [Tutorial diff --git a/README.qmd b/README.qmd index f26c0bca..779999ee 100644 --- a/README.qmd +++ b/README.qmd @@ -52,7 +52,7 @@ To achieve these goals, the design philosophy of `tinytable` rests on three pill `tinytable` is a relatively new package with rapid development. If you want to benefit from the latest features---showcased on the package website---you should install from R-Universe: ``` r -install.packages("tinytable", repos = "https://vincentarelbundock.r-universe.dev") +install.packages("tinytable") ``` Alternatively, you can install it from CRAN: diff --git a/inst/templates/bootstrap.html b/inst/templates/bootstrap.html index fb1694ee..76433e23 100644 --- a/inst/templates/bootstrap.html +++ b/inst/templates/bootstrap.html @@ -25,9 +25,16 @@
diff --git a/inst/templates/typst.typ b/inst/templates/typst.typ index fc4f9b3e..f5bb8e1e 100644 --- a/inst/templates/typst.typ +++ b/inst/templates/typst.typ @@ -16,19 +16,23 @@ block[ // start block // tinytable align-default-array before #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -38,20 +42,29 @@ block[ // start block #table( // tinytable table start stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/format_tt-vignette_digits.txt b/inst/tinytest/_tinysnapshot/format_tt-vignette_digits.txt index 419e641a..aae74195 100644 --- a/inst/tinytest/_tinysnapshot/format_tt-vignette_digits.txt +++ b/inst/tinytest/_tinysnapshot/format_tt-vignette_digits.txt @@ -1,10 +1,10 @@ -+--------+--------+------------+-------+ -| w | x | y | z | -+========+========+============+=======+ -| 143002 | 1.43 | 1972-09-08 | True | -+--------+--------+------------+-------+ -| 201399 | 201.4 | 1970-08-03 | True | -+--------+--------+------------+-------+ -| 100188 | 0.13 | 1970-11-06 | False | -+--------+--------+------------+-------+ ++--------+-------+------------+-------+ +| w | x | y | z | ++========+=======+============+=======+ +| 143002 | 1.43 | 1972-09-08 | True | ++--------+-------+------------+-------+ +| 201399 | 201.4 | 1970-08-03 | True | ++--------+-------+------------+-------+ +| 100188 | 0.13 | 1970-11-06 | False | ++--------+-------+------------+-------+ diff --git a/inst/tinytest/_tinysnapshot/format_tt-vignette_html_markdown.html b/inst/tinytest/_tinysnapshot/format_tt-vignette_html_markdown.html index 838be6d0..ada79f99 100644 --- a/inst/tinytest/_tinysnapshot/format_tt-vignette_html_markdown.html +++ b/inst/tinytest/_tinysnapshot/format_tt-vignette_html_markdown.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/group_tt-3level_md.txt b/inst/tinytest/_tinysnapshot/group_tt-3level.md similarity index 100% rename from inst/tinytest/_tinysnapshot/group_tt-3level_md.txt rename to inst/tinytest/_tinysnapshot/group_tt-3level.md diff --git a/inst/tinytest/_tinysnapshot/group_tt-3level_tex.txt b/inst/tinytest/_tinysnapshot/group_tt-3level.tex similarity index 96% rename from inst/tinytest/_tinysnapshot/group_tt-3level_tex.txt rename to inst/tinytest/_tinysnapshot/group_tt-3level.tex index bdba73e0..88113122 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-3level_tex.txt +++ b/inst/tinytest/_tinysnapshot/group_tt-3level.tex @@ -4,12 +4,12 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, +cell{1}{4}={}{halign=c,}, +cell{2}{1}={c=2,}{halign=c,}, cell{3}{2}={c=2,}{halign=c,}, cell{3}{4}={c=2,}{halign=c,}, -cell{2}{1}={c=2,}{halign=c,}, -cell{2}{3}={c=3,}{halign=c,}, cell{1}{1}={c=3,}{halign=c,}, -cell{1}{4}={c=1,}{halign=c,}, +cell{2}{3}={c=3,}{halign=c,}, } %% tabularray inner close \toprule e & & & f & \\ \cmidrule[lr]{1-3}\cmidrule[lr]{4-4} diff --git a/inst/tinytest/_tinysnapshot/group_tt-3level.typ b/inst/tinytest/_tinysnapshot/group_tt-3level.typ index f49168db..7db8b309 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-3level.typ +++ b/inst/tinytest/_tinysnapshot/group_tt-3level.typ @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -41,23 +46,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 4, start: 0, end: 5, stroke: 0.05em + black), -table.hline(y: 7, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 7, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 3, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 4, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/group_tt-html_tutorial_01.html b/inst/tinytest/_tinysnapshot/group_tt-html_tutorial_01.html index e0baa9b6..eb6bfc04 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-html_tutorial_01.html +++ b/inst/tinytest/_tinysnapshot/group_tt-html_tutorial_01.html @@ -11,11 +11,18 @@
diff --git a/inst/tinytest/_tinysnapshot/group_tt-issue165_html_centering_style.html b/inst/tinytest/_tinysnapshot/group_tt-issue165_html_centering_style.html index f24ed948..98eac8bf 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-issue165_html_centering_style.html +++ b/inst/tinytest/_tinysnapshot/group_tt-issue165_html_centering_style.html @@ -11,11 +11,18 @@
@@ -124,7 +134,7 @@ - + diff --git a/inst/tinytest/_tinysnapshot/group_tt-issue258_01_html.html b/inst/tinytest/_tinysnapshot/group_tt-issue258_01_html.html index 055821a9..ee26f6c5 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-issue258_01_html.html +++ b/inst/tinytest/_tinysnapshot/group_tt-issue258_01_html.html @@ -11,11 +11,18 @@
22.800 4 108 9393 3.850
diff --git a/inst/tinytest/_tinysnapshot/group_tt-issue258_01_latex.txt b/inst/tinytest/_tinysnapshot/group_tt-issue258_01_latex.txt index a83f68bf..8392dfee 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-issue258_01_latex.txt +++ b/inst/tinytest/_tinysnapshot/group_tt-issue258_01_latex.txt @@ -5,13 +5,12 @@ { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, cell{2}{1}={c=5}{}, -cell{3}{1}={preto={\hspace{1em}}}, -cell{4}{1}={preto={\hspace{1em}}}, -cell{5}{1}={preto={\hspace{1em}}}, -cell{6}{1}={preto={\hspace{1em}}}, -cell{7}{1}={preto={\hspace{1em}}}, -cell{8}{1}={preto={\hspace{1em}}}, -cell{9}{1}={preto={\hspace{1em}}}, +cell{3}{1}={}{preto={\hspace{1em}},}, +cell{4}{1}={}{preto={\hspace{1em}},}, +cell{5}{1}={}{preto={\hspace{1em}},}, +cell{6}{1}={}{preto={\hspace{1em}},}, +cell{7}{1}={}{preto={\hspace{1em}},}, +cell{8}{1}={}{preto={\hspace{1em}},}, } %% tabularray inner close \toprule Sepal.Length & Sepal.Width & Petal.Length & Petal.Width & Species \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/group_tt-issue258_01_typst.txt b/inst/tinytest/_tinysnapshot/group_tt-issue258_01_typst.txt index df2fa42b..455cf232 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-issue258_01_typst.txt +++ b/inst/tinytest/_tinysnapshot/group_tt-issue258_01_typst.txt @@ -12,25 +12,30 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (2, 3, 4, 5, 6, 7, 8,), x: (0, 1, 2, 3, 4,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: 1em, background: none, align: none), +(pairs: ((0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7),), indent: 1em,), +(pairs: ((0, 0), (0, 1), (0, 8), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -41,23 +46,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 5, stroke: 0.05em + black), -table.hline(y: 8, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 8, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/group_tt-issue258_02_html.html b/inst/tinytest/_tinysnapshot/group_tt-issue258_02_html.html index 379ae1da..d2a7811e 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-issue258_02_html.html +++ b/inst/tinytest/_tinysnapshot/group_tt-issue258_02_html.html @@ -11,11 +11,18 @@
diff --git a/inst/tinytest/_tinysnapshot/group_tt-issue258_02_latex.txt b/inst/tinytest/_tinysnapshot/group_tt-issue258_02_latex.txt index c0ccd0c9..211f88ec 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-issue258_02_latex.txt +++ b/inst/tinytest/_tinysnapshot/group_tt-issue258_02_latex.txt @@ -5,13 +5,12 @@ { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, cell{3}{1}={c=5}{},cell{4}{1}={c=5}{}, -cell{2}{1}={preto={\hspace{1em}}}, -cell{5}{1}={preto={\hspace{1em}}}, -cell{6}{1}={preto={\hspace{1em}}}, -cell{7}{1}={preto={\hspace{1em}}}, -cell{8}{1}={preto={\hspace{1em}}}, -cell{9}{1}={preto={\hspace{1em}}}, -cell{10}{1}={preto={\hspace{1em}}}, +cell{2}{1}={}{preto={\hspace{1em}},}, +cell{5}{1}={}{preto={\hspace{1em}},}, +cell{6}{1}={}{preto={\hspace{1em}},}, +cell{7}{1}={}{preto={\hspace{1em}},}, +cell{8}{1}={}{preto={\hspace{1em}},}, +cell{9}{1}={}{preto={\hspace{1em}},}, } %% tabularray inner close \toprule Sepal.Length & Sepal.Width & Petal.Length & Petal.Width & Species \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/group_tt-issue258_02_typst.txt b/inst/tinytest/_tinysnapshot/group_tt-issue258_02_typst.txt index abb9598e..c352e332 100644 --- a/inst/tinytest/_tinysnapshot/group_tt-issue258_02_typst.txt +++ b/inst/tinytest/_tinysnapshot/group_tt-issue258_02_typst.txt @@ -12,25 +12,30 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (1, 4, 5, 6, 7, 8, 9, 10,), x: (0, 1, 2, 3, 4,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: 1em, background: none, align: none), +(pairs: ((0, 1), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8),), indent: 1em,), +(pairs: ((0, 0), (0, 2), (0, 3), (0, 9), (0, 10), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (4, 10),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -41,23 +46,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 5, stroke: 0.05em + black), -table.hline(y: 9, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 9, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/html-alignment.html b/inst/tinytest/_tinysnapshot/html-alignment.html index 90e76c4a..9f29e0b6 100644 --- a/inst/tinytest/_tinysnapshot/html-alignment.html +++ b/inst/tinytest/_tinysnapshot/html-alignment.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-bootstrap_css.html b/inst/tinytest/_tinysnapshot/html-bootstrap_css.html index 8da9b362..b6c753e9 100644 --- a/inst/tinytest/_tinysnapshot/html-bootstrap_css.html +++ b/inst/tinytest/_tinysnapshot/html-bootstrap_css.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-borders.html b/inst/tinytest/_tinysnapshot/html-borders.html index ed9b4e7d..46277ef6 100644 --- a/inst/tinytest/_tinysnapshot/html-borders.html +++ b/inst/tinytest/_tinysnapshot/html-borders.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-caption.html b/inst/tinytest/_tinysnapshot/html-caption.html index 70184893..482c0c30 100644 --- a/inst/tinytest/_tinysnapshot/html-caption.html +++ b/inst/tinytest/_tinysnapshot/html-caption.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-conditional_styling.html b/inst/tinytest/_tinysnapshot/html-conditional_styling.html index 60f7fa79..e411f6c3 100644 --- a/inst/tinytest/_tinysnapshot/html-conditional_styling.html +++ b/inst/tinytest/_tinysnapshot/html-conditional_styling.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-font_size.html b/inst/tinytest/_tinysnapshot/html-font_size.html index 65c141a5..3a0ee3c4 100644 --- a/inst/tinytest/_tinysnapshot/html-font_size.html +++ b/inst/tinytest/_tinysnapshot/html-font_size.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-footnote.html b/inst/tinytest/_tinysnapshot/html-footnote.html index ae12af37..954e904d 100644 --- a/inst/tinytest/_tinysnapshot/html-footnote.html +++ b/inst/tinytest/_tinysnapshot/html-footnote.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-formatting.html b/inst/tinytest/_tinysnapshot/html-formatting.html index 15a83e64..70cfdb70 100644 --- a/inst/tinytest/_tinysnapshot/html-formatting.html +++ b/inst/tinytest/_tinysnapshot/html-formatting.html @@ -11,9 +11,16 @@
@@ -75,19 +93,19 @@ - + - + - + diff --git a/inst/tinytest/_tinysnapshot/html-heatmap.html b/inst/tinytest/_tinysnapshot/html-heatmap.html index bf7b527c..63248244 100644 --- a/inst/tinytest/_tinysnapshot/html-heatmap.html +++ b/inst/tinytest/_tinysnapshot/html-heatmap.html @@ -11,9 +11,16 @@
143002 1.431.43 1972-09-26 True
201399201.4 201.4 1971-11-07 True
100188 0.130.13 1970-01-04 False
diff --git a/inst/tinytest/_tinysnapshot/html-images-portable.html b/inst/tinytest/_tinysnapshot/html-images-portable.html index 0373dba8..db178a95 100644 --- a/inst/tinytest/_tinysnapshot/html-images-portable.html +++ b/inst/tinytest/_tinysnapshot/html-images-portable.html @@ -11,9 +11,16 @@
@@ -71,11 +91,11 @@ - + - +
bar
line
diff --git a/inst/tinytest/_tinysnapshot/html-images.html b/inst/tinytest/_tinysnapshot/html-images.html index 8cd069f9..16685908 100644 --- a/inst/tinytest/_tinysnapshot/html-images.html +++ b/inst/tinytest/_tinysnapshot/html-images.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-individual_cells.html b/inst/tinytest/_tinysnapshot/html-individual_cells.html index 0bd40a49..88dc91e5 100644 --- a/inst/tinytest/_tinysnapshot/html-individual_cells.html +++ b/inst/tinytest/_tinysnapshot/html-individual_cells.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-issue297.txt b/inst/tinytest/_tinysnapshot/html-issue297.txt index 8cd069f9..16685908 100644 --- a/inst/tinytest/_tinysnapshot/html-issue297.txt +++ b/inst/tinytest/_tinysnapshot/html-issue297.txt @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-issue58.html b/inst/tinytest/_tinysnapshot/html-issue58.html index 0c15769a..174ed324 100644 --- a/inst/tinytest/_tinysnapshot/html-issue58.html +++ b/inst/tinytest/_tinysnapshot/html-issue58.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-issue88.html b/inst/tinytest/_tinysnapshot/html-issue88.html index d0c39d1b..02674bf3 100644 --- a/inst/tinytest/_tinysnapshot/html-issue88.html +++ b/inst/tinytest/_tinysnapshot/html-issue88.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-issue92.html b/inst/tinytest/_tinysnapshot/html-issue92.html index a05f1e98..c4a53297 100644 --- a/inst/tinytest/_tinysnapshot/html-issue92.html +++ b/inst/tinytest/_tinysnapshot/html-issue92.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-line_break.html b/inst/tinytest/_tinysnapshot/html-line_break.html index d7f16d32..78395267 100644 --- a/inst/tinytest/_tinysnapshot/html-line_break.html +++ b/inst/tinytest/_tinysnapshot/html-line_break.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-merge_cells.html b/inst/tinytest/_tinysnapshot/html-merge_cells.html index d5a2a363..f06fcff0 100644 --- a/inst/tinytest/_tinysnapshot/html-merge_cells.html +++ b/inst/tinytest/_tinysnapshot/html-merge_cells.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-missing_value.html b/inst/tinytest/_tinysnapshot/html-missing_value.html index 541dd7c7..a448ed63 100644 --- a/inst/tinytest/_tinysnapshot/html-missing_value.html +++ b/inst/tinytest/_tinysnapshot/html-missing_value.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-omit_headers.html b/inst/tinytest/_tinysnapshot/html-omit_headers.html index 54057692..c9625d07 100644 --- a/inst/tinytest/_tinysnapshot/html-omit_headers.html +++ b/inst/tinytest/_tinysnapshot/html-omit_headers.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-spanning_cells.html b/inst/tinytest/_tinysnapshot/html-spanning_cells.html index 3658de1f..dd12a9ad 100644 --- a/inst/tinytest/_tinysnapshot/html-spanning_cells.html +++ b/inst/tinytest/_tinysnapshot/html-spanning_cells.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-striped.html b/inst/tinytest/_tinysnapshot/html-striped.html index 11ca219c..12d5121b 100644 --- a/inst/tinytest/_tinysnapshot/html-striped.html +++ b/inst/tinytest/_tinysnapshot/html-striped.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-striped_orange.html b/inst/tinytest/_tinysnapshot/html-striped_orange.html index 7e4def59..5daa8daa 100644 --- a/inst/tinytest/_tinysnapshot/html-striped_orange.html +++ b/inst/tinytest/_tinysnapshot/html-striped_orange.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/html-vectorized_color_j.html b/inst/tinytest/_tinysnapshot/html-vectorized_color_j.html index 2dcd4363..6e6f65be 100644 --- a/inst/tinytest/_tinysnapshot/html-vectorized_color_j.html +++ b/inst/tinytest/_tinysnapshot/html-vectorized_color_j.html @@ -11,9 +11,16 @@
diff --git a/inst/tinytest/_tinysnapshot/latex-align.txt b/inst/tinytest/_tinysnapshot/latex-align.txt index c35edc7e..f038e114 100644 --- a/inst/tinytest/_tinysnapshot/latex-align.txt +++ b/inst/tinytest/_tinysnapshot/latex-align.txt @@ -4,11 +4,9 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -column{1}={halign=c,}, -column{2}={halign=c,}, -column{3}={halign=l,}, -column{4}={halign=l,}, -column{5}={halign=r,}, +column{1,2}={}{halign=c,}, +column{3,4}={}{halign=l,}, +column{5}={}{halign=r,}, } %% tabularray inner close \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-align_d.txt b/inst/tinytest/_tinysnapshot/latex-align_d.txt index acafc31e..9cfead4f 100644 --- a/inst/tinytest/_tinysnapshot/latex-align_d.txt +++ b/inst/tinytest/_tinysnapshot/latex-align_d.txt @@ -4,8 +4,7 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]}, -column{1}={si={table-format=-6.5,table-align-text-before=false,table-align-text-after=false,input-symbols={-,\*+()}},}, -row{1}={guard}, +column{1}={}{si={table-format=-6.5, table-align-text-before=false, table-align-text-after=false, input-symbols={-, \*+()}},}, } %% tabularray inner close \toprule pi \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-borders.txt b/inst/tinytest/_tinysnapshot/latex-borders.txt index 14319d24..32522410 100644 --- a/inst/tinytest/_tinysnapshot/latex-borders.txt +++ b/inst/tinytest/_tinysnapshot/latex-borders.txt @@ -4,8 +4,15 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -hline{1,2,3,4,5}={1,2,3}{solid, 0.4em, orange}, -vline{1,2,3,4}={1,2,3,4}{solid, 0.4em, orange}, +hline{1}={1,2,3}{solid, orange, 0.4em}, +hline{2}={1,2,3}{solid, orange, 0.4em}, +hline{3}={1,2,3}{solid, orange, 0.4em}, +hline{4}={1,2,3}{solid, orange, 0.4em}, +hline{5}={1,2,3}{solid, orange, 0.4em}, +vline{1}={1,2,3,4}{solid, orange, 0.4em}, +vline{2}={1,2,3,4}{solid, orange, 0.4em}, +vline{3}={1,2,3,4}{solid, orange, 0.4em}, +vline{4}={1,2,3,4}{solid, orange, 0.4em}, } %% tabularray inner close mpg & cyl & disp & hp & drat \\ 21.0 & 6 & 160 & 110 & 3.90 \\ diff --git a/inst/tinytest/_tinysnapshot/latex-cell_color.txt b/inst/tinytest/_tinysnapshot/latex-cell_color.txt index f7dba38c..55f92cdd 100644 --- a/inst/tinytest/_tinysnapshot/latex-cell_color.txt +++ b/inst/tinytest/_tinysnapshot/latex-cell_color.txt @@ -4,14 +4,14 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -cell{2}{1}={}{,fg=orange,}, -cell{3}{1}={}{,fg=orange,}, -cell{2}{2}={}{,fg=orange,}, -cell{3}{2}={}{,fg=orange,}, -cell{2}{3}={}{,fg=orange,}, -cell{3}{3}={}{,fg=orange,}, -cell{2}{4}={}{,fg=orange,}, -cell{3}{4}={}{,fg=orange,}, +cell{2}{1}={}{fg=orange,}, +cell{2}{2}={}{fg=orange,}, +cell{2}{3}={}{fg=orange,}, +cell{2}{4}={}{fg=orange,}, +cell{3}{1}={}{fg=orange,}, +cell{3}{2}={}{fg=orange,}, +cell{3}{3}={}{fg=orange,}, +cell{3}{4}={}{fg=orange,}, } %% tabularray inner close \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-col_color.txt b/inst/tinytest/_tinysnapshot/latex-col_color.txt index 89c703bc..93139446 100644 --- a/inst/tinytest/_tinysnapshot/latex-col_color.txt +++ b/inst/tinytest/_tinysnapshot/latex-col_color.txt @@ -4,10 +4,7 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -column{1}={,fg=orange,}, -column{2}={,fg=orange,}, -column{3}={,fg=orange,}, -column{4}={,fg=orange,}, +column{1,2,3,4}={}{fg=orange,}, } %% tabularray inner close \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-conditional_styling.txt b/inst/tinytest/_tinysnapshot/latex-conditional_styling.txt index 70dd176a..d526908f 100644 --- a/inst/tinytest/_tinysnapshot/latex-conditional_styling.txt +++ b/inst/tinytest/_tinysnapshot/latex-conditional_styling.txt @@ -4,9 +4,7 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]}, -row{4}={,bg=teal,fg=white,}, -row{6}={,bg=teal,fg=white,}, -row{8}={,bg=teal,fg=white,}, +row{4,6,8}={}{fg=white, bg=teal,}, } %% tabularray inner close \toprule mpg & am & vs \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-font_size.txt b/inst/tinytest/_tinysnapshot/latex-font_size.txt index 292fede5..90d10843 100644 --- a/inst/tinytest/_tinysnapshot/latex-font_size.txt +++ b/inst/tinytest/_tinysnapshot/latex-font_size.txt @@ -4,8 +4,7 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -column{1}={font=\fontsize{1.5em}{1.8em}\selectfont,}, -column{4}={font=\fontsize{1.5em}{1.8em}\selectfont,}, +column{1,4}={}{font=\fontsize{1.5em}{1.8em}\selectfont,}, } %% tabularray inner close \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-formatting.txt b/inst/tinytest/_tinysnapshot/latex-formatting.txt index 41dc6926..c7284bc4 100644 --- a/inst/tinytest/_tinysnapshot/latex-formatting.txt +++ b/inst/tinytest/_tinysnapshot/latex-formatting.txt @@ -7,10 +7,10 @@ colspec={Q[]Q[]Q[]}, } %% tabularray inner close \toprule a & b & c \\ \midrule %% TinyTableHeader -Food: Burger & 1.432 & 99T \\ +Food: Burger & 1.432 & 99T \\ Food: Halloumi & 201.399 & 7.3B \\ -Food: Tofu & 0.146 & 29M \\ -Food: Beans & 0.003 & 94K \\ +Food: Tofu & 0.146 & 29M \\ +Food: Beans & 0.003 & 94K \\ \bottomrule \end{tblr} \end{table} diff --git a/inst/tinytest/_tinysnapshot/latex-group_style_order.txt b/inst/tinytest/_tinysnapshot/latex-group_style_order.txt index 76d318d4..03ddb709 100644 --- a/inst/tinytest/_tinysnapshot/latex-group_style_order.txt +++ b/inst/tinytest/_tinysnapshot/latex-group_style_order.txt @@ -4,14 +4,10 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]}, -cell{1}{1}={c=2,}{halign=c,}, -cell{1}{3}={c=2,}{halign=c,}, -row{2}={,bg=black,fg=orange,}, -row{1}={,bg=black,fg=orange,}, -row{3}={,bg=black,fg=orange,}, -row{4}={,bg=black,fg=orange,}, -row{5}={,bg=black,fg=orange,}, -row{6}={,bg=black,fg=orange,}, +column{2,4}={}{fg=orange, bg=black,}, +row{2,3,4,5,6}={}{fg=orange, bg=black,}, +cell{1}{1}={c=2,}{fg=orange, bg=black, halign=c,}, +cell{1}{3}={c=2,}{fg=orange, bg=black, halign=c,}, } %% tabularray inner close \toprule blah & & bar & \\ \cmidrule[lr]{1-2}\cmidrule[lr]{3-4} diff --git a/inst/tinytest/_tinysnapshot/latex-heatmaps.txt b/inst/tinytest/_tinysnapshot/latex-heatmaps.txt index 32e87291..2ee915ec 100644 --- a/inst/tinytest/_tinysnapshot/latex-heatmaps.txt +++ b/inst/tinytest/_tinysnapshot/latex-heatmaps.txt @@ -5,31 +5,26 @@ { %% tabularray inner open width={0.7\linewidth}, colspec={X[]X[]X[]X[]X[]}, -column{1}={halign=c,}, -column{2}={halign=c,}, -column{3}={halign=c,}, -column{4}={halign=c,}, -column{5}={halign=c,}, -cell{1}{1}={}{font=\fontsize{0.1em}{0.4em}\selectfont,bg=c040404,fg=cFFFE9E,}, -cell{2}{1}={}{font=\fontsize{0.2em}{0.5em}\selectfont,bg=c120E2A,fg=cFFFE9E,}, -cell{3}{1}={}{font=\fontsize{0.3em}{0.6em}\selectfont,bg=c25123D,fg=cFFFE9E,}, -cell{4}{1}={}{font=\fontsize{0.4em}{0.7em}\selectfont,bg=c3A134C,fg=cFFFE9E,}, -cell{1}{2}={}{font=\fontsize{0.5em}{0.8em}\selectfont,bg=c50125A,fg=cFFFE9E,}, -cell{2}{2}={}{font=\fontsize{0.6em}{0.9em}\selectfont,bg=c671065,fg=cFFFE9E,}, -cell{3}{2}={}{font=\fontsize{0.7em}{1em}\selectfont,bg=c7D106E,fg=cFFFE9E,}, -cell{4}{2}={}{font=\fontsize{0.8em}{1.1em}\selectfont,bg=c931473,fg=cFFFE9E,}, -cell{1}{3}={}{font=\fontsize{0.9em}{1.2em}\selectfont,bg=cA81D75,fg=cFFFE9E,}, -cell{2}{3}={}{font=\fontsize{1em}{1.3em}\selectfont,bg=cBC2A73,fg=cFFFE9E,}, -cell{3}{3}={}{font=\fontsize{1.1em}{1.4em}\selectfont,bg=cCE3A6C,fg=cFFFE9E,}, -cell{4}{3}={}{font=\fontsize{1.2em}{1.5em}\selectfont,bg=cDE4B5F,fg=cFFFE9E,}, -cell{1}{4}={}{font=\fontsize{1.3em}{1.6em}\selectfont,bg=cED5E48,fg=cFFFE9E,}, -cell{2}{4}={}{font=\fontsize{1.4em}{1.7em}\selectfont,bg=cF3762F,fg=cFFFE9E,}, -cell{3}{4}={}{font=\fontsize{1.5em}{1.8em}\selectfont,bg=cF58E22,fg=cFFFE9E,}, -cell{4}{4}={}{font=\fontsize{1.6em}{1.9em}\selectfont,bg=cF7A529,fg=cFFFE9E,}, -cell{1}{5}={}{font=\fontsize{1.7em}{2em}\selectfont,bg=cF8BB41,fg=c040404,}, -cell{2}{5}={}{font=\fontsize{1.8em}{2.1em}\selectfont,bg=cF9D15D,fg=c040404,}, -cell{3}{5}={}{font=\fontsize{1.9em}{2.2em}\selectfont,bg=cFBE77D,fg=c040404,}, -cell{4}{5}={}{font=\fontsize{2em}{2.3em}\selectfont,bg=cFFFE9E,fg=c040404,}, +cell{1}{5}={}{halign=c, fg=c040404, bg=cF8BB41, font=\fontsize{1.7em}{2em}\selectfont,}, +cell{2}{5}={}{halign=c, fg=c040404, bg=cF9D15D, font=\fontsize{1.8em}{2.1em}\selectfont,}, +cell{3}{5}={}{halign=c, fg=c040404, bg=cFBE77D, font=\fontsize{1.9em}{2.2em}\selectfont,}, +cell{4}{5}={}{halign=c, fg=c040404, bg=cFFFE9E, font=\fontsize{2em}{2.3em}\selectfont,}, +cell{1}{1}={}{halign=c, fg=cFFFE9E, bg=c040404, font=\fontsize{0.1em}{0.4em}\selectfont,}, +cell{2}{1}={}{halign=c, fg=cFFFE9E, bg=c120E2A, font=\fontsize{0.2em}{0.5em}\selectfont,}, +cell{3}{1}={}{halign=c, fg=cFFFE9E, bg=c25123D, font=\fontsize{0.3em}{0.6em}\selectfont,}, +cell{4}{1}={}{halign=c, fg=cFFFE9E, bg=c3A134C, font=\fontsize{0.4em}{0.7em}\selectfont,}, +cell{1}{2}={}{halign=c, fg=cFFFE9E, bg=c50125A, font=\fontsize{0.5em}{0.8em}\selectfont,}, +cell{2}{2}={}{halign=c, fg=cFFFE9E, bg=c671065, font=\fontsize{0.6em}{0.9em}\selectfont,}, +cell{3}{2}={}{halign=c, fg=cFFFE9E, bg=c7D106E, font=\fontsize{0.7em}{1em}\selectfont,}, +cell{4}{2}={}{halign=c, fg=cFFFE9E, bg=c931473, font=\fontsize{0.8em}{1.1em}\selectfont,}, +cell{1}{3}={}{halign=c, fg=cFFFE9E, bg=cA81D75, font=\fontsize{0.9em}{1.2em}\selectfont,}, +cell{2}{3}={}{halign=c, fg=cFFFE9E, bg=cBC2A73, font=\fontsize{1em}{1.3em}\selectfont,}, +cell{3}{3}={}{halign=c, fg=cFFFE9E, bg=cCE3A6C, font=\fontsize{1.1em}{1.4em}\selectfont,}, +cell{4}{3}={}{halign=c, fg=cFFFE9E, bg=cDE4B5F, font=\fontsize{1.2em}{1.5em}\selectfont,}, +cell{1}{4}={}{halign=c, fg=cFFFE9E, bg=cED5E48, font=\fontsize{1.3em}{1.6em}\selectfont,}, +cell{2}{4}={}{halign=c, fg=cFFFE9E, bg=cF3762F, font=\fontsize{1.4em}{1.7em}\selectfont,}, +cell{3}{4}={}{halign=c, fg=cFFFE9E, bg=cF58E22, font=\fontsize{1.5em}{1.8em}\selectfont,}, +cell{4}{4}={}{halign=c, fg=cFFFE9E, bg=cF7A529, font=\fontsize{1.6em}{1.9em}\selectfont,}, } %% tabularray inner close \tinytableDefineColor{cFBE77D}{HTML}{FBE77D} \tinytableDefineColor{cF9D15D}{HTML}{F9D15D} diff --git a/inst/tinytest/_tinysnapshot/latex-maths.txt b/inst/tinytest/_tinysnapshot/latex-maths.txt index bcd157e5..bf24b334 100644 --- a/inst/tinytest/_tinysnapshot/latex-maths.txt +++ b/inst/tinytest/_tinysnapshot/latex-maths.txt @@ -4,7 +4,7 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]}, -column{1}={halign=c,}, +column{1}={}{halign=c,}, } %% tabularray inner close \toprule Math \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-merging_cells.txt b/inst/tinytest/_tinysnapshot/latex-merging_cells.txt index 05531b77..127d47d9 100644 --- a/inst/tinytest/_tinysnapshot/latex-merging_cells.txt +++ b/inst/tinytest/_tinysnapshot/latex-merging_cells.txt @@ -4,7 +4,7 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -cell{3}{2}={c=3,r=2,}{valign=m,halign=c,cmd=\bfseries,bg=black,fg=white,}, +cell{3}{2}={c=3, r=2,}{cmd=\bfseries, fg=white, bg=black, halign=c, valign=m,}, } %% tabularray inner close \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-row_color.txt b/inst/tinytest/_tinysnapshot/latex-row_color.txt index 7dff6b51..6bb1f873 100644 --- a/inst/tinytest/_tinysnapshot/latex-row_color.txt +++ b/inst/tinytest/_tinysnapshot/latex-row_color.txt @@ -4,10 +4,7 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -row{2}={,fg=orange,}, -row{3}={,fg=orange,}, -row{4}={,fg=orange,}, -row{5}={,fg=orange,}, +row{2,3,4,5}={}{fg=orange,}, } %% tabularray inner close \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-style.txt b/inst/tinytest/_tinysnapshot/latex-style.txt index bd7ec25b..54b8f390 100644 --- a/inst/tinytest/_tinysnapshot/latex-style.txt +++ b/inst/tinytest/_tinysnapshot/latex-style.txt @@ -4,12 +4,12 @@ ] %% tabularray outer close { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, -cell{3}{1}={}{,cmd=\textit,bg=green,fg=orange,}, -cell{4}{1}={}{,cmd=\textit,bg=green,fg=orange,}, -cell{3}{3}={}{,cmd=\textit,bg=green,fg=orange,}, -cell{4}{3}={}{,cmd=\textit,bg=green,fg=orange,}, -cell{3}{4}={}{,cmd=\textit,bg=green,fg=orange,}, -cell{4}{4}={}{,cmd=\textit,bg=green,fg=orange,}, +cell{3}{1}={}{cmd=\textit, fg=orange, bg=green,}, +cell{3}{3}={}{cmd=\textit, fg=orange, bg=green,}, +cell{3}{4}={}{cmd=\textit, fg=orange, bg=green,}, +cell{4}{1}={}{cmd=\textit, fg=orange, bg=green,}, +cell{4}{3}={}{cmd=\textit, fg=orange, bg=green,}, +cell{4}{4}={}{cmd=\textit, fg=orange, bg=green,}, } %% tabularray inner close \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader diff --git a/inst/tinytest/_tinysnapshot/latex-theme_grid.txt b/inst/tinytest/_tinysnapshot/latex-theme_grid.txt index eaad353f..81f546cc 100644 --- a/inst/tinytest/_tinysnapshot/latex-theme_grid.txt +++ b/inst/tinytest/_tinysnapshot/latex-theme_grid.txt @@ -5,6 +5,10 @@ { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, hlines, vlines, +hlines, vlines, +hlines, vlines, +hlines, vlines, +hlines, vlines, } %% tabularray inner close mpg & cyl & disp & hp & drat \\ 21.0 & 6 & 160 & 110 & 3.90 \\ diff --git a/inst/tinytest/_tinysnapshot/latex-theme_striped.txt b/inst/tinytest/_tinysnapshot/latex-theme_striped.txt index 758e2672..4e6dcac5 100644 --- a/inst/tinytest/_tinysnapshot/latex-theme_striped.txt +++ b/inst/tinytest/_tinysnapshot/latex-theme_striped.txt @@ -5,7 +5,13 @@ { %% tabularray inner open colspec={Q[]Q[]Q[]Q[]Q[]}, row{even}={bg=black!5!white}, +row{even}={bg=black!5!white}, +row{even}={bg=black!5!white}, +row{even}={bg=black!5!white}, +row{even}={bg=black!5!white}, +row{2,4}={}{bg=cededed,}, } %% tabularray inner close +\tinytableDefineColor{cededed}{HTML}{ededed} \toprule mpg & cyl & disp & hp & drat \\ \midrule %% TinyTableHeader 21.0 & 6 & 160 & 110 & 3.90 \\ diff --git a/inst/tinytest/_tinysnapshot/tibble-typst_pillar_num.txt b/inst/tinytest/_tinysnapshot/tibble-typst_pillar_num.txt index c6064d87..0e228e66 100644 --- a/inst/tinytest/_tinysnapshot/tibble-typst_pillar_num.txt +++ b/inst/tinytest/_tinysnapshot/tibble-typst_pillar_num.txt @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -40,23 +45,31 @@ block[ // start block columns: (auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 3, stroke: 0.05em + black), -table.hline(y: 4, start: 0, end: 3, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 3, stroke: 0.1em + black), + table.hline(y: 4, start: 0, end: 3, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 3, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 3, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-complicated.txt b/inst/tinytest/_tinysnapshot/typst-complicated.txt index b02ef92a..7fd688f4 100644 --- a/inst/tinytest/_tinysnapshot/typst-complicated.txt +++ b/inst/tinytest/_tinysnapshot/typst-complicated.txt @@ -12,29 +12,33 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (3,), x: (1, 2,), color: white, underline: none, italic: none, bold: true, mono: none, strikeout: true, fontsize: none, indent: none, background: black, align: center), - (y: (3,), x: (0,), color: red, underline: none, italic: true, bold: true, mono: none, strikeout: true, fontsize: none, indent: none, background: black, align: left), - (y: (0, 1, 2, 4, 5,), x: (0,), color: red, underline: none, italic: true, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: none, align: left), - (y: (0, 1, 2, 3, 4, 5,), x: (4,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: none, align: right), - (y: (0, 1, 2, 4, 5, 3,), x: (1, 2, 3,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: none, align: center), +(pairs: ((4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5),), align: right,), +(pairs: ((0, 0), (0, 1), (0, 2), (0, 4), (0, 5),), align: left, italic: true, color: red,), +(pairs: ((0, 3),), align: left, bold: true, strikeout: true, color: red, background: black, italic: true,), +(pairs: ((1, 3), (2, 3),), align: center, bold: true, strikeout: true, color: white, background: black,), +(pairs: ((1, 0), (1, 1), (1, 2), (1, 4), (1, 5), (2, 0), (2, 1), (2, 2), (2, 4), (2, 5), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5),), align: center,), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -45,23 +49,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 2, start: 0, end: 5, stroke: 0.05em + black), -table.hline(y: 6, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 6, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 2, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-font_size.txt b/inst/tinytest/_tinysnapshot/typst-font_size.txt index 463f0d92..70b1eb49 100644 --- a/inst/tinytest/_tinysnapshot/typst-font_size.txt +++ b/inst/tinytest/_tinysnapshot/typst-font_size.txt @@ -12,25 +12,30 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (0, 1, 2, 3, 4,), x: (0, 3,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: 1.5em, indent: none, background: none, align: none), +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4),), fontsize: 1.5em,), +(pairs: ((1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -41,23 +46,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 5, stroke: 0.05em + black), -table.hline(y: 5, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 5, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-formatting.txt b/inst/tinytest/_tinysnapshot/typst-formatting.txt index dbc4937e..b2dd00c0 100644 --- a/inst/tinytest/_tinysnapshot/typst-formatting.txt +++ b/inst/tinytest/_tinysnapshot/typst-formatting.txt @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -40,23 +45,31 @@ block[ // start block columns: (auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 4, stroke: 0.05em + black), -table.hline(y: 4, start: 0, end: 4, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 4, stroke: 0.1em + black), + table.hline(y: 4, start: 0, end: 4, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 4, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 4, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( @@ -65,9 +78,9 @@ table.hline(y: 0, start: 0, end: 4, stroke: 0.1em + black), ), // tinytable cell content after -[143002], [ 1.43], [1972-06-16], [True ], -[201399], [201.4 ], [1970-08-21], [True ], -[100188], [ 0.13], [1970-07-18], [False], +[143002], [1.43 ], [1972-06-16], [True ], +[201399], [201.4], [1970-08-21], [True ], +[100188], [0.13 ], [1970-07-18], [False], // tinytable footer after diff --git a/inst/tinytest/_tinysnapshot/typst-grid.txt b/inst/tinytest/_tinysnapshot/typst-grid.txt index 527c94ca..e0fe4e6c 100644 --- a/inst/tinytest/_tinysnapshot/typst-grid.txt +++ b/inst/tinytest/_tinysnapshot/typst-grid.txt @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -40,20 +45,29 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: (paint: black), align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-group_rows.txt b/inst/tinytest/_tinysnapshot/typst-group_rows.txt index b85a9e7d..fe03d2c9 100644 --- a/inst/tinytest/_tinysnapshot/typst-group_rows.txt +++ b/inst/tinytest/_tinysnapshot/typst-group_rows.txt @@ -12,25 +12,30 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (1, 2, 4, 6, 7, 8, 10, 11, 12, 13, 14, 15,), x: (0, 1, 2, 3, 4, 5, 6, 7,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: 1em, background: none, align: none), +(pairs: ((0, 1), (0, 2), (0, 4), (0, 6), (0, 7), (0, 8), (0, 10), (0, 11), (0, 12),), indent: 1em,), +(pairs: ((0, 0), (0, 3), (0, 5), (0, 9), (0, 13), (0, 14), (0, 15), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11), (1, 12), (1, 13), (1, 14), (1, 15), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (2, 11), (2, 12), (2, 13), (2, 14), (2, 15), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (4, 10), (4, 11), (4, 12), (4, 13), (4, 14), (4, 15), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (5, 10), (5, 11), (5, 12), (5, 13), (5, 14), (5, 15), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9), (6, 10), (6, 11), (6, 12), (6, 13), (6, 14), (6, 15), (7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (7, 5), (7, 6), (7, 7), (7, 8), (7, 9), (7, 10), (7, 11), (7, 12), (7, 13), (7, 14), (7, 15),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -41,23 +46,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 8, stroke: 0.05em + black), -table.hline(y: 13, start: 0, end: 8, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 8, stroke: 0.1em + black), + table.hline(y: 13, start: 0, end: 8, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 8, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 8, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-issue-139_misaligned_rule_with_group_tt.txt b/inst/tinytest/_tinysnapshot/typst-issue-139_misaligned_rule_with_group_tt.txt index 569e6566..9415a8ff 100644 --- a/inst/tinytest/_tinysnapshot/typst-issue-139_misaligned_rule_with_group_tt.txt +++ b/inst/tinytest/_tinysnapshot/typst-issue-139_misaligned_rule_with_group_tt.txt @@ -12,27 +12,32 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (3,), x: (0, 1, 2, 3, 4,), color: white, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: blue, align: center), - (y: (2, 4, 5, 6,), x: (0, 1, 2, 3, 4,), color: white, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: 1em, background: blue, align: center), - (y: (7, 9, 10, 11, 12, 13, 14, 15,), x: (0, 1, 2, 3, 4,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: 1em, background: none, align: none), +(pairs: ((0, 2), (0, 4), (0, 5), (0, 6),), indent: 1em, align: center, color: white, background: blue,), +(pairs: ((0, 7), (0, 9), (0, 10), (0, 11), (0, 12), (0, 13),), indent: 1em,), +(pairs: ((0, 3), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6),), align: center, color: white, background: blue,), +(pairs: ((0, 0), (0, 1), (0, 8), (0, 14), (0, 15), (1, 0), (1, 1), (1, 7), (1, 8), (1, 9), (1, 10), (1, 11), (1, 12), (1, 13), (1, 14), (1, 15), (2, 0), (2, 1), (2, 7), (2, 8), (2, 9), (2, 10), (2, 11), (2, 12), (2, 13), (2, 14), (2, 15), (3, 0), (3, 1), (3, 7), (3, 8), (3, 9), (3, 10), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15), (4, 0), (4, 1), (4, 7), (4, 8), (4, 9), (4, 10), (4, 11), (4, 12), (4, 13), (4, 14), (4, 15),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -43,23 +48,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 2, start: 0, end: 5, stroke: 0.05em + black), -table.hline(y: 14, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 14, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 2, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-issue323_group_tt_style_tt.txt b/inst/tinytest/_tinysnapshot/typst-issue323_group_tt_style_tt.txt index 5b4d1889..423e8181 100644 --- a/inst/tinytest/_tinysnapshot/typst-issue323_group_tt_style_tt.txt +++ b/inst/tinytest/_tinysnapshot/typst-issue323_group_tt_style_tt.txt @@ -12,27 +12,32 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (0,), x: (0, 1, 2, 3, 4, 5, 6, 7,), color: orange, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: none, align: none), - (y: (4, 6, 10,), x: (0, 1, 2, 3, 4, 5, 6, 7,), color: orange, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: black, align: center), - (y: (2, 3, 5, 7, 8, 9, 11, 12, 13, 14, 15, 16,), x: (0, 1, 2, 3, 4, 5, 6, 7,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: 1em, background: none, align: none), +(pairs: ((0, 2), (0, 3), (0, 5), (0, 7), (0, 8), (0, 9), (0, 11), (0, 12), (0, 13),), indent: 1em,), +(pairs: ((0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0),), color: orange,), +(pairs: ((0, 4), (0, 6), (0, 10), (1, 4), (1, 6), (1, 10), (2, 4), (2, 6), (2, 10), (3, 4), (3, 6), (3, 10), (4, 4), (4, 6), (4, 10), (5, 4), (5, 6), (5, 10), (6, 4), (6, 6), (6, 10), (7, 4), (7, 6), (7, 10),), align: center, color: orange, background: black,), +(pairs: ((0, 1), (0, 14), (0, 15), (0, 16), (1, 1), (1, 2), (1, 3), (1, 5), (1, 7), (1, 8), (1, 9), (1, 11), (1, 12), (1, 13), (1, 14), (1, 15), (1, 16), (2, 1), (2, 2), (2, 3), (2, 5), (2, 7), (2, 8), (2, 9), (2, 11), (2, 12), (2, 13), (2, 14), (2, 15), (2, 16), (3, 1), (3, 2), (3, 3), (3, 5), (3, 7), (3, 8), (3, 9), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15), (3, 16), (4, 1), (4, 2), (4, 3), (4, 5), (4, 7), (4, 8), (4, 9), (4, 11), (4, 12), (4, 13), (4, 14), (4, 15), (4, 16), (5, 1), (5, 2), (5, 3), (5, 5), (5, 7), (5, 8), (5, 9), (5, 11), (5, 12), (5, 13), (5, 14), (5, 15), (5, 16), (6, 1), (6, 2), (6, 3), (6, 5), (6, 7), (6, 8), (6, 9), (6, 11), (6, 12), (6, 13), (6, 14), (6, 15), (6, 16), (7, 1), (7, 2), (7, 3), (7, 5), (7, 7), (7, 8), (7, 9), (7, 11), (7, 12), (7, 13), (7, 14), (7, 15), (7, 16),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -43,23 +48,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 2, start: 0, end: 8, stroke: 0.05em + black), -table.hline(y: 14, start: 0, end: 8, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 8, stroke: 0.1em + black), + table.hline(y: 14, start: 0, end: 8, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 1, start: 0, end: 8, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 2, start: 0, end: 8, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-italic_markdown.txt b/inst/tinytest/_tinysnapshot/typst-italic_markdown.txt index bb9c8ec9..5b576a33 100644 --- a/inst/tinytest/_tinysnapshot/typst-italic_markdown.txt +++ b/inst/tinytest/_tinysnapshot/typst-italic_markdown.txt @@ -12,25 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (0, 1,), x: (0,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: none, align: center), +(pairs: ((0, 0), (0, 1),), align: center,), ) // tinytable align-default-array before #let align-default-array = ( left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -41,23 +45,31 @@ block[ // start block columns: (auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 1, stroke: 0.05em + black), -table.hline(y: 2, start: 0, end: 1, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 1, stroke: 0.1em + black), + table.hline(y: 2, start: 0, end: 1, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 1, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 1, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-missing_value_replacement.txt b/inst/tinytest/_tinysnapshot/typst-missing_value_replacement.txt index 03f8f2cc..4e98d53e 100644 --- a/inst/tinytest/_tinysnapshot/typst-missing_value_replacement.txt +++ b/inst/tinytest/_tinysnapshot/typst-missing_value_replacement.txt @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -40,23 +45,31 @@ block[ // start block columns: (auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 2, stroke: 0.05em + black), -table.hline(y: 4, start: 0, end: 2, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 2, stroke: 0.1em + black), + table.hline(y: 4, start: 0, end: 2, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 2, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 2, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-more_formatting.txt b/inst/tinytest/_tinysnapshot/typst-more_formatting.txt index 10b1387c..0c1b9dbb 100644 --- a/inst/tinytest/_tinysnapshot/typst-more_formatting.txt +++ b/inst/tinytest/_tinysnapshot/typst-more_formatting.txt @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -40,23 +45,31 @@ block[ // start block columns: (auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 3, stroke: 0.05em + black), -table.hline(y: 5, start: 0, end: 3, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 3, stroke: 0.1em + black), + table.hline(y: 5, start: 0, end: 3, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 3, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 3, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( @@ -65,10 +78,10 @@ table.hline(y: 0, start: 0, end: 3, stroke: 0.1em + black), ), // tinytable cell content after -[Food: Burger], [ 1.432], [99T], +[Food: Burger], [1.432], [99T], [Food: Halloumi], [201.399], [7.3B], -[Food: Tofu], [ 0.146], [29M], -[Food: Beans], [ 0.003], [94K], +[Food: Tofu], [0.146], [29M], +[Food: Beans], [0.003], [94K], // tinytable footer after diff --git a/inst/tinytest/_tinysnapshot/typst-no_headers.txt b/inst/tinytest/_tinysnapshot/typst-no_headers.txt index a527a69f..fbe89bc3 100644 --- a/inst/tinytest/_tinysnapshot/typst-no_headers.txt +++ b/inst/tinytest/_tinysnapshot/typst-no_headers.txt @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3), (4, 0), (4, 1), (4, 2), (4, 3),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -40,22 +45,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 5, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 5, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-significant_cell.txt b/inst/tinytest/_tinysnapshot/typst-significant_cell.txt index 6aceae93..32c27589 100644 --- a/inst/tinytest/_tinysnapshot/typst-significant_cell.txt +++ b/inst/tinytest/_tinysnapshot/typst-significant_cell.txt @@ -12,24 +12,29 @@ block[ // start block #let style-array = ( // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2),), ), ) // tinytable align-default-array before #let align-default-array = ( left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -40,23 +45,31 @@ block[ // start block columns: (auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 1, stroke: 0.05em + black), -table.hline(y: 3, start: 0, end: 1, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 1, stroke: 0.1em + black), + table.hline(y: 3, start: 0, end: 1, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 1, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 1, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-striped.txt b/inst/tinytest/_tinysnapshot/typst-striped.txt index 2098cc44..28233a5b 100644 --- a/inst/tinytest/_tinysnapshot/typst-striped.txt +++ b/inst/tinytest/_tinysnapshot/typst-striped.txt @@ -12,25 +12,30 @@ block[ // start block #let style-array = ( // tinytable cell style after - (y: (1, 3,), x: (0, 1, 2, 3, 4,), color: none, underline: none, italic: none, bold: none, mono: none, strikeout: none, fontsize: none, indent: none, background: rgb("#ededed"), align: none), +(pairs: ((0, 1), (0, 3), (1, 1), (1, 3), (2, 1), (2, 3), (3, 1), (3, 3), (4, 1), (4, 3),), background: rgb("#ededed"),), +(pairs: ((0, 0), (0, 2), (0, 4), (1, 0), (1, 2), (1, 4), (2, 0), (2, 2), (2, 4), (3, 0), (3, 2), (3, 4), (4, 0), (4, 2), (4, 4),), ), ) // tinytable align-default-array before #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here #show table.cell: it => { - let tmp = it - let data = style-array.find(data => data.x.contains(it.x) and data.y.contains(it.y)) - if data != none { - if data.fontsize != none { tmp = text(size: data.fontsize, tmp) } - if data.color != none { tmp = text(fill: data.color, tmp) } - if data.indent != none { tmp = pad(left: data.indent, tmp) } - if data.underline != none { tmp = underline(tmp) } - if data.italic != none { tmp = emph(tmp) } - if data.bold != none { tmp = strong(tmp) } - if data.mono != none { tmp = math.mono(tmp) } - if data.strikeout != none { tmp = strike(tmp) } - tmp + if style-array.len() == 0 { + it } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } tmp } } @@ -41,23 +46,31 @@ block[ // start block columns: (auto, auto, auto, auto, auto), stroke: none, align: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.align != none { - data.align + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left } else { left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } } }, fill: (x, y) => { - let data = style-array.find(data => data.x.contains(x) and data.y.contains(y)) - if data != none and data.background != none { - data.background + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } } }, - -table.hline(y: 1, start: 0, end: 5, stroke: 0.05em + black), -table.hline(y: 5, start: 0, end: 5, stroke: 0.1em + black), -table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + black), + table.hline(y: 5, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), // tinytable lines before table.header( diff --git a/inst/tinytest/_tinysnapshot/typst-tblr.txt b/inst/tinytest/_tinysnapshot/typst-tblr.txt new file mode 100644 index 00000000..3b753913 --- /dev/null +++ b/inst/tinytest/_tinysnapshot/typst-tblr.txt @@ -0,0 +1,98 @@ +#show figure: set block(breakable: true) +#figure( // start figure preamble + + kind: "tinytable", + supplement: "Table", // end figure preamble + +block[ // start block + +#let nhead = 1; +#let nrow = 5; +#let ncol = 5; + + #let style-array = ( + // tinytable cell style after +(pairs: ((0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5),), ), + ) + + // tinytable align-default-array before + #let align-default-array = ( left, left, left, left, left, ) // tinytable align-default-array here + #show table.cell: it => { + if style-array.len() == 0 { + it + } else { + let tmp = it + for style in style-array { + let m = style.pairs.find(k => k.at(0) == it.x and k.at(1) == it.y) + if m != none { + if ("fontsize" in style) { tmp = text(size: style.fontsize, tmp) } + if ("color" in style) { tmp = text(fill: style.color, tmp) } + if ("indent" in style) { tmp = pad(left: style.indent, tmp) } + if ("underline" in style) { tmp = underline(tmp) } + if ("italic" in style) { tmp = emph(tmp) } + if ("bold" in style) { tmp = strong(tmp) } + if ("mono" in style) { tmp = math.mono(tmp) } + if ("strikeout" in style) { tmp = strike(tmp) } + } + } + tmp + } + } + + #align(center, [ + + #table( // tinytable table start + columns: (auto, auto, auto, auto, auto), + stroke: none, + align: (x, y) => { + let align-array = ( + // tinytable cell align after + ) + if align-array.len() == 0 { + left + } else { + left + // for style in style-array { + // let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + // if m != none and ("align" in style) { + // let a = style.align + // } + // } + } + }, + fill: (x, y) => { + for style in style-array { + let m = style.pairs.find(k => k.at(0) == x and k.at(1) == y) + if m != none and ("background" in style) { + style.background + } + } + }, + table.hline(y: 2, start: 1, end: 3, stroke: 0.05em + red), table.hline(y: 3, start: 1, end: 3, stroke: 0.05em + red), + table.hline(y: 3, start: 1, end: 3, stroke: 0.05em + red), table.hline(y: 4, start: 1, end: 3, stroke: 0.05em + red), + table.hline(y: 6, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.hline(y: 0, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), table.hline(y: 1, start: 0, end: 5, stroke: 0.1em + rgb("#d3d8dc")), + table.vline(x: 1, start: 2, end: 4, stroke: 0.05em + red), table.vline(x: 2, start: 2, end: 4, stroke: 0.05em + red), + table.vline(x: 2, start: 2, end: 4, stroke: 0.05em + red), table.vline(x: 3, start: 2, end: 4, stroke: 0.05em + red), + // tinytable lines before + + table.header( + repeat: true, +[mpg], [cyl], [disp], [hp], [drat], + ), + + // tinytable cell content after +[21.0], [6], [160], [110], [3.90], +[21.0], [6], [160], [110], [3.90], +[22.8], [4], [108], [ 93], [3.85], +[21.4], [6], [258], [110], [3.08], +[18.7], [8], [360], [175], [3.15], + + // tinytable footer after + + ) // end table + + ]) // end align + +] // end block +) // end figure diff --git a/inst/tinytest/test-group_tt.R b/inst/tinytest/test-group_tt.R index 2c449464..a05dcbdc 100644 --- a/inst/tinytest/test-group_tt.R +++ b/inst/tinytest/test-group_tt.R @@ -18,7 +18,7 @@ tab <- tt(x) |> group_tt(j = list("a" = 2:3, "b" = 4:5)) |> group_tt(j = list("c" = 1:2, "d" = 3:5)) |> group_tt(j = list("e" = 1:3, "f" = 4)) -expect_snapshot_print(tab, label = "group_tt-3level_md") +expect_snapshot_print(tab, label = "group_tt-3level.md") options(tinytable_print_output = NULL) @@ -29,7 +29,7 @@ tab <- tt(x) |> group_tt(j = list("a" = 2:3, "b" = 4:5)) |> group_tt(j = list("c" = 1:2, "d" = 3:5)) |> group_tt(j = list("e" = 1:3, "f" = 4)) -expect_snapshot_print(tab, label = "group_tt-3level_tex") +expect_snapshot_print(tab, label = "group_tt-3level.tex") options(tinytable_print_output = NULL) diff --git a/inst/tinytest/test-typst.R b/inst/tinytest/test-typst.R index c34a34e8..25294338 100644 --- a/inst/tinytest/test-typst.R +++ b/inst/tinytest/test-typst.R @@ -116,6 +116,12 @@ tab@output <- "typst" expect_snapshot_print(tab, label = "typst-issue323_group_tt_style_tt") +# Frame +tab <- tt(mtcars[1:5, 1:5]) |> + style_tt(2:3, 2:3, line_color = "red", line = "tblr", line_width = .05) +tab@output <- "typst" +expect_snapshot_print(tab, label = "typst-tblr") + # Issue #357 tab <- tt(head(iris), notes = "blah") |> save_tt("typst") diff --git a/man/style_eval-tinytable_dataframe-method.Rd b/man/style_eval-tinytable_dataframe-method.Rd index 8a7830bb..792d1106 100644 --- a/man/style_eval-tinytable_dataframe-method.Rd +++ b/man/style_eval-tinytable_dataframe-method.Rd @@ -4,19 +4,7 @@ \alias{style_eval,tinytable_dataframe-method} \title{tinytable S4 method} \usage{ -\S4method{style_eval}{tinytable_dataframe}( - x, - i = NULL, - j = NULL, - bold = FALSE, - italic = FALSE, - monospace = FALSE, - underline = FALSE, - strikeout = FALSE, - rowspan = NULL, - colspan = NULL, - ... -) +\S4method{style_eval}{tinytable_dataframe}(x) } \description{ tinytable S4 method diff --git a/man/style_eval-tinytable_grid-method.Rd b/man/style_eval-tinytable_grid-method.Rd index 37e993ef..5b09f1d5 100644 --- a/man/style_eval-tinytable_grid-method.Rd +++ b/man/style_eval-tinytable_grid-method.Rd @@ -4,19 +4,7 @@ \alias{style_eval,tinytable_grid-method} \title{tinytable S4 method} \usage{ -\S4method{style_eval}{tinytable_grid}( - x, - i = NULL, - j = NULL, - bold = FALSE, - italic = FALSE, - monospace = FALSE, - underline = FALSE, - strikeout = FALSE, - rowspan = NULL, - colspan = NULL, - ... -) +\S4method{style_eval}{tinytable_grid}(x) } \description{ tinytable S4 method diff --git a/man/style_grid_internal.Rd b/man/style_grid_internal.Rd deleted file mode 100644 index c8b9366d..00000000 --- a/man/style_grid_internal.Rd +++ /dev/null @@ -1,24 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/style_grid.R -\name{style_grid_internal} -\alias{style_grid_internal} -\title{tinytable S4 method} -\usage{ -style_grid_internal( - x, - i = NULL, - j = NULL, - bold = FALSE, - italic = FALSE, - monospace = FALSE, - underline = FALSE, - strikeout = FALSE, - rowspan = NULL, - colspan = NULL, - ... -) -} -\description{ -tinytable S4 method -} -\keyword{internal} diff --git a/man/style_tt.Rd b/man/style_tt.Rd index 1ca6d356..14e18a31 100644 --- a/man/style_tt.Rd +++ b/man/style_tt.Rd @@ -20,7 +20,7 @@ style_tt( alignv = NULL, colspan = NULL, rowspan = NULL, - indent = 0, + indent = NULL, line = NULL, line_color = "black", line_width = 0.1, @@ -37,7 +37,7 @@ style_tt( \arguments{ \item{x}{A table object created by \code{tt()}.} -\item{i}{Row indices where the styling should be applied. Can be a single value, a vector, or a logical matrix with the same number of rows and columns as \code{x}. \code{i=0} is the header, and negative values are higher level headers.} +\item{i}{Row indices where the styling should be applied. Can be a single value, a vector, or a logical matrix with the same number of rows and columns as \code{x}. \code{i=0} is the header, and negative values are higher level headers. Row indices refer to rows \emph{after} the insertion of row labels by \code{group_tt()}, when applicable.} \item{j}{Column indices where the styling should be applied. Can be: \itemize{ diff --git a/man/theme_tt.Rd b/man/theme_tt.Rd index e70dcae9..9ac81d50 100644 --- a/man/theme_tt.Rd +++ b/man/theme_tt.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/theme_tt.R +% Please edit documentation in R/theme_zzz.R \name{theme_tt} \alias{theme_tt} \title{Themes for \code{tinytable}} diff --git a/man/tt.Rd b/man/tt.Rd index 033e70e6..24f9b57c 100644 --- a/man/tt.Rd +++ b/man/tt.Rd @@ -10,7 +10,7 @@ tt( caption = get_option("tinytable_tt_caption", default = NULL), notes = get_option("tinytable_tt_notes", default = NULL), width = get_option("tinytable_tt_width", default = NULL), - theme = get_option("tinytable_tt_theme", default = NULL), + theme = get_option("tinytable_tt_theme", default = "default"), rownames = get_option("tinytable_tt_rownames", default = FALSE), escape = get_option("tinytable_tt_escape", default = FALSE), ... @@ -52,7 +52,7 @@ tt( \value{ An object of class \code{tt} representing the table. -The table object has S4 slots which hold information about the structure of the table. This meta-data can be accessed with the usual \code{@} accessor. In general, modifying the content of these slots is not recommended, but it can be useful to some developers, such as those who want to force print to a specific output format without calling \code{print()}. +The table object has S4 slots which hold information about the structure of the table. Relying on or modifying the contents of these slots is strongly discouraged. Their names and contents could change at any time, and the \code{tinytable} developers do not consider changes to the internal structure of the output object to be a "breaking change" for versioning or changelog purposes. } \description{ The \code{tt} function renders a table in different formats with various styling options: HTML, Markdown, LaTeX, Word, PDF, PNG, or Typst. The table can be customized with additional functions: diff --git a/sandbox/typst.qmd b/sandbox/typst.qmd index 8d780f90..bd94b29d 100644 --- a/sandbox/typst.qmd +++ b/sandbox/typst.qmd @@ -8,6 +8,15 @@ keep-typ: true #| include: false pkgload::load_all() options(tinytable_quarto_figure = TRUE) +options(tinytable_print_output = "typst") +``` + +```{r} +dat <- data.frame( + a = c("a", "aa", "aaa"), + b = c("b", "bb", "bbb"), + c = c("c", "cc", "ccc")) +tt(dat) |> style_tt(j = 1:3, align = "lcr") ``` ```{r} @@ -29,6 +38,13 @@ tab <- tt(mtcars[1:10, 1:5]) |> tab ``` +```{r} +# Issue #139 +tab <- tt(mtcars[1:5, 1:5]) |> + style_tt(2:3, 2:3, line_color = "red", line = "tblr", line_width = .05) +tab +``` + ```{r} # Theme striped x <- mtcars[1:4, 1:5] diff --git a/vignettes/format.qmd b/vignettes/format.qmd index 8d2c5f9b..a8721edf 100644 --- a/vignettes/format.qmd +++ b/vignettes/format.qmd @@ -54,6 +54,7 @@ tt(dat) |> digits = 2, num_mark_big = " ", num_mark_dec = ",", + num_zero = TRUE, num_fmt = "decimal") ``` @@ -269,7 +270,7 @@ On top of the built-in features of `format_tt`, a custom formatting function can ```{r} tt(x) |> - format_tt(j = "mpg", fn = function(x) paste0(x, " mpg")) |> + format_tt(j = "mpg", fn = function(x) paste(x, "mi/gal")) |> format_tt(j = "drat", fn = \(x) signif(x, 2)) ``` diff --git a/vignettes/group.qmd b/vignettes/group.qmd index be55cfec..b52ba90e 100644 --- a/vignettes/group.qmd +++ b/vignettes/group.qmd @@ -75,11 +75,8 @@ We can use the `group_tt()` function to group rows and label them using spanners # subset and sort data df <- mtcars |> head(10) |> sort_by(~ am) -# identify row indices -indices <- tapply(1:nrow(df), df$am, \(x) x[1], simplify = FALSE) - # draw table -tt(df) |> group_tt(i = indices) +tt(df) |> group_tt(i = df$am) ``` diff --git a/vignettes/style.qmd b/vignettes/style.qmd index 85eda28b..470b23f1 100644 --- a/vignettes/style.qmd +++ b/vignettes/style.qmd @@ -341,7 +341,7 @@ And here is an example with horizontal rules: ```{r} tt(x, theme = "void") |> style_tt(i = 0, line = "t", line_color = "orange", line_width = 0.4) |> - style_tt(i = 0, line = "b", line_color = "purple", line_width = 0.2) |> + style_tt(i = 1, line = "t", line_color = "purple", line_width = 0.2) |> style_tt(i = 4, line = "b", line_color = "orange", line_width = 0.4) ``` diff --git a/vignettes/theme.qmd b/vignettes/theme.qmd index cce737b1..402ba799 100644 --- a/vignettes/theme.qmd +++ b/vignettes/theme.qmd @@ -57,8 +57,7 @@ Users can also define their own themes to apply consistent visual tweaks to tabl ```{r} theme_vincent <- function(x, ...) { out <- x |> - style_tt(color = "teal") |> - theme_tt("placement") + style_tt(color = "teal") out@caption <- "Always use the same caption." out@width <- .5 return(out) @@ -86,7 +85,6 @@ theme_slides <- function(x, ...) { return(table) } x <- style_tt(x, finalize = fn) - x <- theme_tt(x, theme = "default") return(x) } @@ -182,12 +180,14 @@ Warning: The substitution code is very simple and it may not work properly when theme_mitex <- function(x, ...) { fn <- function(table) { if (isTRUE(table@output == "typst")) { - table@table_string <- gsub("\\$(.*?)\\$", "#mitex(`\\1`)", table@table_string) + table@table_string <- gsub( + "\\$(.*?)\\$", + "#mitex(`\\1`)", + table@table_string) } return(table) } x <- style_tt(x, finalize = fn) - x <- theme_tt(x, theme = "default") return(x) } ```