git.iko.soy/typeable/pandoc
on master help sign in
Add --shift-heading-level-by option.
88dc6faJohn MacFarlane
MANUAL.txt+18−1
@@ -479,9 +479,26 @@ General options {.options}
479Reader options {.options}
479Reader options {.options}
480--------------
480--------------
481
481
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+
482`--base-header-level=`*NUMBER*
498`--base-header-level=`*NUMBER*
483
499
500+: *Deprecated. Use `--shift-heading-level-by` instead.*
484−: Specify the base level for headings (defaults to 1).
501+ Specify the base level for headings (defaults to 1).
485
502
486`--strip-empty-paragraphs`
503`--strip-empty-paragraphs`
487
504
src/Text/Pandoc/App.hs+3
@@ -241,6 +241,9 @@ convertWithOpts opts = do
241 let transforms = (case optBaseHeaderLevel opts of
241 let transforms = (case optBaseHeaderLevel opts of
242 x | x > 1 -> (headerShift (x - 1) :)
242 x | x > 1 -> (headerShift (x - 1) :)
243 | otherwise -> id) .
243 | otherwise -> id) .
244+ (case optShiftHeadingLevel opts of
245+ 0 -> id
246+ x -> (headerShift x :)) .
244 (if optStripEmptyParagraphs opts
247 (if optStripEmptyParagraphs opts
245 then (stripEmptyParagraphs :)
248 then (stripEmptyParagraphs :)
246 else id) .
249 else id) .
src/Text/Pandoc/App/CommandLineOptions.hs+15−2
@@ -436,9 +436,22 @@ options =
436 "SCRIPTPATH")
436 "SCRIPTPATH")
437 "" -- "Lua filter"
437 "" -- "Lua filter"
438
438
439− , Option "" ["base-header-level"]
439+ , Option "" ["shift-heading-level-by"]
440 (ReqArg
440 (ReqArg
441 (\arg opt ->
441 (\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."
442 case safeRead arg of
455 case safeRead arg of
443 Just t | t > 0 && t < 6 ->
456 Just t | t > 0 && t < 6 ->
444 return opt{ optBaseHeaderLevel = t }
457 return opt{ optBaseHeaderLevel = t }
@@ -450,7 +463,7 @@ options =
450 , Option "" ["strip-empty-paragraphs"]
463 , Option "" ["strip-empty-paragraphs"]
451 (NoArg
464 (NoArg
452 (\opt -> do
465 (\opt -> do
453− deprecatedOption "--stripEmptyParagraphs"
466+ deprecatedOption "--strip-empty-paragraphs"
454 "Use +empty_paragraphs extension."
467 "Use +empty_paragraphs extension."
455 return opt{ optStripEmptyParagraphs = True }))
468 return opt{ optStripEmptyParagraphs = True }))
456 "" -- "Strip empty paragraphs"
469 "" -- "Strip empty paragraphs"
src/Text/Pandoc/App/Opt.hs+2
@@ -50,6 +50,7 @@ data Opt = Opt
50 , optReader :: Maybe String -- ^ Reader format
50 , optReader :: Maybe String -- ^ Reader format
51 , optWriter :: Maybe String -- ^ Writer format
51 , optWriter :: Maybe String -- ^ Writer format
52 , optTableOfContents :: Bool -- ^ Include table of contents
52 , optTableOfContents :: Bool -- ^ Include table of contents
53+ , optShiftHeadingLevel :: Int -- ^ Shift heading level by
53 , optBaseHeaderLevel :: Int -- ^ Base header level
54 , optBaseHeaderLevel :: Int -- ^ Base header level
54 , optTemplate :: Maybe FilePath -- ^ Custom template
55 , optTemplate :: Maybe FilePath -- ^ Custom template
55 , optVariables :: [(String,String)] -- ^ Template variables to set
56 , optVariables :: [(String,String)] -- ^ Template variables to set
@@ -124,6 +125,7 @@ defaultOpts = Opt
124 , optReader = Nothing
125 , optReader = Nothing
125 , optWriter = Nothing
126 , optWriter = Nothing
126 , optTableOfContents = False
127 , optTableOfContents = False
128+ , optShiftHeadingLevel = 0
127 , optBaseHeaderLevel = 1
129 , optBaseHeaderLevel = 1
128 , optTemplate = Nothing
130 , optTemplate = Nothing
129 , optVariables = []
131 , optVariables = []
src/Text/Pandoc/Shared.hs+17−4
@@ -565,10 +565,23 @@ isHeaderBlock _ = False
565
565
566-- | Shift header levels up or down.
566-- | Shift header levels up or down.
567headerShift :: Int -> Pandoc -> Pandoc
567headerShift :: Int -> Pandoc -> Pandoc
568−headerShift n = walk shift
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
569− where shift :: Block -> Block
580+ shift :: Block -> Block
570− shift (Header level attr inner) = Header (level + n) attr inner
581+ shift (Header level attr inner)
582+ | level + n > 0 = Header (level + n) attr inner
583+ | otherwise = Para inner
571− shift x = x
584+ shift x = x
572
585
573-- | Remove empty paragraphs.
586-- | Remove empty paragraphs.
574stripEmptyParagraphs :: Pandoc -> Pandoc
587stripEmptyParagraphs :: 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+