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}
|
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*
|
`--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`
|
`--strip-empty-paragraphs`
|
||||||
|
|
||||||
|
|
|
@ -241,6 +241,9 @@ convertWithOpts opts = do
|
||||||
let transforms = (case optBaseHeaderLevel opts of
|
let transforms = (case optBaseHeaderLevel opts of
|
||||||
x | x > 1 -> (headerShift (x - 1) :)
|
x | x > 1 -> (headerShift (x - 1) :)
|
||||||
| otherwise -> id) .
|
| otherwise -> id) .
|
||||||
|
(case optShiftHeadingLevel opts of
|
||||||
|
0 -> id
|
||||||
|
x -> (headerShift x :)) .
|
||||||
(if optStripEmptyParagraphs opts
|
(if optStripEmptyParagraphs opts
|
||||||
then (stripEmptyParagraphs :)
|
then (stripEmptyParagraphs :)
|
||||||
else id) .
|
else id) .
|
||||||
|
|
|
@ -436,9 +436,22 @@ options =
|
||||||
"SCRIPTPATH")
|
"SCRIPTPATH")
|
||||||
"" -- "Lua filter"
|
"" -- "Lua filter"
|
||||||
|
|
||||||
, Option "" ["base-header-level"]
|
, Option "" ["shift-heading-level-by"]
|
||||||
(ReqArg
|
(ReqArg
|
||||||
(\arg opt ->
|
(\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
|
case safeRead arg of
|
||||||
Just t | t > 0 && t < 6 ->
|
Just t | t > 0 && t < 6 ->
|
||||||
return opt{ optBaseHeaderLevel = t }
|
return opt{ optBaseHeaderLevel = t }
|
||||||
|
@ -450,7 +463,7 @@ options =
|
||||||
, Option "" ["strip-empty-paragraphs"]
|
, Option "" ["strip-empty-paragraphs"]
|
||||||
(NoArg
|
(NoArg
|
||||||
(\opt -> do
|
(\opt -> do
|
||||||
deprecatedOption "--stripEmptyParagraphs"
|
deprecatedOption "--strip-empty-paragraphs"
|
||||||
"Use +empty_paragraphs extension."
|
"Use +empty_paragraphs extension."
|
||||||
return opt{ optStripEmptyParagraphs = True }))
|
return opt{ optStripEmptyParagraphs = True }))
|
||||||
"" -- "Strip empty paragraphs"
|
"" -- "Strip empty paragraphs"
|
||||||
|
|
|
@ -50,6 +50,7 @@ data Opt = Opt
|
||||||
, optReader :: Maybe String -- ^ Reader format
|
, optReader :: Maybe String -- ^ Reader format
|
||||||
, optWriter :: Maybe String -- ^ Writer format
|
, optWriter :: Maybe String -- ^ Writer format
|
||||||
, optTableOfContents :: Bool -- ^ Include table of contents
|
, optTableOfContents :: Bool -- ^ Include table of contents
|
||||||
|
, optShiftHeadingLevel :: Int -- ^ Shift heading level by
|
||||||
, optBaseHeaderLevel :: Int -- ^ Base header level
|
, optBaseHeaderLevel :: Int -- ^ Base header level
|
||||||
, optTemplate :: Maybe FilePath -- ^ Custom template
|
, optTemplate :: Maybe FilePath -- ^ Custom template
|
||||||
, optVariables :: [(String,String)] -- ^ Template variables to set
|
, optVariables :: [(String,String)] -- ^ Template variables to set
|
||||||
|
@ -124,6 +125,7 @@ defaultOpts = Opt
|
||||||
, optReader = Nothing
|
, optReader = Nothing
|
||||||
, optWriter = Nothing
|
, optWriter = Nothing
|
||||||
, optTableOfContents = False
|
, optTableOfContents = False
|
||||||
|
, optShiftHeadingLevel = 0
|
||||||
, optBaseHeaderLevel = 1
|
, optBaseHeaderLevel = 1
|
||||||
, optTemplate = Nothing
|
, optTemplate = Nothing
|
||||||
, optVariables = []
|
, optVariables = []
|
||||||
|
|
|
@ -565,10 +565,23 @@ isHeaderBlock _ = False
|
||||||
|
|
||||||
-- | Shift header levels up or down.
|
-- | Shift header levels up or down.
|
||||||
headerShift :: Int -> Pandoc -> Pandoc
|
headerShift :: Int -> Pandoc -> Pandoc
|
||||||
headerShift n = walk shift
|
headerShift n (Pandoc meta (Header m _ ils : bs))
|
||||||
where shift :: Block -> Block
|
| n < 0
|
||||||
shift (Header level attr inner) = Header (level + n) attr inner
|
, m + n == 0 = headerShift n $
|
||||||
shift x = x
|
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.
|
-- | Remove empty paragraphs.
|
||||||
stripEmptyParagraphs :: Pandoc -> Pandoc
|
stripEmptyParagraphs :: Pandoc -> Pandoc
|
||||||
|
|
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…
Add table
Reference in a new issue