]> gitweb @ CieloNegro.org - Rakka.git/commitdiff
Implemented the outline command
authorpho <pho@cielonegro.org>
Tue, 23 Oct 2007 04:46:06 +0000 (13:46 +0900)
committerpho <pho@cielonegro.org>
Tue, 23 Oct 2007 04:46:06 +0000 (13:46 +0900)
darcs-hash:20071023044606-62b54-798c82617b3664c234c6abba6908bbc8f5b98642.gz

15 files changed:
.boring
Main.hs
Rakka.cabal
Rakka/Environment.hs
Rakka/Resource/Render.hs
Rakka/SystemConfig.hs
Rakka/Utils.hs
Rakka/Wiki.hs
Rakka/Wiki/Engine.hs
Rakka/Wiki/Formatter.hs
Rakka/Wiki/Interpreter.hs
Rakka/Wiki/Interpreter/Base.hs
Rakka/Wiki/Interpreter/Base/Outline.hs [new file with mode: 0644]
defaultPages/SideBar/Left
defaultPages/StyleSheet/Default

diff --git a/.boring b/.boring
index d545fc24259110adea012442c37bbeb9cf801cca..0a5b28a5da72eaa6824c05dca00a25a9ea942898 100644 (file)
--- a/.boring
+++ b/.boring
@@ -54,3 +54,4 @@
 ^Setup$
 ^configure$
 ^dist(/|$)
+^repos(/|$)
diff --git a/Main.hs b/Main.hs
index 1b441ee2725d5b2678e1b944722746f371b9d837..44855689c7c26baefd9f2d55f73bbdc94a6040f6 100644 (file)
--- a/Main.hs
+++ b/Main.hs
@@ -7,6 +7,7 @@ import           Rakka.Environment
 import           Rakka.Resource.Index
 import           Rakka.Resource.Object
 import           Rakka.Resource.Render
+import           Subversion
 import           System.Console.GetOpt
 import           System.Directory
 import           System.Environment
@@ -69,7 +70,8 @@ printUsage = do putStrLn "Usage:"
 
 
 main :: IO ()
-main = do (opts, nonOpts, errors) <- return . getOpt Permute options =<< getArgs
+main = withSubversion $
+       do (opts, nonOpts, errors) <- return . getOpt Permute options =<< getArgs
 
           when (not $ null errors)
                    $ do mapM_ putStr errors
index efc767ae5e0cef1ece3a5a5302b900e3b6697c86..844381b4a15aa5bfc8159ee1baf4aef5fb35f01e 100644 (file)
@@ -26,7 +26,7 @@ GHC-Options:
     -fwarn-unused-imports -fglasgow-exts
 Build-Depends:
     Crypto, HUnit, HsSVN, Lucu, base, encoding, filepath, hxt, mtl,
-    network, parsec, unix
+    network, parsec, stm, unix
 Exposed-Modules:
     Rakka.Page
     Rakka.Storage
@@ -60,6 +60,7 @@ Other-Modules:
     Rakka.Resource.Render
     Rakka.Wiki.Interpreter.Base
     Rakka.Wiki.Interpreter.Base.Image
+    Rakka.Wiki.Interpreter.Base.Outline
     Rakka.Wiki.Engine
     Rakka.Wiki.Formatter
     Rakka.Wiki.Parser
index d68892b61590336f7e78c22f6dc5836cb35a5f63..b554df8215e4f7ecf23ba93a073031e79f73c56b 100644 (file)
@@ -7,8 +7,8 @@ module Rakka.Environment
     )
     where
 
+import           Control.Concurrent.STM
 import           Control.Arrow.ArrowIO
-import           Data.IORef
 import           Data.Map (Map)
 import qualified Data.Map as M
 import           Network
@@ -17,14 +17,18 @@ import           Rakka.Storage
 import           Rakka.SystemConfig
 import           Rakka.Wiki.Interpreter
 import           Rakka.Wiki.Interpreter.Base
