git.iko.soy/typeable/pandoc
on master help sign in
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.

commit88dc6fac5d2d6f494e9c334261ecb40d3e156667 authorJohn MacFarlane <jgm@berkeley.edu> dateTue 10 Sep 2019, 23:16 (7 years ago) parenta64b3ab
6 files changed+88−7
MANUAL.txt+18−1 src/Text/Pandoc/App.hs+3 src/Text/Pandoc/App/CommandLineOptions.hs+15−2 src/Text/Pandoc/App/Opt.hs+2 src/Text/Pandoc/Shared.hs+17−4 test/command/shift-heading-level-by.md+33
MANUAL.txt+18−1
@@ -479,9 +479,26 @@ General options {.options}
479479Reader options {.options}
480480--------------
481481
482+`--shift-heading-level-by=`*NUMBER*
483+
484+ Shift heading levels by a positive or negative integer.
485+ For example, with `--shift-heading-level-by=-1`, level 2
486+ headings become level 1 headings, and level 3 headings
487+ become level 2 headings. Headings cannot have a level
488+ less than 1, so a heading that would be shifted below level 1
489+ becomes a regular paragraph. Exception: with a shift of -1,
490+ a level-1 heading at the beginning of the document
491+ replaces the metadata title. Conversely, with a shift
492+ of +1, a nonempty metadata title becomes a level-1 heading at
493+ the beginning of the document. `--shift-heading-level-by=-1`
494+ is a good choice when converting HTML or Markdown documents that
495+ use an initial level-1 heading for the document title and
496+ level-2+ headings for sections.
497+
482498`--base-header-level=`*NUMBER*
483499
484−: Specify the base level for headings (defaults to 1).
500+: *Deprecated. Use `--shift-heading-level-by` instead.*
501+ Specify the base level for headings (defaults to 1).
485502
486503`--strip-empty-paragraphs`
487504
src/Text/Pandoc/App.hs+3
@@ -241,6 +241,9 @@ convertWithOpts opts = do
241241 let transforms = (case optBaseHeaderLevel opts of
242242 x | x > 1 -> (headerShift (x - 1) :)
243243 | otherwise -> id) .
244+ (case optShiftHeadingLevel opts of
245+ 0 -> id
246+ x -> (headerShift x :)) .
244247 (if optStripEmptyParagraphs opts
245248 then (stripEmptyParagraphs :)
246249 else id) .
src/Text/Pandoc/App/CommandLineOptions.hs+15−2
@@ -436,9 +436,22 @@ options =
436436 "SCRIPTPATH")
437437 "" -- "Lua filter"
438438
439− , Option "" ["base-header-level"]
439+ , Option "" ["shift-heading-level-by"]
440440 (ReqArg
441441 (\arg opt ->
442+ case safeRead arg of
443+ Just t ->
444+ return opt{ optShiftHeadingLevel = t }
445+ _ -> E.throwIO $ PandocOptionError
446+ "shift-heading-level-by takes an integer argument")
447+ "NUMBER")
448+ "" -- "Shift heading level"
449+
450+ , Option "" ["base-header-level"]
451+ (ReqArg
452+ (\arg opt -> do
453+ deprecatedOption "--base-header-level"
454+ "Use --shift-heading-level-by instead."
442455 case safeRead arg of
443456 Just t | t > 0 && t < 6 ->
444457 return opt{ optBaseHeaderLevel = t }
@@ -450,7 +463,7 @@ options =
450463 , Option "" ["strip-empty-paragraphs"]
451464 (NoArg
452465 (\opt -> do
453− deprecatedOption "--stripEmptyParagraphs"
466+ deprecatedOption "--strip-empty-paragraphs"
454467 "Use +empty_paragraphs extension."
455468 return opt{ optStripEmptyParagraphs = True }))
456469 "" -- "Strip empty paragraphs"
src/Text/Pandoc/App/Opt.hs+2
@@ -50,6 +50,7 @@ data Opt = Opt
5050 , optReader :: Maybe String -- ^ Reader format
5151 , optWriter :: Maybe String -- ^ Writer format
5252 , optTableOfContents :: Bool -- ^ Include table of contents
53+ , optShiftHeadingLevel :: Int -- ^ Shift heading level by
5354 , optBaseHeaderLevel :: Int -- ^ Base header level
5455 , optTemplate :: Maybe FilePath -- ^ Custom template
5556 , optVariables :: [(String,String)] -- ^ Template variables to set
@@ -124,6 +125,7 @@ defaultOpts = Opt
124125 , optReader = Nothing
125126 , optWriter = Nothing
126127 , optTableOfContents = False
128+ , optShiftHeadingLevel = 0
127129 , optBaseHeaderLevel = 1
128130 , optTemplate = Nothing
129131 , optVariables = []
src/Text/Pandoc/Shared.hs+17−4
@@ -565,10 +565,23 @@ isHeaderBlock _ = False
565565
566566-- | Shift header levels up or down.
567567headerShift :: Int -> Pandoc -> Pandoc
568−headerShift n = walk shift
569− where shift :: Block -> Block
570− shift (Header level attr inner) = Header (level + n) attr inner
571− shift x = x
568+headerShift n (Pandoc meta (Header m _ ils : bs))
569+ | n < 0
570+ , m + n == 0 = headerShift n $
571+ B.setTitle (B.fromList ils) $ Pandoc meta bs
572+headerShift n (Pandoc meta bs)
573+ | n > 0
574+ , not (null (docTitle meta))
575+ = Pandoc meta' (Header n nullAttr (docTitle meta) : bs')
576+ where
577+ Pandoc meta' bs' = headerShift n $ B.deleteMeta "title" $ Pandoc meta bs
578+headerShift n (Pandoc meta bs) = Pandoc meta (walk shift bs)
579+ where
580+ shift :: Block -> Block
581+ shift (Header level attr inner)
582+ | level + n > 0 = Header (level + n) attr inner
583+ | otherwise = Para inner
584+ shift x = x
572585
573586-- | Remove empty paragraphs.
574587stripEmptyParagraphs :: Pandoc -> Pandoc
test/command/shift-heading-level-by.mdnew file+33
@@ -0,0 +1,33 @@
1+```
2+% pandoc --shift-heading-level-by 1 -t native -s
3+---
4+title: My title
5+...
6+
7+# First heading
8+
9+## Second
10+^D
11+Pandoc (Meta {unMeta = fromList []})
12+[Header 1 ("",[],[]) [Str "My",Space,Str "title"]
13+,Header 2 ("first-heading",[],[]) [Str "First",Space,Str "heading"]
14+,Header 3 ("second",[],[]) [Str "Second"]]
15+```
16+
17+```
18+% pandoc --shift-heading-level-by -1 -t native -s
19+---
20+title: Old title
21+...
22+
23+# First heading
24+
25+## Second
26+
27+# Another top-level heading
28+^D
29+Pandoc (Meta {unMeta = fromList [("title",MetaInlines [Str "First",Space,Str "heading"])]})
30+[Header 1 ("second",[],[]) [Str "Second"]
31+,Para [Str "Another",Space,Str "top-level",Space,Str "heading"]]
32+```
33+