pandoc / lua-filters

A collection of lua filters for pandoc
MIT License
603 stars 165 forks source link

short-captions for section title #76

Open rnuske opened 4 years ago

rnuske commented 4 years ago

I would love to use a filter similar to short-captions to add a short title to my titles. For instance like

# very long title {short="short title"} {#mylink}

should become

\hypertarget{mylink}{%
\section[short title]{very long title}%
\label{mylink}}

A python filter suggested in a pandoc issue handles that case as long as there is no pandoc-crossref link anchor.

Nodraak commented 4 years ago

Hi Rnuske!

I've updated my filter, here is the new version:

#!/usr/bin/env python3

"""
Usage:
Copy this code to short-title-for-toc.py
pip3 install pandocfilters
pandoc --filter ./short-title-for-toc.py
"""

from pandocfilters import toJSONFilter, RawBlock, get_value, stringify

LEVEL2TAG = {
    -1: 'part',
    0: 'chapter',
    1: 'section',
    2: 'subsection',
    3: 'subsubsection',
}

def f(key, value, format, meta):
    if not (format == 'latex' and key == 'Header'):
        return

    # get data

    level, (_, classes, keyvals), _ = value             # level, (ident, classes, keyvals), internal_pandoc
    short, _ = get_value(keyvals, 'short')
    link, _ = get_value(keyvals, 'link')

    if level not in LEVEL2TAG:
        raise Exception('short-title-for-toc.py: level %d not handled' % level)
    tag = LEVEL2TAG[level]

    # check if we should override pandoc default behavior

    if not short and not link:
        return

    if classes:
        raise Exception(
            'short-title-for-toc.py: If class "short" is used, I cant handle another one (Header="%s")'
            % (stringify(value))
        )

    # build overriden code

    if short:
        latextitle = '\\%s[%s]{%s}' % (tag, short, stringify(value))
    else:
        latextitle = '\\%s{%s}' % (tag, stringify(value))

    if link:
        latextitle = '\hypertarget{%s}{%s\label{%s}}' % (link, latextitle, link)

    # return

    return RawBlock('latex', latextitle)

if __name__ == '__main__':
    toJSONFilter(f)

I have tested with this:

---
toc: true
---

# 1-onlyshort-long {short="1-onlyshort-short"}

hello

# 2-onlylink-long {link="2-onlylink-link"}

hello

# 3-both-long {short="3-both-short" link="3-both-link"}

hello

Compiled with:

all:
        pandoc -i foo.md -o foo.tex -s --filter ./short-title-for-toc.py
        pandoc -i foo.md -o foo.pdf -s --filter ./short-title-for-toc.py

The (partial) output is:

\section[1-onlyshort-short]{1-onlyshort-long}

hello

\hypertarget{2-onlylink-link}{\section{2-onlylink-long}\label{2-onlylink-link}}

hello

\hypertarget{3-both-link}{\section[3-both-short]{3-both-long}\label{3-both-link}}

hello

I hope this helps :)

rnuske commented 4 years ago

Thank you @Nodraak!

On closer inspection, I had to change LEVEL2TAG because the filter returned section instead of chapter for a scrbook-document.

The filter lets pandoc drop stuff it does not like such as \mbox{} instead of treating it with \texorpdfstring{}. That way one gets the full title in TOC and PDF bookmarks but not at the top of the chapter.

The following processed with pandoc -t latex --filter short-title-for-toc.py

# Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam \mbox{nonumy} eirmod tempor {short="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor" link="Lorem"}

leads to

\hypertarget{Lorem}{\chapter[Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor]{Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam  eirmod tempor}\label{Lorem}}

Without the filter pandoc would produce

\hypertarget{Lorem}{%
\chapter{\texorpdfstring{Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam \mbox{nonumy} eirmod tempor}{Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam  eirmod tempor}}\label{Lorem}}

resulting in a full title at the top of the chapter but an incomplete title in PDF Bookmarks

Nodraak commented 4 years ago

You can try to remove stringify, I dont know why I added it

rnuske commented 4 years ago

You are probably right, it's stringify that drops mbox. But I have no idea what to replace stringify with to extract the raw latex string from the value object. Just removing stringify does not work.

Sjors commented 2 years ago

I'm having trouble using this in combination with secnos.

  1. It seems necessary to run short-title-for-toc before secnos (probably good to document somewhere)
  2. It uses the short name for the table of contents (I'd like to only use it for the page header)
  3. It throws pandoc-secnos: Bad reference: @sec:link even though it does correctly replace the (chapter) numbers
  4. Using the {#sec:link short="Short"} notation instead of {link="sec:link" short="Short"} link notation would be nice, since it's closer to the syntax used for chapters that don't need a short title.
  5. It would be nice if the latex output added a line break, like \hypertarget{sec:link}{% which would match what Pandoc seems to do otherwise.