module Rakka.Wiki.Interpreter.Outline ( interpreters ) where import Data.Maybe import Rakka.Wiki import Rakka.Wiki.Interpreter interpreters :: [Interpreter] interpreters = [ outlineInterp ] outlineInterp :: Interpreter outlineInterp = BlockCommandInterpreter { bciName = "outline" , bciInterpret = \ ctx _ -> case ctxMainWiki ctx of Just tree -> return $ Div [("class", "outline")] [Block $ mkOutline tree] Nothing -> return EmptyBlock } mkOutline :: WikiPage -> BlockElement mkOutline tree = fst (mkOutline' emptyOutline 1 headings) where headings :: [BlockElement] headings = concatMap collectInBlock tree collectInBlock :: BlockElement -> [BlockElement] collectInBlock hd@(Heading _ _) = [hd] collectInBlock (Div _ xs) = concatMap collectInBlock $ catMaybes (map castToBlock xs) collectInBlock (BlockCmd (BlockCommand _ _ xs)) = concatMap collectInBlock xs collectInBlock _ = [] castToBlock :: Element -> Maybe BlockElement castToBlock (Block e) = Just e castToBlock _ = Nothing emptyOutline :: BlockElement emptyOutline = List Bullet [] mkOutline' :: BlockElement -> Int -> [BlockElement] -> (BlockElement, [BlockElement]) mkOutline' soFar _ [] = (soFar, []) mkOutline' soFar level (x:xs) = case x of Heading n text | n == level -- 同じレベルなので soFar に單獨の ListItem を追加して -- 續行。 -> let link = PageLink { linkPage = Nothing , linkFragment = Just text , linkText = Just text } item = [Inline link] in mkOutline' (soFar { listItems = listItems soFar ++ [item] }) n xs | n < level -- 低いレベルなのでここで終了。 -> (soFar, x:xs) | n > level -- 高いレベルなので再帰して ListElement を作り、 -- それを soFar の最後の ListItem に追加する。 -> let (nested, ys) = mkOutline' emptyOutline (level + 1) (x:xs) itemsSoFar = listItems soFar nonLastItems, lastItem :: [ListItem] (nonLastItems, lastItem) = splitAt (length itemsSoFar - 1) itemsSoFar lastItem' :: ListItem lastItem' = case lastItem of [] -> [Block nested] i:[] -> i ++ [Block nested] _ -> undefined soFar' = soFar { listItems = nonLastItems ++ [lastItem'] } in mkOutline' soFar' level ys _ -> undefined