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:
parent
a64b3ab61f
commit
88dc6fac5d
6 changed files with 88 additions and 7 deletions
19
MANUAL.txt
19
MANUAL.txt
|
@ -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`
|
||||
|
||||
|
|
|
@ -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) .
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 = []
|
||||
|
|
|
@ -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.
|
||||
|
|
33
test/command/shift-heading-level-by.md
Normal file
33
test/command/shift-heading-level-by.md
Normal 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"]]
|
||||
```
|
||||
|
Loading…
Reference in a new issue