This repository has been archived by the owner on Apr 9, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 44
/
redoc.R
149 lines (132 loc) · 5.3 KB
/
redoc.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#' R Markdown format for Reversible Reproducible Word Documents
#'
#' Format for converting from R Markdown to a Microsoft Word Document that can
#' be reversed using [dedoc()] after editing in Word.
#'
#' @param highlight_outputs whether to highlight outputs from chunks and inline
#' code in the final document
#' @param wrap when round-tripping the document, at what width to wrap the
#' markdown output? Set the default with `"redoc.wrap"` in `options()`. See [dedoc()].
#' @param margins page margin size. Can be a single value or a named vector
#' with values, `top`, `bottom`, `left`, `right`, `gutter`, `header`, and
#' `footer`. If NULL defaults to the reference document.
#' @param line_numbers either TRUE or list with any of the arguments `start`,
#' `by`, `restart`, and `distance`
#' @param comment_author The name to attribute any CriticMarkup tracked
#' changes to. Defaults to [whoami::fullname()].
#' @param keep_md whether to keep the intermediate markdown document
#' @param wrappers a list of wrapper functions to capture text to protect when
#' rendering and de-rendering. See [make_wrapper()].
#' @param diagnostics Whether to embed diagnostic information in the output
#' file. If TRUE, this will save session information and the current
#' pandoc and (if used) RStudio versions inside the Word document for later
#' bug-checking.
#' @param ... other parameters passed to [rmarkdown::word_document()]
#' @importFrom rmarkdown output_format word_document
#' @importFrom officer read_docx
#' @importFrom tools file_path_sans_ext
#' @importFrom rmarkdown word_document
#' @importFrom knitr knit_print knit_global opts_chunk opts_knit
#' @export
redoc <- function(highlight_outputs = FALSE, wrap = getOption("redoc.wrap", 80),
margins = NULL, line_numbers = NULL,
comment_author = NULL, keep_md = FALSE,
wrappers = list(
htmlcommentwrap, latexwrap,
rawblockwrap, rawspanwrap,
cmwrap, citationwrap
),
diagnostics = TRUE,
...) {
# Make a function to pre-process the Rmd file
pre_knit <- make_preknitter(wrappers = wrappers)
md_extensions <- c("+smart", "+fenced_divs", "+bracketed_spans")
pandoc <- rmarkdown::pandoc_options(
to = "docx+empty_paragraphs",
from = rmarkdown::from_rmarkdown(extensions = md_extensions),
args = c(
"--lua-filter",
system.file("lua-filters", "protect-empty.lua",
package = "redoc"
),
"--eol=lf"
)
)
post_processor <-
function(metadata, input_file, output_file, clean, verbose) {
docx <- officer::read_docx(output_file)
render_env <- get_parent_env_with(c(
"intermediates", "intermediates_loc",
"knit_input", "original_input"
))
original_rmd_input <- get("original_input", envir = render_env)
renv_intermediates <- get("intermediates", envir = render_env)
renv_intermediates_loc <- get("intermediates_loc", envir = render_env)
renv_intermediates_dir <- get("intermediates_dir", envir = render_env)
codefile <- renv_intermediates_loc(
file_with_meta_ext(basename(original_rmd_input), "codelist", "yml")
)
codelist <- read_yaml(codefile)
embed_files(docx, c(original_rmd_input, renv_intermediates),
internal_dir = "redoc"
)
roundtrip_rmd <- dedoc(
output_file,
to = file_with_meta_ext(
basename(original_rmd_input), "roundtrip", "Rmd"
),
dir = renv_intermediates_dir,
wrap = wrap,
overwrite = TRUE,
orig_codefile = codefile
)
add_intermediates(roundtrip_rmd)
embed_files(docx, roundtrip_rmd, internal_dir = "redoc")
if (diagnostics) {
diag_file <- renv_intermediates_loc(
file_with_meta_ext(basename(original_rmd_input), "diagnostics", "yml")
)
write_yaml(get_diagnostics(), diag_file, column.major = FALSE)
add_intermediates(diag_file)
embed_files(docx, diag_file, internal_dir = "redoc")
}
docx <- hide_output_styles(docx)
if (highlight_outputs) docx <- highlight_output_styles(docx)
# Stuff to go to worded/officedown
if (!is.null(margins)) docx <- set_body_margins(docx, margins)
if (isTRUE(line_numbers)) {
set_body_linenumbers(docx)
} else if (is.list(line_numbers)) {
do.call(set_body_linenumbers, c(list(x = docx), line_numbers))
}
print(docx, output_file)
return(output_file)
}
output_format <- rmarkdown::output_format(
pandoc = pandoc,
knitr = rmarkdown::knitr_options(),
keep_md = keep_md,
pre_knit = pre_knit,
post_processor = post_processor,
base_format = word_document(...)
)
output_format
}
get_diagnostics <- function() {
pandoc_version <- as.character(rmarkdown::pandoc_version())
session_info <- sessioninfo::session_info()
if (requireNamespace("rstudioapi") &&
rstudioapi::isAvailable()) {
rstudio_info <- rstudioapi::versionInfo()[c("version", "mode")]
} else {
rstudio_info <- NULL
}
list(
redoc_version = as.list(
session_info$packages[session_info$packages$package == "redoc", ]
),
pandoc_version = pandoc_version,
rstudio_info = rstudio_info,
session_info = session_info
)
}