From 0558ea9836f5350a00f3df19d55ca6bddda1947b Mon Sep 17 00:00:00 2001 From: Brian Leung <29217594+leungbk@users.noreply.github.com> Date: Mon, 9 Sep 2019 07:34:10 +0200 Subject: 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. --- src/Text/Pandoc/Readers/Org/Blocks.hs | 55 ++++++++++++++++++++++-------- src/Text/Pandoc/Readers/Org/ParserState.hs | 2 ++ 2 files changed, 43 insertions(+), 14 deletions(-) (limited to 'src/Text/Pandoc') diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs index 8ee9c025d..cba876f06 100644 --- a/src/Text/Pandoc/Readers/Org/Blocks.hs +++ b/src/Text/Pandoc/Readers/Org/Blocks.hs @@ -186,7 +186,7 @@ orgBlock = try $ do "html" -> rawBlockLines (return . B.rawBlock (lowercase blkType)) "latex" -> rawBlockLines (return . B.rawBlock (lowercase blkType)) "ascii" -> rawBlockLines (return . B.rawBlock (lowercase blkType)) - "example" -> rawBlockLines (return . exampleCode) + "example" -> exampleBlock blockAttrs "quote" -> parseBlockLines (fmap B.blockQuote) "verse" -> verseBlock "src" -> codeBlock blockAttrs @@ -200,6 +200,16 @@ orgBlock = try $ do lowercase :: String -> String lowercase = map toLower +exampleBlock :: PandocMonad m => BlockAttributes -> String -> OrgParser m (F Blocks) +exampleBlock blockAttrs _label = do + skipSpaces + (classes, kv) <- switchesAsAttributes + newline + content <- rawBlockContent "example" + let id' = fromMaybe mempty $ blockAttrName blockAttrs + let codeBlck = B.codeBlockWith (id', "example":classes, kv) content + return . return $ codeBlck + rawBlockLines :: Monad m => (String -> F Blocks) -> String -> OrgParser m (F Blocks) rawBlockLines f blockType = ignHeaders *> (f <$> rawBlockContent blockType) @@ -216,11 +226,13 @@ rawBlockContent :: Monad m => String -> OrgParser m String rawBlockContent blockType = try $ do blkLines <- manyTill rawLine blockEnder tabLen <- getOption readerTabStop - return - . unlines - . stripIndent - . map (tabsToSpaces tabLen . commaEscaped) - $ blkLines + trimP <- orgStateTrimLeadBlkIndent <$> getState + let stripIndent strs = if trimP then map (drop (shortestIndent strs)) strs else strs + (unlines + . stripIndent + . map (tabsToSpaces tabLen . commaEscaped) + $ blkLines) + <$ updateState (\s -> s { orgStateTrimLeadBlkIndent = True }) where rawLine :: Monad m => OrgParser m String rawLine = try $ ("" <$ blankline) <|> anyLine @@ -228,9 +240,6 @@ rawBlockContent blockType = try $ do blockEnder :: Monad m => OrgParser m () blockEnder = try $ skipSpaces <* stringAnyCase ("#+end_" <> blockType) - stripIndent :: [String] -> [String] - stripIndent strs = map (drop (shortestIndent strs)) strs - shortestIndent :: [String] -> Int shortestIndent = foldr (min . length . takeWhile isSpace) maxBound . filter (not . null) @@ -357,12 +366,19 @@ switchPolarity = (SwitchMinus <$ char '-') <|> (SwitchPlus <$ char '+') -- | Parses a source block switch option. switch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity) -switch = try $ lineNumberSwitch <|> labelSwitch <|> simpleSwitch +switch = try $ lineNumberSwitch <|> labelSwitch + <|> whitespaceSwitch <|> simpleSwitch where simpleSwitch = (\pol c -> (c, Nothing, pol)) <$> switchPolarity <*> letter labelSwitch = genericSwitch 'l' $ char '"' *> many1Till nonspaceChar (char '"') +whitespaceSwitch :: Monad m => OrgParser m (Char, Maybe String, SwitchPolarity) +whitespaceSwitch = do + string "-i" + updateState $ \s -> s { orgStateTrimLeadBlkIndent = False } + return ('i', Nothing, SwitchMinus) + -- | Generic source block switch-option parser. genericSwitch :: Monad m => Char @@ -821,11 +837,22 @@ listItem parseIndentedMarker = try . withContext ListItemState $ do -- continuation of a list item - indented and separated by blankline or endline. -- Note: nested lists are parsed as continuations. -listContinuation :: Monad m => Int - -> OrgParser m String +listContinuation :: PandocMonad m => Int -> OrgParser m String listContinuation markerLength = try $ do notFollowedBy' blankline - mappend <$> (concat <$> many1 listLine) + mappend <$> (concat <$> many1 (listContinuation' markerLength)) <*> many blankline where - listLine = try $ indentWith markerLength *> anyLineNewline + listContinuation' indentation = + blockLines indentation <|> listLine indentation + listLine indentation = try $ indentWith indentation *> anyLineNewline + -- The block attributes and start must be appropriately indented, + -- but the contents, and end do not. + blockLines indentation = + try $ lookAhead (indentWith indentation + >> blockAttributes + >>= (\blockAttrs -> + case attrFromBlockAttributes blockAttrs of + ("", [], []) -> count 1 anyChar + _ -> indentWith indentation)) + >> (snd <$> withRaw orgBlock) diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs index 374741893..d6dde8b22 100644 --- a/src/Text/Pandoc/Readers/Org/ParserState.hs +++ b/src/Text/Pandoc/Readers/Org/ParserState.hs @@ -117,6 +117,7 @@ data OrgParserState = OrgParserState , orgStateSelectTags :: Set.Set Tag , orgStateSelectTagsChanged :: Bool , orgStateTodoSequences :: [TodoSequence] + , orgStateTrimLeadBlkIndent :: Bool , orgLogMessages :: [LogMessage] , orgMacros :: M.Map Text Macro } @@ -184,6 +185,7 @@ defaultOrgParserState = OrgParserState , orgStateParserContext = NullState , orgStateSelectTags = Set.singleton $ Tag "export" , orgStateSelectTagsChanged = False + , orgStateTrimLeadBlkIndent = True , orgStateTodoSequences = [] , orgLogMessages = [] , orgMacros = M.empty -- cgit v1.2.3