From 672a4bdd1d4a587feaa38613fce64335adaad76d Mon Sep 17 00:00:00 2001
From: Albert Krewinkel <albert@zeitkraut.de>
Date: Wed, 15 Jan 2020 23:26:00 +0100
Subject: Lua filters: allow filtering of element lists (#6040)

Lists of Inline and Block elements can now be filtered via `Inlines` and
`Blocks` functions, respectively. This is helpful if a filter conversion
depends on the order of elements rather than a single element.

For example, the following filter can be used to remove all spaces
before a citation:

    function isSpaceBeforeCite (spc, cite)
      return spc and spc.t == 'Space'
       and cite and cite.t == 'Cite'
    end

    function Inlines (inlines)
      for i = #inlines-1,1,-1 do
        if isSpaceBeforeCite(inlines[i], inlines[i+1]) then
          inlines:remove(i)
        end
      end
      return inlines
    end

Closes: #6038
---
 doc/lua-filters.md | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 71 insertions(+), 1 deletion(-)

(limited to 'doc')

diff --git a/doc/lua-filters.md b/doc/lua-filters.md
index fea3d4c1b..31beed162 100644
--- a/doc/lua-filters.md
+++ b/doc/lua-filters.md
@@ -136,13 +136,52 @@ Elements without matching functions are left untouched.
 See [module documentation](#module-pandoc) for a list of pandoc
 elements.
 
-## Execution order
+## Filters on element sequences
+
+For some filtering tasks, the it is necessary to know the order
+in which elements occur in the document. It is not enough then to
+inspect a single element at a time.
+
+There are two special function names, which can be used to define
+filters on lists of blocks or lists of inlines.
+
+[`Inlines (inlines)`]{#inlines-filter}
+:   If present in a filter, this function will be called on all
+    lists of inline elements, like the content of a [Para]
+    (paragraph) block, or the description of an [Image]. The
+    `inlines` argument passed to the function will be a [List] of
+    [Inlines] for each call.
+
+[`Blocks (blocks)`]{#blocks-filter}
+:   If present in a filter, this function will be called on all
+    lists of block elements, like the content of a [MetaBlocks]
+    meta element block, on each item of a list, and the main
+    content of the [Pandoc] document. The `blocks` argument
+    passed to the function will be a [List] of [Inlines] for each
+    call.
+
+These filter functions are special in that the result must either
+be nil, in which case the list is left unchanged, or must be a
+list of the correct type, i.e., the same type as the input
+argument. Single elements are **not** allowed as return values,
+as a single element in this context usually hints at a bug.
+
+See ["Remove spaces before normal citations"][Inlines filter
+example] for an example.
+
+This functionality has been added in pandoc 2.9.2.
+
+[Inlines filter example]: #remove-spaces-before-citations
+
+## Execution Order
 
 Element filter functions within a filter set are called in a
 fixed order, skipping any which are not present:
 
   1. functions for [*Inline* elements](#type-inline),
+  2. the [`Inlines`](#inlines-filter) filter function,
   2. functions for [*Block* elements](#type-block) ,
+  2. the [`Blocks`](#inlines-filter) filter function,
   3. the [`Meta`](#type-meta) filter function, and last
   4. the [`Pandoc`](#type-pandoc) filter function.
 
@@ -368,6 +407,34 @@ function Doc (blocks, meta)
 end
 ```
 
+## Remove spaces before citations
+
+This filter removes all spaces preceding an "author-in-text"
+citation. In Markdown, author-in-text citations (e.g.,
+`@citekey`), must be preceded by a space. If these spaces are
+undesired, they must be removed with a filter.
+
+``` lua
+local function is_space_before_author_in_text(spc, cite)
+  return spc and spc.t == 'Space'
+    and cite and cite.t == 'Cite'
+    -- there must be only a single citation, and it must have
+    -- mode 'AuthorInText'
+    and #cite.citations == 1
+    and cite.citations[1].mode == 'AuthorInText'
+end
+
+function Inlines (inlines)
+  -- Go from end to start to avoid problems with shifting indices.
+  for i = #inlines-1, 1, -1 do
+    if is_space_before_author_in_text(inlines[i], inlines[i+1]) then
+      inlines:remove(i)
+    end
+  end
+  return inlines
+end
+```
+
 ## Replacing placeholders with their metadata value
 
 Lua filter functions are run in the order
@@ -1650,15 +1717,18 @@ Usage:
 [Citation]: #type-citation
 [Citations]: #type-citation
 [CommonState]: #type-commonstate
+[Image]: #type-image
 [Inline]: #type-inline
 [Inlines]: #type-inline
 [List]: #type-list
 [ListAttributes]: #type-listattributes
 [Meta]: #type-meta
+[MetaBlocks]: #type-metablocks
 [MetaValue]: #type-metavalue
 [MetaValues]: #type-metavalue
 [LogMessage]: #type-logmessage
 [Pandoc]: #type-pandoc
+[Para]: #type-para
 [Version]: #type-version
 [`pandoc.utils.equals`]: #pandoc.utils.equals
 
-- 
cgit v1.2.3