diff --git a/first-line-indent/LICENSE b/first-line-indent/LICENSE new file mode 100644 index 00000000..b4e8923c --- /dev/null +++ b/first-line-indent/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Julien Dutant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/first-line-indent/Makefile b/first-line-indent/Makefile new file mode 100644 index 00000000..62bfcbae --- /dev/null +++ b/first-line-indent/Makefile @@ -0,0 +1,19 @@ +DIFF ?= diff --strip-trailing-cr -u + +.PHONY: test + +test: test_latex test_html + +test_html: sample.md expected.html first-line-indent.lua + @pandoc -s --lua-filter first-line-indent.lua --to=html $< \ + | $(DIFF) expected.html - + +test_latex: sample.md expected.tex first-line-indent.lua + @pandoc -s --lua-filter first-line-indent.lua --to=latex $< \ + | $(DIFF) expected.tex - + +expected.html: sample.md first-line-indent.lua + pandoc -s --lua-filter first-line-indent.lua --output $@ $< + +expected.tex: sample.md first-line-indent.lua + pandoc -s --lua-filter first-line-indent.lua --output $@ $< diff --git a/first-line-indent/README.md b/first-line-indent/README.md new file mode 100644 index 00000000..c4328829 --- /dev/null +++ b/first-line-indent/README.md @@ -0,0 +1,232 @@ +--- +title: "First Line Indent - First-line idented paragraphs + in Pandoc's markdown" +author: "Julien Dutant" +--- + +First Line Indent +======= + +First-line idented paragraphs in Pandoc's markdown. + +This Lua filter for Pandoc improves Pandoc's first-line ident +paragraph separation style by removing first-line idents after +blockquotes, lists and code blocks unless specified otherwise. + +v1.0. Copyright: © 2021 Julien Dutant +License: MIT - see LICENSE file for details. + +Introduction +------------ + +In typography paragraphs can be distinguished in two ways: by vertical +whitespace (a style common on the web) or by indenting their first +line (a style common in books). For the latter conventions vary across +typographic traditions: some (*e.g.* French) indent the first line of +every paragraph while others (*e.g.* English) don't indent paragraphs +after section headings and most indented material such as blockquotes +or lists. + +In Pandoc the default output uses the vertical whitespace style but +can be switched in some formats (PDF via `LaTeX`, though not in `docx` +or `html`) to the first-line indent style by setting the metadata +variable `indent` to `true` and the `lang` variable is used to decide +which convention to follow (the default is the English one). + +However the default first-line indent style output still adds first-line indents to every paragraph that starts after a blockquote, list, code +block, etc. These are typically (though not always) unwanted, namely when +the text after the blockquote or list is a continuation of the same +paragraph. + +This filter improves the handling of first-line indent following +indented material such as blockquotes and provides first-line indent +style for html outputs: + +1) The filter activates Pandoc's first-line indent style by setting + the metadata variable `indent` to true, unless otherwise specified. +2) The filter generates HTML outputs with first-line indent style. That + is done by inserting CSS code in the document's metadata + `header-includes` field. (Note that this still works if the document + has its own `header-includes` material, but not if a + `header-includes` value is given to Pandoc via the command line.) + This default behaviour can be deactivated if the user wants to handle + first-line indent formatting with a custom pandoc template. +3) If the user manually specifies `\indent` (resp., `\noindent`) at the start + of a paragraph (in markdown source), the paragraphs are typeset with + (resp., without) first-line indentation in HTML output as well as + LaTeX output. +4) The filter removes (typically unwanted) first-line indents after + blockquotes, lists, code blocks and the like. The user can + override this by inserting `\indent` at the beginning of a paragraph + that does require a first-line indent. By default first-line indent + is removed after the block of the following types, though this can + be customized by the user: block quotes, lists (of all types: + unordered, ordered, numbered examples, definition lists), + horizontal rules. +5) A custom size for the first-line indentation in HTML and LaTeX output + can be specified. + +Usage +----- + +### Basic usage + +Copy `first-line-indent.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 +command line option: + +```bash +pandoc --luafilter first-line-indent.lua SOURCE.md -o OUTPUT.html + +pandoc -L first-line-indent.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 HTML and PDF outputs in first-line indent paragraph +separation style with the indent automatically removed after headings, +blockquotes, lists of all kinds and horizontal rules. + +If you want to keep the first-line indent of a certain paragraph after +a list or blockquote, this must be done in markdown (convert your +source to markdown first with pandoc). You simply add `\indent` at the +beginning of the paragraph: + +```markdown +> This is a blockquote + +\indent This paragraph will have an indent even though it follows a +blockquote. +``` + +### Advanced usage + +The filter has options that can be specified in a [pandoc default +file](https://pandoc.org/MANUAL.html#option--defaults) or, if the +source is markdown, in the source document's metadata block. +Either way they are specified as sub-fields of a `first-line-indent` +field. In the source's metadata block, they are specified as +follows (these are the default values): + +```yaml +first-line-indent: + size: 1em + auto-remove: true + set-metadata-variable: true + set-header-includes: true + remove-after: + - BlockQuote + - BulletList + - CodeBlock + - DefinitionList + - HorizontalRule + - OrderedList + dont-remove-after: Table +``` + +And as follows in a default file: + +```yaml +metadata: + first-line-indent: + size: 1em + auto-remove: true + set-metadata-variable: true + set-header-includes: true + remove-after: + - BlockQuote + - BulletList + - CodeBlock + - DefinitionList + - HorizontalRule + - OrderedList + dont-remove-after: Table +``` + +The options are described below. + +* `size`: string specificing size of the first-line indent. Must be in a + format suitable for all desired outputs. `1.5em`, `2ex`, `.5pc`, `10pt`, + `25mm`, `2.5cm`, `0.3in`, all work in LaTeX and HTML. `25px` only works + in HTML. LaTeX commands (`\textheight`) are not supported. +* `auto-remove`: whether the filter automatically removes first-line + indent from paragraphs that follow blockquotes and the like, unless + they start with the `\indent` string. (Default: true) +* `set-metadata-variable`: whether the filter should tell Pandoc to use + first-line-indent paragraph separation style by setting the metadata + variable `indent` to `true`. (Default: true) +* `set-header-includes`: whether the filter should add formatting code + to the document's `header-includes` metadata field. Set it to false if + you use a custom template instead. +* `remove-after`, `dont-remove-after`: use these options to customize + the automatic removal of first-line indent on paragraphs following + blocks of a certain type. These options can be a single string or + an list of strings. The strings are case-sensitive and should be + those corresponding to [block types in Lua + filters](https://pandoc.org/lua-filters.html#type-block): BlockQuote, + BulletList, CodeBlock, DefinitionList, Div, Header, HorizontalRule, + LineBlock, Null, OrderedList, Para, Plain, RawBlock, Table. + +To illustrate the last option, suppose you don't want to filter to remove +first-line indent after definition lists. You can add the following +lines in the document's metadata block (if the source is markdown): + +```yaml +first-line-indent: + dont-remove-after: DefinitionList +``` + +### Styling the outputs + +In LaTeX output the filters adds `\noindent` commands at beginning of +paragraphs that shouldn't be indented. These can be controlled in +LaTeX as usual. + +In HTML output paragraphs that are explicitly marked to have no first-line +indent are preceded by an empty `div` with class `no-first-line-indent-after` +and those that are explictly marked (with `\indent` in the markdown +source) to have a first-line indent are preceded by an empty `div` with class +`first-line-indent-after`, as follows: + +```html + +
+

This paragraph should not have first-line indent.

+... +
+

This paragraph should have first-line indent.

+``` + +These can be styled in CSS as follows: + +```css +p { + text-indent: 1em; + margin: 0; +} +:is(h1, h2, h3, h4, h5, h6) + p { + text-indent: 0em; +} +:is(div.no-first-line-indent-after) + p { + text-indent: 0em; +} +:is(div.first-line-indent-after) + p { + text-indent: 1em; +} +``` + +The `p` rule adds a first-line identation to every paragraph (and `margin: 0` removes the default vertical space between paragraphs). The +`is(h1, h2, h3, h4, h5, h6) + p` rule removes first-line indentation from +every paragraph that follows a heading. The +`:is(div.no-first-line-indent-after) + p` and +`:is(div.first-line-indent-after) + p` rules remove/add first-line indentation +from every paragraph that follows `div`s of the classes `no-first-line-indent-after` and `first-line-indent-after`, respectively. + +Contributing +------------ + +PRs welcome. + diff --git a/first-line-indent/expected.html b/first-line-indent/expected.html new file mode 100644 index 00000000..7957cfb5 --- /dev/null +++ b/first-line-indent/expected.html @@ -0,0 +1,317 @@ + + + + + + + Sample first line indent + + + + + +
+

Sample first line indent

+
+

First paragraph. In English-style typography, the first paragraph shouldn’t have a first-line indent, nor the paragraphs below headers.

+

This paragraph should start with a first-line indent. But after this quote:

+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+
+
+

the paragraph continues, so there should not be a first-line indent.

+

The quote below ends a paragraph:

+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+
+
+

This paragraph, then, is genuinely a new paragraph and starts with a first-line indent.

+

Further tests

+

After a heading (in English typographic style) the paragraph does not have a first-line indent.

+

In the couple couple of paragraphs that follow the quotes below, we have manually specified \noindent and \indent respectively. This is to check that the filter doesn’t add its own commands to those.

+
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+
+
+

Manually specified no first line indent.

+
+

Manually specified first line ident.

+

We can also check that indent is removed after lists:

+ +
+

And after code blocks:

+
local variable = "value"
+
+

Or horizontal rules.

+
+
+

In this document we added a few custom filter options. The size of first-line indents is 2em instead of the standard 1em. We also added an option to remove indent after tables:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Demonstration of simple table syntax.
RightLeftCenterDefault
12121212
123123123123
1111
+
+

So this paragraph’s first line is not indented. And we included custom options not to remove ident after ordered lists and definition lists:

+
+
Definition
+
This is a definition block. +
+
+

This paragraph is indented.

+
    +
  1. An ordered
  2. +
  3. list
  4. +
+

This paragraph is indented.

+ + diff --git a/first-line-indent/expected.tex b/first-line-indent/expected.tex new file mode 100644 index 00000000..23e9a1d9 --- /dev/null +++ b/first-line-indent/expected.tex @@ -0,0 +1,203 @@ +% Options for packages loaded elsewhere +\PassOptionsToPackage{unicode}{hyperref} +\PassOptionsToPackage{hyphens}{url} +% +\documentclass[ +]{article} +\usepackage{amsmath,amssymb} +\usepackage{lmodern} +\usepackage{iftex} +\ifPDFTeX + \usepackage[T1]{fontenc} + \usepackage[utf8]{inputenc} + \usepackage{textcomp} % provide euro and other symbols +\else % if luatex or xetex + \usepackage{unicode-math} + \defaultfontfeatures{Scale=MatchLowercase} + \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1} +\fi +% Use upquote if available, for straight quotes in verbatim environments +\IfFileExists{upquote.sty}{\usepackage{upquote}}{} +\IfFileExists{microtype.sty}{% use microtype if available + \usepackage[]{microtype} + \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts +}{} +\usepackage{xcolor} +\IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available +\IfFileExists{bookmark.sty}{\usepackage{bookmark}}{\usepackage{hyperref}} +\hypersetup{ + pdftitle={Sample first line indent}, + hidelinks, + pdfcreator={LaTeX via pandoc}} +\urlstyle{same} % disable monospaced font for URLs +\usepackage{color} +\usepackage{fancyvrb} +\newcommand{\VerbBar}{|} +\newcommand{\VERB}{\Verb[commandchars=\\\{\}]} +\DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}} +% Add ',fontsize=\small' for more characters per line +\newenvironment{Shaded}{}{} +\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}} +\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}} +\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{#1}} +\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}} +\newcommand{\BuiltInTok}[1]{#1} +\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}} +\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{#1}}} +\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}} +\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{#1}} +\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}} +\newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.56,0.13,0.00}{#1}} +\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}} +\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{#1}}} +\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{#1}}} +\newcommand{\ExtensionTok}[1]{#1} +\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{#1}} +\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{#1}} +\newcommand{\ImportTok}[1]{#1} +\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}} +\newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{#1}}} +\newcommand{\NormalTok}[1]{#1} +\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{#1}} +\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{#1}} +\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{#1}} +\newcommand{\RegionMarkerTok}[1]{#1} +\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}} +\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{#1}} +\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}} +\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{#1}} +\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{#1}} +\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{#1}}}} +\usepackage{longtable,booktabs,array} +\usepackage{calc} % for calculating minipage widths +% Correct order of tables after \paragraph or \subparagraph +\usepackage{etoolbox} +\makeatletter +\patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{} +\makeatother +% Allow footnotes in longtable head/foot +\IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}} +\makesavenoteenv{longtable} +\setlength{\emergencystretch}{3em} % prevent overfull lines +\providecommand{\tightlist}{% + \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} +\setcounter{secnumdepth}{-\maxdimen} % remove section numbering +\setlength{\parindent}{2em} +\ifLuaTeX + \usepackage{selnolig} % disable illegal ligatures +\fi + +\title{Sample first line indent} +\author{} +\date{} + +\begin{document} +\maketitle + +First paragraph. In English-style typography, the first paragraph +shouldn't have a first-line indent, nor the paragraphs below headers. + +This paragraph should start with a first-line indent. But after this +quote: + +\begin{quote} +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +\end{quote} + +\noindent the paragraph continues, so there should not be a first-line +indent. + +The quote below ends a paragraph: + +\begin{quote} +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +\end{quote} + +\indent This paragraph, then, is genuinely a new paragraph and starts +with a first-line indent. + +\hypertarget{further-tests}{% +\section{Further tests}\label{further-tests}} + +After a heading (in English typographic style) the paragraph does not +have a first-line indent. + +In the couple couple of paragraphs that follow the quotes below, we have +manually specified \texttt{\textbackslash{}noindent} and +\texttt{\textbackslash{}indent} respectively. This is to check that the +filter doesn't add its own commands to those. + +\begin{quote} +Lorem ipsum dolor sit amet, consectetur adipiscing elit. +\end{quote} + +\noindent Manually specified no first line indent. + +\indent Manually specified first line ident. + +We can also check that indent is removed after lists: + +\begin{itemize} +\tightlist +\item + A bullet +\item + list +\end{itemize} + +\noindent And after code blocks: + +\begin{Shaded} +\begin{Highlighting}[] +\KeywordTok{local}\NormalTok{ variable }\OperatorTok{=} \StringTok{"value"} +\end{Highlighting} +\end{Shaded} + +\noindent Or horizontal rules. + +\begin{center}\rule{0.5\linewidth}{0.5pt}\end{center} + +\noindent In this document we added a few custom filter options. The +size of first-line indents is 2em instead of the standard 1em. We also +added an option to remove indent after tables: + +\begin{longtable}[]{@{}rlcl@{}} +\caption{Demonstration of simple table syntax.}\tabularnewline +\toprule +Right & Left & Center & Default \\ +\midrule +\endfirsthead +\toprule +Right & Left & Center & Default \\ +\midrule +\endhead +12 & 12 & 12 & 12 \\ +123 & 123 & 123 & 123 \\ +1 & 1 & 1 & 1 \\ +\bottomrule +\end{longtable} + +\noindent So this paragraph's first line is not indented. And we +included custom options \emph{not} to remove ident after ordered lists +and definition lists: + +\begin{description} +\tightlist +\item[Definition] +This is a definition block. +\end{description} + +This paragraph is indented. + +\begin{enumerate} +\def\labelenumi{\arabic{enumi}.} +\tightlist +\item + An ordered +\item + list +\end{enumerate} + +This paragraph is indented. + +\end{document} diff --git a/first-line-indent/first-line-indent.lua b/first-line-indent/first-line-indent.lua new file mode 100644 index 00000000..98899a77 --- /dev/null +++ b/first-line-indent/first-line-indent.lua @@ -0,0 +1,345 @@ +--[[-- # First-line-indent - First-line idented paragraphs + in Pandoc's markdown. + +@author Julien Dutant +@copyright 2021 Julien Dutant +@license MIT - see LICENSE file for details. +@release 0.1 +]] + +-- # Options + +--- Options map, including defaults. +-- @param set_metadata_variable boolean whether to set the `indent` +-- metadata variable. +-- @param set_header_includes boolean whether to add formatting code in +-- header-includes to handle first-line indent paragraph style. +-- @param auto_remove_indents boolean whether to automatically remove +-- indents after blockquotes and the like. +-- @param remove_indent_after list of strings, Pandoc AST block types +-- after which first-line indents should be automatically removed. +-- @param size string a CSS / LaTeX specification of the first line +-- indent length +local options = { + set_metadata_variable = true, + set_header_includes = true, + auto_remove = true, + remove_indent_after = pandoc.List({ + 'BlockQuote', + 'BulletList', + 'CodeBlock', + 'DefinitionList', + 'HorizontalRule', + 'OrderedList', + }), + size = "1em", +} + +-- # Filter global variables +-- @utils pandoc's module of utilities functions +-- @param code map of pandoc objects for indent/noindent Raw code +-- @param header_code map of pandoc code to add to header-includes +local utils = pandoc.utils +local code = { + latex = { + indent = pandoc.RawInline('tex', '\\indent '), + noindent = pandoc.RawInline('tex', '\\noindent '), + }, + html = { + indent = pandoc.RawBlock('html', + '
'), + noindent = pandoc.RawBlock('html', + '
'), + } +} +local header_code = { + html = [[ + +]], +} + +--- Add a block to the document's header-includes meta-data field. +-- @param meta the document's metadata block +-- @param blocks list of Pandoc block elements (e.g. RawBlock or Para) +-- to be added to the header-includes of meta +-- @return meta the modified metadata block +local function add_header_includes(meta, blocks) + + local header_includes = pandoc.List(blocks) + + -- add any exisiting meta['header-includes'] + -- it could be a MetaList or a single String + if meta['header-includes'] then + if meta['header-includes'].t == 'MetaList' then + header_includes:extend(meta['header-includes']) + else + header_includes:insert(meta['header-includes']) + end + end + + meta['header-includes'] = pandoc.MetaBlocks(header_includes) + + return meta + +end + +-- # Filter functions + + +--- Filter for the metablock. +-- reads the user options. +-- sets the metadata variable `indent` to `true` unless otherwise specified. +-- adds formatting code to `header-includes` unless otherwise specified. +function process_metadata(meta) + + -- read user options + if meta['first-line-indent'] then + + local user_options = meta['first-line-indent'] + + if not(user_options['set-metadata-variable'] == nil) + and user_options['set-metadata-variable'] == false then + options.set_metadata_variable = false + + end + + if not(user_options['set-header-includes'] == nil) + and user_options['set-header-includes'] == false then + options.set_header_includes = false + end + + if not(user_options['auto-remove'] == nil) + and user_options['auto-remove'] == false then + options.auto_remove = false + end + + if (user_options['remove-after']) then + + if user_options['remove-after'].t == 'MetaInlines' or + user_options['remove-after'].t == 'MetaList' then + + if user_options['remove-after'].t == 'MetaInlines' then + + options.remove_indent_after:insert ( + utils.stringify(user_options['remove-after'])) + + else + + for _,item in ipairs(user_options['remove-after']) do + + options.remove_indent_after:insert(utils.stringify(item)) + + end + + end + + end + end + + if (user_options['dont-remove-after']) then + + if user_options['dont-remove-after'].t == 'MetaInlines' or + user_options['dont-remove-after'].t == 'MetaList' then + + -- list of strings to be removed + local blacklist = pandoc.List({}) + + if user_options['dont-remove-after'].t == 'MetaInlines' then + + blacklist:insert ( + utils.stringify(user_options['dont-remove-after'])) + + else + + for _,item in ipairs(user_options['dont-remove-after']) do + + blacklist:insert(utils.stringify(item)) + + end + + end + + -- filter the options.remove_indent_after list to only + -- include items that are not blacklisted + predicate = function (str) + return not(blacklist:includes(str)) + end + + options.remove_indent_after = + options.remove_indent_after:filter(predicate) + + end + end + + if not(user_options['size'] == nil) then + + -- @todo using stringify means that LaTeX commands in + -- size are erased. But it ensures that the filter gets + -- a string. Improvement: check that we have a string + -- and throw a warning otherwise + options.size = utils.stringify(user_options['size']) + + end + + end + + -- variable to track whether we've changed `meta` + changes = false + + -- set the `indent` metadata variable unless otherwise specified or + -- already set to false + if options.set_metadata_variable and not(meta.indent == false) then + meta.indent = true + changes = true + end + + -- set the `header-includes` metadata variable + if options.set_header_includes then + + if FORMAT:match('html*') then + + header_code.html = string.gsub(header_code.html, "SIZE", options.size) + add_header_includes(meta, { pandoc.RawBlock('html', header_code.html) }) + + elseif FORMAT:match('latex') and not(options.size == "1em") then + + add_header_includes(meta, { pandoc.RawBlock('tex', + '\\setlength{\\parindent}{'.. options.size ..'}') }) + + end + + end + + if changes then return meta end + +end + +--- Add format-specific explicit indent markup to a paragraph. +-- @param type string 'indent' or 'noindent', type of markup to add +-- @param elem pandoc AST paragraph +-- @return a list of blocks (containing a single paragraph element or +-- a rawblock and a paragraph element, depending on output format) +local function indent_markup(type, elem) + + if FORMAT:match('latex') and (type == 'indent' or type == 'noindent') then + + -- in LaTeX, replace any `\indent` or `\noindent` command at + -- the start of the paragraph with the desired one, add it otherwise + + local content = pandoc.List(elem.content) + + if content[1] and (utils.equals(content[1], + code.latex.indent) or utils.equals(content[1], + code.latex.noindent)) then + + content[1] = code.latex[type] + + else + + content:insert(1, code.latex[type]) + + end + + elem.content = content + return({ elem }) + + -- in HTML, insert a block (div) before the paragraph + + elseif FORMAT:match('html*') and (type == 'indent' or type == 'noindent') then + + return({ code.html[type], elem }) + + else + + return({elem}) + + end + +end + +--- Process indents in the document's body text. +-- Adds output code for explicitly specified first-line indents, +-- automatically removes first-line indents after blocks of the +-- designed types unless otherwise specified. +local function process_body(doc) + + -- result will be the new doc.blocks + local result = pandoc.List({}) + local do_not_indent_next_block = false + + for _,elem in pairs(doc.blocks) do + + if elem.t == "Para" then + + -- if explicit indentation marking, leave as is and style output + if elem.content[1] and (utils.equals(elem.content[1], + code.latex.indent) or utils.equals(elem.content[1], + code.latex.noindent)) then + + if utils.equals(elem.content[1], code.latex.indent) then + result:extend(indent_markup('indent', elem)) + else + result:extend(indent_markup('noindent', elem)) + end + + -- if auto_remove is on remove the first-line indent if needed + elseif options.auto_remove and do_not_indent_next_block then + + result:extend(indent_markup('noindent', elem)) + + else + + result:insert(elem) + + end + + do_not_indent_next_block = false + + elseif options.remove_indent_after:includes(elem.t) then + + do_not_indent_next_block = true + result:insert(elem) + + else + + do_not_indent_next_block = false + result:insert(elem) + + end + + end + + doc.blocks = result + return doc + +end + +--- Main code +-- Returns the filters in the desired order of execution +local metadata_filter = { + Meta = process_metadata +} +local body_filter = { + Pandoc = process_body +} +return { + metadata_filter, + body_filter +} diff --git a/first-line-indent/sample.md b/first-line-indent/sample.md new file mode 100644 index 00000000..f4ddd383 --- /dev/null +++ b/first-line-indent/sample.md @@ -0,0 +1,80 @@ +--- +title: "Sample first line indent" +# Filter options. These are defaults, you will get the same +# if you don't specify anything. See the README.md for details. +first-line-indent: + set-metadata-variable: true + set-header-includes: true + auto-remove: true + remove-after: Table + dont-remove-after: + - DefinitionList + - OrderedList + size: "2em" +--- + +First paragraph. In English-style typography, the first paragraph shouldn't have a first-line indent, nor the paragraphs below headers. + +This paragraph should start with a first-line indent. But after this quote: + +> Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +the paragraph continues, so there should not be a first-line indent. + +The quote below ends a paragraph: + +> Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +\indent This paragraph, then, is genuinely a new paragraph and starts with +a first-line indent. + +# Further tests + +After a heading (in English typographic style) the paragraph does not have a first-line indent. + +In the couple couple of paragraphs that follow the quotes below, we have manually specified `\noindent` and `\indent` respectively. This is to check that the filter doesn't add its own commands to those. + +> Lorem ipsum dolor sit amet, consectetur adipiscing elit. + +\noindent Manually specified no first line indent. + +\indent Manually specified first line ident. + +We can also check that indent is removed after lists: + +* A bullet +* list + +And after code blocks: + +```lua +local variable = "value" +``` + +Or horizontal rules. + +--- + +In this document we added a few custom filter options. The size of first-line +indents is 2em instead of the standard 1em. We also added an option to remove indent after tables: + + Right Left Center Default +------- ------ ---------- ------- + 12 12 12 12 + 123 123 123 123 + 1 1 1 1 + +Table: Demonstration of simple table syntax. + +So this paragraph's first line is not indented. And we included custom options +*not* to remove ident after ordered lists and definition lists: + +Definition +: This is a definition block. + +This paragraph is indented. + +1. An ordered +2. list + +This paragraph is indented.