Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/clauswilke/sinab
Sinab is not a browser.
https://github.com/clauswilke/sinab
Last synced: 2 months ago
JSON representation
Sinab is not a browser.
- Host: GitHub
- URL: https://github.com/clauswilke/sinab
- Owner: clauswilke
- License: other
- Created: 2020-06-07T18:08:37.000Z (over 4 years ago)
- Default Branch: master
- Last Pushed: 2020-12-02T01:48:04.000Z (about 4 years ago)
- Last Synced: 2024-10-14T17:29:10.154Z (3 months ago)
- Language: Rust
- Homepage: https://clauswilke.com/sinab
- Size: 1.15 MB
- Stars: 27
- Watchers: 3
- Forks: 2
- Open Issues: 10
-
Metadata Files:
- Readme: README.Rmd
- License: LICENSE
Awesome Lists containing this project
README
---
output: github_document
---```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%",
dpi = 192
)
```# Sinab is not a browser
[![R build status](https://github.com/clauswilke/sinab/workflows/R-CMD-check/badge.svg)](https://github.com/clauswilke/sinab/actions)
[![AppVeyor build status](https://ci.appveyor.com/api/projects/status/github/clauswilke/sinab?branch=master&svg=true)](https://ci.appveyor.com/project/clauswilke/sinab)
[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental)A basic html rendering engine for R, written in Rust. The purpose is not to write a browser, but rather to provide the ability to render simple, static html documents to an R graphics device.
## Installation
This package needs to be compiled from source and requires a working Rust toolchain (i.e., [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html)). If you have Cargo up and running, the following should work to install this package:
```{r eval = FALSE}
remotes::install_github("clauswilke/sinab")
```To get Rust up and running on your system, follow the instructions [provided here.](https://www.rust-lang.org/learn/get-started)
In brief, on macOS or Linux, you simply run the following command in a shell:
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
(You can also install `rustc` and `cargo` through your package manager of choice, though `rustup` is preferred if you want to do any Rust development work yourself.)On Windows, things are a little more complicated:
- Download `rustup-init.exe` from here: https://win.rustup.rs/
- Then run the following three commands in the Windows
command prompt (not powershell):
```
rustup-init.exe -y --default-host x86_64-pc-windows-gnu --default-toolchain stable
set PATH=%PATH%;\%USERPROFILE%\.cargo\bin
rustup target add i686-pc-windows-gnu
```
(If the last line gives you trouble, try restarting your
command prompt window.)If you are using Rust regularly on Windows but normally build for the Visual Studio target (`x86_64-pc-windows-msvc`), then you may have to run the following two commands to successfully build this R package on your machine:
```
rustup target add x86_64-pc-windows-gnu
rustup target add i686-pc-windows-gnu
```## Examples
**Note:** This project is in the early proof-of-concept stage. Expect most things to be broken.
The main function provided by this package is `html_grob()`, which takes as input some Markdown or HTML text and associated CSS and renders it using the grid graphics system. The convenience function `draw_html()` uses `html_grob()` to generate the grob and then draws it with `grid::grid.draw()`.
```{r}
library(sinab)
library(grid)mdtext <- "
Here are a few examples of word-wrapped and non-word-wrapped text. First
regular text pre-formatted:
The quick brown
fox jumps over
the lazy dog.
Now some inline code: `x <- 10; y <- 200; z <- 2*x + y;`
It gets wrapped.We can also write block code. Notice how the long comment runs beyond
the box limits:x <- 10
y <- 200
z <- 2*x + y; # and a really really long comment
"css <- '
pre { background-color: #eee;
padding: 6px;
border-left: 5px solid #888; }
p { background-color: #def;
margin: 16px 0px 4px 0px;
padding: 4px; }
code { border: 1px solid #aaa;
padding: 2px; }
pre code { border: none;
padding: 0px; }
'# can also use `html_grob()` to obtain a grid grob for later drawing
draw_html(
mdtext, css = css,
x = unit(0.1, "npc"), y = unit(1, "npc"), width = unit(4, "inches"),
)
```If the grob width is specified as a relative unit, then the grob is reactive and reflows as the graphics window is resized. (Try this example interactively.)
```{r}
draw_html(
mdtext, css = css,
x = unit(0.1, "npc"), y = unit(1, "npc"), width = unit(0.8, "npc"),
)
```Simple markdown-to-html conversion is also implemented:
```{r}
md_to_html("This is *a* **test**.")
```## FAQ
* **Why is HTML/CSS feature X, Y, or Z not available?**
Rendering is done with a purpose-built layouting pipeline, and to date only a small subset of all possible features has been implemented.* **Will you support Javascript?**
Probably not. The goal for Sinab is to render static pages. Interactivity doesn't work well with R graphics devices.* **Is MathML supported?**
Not at this time.* **Why is rendering so slow?**
The Sinab library itself is actually quite fast. Slowness comes mostly from R graphics devices. In particular, text shaping can be extremely slow. For faster rendering, try one of the graphics devices provided by the ragg library, such as `agg_png()`. The following benchmark highlights the importance of the graphics device. The agg device is approximately 300 times faster than the quartz device! All this extra time is spent text shaping.text <- paste(rep("Hello", 50), collapse = " ")
n <- 100Lfile <- tempfile(fileext = ".png")
png(file, width = 1920, height = 1920, res = 288, type = "quartz")
microbenchmark::microbenchmark(render_markdown(text), times = n)
#> Unit: milliseconds
#> expr min lq mean median uq max
#> render_markdown(text) 685.3594 704.2026 722.0359 711.3405 720.7934 894.4264
#> neval
#> 100
invisible(dev.off())ragg::agg_png(file, width = 1920, height = 1920, res = 288)
microbenchmark::microbenchmark(render_markdown(text), times = n)
#> Unit: milliseconds
#> expr min lq mean median uq max
#> render_markdown(text) 2.097382 2.145262 2.400133 2.207823 2.349058 13.56952
#> neval
#> 100
invisible(dev.off())* **Why aren't you supporting links (i.e., the `` tag)?**
This is a limitation of the current R graphics device API. There is simply no way to create a link in an R graphics device. Once this feature gets added, it will be easy to support it in Sinab.* **Why do my colors look wrong?**
Sinab uses the color names defined by CSS, which in some cases are different from the color names that R uses. The most obvious example is probably "green", which corresponds to #00ff00 in R but #008000 in CSS. If you want to be certain that you get the colors you want, specify them with hex codes in RGB format.## Acknowledgments
The actual HTML/CSS parsing and rendering code is written in Rust, and it draws heavily from software developed for the Servo project. HTML parsing is done with [html5ever](https://github.com/servo/html5ever), CSS parsing is done with [cssparser](https://github.com/servo/rust-cssparser), and CSS selectors are implemented using the [selectors](https://github.com/servo/servo/tree/master/components/selectors) crate. DOM, layout, and rendering is using custom code that is in no small part based on the experimental [Victor](https://github.com/SimonSapin/victor) project written by Simon Sapin.
Markdown to HTML conversion is performed through the [pulldown-cmark](https://github.com/raphlinus/pulldown-cmark) crate, which implements a lightweight Markdown parser that complies with the [CommonMark spec.](https://spec.commonmark.org/)