[Feature request]: Font color and text highlighting via Pandoc attributes & lua filter
As per discussion with @cderv, we suggest including a lua filter that allows users to change font color and/or text highlighting via simple pandoc attributes.
This originated from this SO question.
A live example from the oxforddown, where this is implemented for HTML and PDF output is here
In oxforddown this is implemented via this lua filter.
Here is an adaptation of this lua filter for rmarkdown:
---
title: "Color and highlight text with a Lua filter"
output:
pdf_document:
pandoc_args: ["--lua-filter=color-text.lua"]
extra_dependencies: "soul"
html_document:
pandoc_args: ["--lua-filter=color-text.lua"]
---
First, we define a Lua filter and write it to
the file `color-text.lua`.
```{cat, engine.opts = list(file = "color-text.lua")}
Span = function (el)
-- store the attributes for color and highlight
color = el.attributes['color']
highlight = el.attributes['highlight']
-- create a function to check for emptiness
local function isempty(s)
return s == nil or s == ''
end
if FORMAT:match 'latex' then
-- use \hl to highlight stuff with {highlight = "some-color"}.
-- for LaTeX reasons, highlighting should come before font coloring
if not isempty(highlight) then
-- remove highlight attributes
el.attributes['highlight'] = nil
-- encapsulate in latex code
table.insert(
el.content, 1,
pandoc.RawInline('latex', '\\sethlcolor{'..highlight..'}\\hl{')
)
table.insert(
el.content,
pandoc.RawInline('latex', '}')
)
end
-- use \textcolor to color text with {color = "some-color"}
if not isempty(color) then
-- remove color attributes
el.attributes['color'] = nil
-- encapsulate in latex code
table.insert(
el.content, 1,
pandoc.RawInline('latex', '\\textcolor{'..color..'}{')
)
table.insert(
el.content,
pandoc.RawInline('latex', '}')
)
end
return el.content
end
if FORMAT:match 'html' then
style_attributes = ''
if not isempty(highlight) then
-- remove highlight attributes
el.attributes['highlight'] = nil
-- use style attribute instead
style_attributes = 'background-color: ' .. highlight .. ';'
end
if not isempty(color) then
-- remove color attributes
el.attributes['color'] = nil
-- use style attribute instead
style_attributes = style_attributes .. ' color: ' .. color .. ';'
end
if not isempty(style_attributes) then
el.attributes['style'] = style_attributes
end
-- return entire span content
return el
end
end
```
Now we test it:
- Here’s [some text in pink highlighting]{highlight="pink"}
- Here's [some text with blue font]{color="blue"}
- Finally — never actually do this – here's [some text with black highlighting and yellow font]{highlight="black" color="yellow"}
By filing an issue to this repo, I promise that
- [ x] I have fully read the issue guide at https://yihui.org/issue/.
- [x ] I have provided the necessary information about my issue.
- If I'm asking a question, I have already asked it on Stack Overflow or RStudio Community, waited for at least 24 hours, and included a link to my question there.
- If I'm filing a bug report, I have included a minimal, self-contained, and reproducible example, and have also included
xfun::session_info('rmarkdown'). I have upgraded all my packages to their latest versions (e.g., R, RStudio, and R packages), and also tried the development version:remotes::install_github('rstudio/rmarkdown'). - If I have posted the same issue elsewhere, I have also mentioned it in this issue.
- [ x] I have learned the Github Markdown syntax, and formatted my issue correctly.
I understand that my issue may be closed if I don't fulfill my promises.
Thanks for opening the FR!
For reference we also mention such Lua filter in the R Markdown Cookbook: https://bookdown.org/yihui/rmarkdown-cookbook/font-color.html
I'll add this one in the list of issue for better support of various features via Lua filter.
@cderv I am reading the page you referred to and I don't get it: is there anything required for elem.attributes to be defined? Given a markdown document and a Lua filter as simple as that:
function Para(elem)
print(elem.attributes);
end
I get nil for every paragraph. I read the page a few times but I can't see anything to be required for attributes to exist, right?
FWIW, I'm another user who stumbled upon Pandoc not understanding CSS, so am trying to use the built-in attributes to work around that.
Hi @Hi-Angel
I am not sure what you are trying, but Para element in Pandoc does not have attributes
See the Lua doc for Pandoc: https://pandoc.org/lua-filters.html#type-para
Aah, I see. That's interesting, looking at --to=native of a Markdown document, there's nothing useful that could possibly have attributes. There's a Para and Str, but Str doesn't have it too.
So, to future readers: I was confused because this issue starts with the following:
As per discussion with @cderv, we suggest including a lua filter that allows users to change font color and/or text highlighting via simple pandoc attributes.
I have done some research and experimentation and AFAIK it is not generally possible to apply colors to arbitrary elements. Apparently there are some elements that support it (which resulted in my confusion above), but for example Para being one of the most frequent ones doesn't.
So I created a separate RFE on that
Span and Div are the most common structure you can use to add attributes
Currently you can play with those to add styling for exemple.
- using a Span in a Para for example, to target specific part of the Para
- wrapping your Para in a Div, to target the whole Para
For HTML, with help of CSS, it works well. For other tool, it needs some work. Example of Quarto extension using Span to help highlight text in different format: https://github.com/mcanouil/quarto-highlight-text. You can look at the Lua filter there, which could be adapted for R Markdown.