1 {-# LANGUAGE DuplicateRecordFields #-}
2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE FlexibleContexts #-}
4 {-# LANGUAGE MultiParamTypeClasses #-}
5 {-# LANGUAGE OverloadedStrings #-}
6 {-# LANGUAGE ScopedTypeVariables #-}
7 {-# LANGUAGE TypeApplications #-}
8 {-# LANGUAGE ViewPatterns #-}
9 {-# OPTIONS_GHC -fno-warn-orphans #-}
10 -- | Compute an Index for a DTC.
11 module Language.DTC.Index where
13 import Control.Applicative (Applicative(..))
14 import Control.Monad (Monad(..), mapM, forM)
16 import Data.Char (Char)
17 import Data.Default.Class (Default(..))
18 import Data.Foldable (Foldable(..), concat)
19 import Data.Function (($), (.))
20 import Data.Functor ((<$>))
22 import Data.Map.Strict (Map)
23 import Data.Maybe (Maybe(..))
24 import Data.Ord (Ord(..))
25 import Data.Semigroup (Semigroup(..))
26 import Data.Sequence (Seq)
28 import Data.Text (Text)
29 import Data.TreeSeq.Strict (Tree(..))
30 import Prelude (Num(..))
31 import Text.Show (Show(..))
32 import qualified Control.Monad.Trans.State as S
33 import qualified Data.Char as Char
34 import qualified Data.List as List
35 import qualified Data.Map.Strict as Map
36 import qualified Data.Set as Set
37 import qualified Data.Text as Text
39 import qualified Language.DTC.Document as DTC
40 import Language.XML (XmlPos(..))
44 terms :: [Term] -> Set Term
45 terms = Set.fromList . foldMap ((Text.strip <$>) . Text.lines)
50 aliasesByChar :: [Aliases] -> Map Char [Aliases]
52 -- TODO: case insensitivity?
55 (Char.toUpper $ List.head ts `Text.index` 0)
73 { state_terms :: Map Term [Ref]
75 , state_section :: XmlPos
79 { state_terms = Map.empty
85 class Indexify a where
86 indexify :: a -> S.State State a
87 instance Indexify (Tree k a) => Indexify [Tree k a] where
88 indexify = mapM indexify
89 instance Indexify a => Indexify (Tree DTC.BodyKey a) where
91 Tree0 v -> Tree0 <$> indexify v
95 before@State{state_section} <- S.get
96 S.put before{state_section = pos}
97 t <- TreeN <$> indexify k <*> indexify v
99 S.put after{state_section}
102 instance Indexify a => Indexify [a] where
103 indexify = mapM indexify
105 instance Indexify a => Indexify (Seq a) where
106 indexify = mapM indexify
107 instance Indexify DTC.BodyKey where
110 DTC.Section pos attrs
113 instance Indexify DTC.BodyValue where
115 d@DTC.ToC{} -> pure d
116 d@DTC.ToF{} -> pure d
117 d@DTC.Index{} -> pure d
119 DTC.Figure pos attrs type_
123 DTC.Vertical <$> indexify v
124 instance Indexify [DTC.Reference] where
125 indexify = mapM indexify
126 instance Indexify [DTC.Vertical] where
127 indexify = mapM indexify
128 instance Indexify [[DTC.Vertical]] where
129 indexify = mapM (mapM indexify)
130 instance Indexify DTC.Title where
131 indexify (DTC.Title t) = DTC.Title <$> indexify t
132 instance Indexify DTC.Vertical where
134 DTC.Para{..} -> DTC.Para pos attrs <$> indexify horis
135 DTC.OL{..} -> DTC.OL pos attrs <$> indexify items
136 DTC.UL{..} -> DTC.UL pos attrs <$> indexify items
137 DTC.RL{..} -> DTC.RL pos attrs <$> indexify refs
138 DTC.Artwork{..} -> DTC.Artwork pos attrs <$> indexify art
139 d@DTC.Comment{} -> pure d
140 instance Indexify [DTC.Horizontal] where
142 (concat <$>) $ forM hs $ \case
143 d@DTC.BR -> return [d]
144 DTC.B s -> pure . DTC.B <$> indexify s
145 DTC.Code s -> pure . DTC.Code <$> indexify s
146 DTC.Del s -> pure . DTC.Del <$> indexify s
147 DTC.I s -> pure . DTC.I <$> indexify s
148 DTC.Note s -> pure . DTC.Note <$> indexify s
149 DTC.Q s -> pure . DTC.Q <$> indexify s
150 DTC.SC s -> pure . DTC.SC <$> indexify s
151 DTC.Sub s -> pure . DTC.Sub <$> indexify s
152 DTC.Sup s -> pure . DTC.Sup <$> indexify s
153 DTC.U s -> pure . DTC.U <$> indexify s
154 DTC.Eref{..} -> pure . DTC.Eref href <$> indexify text
155 DTC.Iref{..} -> pure . DTC.Iref count term <$> indexify text
156 DTC.Ref{..} -> pure . DTC.Ref to <$> indexify text
157 DTC.Rref{..} -> pure . DTC.Rref to <$> indexify text
158 DTC.Plain p -> List.reverse <$> go 0 p p []
160 flt c = Char.isAlphaNum c || Char.isPunctuation c
161 go :: Int -> Text -> Text -> [DTC.Horizontal] -> S.State State [DTC.Horizontal]
162 go len plain curr acc =
163 -- NOTE: keep the number of DTC.Plain to the minimum
164 -- while sharing their Text with the original.
165 case Text.span flt curr of
166 ("","") | len > 0 -> return $ DTC.Plain plain:acc
167 | otherwise -> return acc
169 case Text.break flt r of
170 (m,n) -> go (len + Text.length m) plain n acc
172 st@State{..} <- S.get
173 case Map.updateLookupWithKey
175 let count = case refs of [] -> 1; Ref{count=c}:_ -> c + 1 in
176 Just $ Ref{term, count, section=state_section} : refs)
179 go (len + Text.length term) plain r acc
181 S.put st{state_terms=m}
185 , count = count $ List.head refs
186 , text = [DTC.Plain term]
189 then DTC.Plain (Text.take len plain) : acc
191 instance Indexify DTC.Reference where
193 instance Indexify DTC.Artwork where
197 countIref :: Seq XmlPos -> Int
200 _ :> XmlPos{xmlPosAncestors=(_,c):_} -> c + 1
204 { iref_pos :: Seq.XmlPos
207 -- Map Text DTC.Horizontal