+import           Subversion.Repository
+import           System.Directory
+import           System.FilePath
 
 
 data Environment = Environment {
       envLocalStateDir :: !FilePath
     , envLucuConf      :: !LC.Config
+    , envRepository    :: !Repository
     , envStorage       :: !Storage
     , envSysConf       :: !SystemConfig
-    , envInterpTable   :: !(IORef InterpTable)
+    , envInterpTable   :: !(TVar InterpTable)
     }
 
 
@@ -33,23 +37,32 @@ type InterpTable = Map String Interpreter
 
 setupEnv :: FilePath -> PortNumber -> IO Environment
 setupEnv lsdir portNum
-    = do let lucuConf = LC.defaultConfig {
-                          LC.cnfServerPort = PortNumber portNum
-                        }
-             storage  = mkStorage
-             sysConf  = mkSystemConfig lucuConf
+    = do let lucuConf  = LC.defaultConfig {
+                           LC.cnfServerPort = PortNumber portNum
+                         }
+             reposPath = lsdir `combine` "repos"
+             storage   = mkStorage
+         
+         reposExist  <- doesDirectoryExist reposPath
+         repos       <- if reposExist then
+                            openRepository reposPath
+                        else
+                            createRepository reposPath [] []
+         sysConf     <- mkSystemConfig lucuConf repos
          interpTable <- mkInterpTable
+
          return $ Environment {
                       envLocalStateDir = lsdir
                     , envLucuConf      = lucuConf
+                    , envRepository    = repos
                     , envStorage       = storage
                     , envSysConf       = sysConf
                     , envInterpTable   = interpTable
                     }
 
 
-mkInterpTable :: IO (IORef InterpTable)
-mkInterpTable = newIORef (listToTable baseInterpreters)
+mkInterpTable :: IO (TVar InterpTable)
+mkInterpTable = newTVarIO (listToTable baseInterpreters)
     where
       listToTable :: [Interpreter] -> InterpTable
       listToTable xs
@@ -57,7 +70,7 @@ mkInterpTable = newIORef (listToTable baseInterpreters)
 
 
 getInterpTable :: Environment -> IO InterpTable
-getInterpTable = readIORef . envInterpTable
+getInterpTable = atomically . readTVar . envInterpTable
 
 
 getInterpTableA :: ArrowIO a => Environment -> a b InterpTable
index df141b13ee2445db2df690fb8094ca54427c520a..698e789e7467c1ce86fc6b6a0f4c99686f9095c0 100644 (file)
@@ -155,20 +155,20 @@ handleGetEntity env
                                             | (lang, page) <- xs ]
                             )
                          += ( eelem "pageTitle"
-                              += ( (constA (pageName page) &&& constA pageTitle)
+                              += ( (constA (pageName page) &&& constA (Just page) &&& constA pageTitle)
                                    >>>
                                    formatSubPage env
                                  )
                             )
                          += ( eelem "sideBar"
                               += ( eelem "left"
-                                   += ( (constA (pageName page) &&& constA leftSideBar)
+                                   += ( (constA (pageName page) &&& constA (Just page) &&& constA leftSideBar)
                                         >>>
                                         formatSubPage env
                                       )
                                  )
                               += ( eelem "right"
-                                   += ( (constA (pageName page) &&& constA rightSideBar)
+                                   += ( (constA (pageName page) &&& constA (Just page) &&& constA rightSideBar)
                                         >>>
                                         formatSubPage env
                                       )
@@ -293,20 +293,20 @@ handlePageNotFound env
                          += sattr "name"       name
                          
                          += ( eelem "pageTitle"
-                              += ( (constA name &&& constA pageTitle)
+                              += ( (constA name &&& constA Nothing &&& constA pageTitle)
                                    >>>
                                    formatSubPage env
                                  )
                             )
                          += ( eelem "sideBar"
                               += ( eelem "left"
-                                   += ( (constA name &&& constA leftSideBar)
+                                   += ( (constA name &&& constA Nothing &&& constA leftSideBar)
                                         >>>
                                         formatSubPage env
                                       )
                                  )
                               += ( eelem "right"
-                                   += ( (constA name &&& constA rightSideBar)
+                                   += ( (constA name &&& constA Nothing &&& constA rightSideBar)
                                         >>>
                                         formatSubPage env
                                       )
index 423e6c508d88402a9c1df0a2b264e88662bf22e6..8a6be0283914eb5e78b35fee2ec88aec5244986e 100644 (file)
@@ -10,16 +10,30 @@ module Rakka.SystemConfig
     where
 
 import           Control.Arrow.ArrowIO
+import           Control.Concurrent.STM
 import           Control.Monad.Trans
 import qualified Data.ByteString.Char8 as C8
+import           Data.Encoding
+import           Data.Encoding.UTF8
+import           Data.Map (Map)
+import qualified Data.Map as M
 import           Data.Maybe
+import           GHC.Conc (unsafeIOToSTM)
 import           Network
 import qualified Network.HTTP.Lucu.Config as LC
 import           Network.URI
+import           Rakka.Utils
+import           Subversion.FileSystem
+import           Subversion.FileSystem.Revision
+import           Subversion.FileSystem.Root
+import           Subversion.Repository
+import           System.FilePath.Posix
 
 
 data SystemConfig = SystemConfig {
-      scLucuConf :: !LC.Config
+      scLucuConf   :: !LC.Config
+    , scRepository :: !Repository
+    , scCache      :: !(TVar (Map FilePath SysConfValue))
     }
 
 
@@ -28,27 +42,66 @@ data SysConfValue
     | BaseURI URI
     | DefaultPage String
     | StyleSheet String
+    deriving (Eq, Show)
 
 
-mkSystemConfig :: LC.Config -> SystemConfig
-mkSystemConfig = SystemConfig
+mkSystemConfig :: LC.Config -> Repository -> IO SystemConfig
+mkSystemConfig lc repos
+    = do cache <- newTVarIO M.empty
+         return $ SystemConfig {
+                      scLucuConf   = lc
+                    , scRepository = repos
+                    , scCache      = cache
+                    }
 
 
 getSysConf :: MonadIO m => SystemConfig -> SysConfValue -> m SysConfValue
 getSysConf sc key
-    = liftIO $ sysConfDefault sc key -- FIXME
+    = liftIO $
+      atomically $
+      do let path = sysConfPath key
+
+         cache <- readTVar (scCache sc)
+
+         case M.lookup path cache of
+           Just val -> return val
+           Nothing  -> do val <- unsafeIOToSTM (getSysConf' sc key)
+                          writeTVar (scCache sc) (M.insert path val cache)
+                          return val
+
+
+getSysConf' :: SystemConfig -> SysConfValue -> IO SysConfValue
+getSysConf' sc key
+    = do fs    <- getRepositoryFS (scRepository sc)
+         rev   <- getYoungestRev fs
+         value <- withRevision fs rev
+                  $ do let path = fromConfPath (sysConfPath key)
+                       exists <- isFile path
+                       case exists of
+                         True
+                             -> do str <- getFileContentsLBS path
+                                   return $ Just $ chomp $ decodeLazy UTF8 str
+                         False
+                             -> return Nothing
+         case value of
+           Just str -> return $ unmarshalSysConf key str
+           Nothing  -> sysConfDefault sc key
 
 
 getSysConfA :: ArrowIO a => SystemConfig -> SysConfValue -> a b SysConfValue
 getSysConfA = (arrIO0 .) . getSysConf
 
 
+fromConfPath :: FilePath -> FilePath
+fromConfPath = combine "/config"
+
+
 {- paths -}
 sysConfPath :: SysConfValue -> FilePath
-sysConfPath (SiteName    _) = "/siteName"
-sysConfPath (BaseURI     _) = "/baseURI"
-sysConfPath (DefaultPage _) = "/defaultPage"
-sysConfPath (StyleSheet  _) = "/styleSheet"
+sysConfPath (SiteName    _) = "siteName"
+sysConfPath (BaseURI     _) = "baseURI"
+sysConfPath (DefaultPage _) = "defaultPage"
+sysConfPath (StyleSheet  _) = "styleSheet"
 
 
 {- marshalling -}
index e411694477f9c295c94583d2e04b6bcb0309f91a..9f2873c9ae328d626d9679b2ac0c777750c1e50e 100644 (file)
@@ -4,6 +4,7 @@ module Rakka.Utils
     , maybeA
     , deleteIfEmpty
     , formatW3CDateTime
+    , chomp
     )
     where
 
@@ -71,4 +72,8 @@ formatW3CDateTime time
             
       show2 :: Int -> String
       show2 n | n < 10    = '0':(show n)
-              | otherwise = show n
\ No newline at end of file
+              | otherwise = show n
+
+
+chomp :: String -> String
+chomp = reverse . snd . break (/= '\n') . reverse
index f8341ec8506d6069e4a152d4db50371b5bcaee1b..0fcf38a6bca33b31550bb2ddbc8d5d49f37a19e7 100644 (file)
@@ -35,6 +35,7 @@ data BlockElement
     | Preformatted ![InlineElement]
     | Paragraph ![InlineElement]
     | Div ![Attribute] ![BlockElement]
+    | EmptyBlock
     | BlockCmd !BlockCommand
     deriving (Eq, Show, Typeable, Data)
 
@@ -56,6 +57,7 @@ data InlineElement
     | Span ![Attribute] ![InlineElement]
     | Image ![Attribute]
     | Anchor ![Attribute] ![InlineElement]
+    | EmptyInline
     | InlineCmd !InlineCommand
     deriving (Eq, Show, Typeable, Data)
 
index aa897e841e01b6429d9dd9fd1d5d81ebedb9f532..ffaab2f4edf28a9a41b19be39b223be3999d4e8f 100644 (file)
@@ -6,7 +6,6 @@ module Rakka.Wiki.Engine
 
 import           Control.Arrow
 import           Control.Arrow.ArrowIO
-import           Control.Arrow.ArrowTree
 import           Data.Encoding
 import           Data.Encoding.UTF8
 import           Data.Generics
@@ -29,42 +28,47 @@ formatPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
            -> a Page XmlTree
 formatPage env
     = proc page
-    -> do tree <- case pageType page of
-                    MIMEType "text" "x-rakka" _
-                        -> do let source = decodeLazy UTF8 (pageContent page)
-                              formatWikiPage env -< (pageName page, source)
-          attachXHtmlNs -< tree
+    -> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< ()
+          interpTable     <- getInterpTableA env -< ()
+          wiki            <- wikifyPage env -< (interpTable, page)
+          xs              <- interpretCommandsA env -< (interpTable, (pageName page, (Just wiki, wiki)))
+          formatWikiBlocks -< (baseURI, xs)
 
 
 formatSubPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
                  Environment
-              -> a (PageName, Page) XmlTree
+              -> a (PageName, (Maybe Page, Page)) XmlTree
 formatSubPage env
-    = proc (mainPageName, subPage)
-    -> do tree <- case pageType subPage of
-                    MIMEType "text" "x-rakka" _
-                        -> do let source = decodeLazy UTF8 (pageContent subPage)
-                              formatWikiPage env -< (mainPageName, source)
-          attachXHtmlNs -< tree
-
-
-formatWikiPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
-                  Environment
-               -> a (PageName, String) XmlTree
-formatWikiPage env
-    = proc (name, source)
+    = proc (mainPageName, (mainPage, subPage))
     -> do BaseURI baseURI <- getSysConfA (envSysConf env) (BaseURI undefined) -< ()
           interpTable     <- getInterpTableA env -< ()
-
-          let parser = wikiPage (tableToFunc interpTable)
-
-          case parse parser "" source of
-            Left  err
-                -> formatParseError -< err
-
-            Right blocks
-                -> do xs <- interpretCommandsA env -< (interpTable, (name, blocks))
-                      formatWikiBlocks -< (baseURI, xs)
+          mainWiki        <- case mainPage of
+                               Just page
+                                   -> do wiki <- wikifyPage env -< (interpTable, page)
+                                         returnA -< Just wiki
+                               Nothing
+                                   -> returnA -< Nothing
+          subWiki        <- wikifyPage env -< (interpTable, subPage)
+          xs             <- interpretCommandsA env -< (interpTable, (mainPageName, (mainWiki, subWiki)))
+          formatWikiBlocks -< (baseURI, xs)
+
+
+wikifyPage :: (ArrowXml a, ArrowChoice a, ArrowIO a) =>
+                 Environment
+              -> a (InterpTable, Page) WikiPage
+wikifyPage env
+    = proc (interpTable, page)
+    -> case pageType page of
+         MIMEType "text" "x-rakka" _
+             -> do let source = decodeLazy UTF8 (pageContent page)
+                       parser = wikiPage (tableToFunc interpTable)
+
+                   case parse parser "" source of
+                     Left  err
+                         -> wikifyParseError -< err
+
+                     Right xs
+                         -> returnA -< xs
     where
       tableToFunc :: InterpTable -> String -> Maybe CommandType
       tableToFunc table name
@@ -73,22 +77,24 @@ formatWikiPage env
 
 interpretCommandsA :: ArrowIO a =>
                       Environment
-                   -> a (InterpTable, (PageName, WikiPage)) WikiPage
-interpretCommandsA = arrIO3 . interpretCommands
+                   -> a (InterpTable, (PageName, (Maybe WikiPage, WikiPage))) WikiPage
+interpretCommandsA = arrIO4 . interpretCommands
 
 
-interpretCommands :: Environment -> InterpTable -> PageName -> WikiPage -> IO WikiPage
-interpretCommands _   _     _    []     = return []
-interpretCommands env table name blocks = everywhereM' (mkM interpBlockCmd) blocks
-                                          >>=
-                                          everywhereM' (mkM interpInlineCmd)
+interpretCommands :: Environment -> InterpTable -> PageName -> Maybe WikiPage -> WikiPage -> IO WikiPage
+interpretCommands _   _     _    _        []         = return []
+interpretCommands env table name mainTree targetTree
+    = everywhereM' (mkM interpBlockCmd) targetTree
+      >>=
+      everywhereM' (mkM interpInlineCmd)
     where
       ctx :: InterpreterContext
       ctx = InterpreterContext {
-              ctxPageName = name
-            , ctxTree     = blocks
-            , ctxStorage  = envStorage env
-            , ctxSysConf  = envSysConf env
+              ctxPageName   = name
+            , ctxMainTree   = mainTree
+            , ctxTargetTree = targetTree
+            , ctxStorage    = envStorage env
+            , ctxSysConf    = envSysConf env
             }
 
       interpBlockCmd :: BlockElement -> IO BlockElement
@@ -124,16 +130,6 @@ everywhereM' :: Monad m => GenericM m -> GenericM m
 everywhereM' f x = f x >>= gmapM (everywhereM' f)
 
 
-formatParseError :: ArrowXml a => a ParseError XmlTree
-formatParseError 
-    = proc err -> (eelem "pre" += txt (show err)) -<< ()
-
-
-attachXHtmlNs :: ArrowXml a => a XmlTree XmlTree
-attachXHtmlNs = processBottomUp (changeQName attach')
-    where
-      attach' :: QName -> QName
-      attach' qn = qn {
-                     namePrefix   = "xhtml"
-                   , namespaceUri = "http://www.w3.org/1999/xhtml"
-                   }
+wikifyParseError :: ArrowXml a => a ParseError WikiPage
+wikifyParseError 
+    = proc err -> returnA -< [Preformatted [Text (show err)]]
index a08fe304ff74385cfe66f19cdd8e73d6edece596..b81c510594f75253678f9dfc7995899e627615c5 100644 (file)
@@ -5,6 +5,7 @@ module Rakka.Wiki.Formatter
 
 import           Control.Arrow
 import           Control.Arrow.ArrowList
+import           Control.Arrow.ArrowTree
 import           Data.Char
 import           Data.List
 import           Data.Maybe
@@ -18,8 +19,9 @@ import           Text.XML.HXT.DOM.TypeDefs
 formatWikiBlocks :: (ArrowXml a, ArrowChoice a) => a (URI, [BlockElement]) XmlTree
 formatWikiBlocks
     = proc (baseURI, blocks)
-    -> do block <- arrL id -< blocks
-          formatBlock -< (baseURI, block)
+    -> do block   <- arrL id     -< blocks
+          tree    <- formatBlock -< (baseURI, block)
+          attachXHtmlNs -< tree
 
 
 formatBlock :: (ArrowXml a, ArrowChoice a) => a (URI, BlockElement) XmlTree
@@ -46,6 +48,9 @@ formatBlock
 
          Div attrs contents
              -> formatElem "div" -< (baseURI, attrs, contents)
+
+         EmptyBlock
+             -> none -< ()
     where
       formatElem :: (ArrowXml a, ArrowChoice a) =>
                     String
@@ -178,6 +183,9 @@ formatInline
 
          Anchor attrs contents
              -> formatElem "a" -< (baseURI, attrs, contents)
+
+         EmptyInline
+             -> none -< ()
     where
       formatElem :: (ArrowXml a, ArrowChoice a) =>
                     String
@@ -229,3 +237,13 @@ formatExternalLink
            += attr "href" (arr fst >>> mkText)
            += (arr snd >>> mkText)
          ) -< (href, label)
+
+
+attachXHtmlNs :: ArrowXml a => a XmlTree XmlTree
+attachXHtmlNs = processBottomUp (changeQName attach')
+    where
+      attach' :: QName -> QName
+      attach' qn = qn {
+                     namePrefix   = "xhtml"
+                   , namespaceUri = "http://www.w3.org/1999/xhtml"
+                   }
index 2a830b36de093415a7a74ce84d68ab24de859d1a..1bf10ccc195ee495777aec363471bf06747a8d03 100644 (file)
@@ -26,10 +26,11 @@ data Interpreter
 
 data InterpreterContext
     = InterpreterContext {
-        ctxPageName :: !PageName
-      , ctxTree     :: !WikiPage
-      , ctxStorage  :: !Storage
-      , ctxSysConf  :: !SystemConfig
+        ctxPageName   :: !PageName
+      , ctxMainTree   :: !(Maybe WikiPage)
+      , ctxTargetTree :: !WikiPage
+      , ctxStorage    :: !Storage
+      , ctxSysConf    :: !SystemConfig
       }
 
 
index c749589609eeb66cc9a891e795c19bd0be101157..f2fd602fe791e9c02e4bad41a09ea08509b97178 100644 (file)
@@ -6,6 +6,7 @@ module Rakka.Wiki.Interpreter.Base
 import           Rakka.Wiki
 import           Rakka.Wiki.Interpreter
 import           Rakka.Wiki.Interpreter.Base.Image
+import           Rakka.Wiki.Interpreter.Base.Outline
 
 
 baseInterpreters :: [Interpreter]
@@ -16,6 +17,7 @@ baseInterpreters = [ lineBreakInterp
                    , imgFrameInterp
 
                    , pageNameInterp
+                   , outlineInterp
                    ]
 
 
@@ -48,4 +50,4 @@ pageNameInterp = InlineCommandInterpreter {
                    iciName      = "pageName"
                  , iciInterpret
                      = \ ctx _ -> return $ Text (ctxPageName ctx)
-                 }
\ No newline at end of file
+                 }
diff --git a/Rakka/Wiki/Interpreter/Base/Outline.hs b/Rakka/Wiki/Interpreter/Base/Outline.hs
new file mode 100644 (file)
index 0000000..d0e21ab
--- /dev/null
@@ -0,0 +1,76 @@
+module Rakka.Wiki.Interpreter.Base.Outline
+    ( outlineInterp
+    )
+    where
+
+import           Data.Generics
+import           Rakka.Wiki
+import           Rakka.Wiki.Interpreter
+
+
+outlineInterp :: Interpreter
+outlineInterp = BlockCommandInterpreter {
+                  bciName      = "outline"
+                , bciInterpret
+                    = \ ctx _ ->
+                      case ctxMainTree ctx of
+                        Just tree -> return $ Div [("class", "outline")] [List $ mkOutline tree]
+                        Nothing   -> return EmptyBlock
+                }
+
+
+mkOutline :: WikiPage -> ListElement
+mkOutline tree
+    = let headings = listify query tree
+      in
+        fst (mkOutline' emptyOutline 1 headings)
+
+
+query :: Typeable a => a -> Bool
+query = mkQ False $ \ x -> case x of
+                             Heading _ _ -> True
+                             _           -> False
+
+
+emptyOutline :: ListElement
+emptyOutline = ListElement Bullet []
+
+                                   
+mkOutline' :: ListElement -> Int -> [BlockElement] -> (ListElement, [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 = [Right 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
+                                     []   -> [Left nested]
+                                     i:[] -> i ++ [Left nested]
+
+                       soFar' = soFar { listItems = nonLastItems ++ [lastItem'] }
+                   in
+                     mkOutline' soFar' level ys
index 9b3a18df3e3658e0eca2479c44d22fc75a3daec0..d03ad83ea7c5d456c42d4db270bcf962e670d772 100644 (file)
@@ -4,6 +4,7 @@
       isBoring="yes">
   <textData><![CDATA[
 = Outline =
+<outline />
 
 = Menu =
 
index bd566ef9130cc5e02fc4fb31bb91f0916099142c..0c324b5b421eca674d7a62f4197e3eaec576cfd8 100644 (file)
@@ -4,14 +4,13 @@
       isBoring="yes"
       isTheme="yes">
   <textData>
-/* global configuration */
+/* global configuration ********************************************************/
 * {
     padding: 0;
     margin: 0;
 }
 
-/* layout */
-
+/* layout **********************************************************************/
 .center {
     position: absolute;
     
@@ -58,7 +57,7 @@
     overflow: auto;
 }
 
-/* spacing */
+/* spacing *********************************************************************/
 .title {
     padding: 5px 20px;
 }
@@ -77,7 +76,7 @@
 
 .body ul, .body ol {
     list-style-position: inside;
-    margin: 1em 0;
+    margin: 0 0 0.8em 0;
 }
 .body ul ul, .body ul ol, .body ol ul, .body ol ol {
     margin: 0;
 .sideBar ul, .sideBar ol {
     list-style-type: none;
     margin-top: 0.4em;
+    margin-bottom: 0.4em;
 }
 
 .sideBar li + li {
     margin-top: 1.2em;
 }
 
-/* color and text */
+/* color and text **************************************************************/
 * {
     font-family: sans-serif;
 }
@@ -220,29 +220,35 @@ a {
 }
 
 .sideBar .outline li {
-    list-style-type: circle;
+    list-style-type: disc;
     margin-left: 1em;
     
     padding: 0;
-    background-color: black;
+    line-height: 1.0;
 }
 .sideBar .outline li li {
-    list-style-type: disc;
+    list-style-type: circle;
 }
 .sideBar .outline li li li {
     list-style-type: square;
 }
+.sideBar .outline li li li li {
+    list-style-type: disc;
+}
+.sideBar .outline li li li li li {
+    list-style-type: circle;
+}
 
 p {
     margin: 0 0 0.8em 0;
 }
 
-/* float */
+/* float ***********************************************************************/
 h1, h2, h3, h4, h5, h6 {
     clear: both;
 }
 
-/* image */
+/* image ***********************************************************************/
 img {
     border-width: 0;
 }