Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve html preview #470

Merged
merged 10 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test-coverage.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: r-lib/actions/setup-pandoc@v2

- uses: r-lib/actions/setup-r@v2
with:
use-public-rspm: true
Expand Down
25 changes: 10 additions & 15 deletions R/reprex_render.R
Original file line number Diff line number Diff line change
Expand Up @@ -182,26 +182,21 @@ reprex_render_impl <- function(input,
invisible(reprex_file)
}

# heavily influenced by the post_processor() function of github_document()
# influenced by the post_processor() function of github_document()
# but with substantial reprex-specific updates in 2024-09
preview <- function(input) {
css <- rmarkdown::pandoc_path_arg(
mode <- if (is_dark_mode()) "dark" else "light"
res_dir <- rmarkdown::pandoc_path_arg(
path_package(
"rmarkdown",
"rmarkdown/templates/github_document/resources/github.css"
)
)
css <- glue("github-markdown-css:{css}")
template <- rmarkdown::pandoc_path_arg(
path_package(
"rmarkdown",
"rmarkdown/templates/github_document/resources/preview.html"
"reprex",
glue("rmarkdown/templates/reprex_document/resources")
)
)
args <- c(
"--standalone", "--self-contained",
"--highlight-style", "pygments",
"--template", template,
"--variable", css,
"--standalone", "--embed-resources",
Copy link
Member Author

Choose a reason for hiding this comment

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

Apparently this is just how modern Pandoc calls should look.

"--highlight-style", path(res_dir, glue("starry-nights-{mode}.theme")),
Copy link
Member Author

Choose a reason for hiding this comment

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

Previously, the --highlight-style call wasn't actually doing anything! But now this one does, because we've also eliminated the use of an html template.

"--css", path(res_dir, glue("github-{mode}.css")),
"--syntax-definition", path(res_dir, "r.xml"),
Comment on lines +198 to +199
Copy link
Member Author

Choose a reason for hiding this comment

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

No more template. I'm providing the github css in a way that works with the default html template. Plus a new custom syntax definition.

"--metadata", "pagetitle=PREVIEW",
"--quiet"
)
Expand Down
9 changes: 9 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,12 @@
is_testing <- function() {
identical(Sys.getenv("TESTTHAT"), "true")
}

is_dark_mode <- function() {
if (rstudioapi::isAvailable() && rstudioapi::hasFun("getThemeInfo")) {
theme_info <- rstudioapi::getThemeInfo()
theme_info$dark

Check warning on line 70 in R/utils.R

View check run for this annotation

Codecov / codecov/patch

R/utils.R#L69-L70

Added lines #L69 - L70 were not covered by tests
} else {
FALSE
Copy link
Member Author

Choose a reason for hiding this comment

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

Positron ends up here unconditionally today (FALSE), but in the fullness of time, it will provide theme info.

}
}
20 changes: 20 additions & 0 deletions data-raw/github_css.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# use the CSS found here:
# https://github.com/sindresorhus/github-markdown-css
# which aims to be:
# "The minimal amount of CSS to replicate the GitHub Markdown style"

library(usethis)

use_directory("inst/rmarkdown/templates/reprex_document/resources")

use_github_file(
repo_spec = "sindresorhus/github-markdown-css",
path = "github-markdown-dark.css",
save_as = "inst/rmarkdown/templates/reprex_document/resources/github-dark.css"
)

use_github_file(
repo_spec = "sindresorhus/github-markdown-css",
path = "github-markdown-light.css",
save_as = "inst/rmarkdown/templates/reprex_document/resources/github-light.css"
)
195 changes: 195 additions & 0 deletions data-raw/pandoc-syntax-highlighting.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
# write Pandoc's default (pygments) highlight style to a JSON file
# pandoc --print-highlight-style pygments > data-raw/pygments.theme
# use this as a scaffold, but modify colors to match the Starry Night theme
# that GitHub uses

library(tidyverse)

pyg <- jsonlite::fromJSON("data-raw/pygments.theme")
pyg |> pluck("text-styles") |> names()

# How does Pandoc do syntax highlighting?
# https://pandoc.org/chunkedhtml-demo/13-syntax-highlighting.html
# "The Haskell library skylighting is used for highlighting."

# Pandoc/skylighting store themes using the
# Syntax-Highlighting framework from KDE Frameworks

# Learn the meaning of the styles (classes) supported by Pandoc here:
# https://docs.kde.org/stable5/en/kate/katepart/highlight.html
# see "Available Default Styles"
# https://docs.kde.org/stable5/en/kate/katepart/color-themes.html
# see "Default Text Styles"

# this is me taking the styles Pandoc/skylighting expects,
# noting what they are meant for conceptually,
# and picking the starry-night color alias/variable that seems the best fit

x <- str_glue('
Alert,"Text style for special words in comments, such as TODO, FIXME, XXXX and WARNING.",\\
comment,
Annotation,"Text style for annotations in comments or documentation commands, such as @param in Doxygen or JavaDoc.",\\
comment,
Attribute,"Text style for annotations or attributes of functions or objects, e.g. @override in Java, or __declspec(...) and __attribute__((...)) in C++.",\\
entity-tag,
BaseN,"(Base-N Integer): Text style for numbers with base other than 10.",\\
constant,
BuiltIn,"(Built-in): Text style for built-in language classes, functions and objects.",\\
entity,
Char,"(Character): Text style for single characters such as \'x\'.",\\
string,
Comment, "Text style for normal comments.",\\
comment,
CommentVar,"(Comment Variable): Text style that refers to variables names used in above commands in a comment, such as foobar in \'@param foobar\', in Doxygen or JavaDoc.",\\
comment,
Constant,"Text style for language constants and user defined constants, e.g. True, False, None in Python or nullptr in C/C++; or math constants like PI.",\\
constant,
ControlFlow,"(Control Flow): Text style for control flow keywords, such as if, then, else, return, switch, break, yield, continue, etc.",\\
keyword,
DataType,"(Data Type): Text style for built-in data types such as int, char, float, void, u64, etc.",\\
constant,
DecVal,"(Decimal/Value): Text style for decimal values.",\\
constant,
Documentation,"Text style for comments that reflect API documentation, such as /** doxygen comments */ or \"\"\"docstrings\"\"\".",\\
comment,
Error,"Text style indicating error highlighting and wrong syntax.",\\
invalid-illegal-text,invalid-illegal-bg
Extension,"Text style for well-known extensions, such as Qt™ classes, functions/macros in C++ and Python or boost.",\\
entity,
Float,"(Floating Point): Text style for floating point numbers.",\\
constant,
Function,"Text style for function definitions and function calls.",\\
entity,
Import,"(Imports, Modules, Includes): Text style for includes, imports, modules or LATEX packages.",\\
storage-modifier-import,
Information,"Text style for information, notes and tips, such as the keyword @note in Doxygen.",\\
comment,
Keyword,"Text style for built-in language keywords.",\\
keyword,
Operator,"Text style for operators, such as +, -, *, /, %, etc.",\\
keyword,
Others,"Text style for attributes that do not match any of the other default styles.",\\
,
Preprocessor,"Text style for preprocessor statements or macro definitions.",\\
keyword,
SpecialChar,"(Special Character): Text style for escaped characters in strings, e.g. \"hello\\n\", and other characters with special meaning in strings, such as substitutions or regex operators.",\\
carriage-return-text,carriage-return-bg
SpecialString,"(Special String): Text style for special strings, such as regular expressions in ECMAScript, the LATEX math mode, SQL, etc.",\\
string-regexp,
String,"Text style for strings like \"hello world\".",\\
string,
Variable,"Text style for variables, if applicable. For instance, variables in PHP/Perl typically start with a $, so all identifiers following the pattern $foo are highlighted as variable.",\\
variable,
VerbatimString,"(Verbatim String): Text style for verbatim or raw strings like \'raw \backlash\' in Perl, CoffeeScript, and shells, as well as r\'\raw\' in Python, or such as HERE docs.",\\
string,
Warning,"Text style for warnings, such as the keyword @warning in Doxygen.",\\
comment,
')

dat <- read_csv(x, col_names = c("pyg_class", "pyg_note", "pl_text_style", "pl_background_style"))
dat

# get the starry-night css in order to excavate the colors
use_github_file(
repo_spec = "wooorm/starry-night",
path = "style/dark.css",
save_as = "data-raw/starry-night-dark.css"
)

use_github_file(
repo_spec = "wooorm/starry-night",
path = "style/light.css",
save_as = "data-raw/starry-night-light.css"
)

raw_css_lines <- readLines("data-raw/starry-night-light.css")
sn_light <- raw_css_lines |>
str_subset(" --color-prettylights-syntax-") |>
tibble() |>
set_names("raw") |>
mutate(comment = str_extract(raw, ".+:")) |>
mutate(color = str_extract(raw, "#[0-9a-fA-F]{6}")) |>
mutate(comment = str_remove(comment, " --color-prettylights-syntax-")) |>
mutate(comment = str_remove(comment, ":$")) |>
select(comment, color)

raw_css_lines <- readLines("data-raw/starry-night-dark.css")
sn_dark <- raw_css_lines |>
str_subset(" --color-prettylights-syntax-") |>
tibble() |>
set_names("raw") |>
mutate(comment = str_extract(raw, ".+:")) |>
mutate(color = str_extract(raw, "#[0-9a-fA-F]{6}")) |>
mutate(comment = str_remove(comment, " --color-prettylights-syntax-")) |>
mutate(comment = str_remove(comment, ":$")) |>
select(comment, color)

dat
sn_light
sn_dark

dat_light <- dat |>
rename(cls = pyg_class) |>
select(-pyg_note) |>
left_join(
sn_light,
by = join_by(pl_text_style == comment)
) |>
rename(txt_col = color) |>
left_join(
sn_light,
by = join_by(pl_background_style == comment)
) |>
rename(bg_col = color) |>
select(-starts_with("pl_"))
dat_light

dat_dark <- dat |>
rename(cls = pyg_class) |>
select(-pyg_note) |>
left_join(
sn_dark,
by = join_by(pl_text_style == comment)
) |>
rename(txt_col = color) |>
left_join(
sn_dark,
by = join_by(pl_background_style == comment)
) |>
rename(bg_col = color) |>
select(-starts_with("pl_"))
dat_dark

g <- function(cls, txt_col, bg_col) {
list(
`text-color` = txt_col,
`background-color` = bg_col,
bold = FALSE,
italic = FALSE,
underline = FALSE
)
}

theme_light <- theme_dark <- pyg
theme_light[["text-styles"]] <- dat_light |>
pmap(g) |>
set_names(dat_light$cls)
theme_dark[["text-styles"]] <- dat_dark |>
pmap(g) |>
set_names(dat_dark$cls)

jsonlite::write_json(
theme_light,
"inst/rmarkdown/templates/reprex_document/resources/starry-nights-light.theme",
null = "null",
auto_unbox = TRUE,
pretty = TRUE
)

jsonlite::write_json(
theme_dark,
"inst/rmarkdown/templates/reprex_document/resources/starry-nights-dark.theme",
null = "null",
auto_unbox = TRUE,
pretty = TRUE
)
Loading
Loading