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

A lua filter enabling multiple columns in Latex, PDF, and HTML documents #191

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
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
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@
[GitHub Actions badge]: https://img.shields.io/github/workflow/status/pandoc/lua-filters/CI?logo=github
[GitHub Actions]: https://github.com/pandoc/lua-filters/actions

--------------------------------------------------------

**DISCLAIMER : This repositoy is not active any more.**

**See [hk-pandoc-filters](https://github.com/chrisaga/hk-pandoc-filters)**

**I started this fork almost when pandoc/lus-filters stoped accepting third party contributions.**
**Hence I started a fresh new repository to host my own lua filters.**
**As soon as they'll provide a way to contribute or be referenced, I will apply.**

--------------------------------------------------------

A collection of Lua filters for pandoc.

To learn about Lua filters, see the [documentation].
Expand Down
19 changes: 19 additions & 0 deletions column-div/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
DIFF ?= diff --strip-trailing-cr -u

.PHONY: test

test: test_latex test_html

test_html: sample.md expected.html column-div.lua
@pandoc -s --lua-filter column-div.lua --to=html $< \
| $(DIFF) expected.html -

test_latex: sample.md expected.tex column-div.lua
@pandoc -s --lua-filter column-div.lua --to=latex $< \
| $(DIFF) expected.tex -

expected.html: sample.md column-div.lua
pandoc -s --lua-filter column-div.lua --output $@ $<

expected.tex: sample.md column-div.lua
pandoc -s --lua-filter column-div.lua --output $@ $<
149 changes: 149 additions & 0 deletions column-div/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
title: "Column Div - leverage Pandoc native divs to make columns
and other things"
author: "Christophe Agathon"
---

Column Div
=======

Columns and other things with Pandoc's markdown

This Lua filter for Pandoc improves Pandoc's Div usage.Especially
fenced divs witten in Pandocs markdown.

v1.0. Copyright: © 2021 Christophe Agathon
<[email protected]>
License: MIT - see LICENSE file for details.

Introduction
------------
Pandoc fenced divs can be very powerful allowing providing, in
theory many document formating possibilities. Unfortunately, plain
Panfoc processing doesn't make full adventage of it and discards
some formating in HTML outputs and most of it in Latex outputs.

Multiple columns in document are only partialy accessible in
Beamer (not plain Latex) and HTML outputs.

As a result, it's not possible to render fancy multi columns
PDF document from markdown sources.

The main purpose of this filter is to make it possible and give
similar formating features for both Latex/PDF and HTML outputs.

My guidelines are :

1) Use Pandoc divs like many already have proposed for uneven and even columns
2) Same functionalities and rendering in HTML and Latex+PDF
3) Mess the least possible with plain Pandoc processing which is quite OK already for HTML (miss only column-count for even columning).
4) Allow users to use unknown Latex environments from exotic packages if they wish, provided they include them in the preamble.


Usage
-----

### Basic usage

