rmarkdown icon indicating copy to clipboard operation
rmarkdown copied to clipboard

[Feature request]: Font color and text highlighting via Pandoc attributes & lua filter

Open ulyngs opened this issue 5 years ago • 6 comments

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.

ulyngs avatar Jan 11 '21 12:01 ulyngs

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 avatar Jan 11 '21 12:01 cderv

@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-Angel avatar Sep 03 '24 07:09 Hi-Angel

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

cderv avatar Sep 03 '24 07:09 cderv

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.

Hi-Angel avatar Sep 03 '24 08:09 Hi-Angel

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

Hi-Angel avatar Sep 03 '24 08:09 Hi-Angel

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.

cderv avatar Sep 03 '24 14:09 cderv