Add --shift-heading-level-by option.

Deprecate --base-heading-level.

The new option does everything the old one does, but also
allows negative shifts.  It also promotes the document
metadata (if not null) to a level-1 heading with a +1 shift,
and demotes an initial level-1 heading to document metadata
with a -1 shift. This supports converting documents that
use an initial level-1 heading for the document title.

Closes #5615.
This commit is contained in:
John MacFarlane 2019-09-10 23:16:13 -07:00
parent a64b3ab61f
commit 88dc6fac5d
6 changed files with 88 additions and 7 deletions

View file

@ -479,9 +479,26 @@ General options {.options}
Reader options {.options}
--------------
`--shift-heading-level-by=`*NUMBER*
Shift heading levels by a positive or negative integer.
For example, with `--shift-heading-level-by=-1`, level 2
headings become level 1 headings, and level 3 headings
become level 2 headings. Headings cannot have a level
less than 1, so a heading that would be shifted below level 1
becomes a regular paragraph. Exception: with a shift of -1,
a level-1 heading at the beginning of the document
replaces the metadata title. Conversely, with a shift
of +1, a nonempty metadata title becomes a level-1 heading at
the beginning of the document. `--shift-heading-level-by=-1`
is a good choice when converting HTML or Markdown documents that
use an initial level-1 heading for the document title and
level-2+ headings for sections.
`--base-header-level=`*NUMBER*
: Specify the base level for headings (defaults to 1).
: *Deprecated. Use `--shift-heading-level-by` instead.*
Specify the base level for headings (defaults to 1).
`--strip-empty-paragraphs`

View file

@ -241,6 +241,9 @@ convertWithOpts opts = do
let transforms = (case optBaseHeaderLevel opts of
x | x > 1 -> (headerShift (x - 1) :)
| otherwise -> id) .
(case optShiftHeadingLevel opts of
0 -> id
x -> (headerShift x :)) .
(if optStripEmptyParagraphs opts
then (stripEmptyParagraphs :)
else id) .

View file

@ -436,9 +436,22 @@ options =
"SCRIPTPATH")
"" -- "Lua filter"
, Option "" ["base-header-level"]
, Option "" ["shift-heading-level-by"]
(ReqArg
(\arg opt ->
case safeRead arg of
Just t ->
return opt{ optShiftHeadingLevel = t }
_ -> E.throwIO $ PandocOptionError
"shift-heading-level-by takes an integer argument")
"NUMBER")
"" -- "Shift heading level"
, Option "" ["base-header-level"]
(ReqArg
(\arg opt -> do
deprecatedOption "--base-header-level"
"Use --shift-heading-level-by instead."
case safeRead arg of
Just t | t > 0 && t < 6 ->
return opt{ optBaseHeaderLevel = t }
@ -450,7 +463,7 @@ options =
, Option "" ["strip-empty-paragraphs"]
(NoArg
(\opt -> do
deprecatedOption "--stripEmptyParagraphs"
deprecatedOption "--strip-empty-paragraphs"
"Use +empty_paragraphs extension."
return opt{ optStripEmptyParagraphs = True }))
"" -- "Strip empty paragraphs"

View file

@ -50,6 +50,7 @@ data Opt = Opt
, optReader :: Maybe String -- ^ Reader format
, optWriter :: Maybe String -- ^ Writer format
, optTableOfContents :: Bool -- ^ Include table of contents
, optShiftHeadingLevel :: Int -- ^ Shift heading level by
, optBaseHeaderLevel :: Int -- ^ Base header level
, optTemplate :: Maybe FilePath -- ^ Custom template
, optVariables :: [(String,String)] -- ^ Template variables to set
@ -124,6 +125,7 @@ defaultOpts = Opt
, optReader = Nothing
, optWriter = Nothing
, optTableOfContents = False
, optShiftHeadingLevel = 0
, optBaseHeaderLevel = 1
, optTemplate = Nothing
, optVariables = []

View file

@ -565,9 +565,22 @@ isHeaderBlock _ = False
-- | Shift header levels up or down.
headerShift :: Int -> Pandoc -> Pandoc
headerShift n = walk shift
where shift :: Block -> Block
shift (Header level attr inner) = Header (level + n) attr inner
headerShift n (Pandoc meta (Header m _ ils : bs))
| n < 0
, m + n == 0 = headerShift n $
B.setTitle (B.fromList ils) $ Pandoc meta bs
headerShift n (Pandoc meta bs)
| n > 0
, not (null (docTitle meta))
= Pandoc meta' (Header n nullAttr (docTitle meta) : bs')
where
Pandoc meta' bs' = headerShift n $ B.deleteMeta "title" $ Pandoc meta bs
headerShift n (Pandoc meta bs) = Pandoc meta (walk shift bs)
where
shift :: Block -> Block
shift (Header level attr inner)
| level + n > 0 = Header (level + n) attr inner
| otherwise = Para inner
shift x = x
-- | Remove empty paragraphs.

View file

@ -0,0 +1,33 @@
```
% pandoc --shift-heading-level-by 1 -t native -s
---
title: My title
...
# First heading
## Second
^D
Pandoc (Meta {unMeta = fromList []})
[Header 1 ("",[],[]) [Str "My",Space,Str "title"]
,Header 2 ("first-heading",[],[]) [Str "First",Space,Str "heading"]
,Header 3 ("second",[],[]) [Str "Second"]]
```
```
% pandoc --shift-heading-level-by -1 -t native -s
---
title: Old title
...
# First heading
## Second
# Another top-level heading
^D
Pandoc (Meta {unMeta = fromList [("title",MetaInlines [Str "First",Space,Str "heading"])]})
[Header 1 ("second",[],[]) [Str "Second"]
,Para [Str "Another",Space,Str "top-level",Space,Str "heading"]]
```