Copy `column-div.lua` in your document folder or in your pandoc
data directory (details in
[Pandoc's manual](https://pandoc.org/MANUAL.html#option--lua-filter)).
Run it on your document with a `--luafilter` option:

```bash
pandoc --luafilter column-div.lua SOURCE.md -o OUTPUT.pdf

```

or specify it in a defaults file (details in
[Pandoc's manual](https://pandoc.org/MANUAL.html#option--defaults)).

This will generate consistent HTML, Latex and PDF outputs from
Pandoc markdown files.

### Formating the document

Everything is done with Pandoc's fenced divs with class names and
attributes. The attributes are similar to those from HTML styling and/or
Latex.

#### Multiple even columns
For Latex and PDF output, you will need to call the multicol
package. This can be done un the YAML header.

**Example:**

```markdown
---
header-includes:
- |
```{=latex}
\usepackage{multicol}

```
---

Some regular text

:::: {.multicols column-count="2"}
Some text formatted on 2 columns
::::
```

* Latex output is done with `multicols` environment.
* HTML output uses `style="column-count: 2"` on a div block.

#### Uneven columns

No specific Latex package are needed. We use Nested Pandoc divs in
the same way that columns and column environments are used in
Beamer/Latex.

**Example:**

```markdown

:::::::: {.columns}
:::: {.column width="20%" valign="c"}
Some text or image using 20% of the page width.
::::
:::: {.column width="80%" valign="c"}
Some text or image using 80% of the page with.
::::
::::::::
```

* Beamer/Latex output is based on columns and column environments
* Plain Latex (and PDF) rendering use minipage environments
* HTML rendering is not affected by this filter since Pandoc do it
well already (based on divs with `width` attributes).

#### Other usages

For HTML outputs, you already can create divs with whatever class names you
like and style them with `style=" … "` attributes. This is
processed by Pandoc and has nothing to do with this filter.

This filter allows to do the same in Latex (and PDF).
You can create whatever environment you need. The environment name is the
class name given to the fenced div. In case of multiple class names, the
first one is used. Other are ignored but allowed to help you to maintain
a single markdown source for PDF and HTML outputs.
The `data-latex=" … "` attribute allows you to pass options and
parameters to the `\begin` environment instruction.

To Do
-----

Others multi column features could be implemented as column
spacing, rules, etc.

Since Pandoc does a very good job with the `width` styling
attribute to implement variable column width, it could easily
support HTML even column via the `column-count` attribute.

Contributing
------------

PRs welcome.

161 changes: 161 additions & 0 deletions column-div/column-div.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
--[[
column-div - leverage Pandoc native divs to make balanced and unbalanced column
and other things based on class name and attributes.

Copyright: © 2021 Christophe Agathon <[email protected]>
License: MIT – see LICENSE file for details

Credits: Romain Lesur and Yihui Xie for the original column filter
implementation (output in beamer format).

Output: latex, pdf, html

Usage: classname attributes
balanced columns .columns column-count
columns(container) .columns
column(each column) .column width(percent) valign(t|c|b)

See README.md for details

Note: You don't need to include multicol latex package to get balanced
columns in latex or pdf. The filter does it.

I tried to use well known html or latex parameter.
Even if lua doen't like hyphens like in column-count.

--]]
local List = require 'pandoc.List'

function Div(div)
local options = ''
local env = ''
local returned_list
local begin_env
local end_env
local opt

-- if the div has no class, the object is left unchanged
-- if the div has no class but an id, div.classes ~= nil
if not div.classes or #div.classes == 0 then return nil end

-- if the format is latex then do minipage and others (like multicol)
if FORMAT:match 'latex' then
-- build the returned list of blocks
if div.classes:includes('column') then
env = 'column'
opt = div.attributes.width
if opt then
local width=tonumber(string.match(opt,'(%f[%d]%d[,.%d]*%f[%D])%%'))/100
options = '{' .. tostring(width)
if div.attributes['background-color'] then
-- fix the width for the \colorbox
options = '{\\dimexpr' .. tostring(width)
.. '\\columnwidth-4\\fboxsep\\relax}'
else
options = '{' .. tostring(width) .. '\\columnwidth}'
end
end

opt = div.attributes.valign
if opt then options = '[' .. opt .. ']' .. options end

begin_env = List:new{pandoc.RawBlock('tex',
'\\begin{minipage}' .. options)}
end_env = List:new{pandoc.RawBlock('tex', '\\end{minipage}')}

-- add support for color
opt = div.attributes.color
if opt then
begin_env = begin_env .. List:new{pandoc.RawBlock('tex',
'\\color{' .. opt .. '}')}
div.attributes.color = nil -- consume attribute
end

opt = div.attributes['background-color']
if opt then
begin_env = List:new{pandoc.RawBlock('tex',
'\\colorbox{' .. opt .. '}{')}
.. begin_env
end_env = end_env .. List:new{pandoc.RawBlock('tex', '}')}
div.attributes['background-color'] = nil -- consume attribute
end

returned_list = begin_env .. div.content .. end_env

elseif div.classes:includes('columns') then
-- it turns-out that asimple Tex \mbox do the job
begin_env = List:new{pandoc.RawBlock('tex', '\\mbox{')}
end_env = List:new{pandoc.RawBlock('tex', '}')}
returned_list = begin_env .. div.content .. end_env

else
-- other environments ex: multicols
if div.classes:includes('multicols') then
env = 'multicols'
-- process supported options
opt = div.attributes['column-count']
if opt then options = '{' .. opt .. '}' end
end

begin_env = List:new{pandoc.RawBlock('tex',
'\\begin{' .. env .. '}' .. options)}
end_env = List:new{pandoc.RawBlock('tex', '\\end{' .. env .. '}')}
returned_list = begin_env .. div.content .. end_env
end

-- if the format is html add what is not already done by plain pandoc
elseif FORMAT:match 'html' then
local style
-- add support for multi columns
opt = div.attributes['column-count']
if opt then
-- add column-count to style
style = 'column-count: ' .. opt .. ';' .. (style or '')
div.attributes['column-count'] = nil
-- column-count is "consumed" by the filter otherwise it would appear as
-- data-column-count="…" in the resulting document
end
-- add support for color
opt = div.attributes.color
if opt then
-- add color to style
style = 'color: ' .. opt .. ';' .. (style or '')
div.attributes.color = nil -- consume attribute
end
opt = div.attributes['background-color']
if opt then
-- add color to style
style = 'background-color: ' .. opt .. ';' .. (style or '')
div.attributes['background-color'] = nil -- consume attribute
end
-- if we have style then build returned list
if style then
-- process width attribute since Pandoc complains about duplicate
-- style attribute and ignores it.
opt = div.attributes.width
if opt then
style = 'width: ' .. opt .. ';' .. (style or '')
div.attributes.width = nil -- consume attribute
end
div.attributes.style = style .. (div.attributes.style or '')
returned_list = List:new{pandoc.Div(div.content, div.attr)}
end
end
return returned_list
end

function Meta(meta)
-- Include multicol latex package to get balanced columns in latex or pdf

includes = [[\usepackage{multicol}]]

if FORMAT:match 'latex' then
if meta['header-includes'] then
table.insert(meta['header-includes'], pandoc.RawBlock('tex', includes))
else
meta['header-includes'] = List:new{pandoc.RawBlock('tex', includes)}
end
end

return meta
end
Loading