简体   繁体   中英

How to apply two separate lua filters to Span elements, in R Markdown?

Using lua filters, I'm trying to allow people to do the following to PDF output from R Markdown:

  1. Apply a pre-defined highlighting color to text [like this]{.correction}
  2. Apply a user-defined highlighting color to text [like this]{highlight = "red"}
  3. Apply a custom font color [like this]{color = "blue"}

I can make all three possible with the lua filter shown by the end. However , I want to allow the user to turn off (1).

So I need (1) and (2)+(3) to be supplied by separate .lua files.

When I split my code into two files, however, I can only get the functionality of one or the other. I assume this is because I can only use one filter that targets Span elements at a time ?

Any suggestions for solutions is much appreciated!

Here is the lua filter:

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
  
  -- highlight stuff that ends in {.correction}
  if el.classes[1] == "correction" then
    table.insert(
      el.content, 1, 
      pandoc.RawInline('latex', '\\hl{')
    )
    table.insert(
      el.content, 
      pandoc.RawInline('latex', '}')
    )
  end
  
  -- highlight stuff with {highlight = "some-color"}
  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', '}\\sethlcolor{correctioncolor}')
    )
  end
  
  -- 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

Using the same filter but having a conditional part

This will answer your question not in the title but in the post.

I can make all three possible with the lua filter shown by the end. However, I want to allow the user to turn off (1).

You can do that from within the same filter by using Metadata that can allow to pass value to Pandoc which the Lua filter can use. See about Pandoc's metadata

You can take a value from your user in R, pass it to Pandoc using the -M arg (or rmarkdown::pandoc_metadata_arg() ) - it would then be known by Pandoc. Lua filter can have access using Meta. You just need to take care of the execution order

For example, this example will take the value directly in the yaml header and it will be processed in Lua to create a variable acting as a switch to activated or not one part of the filter.

Setting to false below will not run the part in Lua. Setting to true (or nothing as it is the default) will run the part in Lua and highlight.

---
title: several Lua
output: 
  pdf_document: 
    keep_tex: true
    pandoc_args: ["--lua-filter", "custom.lua"]
    extra_dependencies: soul
correction: false
---

# write the lua files

## Correction

```{cat, engine.opts = list(file = "custom.lua")}

local correction_activated = true

Meta = function(m)
  if m['correction'] ~= nil then 
    correction_activated = m['correction']
  end
end
  

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
  
  -- highlight stuff that ends in {.correction}
  if correction_activated and el.classes[1] == "correction" then
    table.insert(
      el.content, 1, 
      pandoc.RawInline('latex', '\\hl{')
    )
    table.insert(
      el.content, 
      pandoc.RawInline('latex', '}')
    )
  end
  
  -- highlight stuff with {highlight = "some-color"}
  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', '}\\sethlcolor{correctioncolor}')
    )
  end
  
  -- 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

return {
  { Meta = Meta },
  { Span = Span }
}

```


Something [here]{.correction}

With what I mentioned earlier you can pass as metadata from within R directly if you prefer a switch as an argument in your format function.

This is one way of doing it and keep one filter.

Using several filters to pass to Pandoc conditionally

This is now in several filters

---
title: several Lua
output: 
  pdf_document: 
    keep_tex: true
    pandoc_args: ["--lua-filter", "correction.lua", "--lua-filter", "hl-color.lua"]
    extra_dependencies: soul
---

# write the lua files

## Correction

```{cat, engine.opts = list(file = "correction.lua")}

Span = function (el)
  -- create a function to check for emptiness
  local function isempty(s)
    return s == nil or s == ''
  end
  
  -- highlight stuff that ends in {.correction}
  if el.classes[1] == "correction" then
    table.insert(
      el.content, 1, 
      pandoc.RawInline('latex', '\\hl{')
    )
    table.insert(
      el.content, 
      pandoc.RawInline('latex', '}')
    )
  end
  
  return el 
end
```

## Highlight + colors

```{cat, engine.opts = list(file = "hl-color.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
  
  -- highlight stuff with {highlight = "some-color"}
  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', '}\\sethlcolor{correctioncolor}')
    )
  end
  
  -- 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
end
```


Something [here]{.correction}

Something [like this]{highlight="red"}

Or [like this]{color="blue"}

Put it in test.Rmd

Try

  • both
rmarkdown::render("test.Rmd")
  • Only correction
rmarkdown::render("test.Rmd", output_options = list(pandoc_args = rmarkdown::pandoc_lua_filter_args("correction.lua")))
  • Only hl+color
rmarkdown::render("test.Rmd", output_options = list(pandoc_args = rmarkdown::pandoc_lua_filter_args("hl-color.lua")))

I hope you'll manage to integrate this into your tool.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM