]> git.wincent.com - docvim.git/blob - lib/Docvim/Visitor/Section.hs
Use mapM_ rather than mapM in the Section visitor
[docvim.git] / lib / Docvim / Visitor / Section.hs
1 {-# LANGUAGE FlexibleContexts #-}
2 {-# LANGUAGE TemplateHaskell #-}
3
4 module Docvim.Visitor.Section (getSectionInfo) where
5
6 import Control.Lens
7 import Control.Monad.State
8 import Data.Data.Lens (uniplate)
9 import Docvim.AST
10
11 data SectionInfo = SectionInfo { _hasCommand :: Bool
12                                , _hasCommands :: Bool
13                                , _hasFunction :: Bool
14                                , _hasFunctions :: Bool
15                                , _hasMapping :: Bool
16                                , _hasMappings :: Bool
17                                , _hasOption :: Bool
18                                , _hasOptions :: Bool
19                                } deriving (Show)
20
21 type Env = State SectionInfo
22
23 -- Could also have written record setters by hand, but too lazy to do this:
24 --
25 --     setHasCommand :: SectionInfo -> SectionInfo
26 --     setHasCommand info = info { hasCommand = True }
27 --
28 -- With lenses, we can auto-generate functions that we call like this:
29 --
30 --     view hasCommand info             (reading)
31 --     info ^. hasCommand               (reading, using operator)
32 --     set hasCommand True info         (writing)
33 --     info & hasCommand .~ True        (writing, using operators)
34 --
35 -- Or, given that we are using the State monad here, we'll be using the `.=`
36 -- operator to update the state using a lens.
37 --
38 makeLenses ''SectionInfo
39
40 defaultSectionInfo :: SectionInfo
41 defaultSectionInfo = SectionInfo { _hasCommand = False
42                                  , _hasCommands = False
43                                  , _hasFunction = False
44                                  , _hasFunctions = False
45                                  , _hasMapping = False
46                                  , _hasMappings = False
47                                  , _hasOption = False
48                                  , _hasOptions = False
49                                  }
50
51 -- | Walks the supplied AST detecting whether it contains
52 -- `@commands`/`@command`, `@functions`/`@function`, `@mappings`/`@mapping` or
53 -- `@options`/`@options` sections.
54 --
55 -- Will be used as follows:
56 --   - DO have @commands? -> do nothing
57 --   - DON'T have @commands but DO have @command? -> Synthesize CommandsAnnotation
58 --   - DON'T we have either? -> do nothing
59 --
60 getSectionInfo :: Node -> SectionInfo
61 getSectionInfo n = execState (mapM_ check nodes) defaultSectionInfo
62   where
63     nodes = n ^.. cosmosOf uniplate
64     check (CommandAnnotation {}) = hasCommand .= True
65     check CommandsAnnotation     = hasCommands .= True
66     check (FunctionAnnotation _) = hasFunction .= True
67     check FunctionsAnnotation    = hasFunctions .= True
68     check (MappingAnnotation _)  = hasMapping .= True
69     check MappingsAnnotation     = hasMappings .= True
70     check (OptionAnnotation {})  = hasOption .= True
71     check OptionsAnnotation      = hasOptions .= True
72     check _                      = do
73       state <- get
74       put state