git.iko.soy/typeable/pandoc
on master help sign in
Org reader: modify handling of example blocks. (#5717)

* Org reader: allow the `-i` switch to ignore leading spaces. * Org reader: handle awkwardly-aligned code blocks within lists. Code blocks in Org lists must have their #+BEGIN_ aligned in a reasonable way, but their other components can be positioned otherwise.

commit0558ea9836f5350a00f3df19d55ca6bddda1947b authorBrian Leung <29217594+leungbk@users.noreply.github.com> dateMon 9 Sep 2019, 07:34 (7 years ago) parent8f5ab97
3 files changed+103−14
src/Text/Pandoc/Readers/Org/Blocks.hs+41−14 src/Text/Pandoc/Readers/Org/ParserState.hs+2 test/command/4186.md+60
src/Text/Pandoc/Readers/Org/Blocks.hs+41−14
@@ -186,7 +186,7 @@ orgBlock = try $ do
186186 "html" -> rawBlockLines (return . B.rawBlock (lowercase blkType))
187187 "latex" -> rawBlockLines (return . B.rawBlock (lowercase blkType))
188188 "ascii" -> rawBlockLines (return . B.rawBlock (lowercase blkType))
189− "example" -> rawBlockLines (return . exampleCode)
189+ "example" -> exampleBlock blockAttrs
190190 "quote" -> parseBlockLines (fmap B.blockQuote)
191191 "verse" -> verseBlock
192192 "src" -> codeBlock blockAttrs
@@ -200,6 +200,16 @@ orgBlock = try $ do
200200 lowercase :: String -> String
201201 lowercase = map toLower
202202
203+exampleBlock :: PandocMonad m => BlockAttributes -> String -> OrgParser m (F Blocks)
204+exampleBlock blockAttrs _label = do
205+ skipSpaces
206+ (classes, kv) <- switchesAsAttributes
207+ newline
208+ content <- rawBlockContent "example"
209+ let id' = fromMaybe mempty $ blockAttrName blockAttrs
210+ let codeBlck = B.codeBlockWith (id', "example":classes, kv) content
211+ return . return $ codeBlck
212+
203213rawBlockLines :: Monad m => (String -> F Blocks) -> String -> OrgParser m (F Blocks)
204214rawBlockLines f blockType = ignHeaders *> (f <$> rawBlockContent blockType)
205215
@@ -216,11 +226,13 @@ rawBlockContent :: Monad m => String -> OrgParser m String
216226rawBlockContent blockType = try $ do
217227 blkLines <- manyTill rawLine blockEnder
218228 tabLen <- getOption readerTabStop
219− return
220− . unlines
221− . stripIndent
222− . map (tabsToSpaces tabLen . commaEscaped)
223− $ blkLines
229+ trimP <- orgStateTrimLeadBlkIndent <$> getState
230+ let stripIndent strs = if trimP then map (drop (shortestIndent strs)) strs else strs
231+ (unlines
232+ . stripIndent
233+ . map (tabsToSpaces tabLen . commaEscaped)
234+ $ blkLines)
235+ <$ updateState (\s -> s { orgStateTrimLeadBlkIndent = True })
224236 where
225237 rawLine :: Monad m => OrgParser m String
226238 rawLine = try $ ("" <$ blankline) <|> anyLine
@@ -228,9 +240,6 @@ rawBlockContent blockType = try $ do
228240 blockEnder :: Monad m => OrgParser m ()
229241 blockEnder = try $ skipSpaces <* stringAnyCase ("#+end_" <> blockType)
230242
231− stripIndent :: [String] -> [String]
232− stripIndent strs = map (drop (shortestIndent strs)) strs
233−
234243 shortestIndent :: [String] -> Int
235244 shortestIndent = foldr (min . length . takeWhile isSpace) maxBound
236245 . filter (not . null)
@@ -357,12 +366,19 @@ switchPolarity = (SwitchMinus <$ char '-') <|> (SwitchPlus <$ char '+')
357366
358367-- | Parses a source block switch option.
359368switch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity)
360−switch = try $ lineNumberSwitch <|> labelSwitch <|> simpleSwitch
369+switch = try $ lineNumberSwitch <|> labelSwitch
370+ <|> whitespaceSwitch <|> simpleSwitch
361371 where
362372 simpleSwitch = (\pol c -> (c, Nothing, pol)) <$> switchPolarity <*> letter
363373 labelSwitch = genericSwitch 'l' $
364374 char '"' *> many1Till nonspaceChar (char '"')
365375
376+whitespaceSwitch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity)
377+whitespaceSwitch = do
378+ string "-i"
379+ updateState $ \s -> s { orgStateTrimLeadBlkIndent = False }
380+ return ('i', Nothing, SwitchMinus)
381+
366382-- | Generic source block switch-option parser.
367383genericSwitch :: Monad m
368384 => Char
@@ -821,11 +837,22 @@ listItem parseIndentedMarker = try . withContext ListItemState $ do
821837
822838-- continuation of a list item - indented and separated by blankline or endline.
823839-- Note: nested lists are parsed as continuations.
824−listContinuation :: Monad m => Int
825− -> OrgParser m String
840+listContinuation :: PandocMonad m => Int -> OrgParser m String
826841listContinuation markerLength = try $ do
827842 notFollowedBy' blankline
828− mappend <$> (concat <$> many1 listLine)
843+ mappend <$> (concat <$> many1 (listContinuation' markerLength))
829844 <*> many blankline
830845 where
831− listLine = try $ indentWith markerLength *> anyLineNewline
846+ listContinuation' indentation =
847+ blockLines indentation <|> listLine indentation
848+ listLine indentation = try $ indentWith indentation *> anyLineNewline
849+ -- The block attributes and start must be appropriately indented,
850+ -- but the contents, and end do not.
851+ blockLines indentation =
852+ try $ lookAhead (indentWith indentation
853+ >> blockAttributes
854+ >>= (\blockAttrs ->
855+ case attrFromBlockAttributes blockAttrs of
856+ ("", [], []) -> count 1 anyChar
857+ _ -> indentWith indentation))
858+ >> (snd <$> withRaw orgBlock)
src/Text/Pandoc/Readers/Org/ParserState.hs+2
@@ -117,6 +117,7 @@ data OrgParserState = OrgParserState
117117 , orgStateSelectTags :: Set.Set Tag
118118 , orgStateSelectTagsChanged :: Bool
119119 , orgStateTodoSequences :: [TodoSequence]
120+ , orgStateTrimLeadBlkIndent :: Bool
120121 , orgLogMessages :: [LogMessage]
121122 , orgMacros :: M.Map Text Macro
122123 }
@@ -184,6 +185,7 @@ defaultOrgParserState = OrgParserState
184185 , orgStateParserContext = NullState
185186 , orgStateSelectTags = Set.singleton $ Tag "export"
186187 , orgStateSelectTagsChanged = False
188+ , orgStateTrimLeadBlkIndent = True
187189 , orgStateTodoSequences = []
188190 , orgLogMessages = []
189191 , orgMacros = M.empty
test/command/4186.mdnew file+60
@@ -0,0 +1,60 @@
1+```
2+% pandoc -f org -t native
3+#+BEGIN_EXAMPLE -i
4+ This should retain the four leading spaces
5+#+END_EXAMPLE
6+^D
7+[CodeBlock ("",["example"],[]) " This should retain the four leading spaces\n"]
8+```
9+
10+```
11+% pandoc -f org -t html
12+- depth 1
13+ #+NAME: bob
14+ #+BEGIN_EXAMPLE -i
15+ Vertical alignment is four spaces beyond the appearance of the word "depth".
16+ #+END_EXAMPLE
17+ - depth 2
18+ #+begin_example
19+ Vertically aligned with the second appearance of the word "depth".
20+ #+end_example
21+ #+begin_example -i
22+ Vertical alignment is four spaces beyond the second
23+ appearance of the word "depth".
24+ The "begin" portion is a component of
25+ this deeper list element, so that guarantees
26+ that the entire block must be a component of the
27+ inner list element.
28+ #+end_example
29+ Still inside the inner list element
30+ #+NAME: carrie
31+ #+BEGIN_EXAMPLE
32+ This belongs to the outer list element, and is aligned accordingly, since the NAME attribute is not indented deeply enough. It is not enough for the BEGIN alone to be aligned deeply if the block is meant to have a NAME.
33+ #+END_EXAMPLE
34+ Still in the shallower list element since the preceding example
35+ block forced the deeper list element to terminate.
36+Outside all lists.
37+^D
38+<ul>
39+<li><p>depth 1</p>
40+<pre id="bob" class="example"><code> Vertical alignment is four spaces beyond the appearance of the word &quot;depth&quot;.
41+</code></pre>
42+<ul>
43+<li><p>depth 2</p>
44+<pre class="example"><code>Vertically aligned with the second appearance of the word &quot;depth&quot;.
45+</code></pre>
46+<pre class="example"><code> Vertical alignment is four spaces beyond the second
47+ appearance of the word &quot;depth&quot;.
48+ The &quot;begin&quot; portion is a component of
49+ this deeper list element, so that guarantees
50+ that the entire block must be a component of the
51+ inner list element.
52+</code></pre>
53+<p>Still inside the inner list element</p></li>
54+</ul>
55+<pre id="carrie" class="example"><code>This belongs to the outer list element, and is aligned accordingly, since the NAME attribute is not indented deeply enough. It is not enough for the BEGIN alone to be aligned deeply if the block is meant to have a NAME.
56+</code></pre>
57+<p>Still in the shallower list element since the preceding example block forced the deeper list element to terminate.</p></li>
58+</ul>
59+<p>Outside all lists.</p>
60+```