1 {-# LANGUAGE DeriveGeneric #-}
2 {-# LANGUAGE DisambiguateRecordFields #-}
3 {-# LANGUAGE DuplicateRecordFields #-}
4 {-# LANGUAGE FlexibleInstances #-}
5 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
6 {-# LANGUAGE OverloadedStrings #-}
7 module Hdoc.DTC.Document
8 ( module Hdoc.DTC.Document
12 import Control.Applicative (Applicative(..))
14 import Data.Default.Class (Default(..))
15 import Data.Default.Instances.Containers ()
16 import Data.Eq (Eq(..))
17 import Data.Foldable (Foldable(..))
18 import Data.Function (on, ($), (.))
19 import Data.Hashable (Hashable(..))
21 import Data.Map.Strict (Map)
22 import Data.Maybe (Maybe(..))
23 import Data.Monoid (Monoid(..))
24 import Data.Ord (Ord(..))
25 import Data.Semigroup (Semigroup(..))
26 import Data.Sequence (Seq, ViewR(..), viewr)
27 import Data.String (IsString)
28 import GHC.Generics (Generic)
29 import Text.Show (Show)
30 import qualified Data.Char as Char
31 import qualified Data.HashMap.Strict as HM
32 import qualified Data.HashSet as HS
33 import qualified Data.List as List
34 import qualified Data.Text.Lazy as TL
35 import qualified Data.Tree as Tree
36 import qualified Data.TreeSeq.Strict as TS
37 import qualified Hjugement as MJ
43 data Document = Document
47 instance Default Document where
56 , judgments :: [Judgment]
57 -- [(Judgment, [Tree.Tree (Maybe MJ.Share, [Choice])])]
59 instance Default Head where
71 , editor :: Maybe Entity
76 , includes :: [Include] -- FIXME: remove?
78 instance Default About where
91 instance Semigroup About where
93 { headers = headers x <> headers y
94 , titles = titles x <> titles y
95 , url = url (x::About) <> url (y::About)
96 , authors = authors x <> authors y
97 , editor = editor x <> editor y
98 , date = date x <> date y
99 , tags = tags x <> tags y
100 , links = links x <> links y
101 , series = series x <> series y
102 , includes = includes x <> includes y
112 type Body = TS.Trees BodyNode
114 -- ** Type 'BodyNode'
116 = BodySection { pos :: Pos
117 , attrs :: CommonAttrs
120 , judgments :: [Judgment]
122 | BodyBlock Block -- ^ leaf
128 | BlockBreak { attrs :: CommonAttrs }
129 | BlockToC { pos :: Pos
130 , attrs :: CommonAttrs
133 | BlockToF { pos :: Pos
134 , attrs :: CommonAttrs
137 | BlockAside { pos :: Pos
138 , attrs :: CommonAttrs
141 | BlockFigure { pos :: Pos
143 , attrs :: CommonAttrs
144 , mayTitle :: Maybe Title
147 | BlockIndex { pos :: Pos
148 , attrs :: CommonAttrs
151 | BlockReferences { pos :: Pos
152 , attrs :: CommonAttrs
153 , refs :: [Reference]
154 } -- FIXME: move to ParaReferences?
155 | BlockJudges { pos :: Pos
156 , attrs :: CommonAttrs
159 | BlockGrades { pos :: Pos
160 , attrs :: CommonAttrs
166 data Judgment = Judgment
169 , importance :: Maybe MJ.Share
170 , question :: Maybe Title
171 , choices :: [Choice]
173 instance Eq Judgment where
175 judges x == judges y &&
176 grades x == grades y &&
177 question x == question y
178 instance Hashable Judgment where
179 hashWithSalt s Judgment{..} =
180 s`hashWithSalt`judges
182 `hashWithSalt`question
187 , title :: Maybe Title
188 , defaultGrades :: [(Ident, Name)]
197 , title :: Maybe Title
202 { title :: Maybe Title
203 , opinions :: [Opinion]
205 instance Eq Choice where
206 (==) = (==)`on`(title::Choice -> Maybe Title)
207 instance Hashable Choice where
208 hashWithSalt s Choice{..} =
212 data Opinion = Opinion
215 , importance :: Maybe MJ.Share
216 , comment :: Maybe Title
221 = ParaItem { item :: ParaItem }
222 | ParaItems { pos :: Pos
223 , attrs :: CommonAttrs
224 , items :: [ParaItem]
228 -- ** Type 'ParaItem'
231 | ParaComment TL.Text
234 | ParaQuote { type_ :: TL.Text
237 | ParaArtwork { type_ :: TL.Text
240 | ParaJudgment Judgment
243 -- *** Type 'ListItem'
244 data ListItem = ListItem
250 type Plain = TS.Trees PlainNode
252 -- ** Type 'PlainNode'
256 | PlainCode -- ^ Code (monospaced)
257 | PlainDel -- ^ Deleted (crossed-over)
259 | PlainGroup -- ^ Group subTrees (neutral)
261 | PlainSC -- ^ Small Caps
262 | PlainSub -- ^ Subscript
263 | PlainSup -- ^ Superscript
264 | PlainU -- ^ Underlined
265 | PlainEref { href :: URL } -- ^ External reference
266 | PlainIref { anchor :: Maybe Anchor -- ^ Set by 'anchorify'.
268 } -- ^ Index reference
269 | PlainRef { to :: Ident }
271 | PlainRref { anchor :: Maybe Anchor -- ^ Set by 'anchorify'.
273 } -- ^ Reference reference
274 | PlainSpan { attrs :: CommonAttrs } -- ^ Neutral node
276 | PlainBreak -- ^ Line break (\n)
278 | PlainNote { number :: Maybe Nat1
285 { pos_Ancestors :: PosPath
286 , pos_AncestorsWithFigureNames :: PosPath
287 , pos_PrecedingSiblings :: Map XmlName Rank
289 instance Ord Pos where
290 compare = compare`on`pos_Ancestors
291 -- | Return only the hash on 'pos_Ancestors',
292 -- which is unique because 'PosPath'
293 -- includes the 'Rank' of each 'XmlNode'.
294 instance Hashable Pos where
295 hashWithSalt s Pos{..} =
296 s`hashWithSalt`pos_Ancestors
297 instance Default Pos where
298 def = Pos mempty mempty mempty
300 -- *** Type 'PosPath'
301 type PosPath = Seq (XmlName,Rank)
303 posParent :: PosPath -> Maybe PosPath
309 -- * Type 'CommonAttrs'
310 data CommonAttrs = CommonAttrs
312 , classes :: [TL.Text]
313 } deriving (Eq,Ord,Show)
314 instance Default CommonAttrs where
324 } deriving (Eq,Ord,Show)
327 newtype Name = Name { unName :: TL.Text }
328 deriving (Eq,Ord,Show,Semigroup,Monoid,Default,IsString,Hashable)
331 newtype Title = Title { unTitle :: Plain }
332 deriving (Show,Semigroup,Monoid,Default)
333 instance Eq Title where
334 (==) = (==) `on` similarPlain . unTitle
335 -- | Return a similar version of a 'Plain' by removing:
337 -- * parsing residues ('PlainGroup'),
338 -- * notes ('PlainNote'),
339 -- * and position specific annotations ('Ident' and 'Anchor').
340 similarPlain :: Plain -> Plain
341 similarPlain = foldMap $ \(TS.Tree n ts) ->
342 let skip = similarPlain ts in
343 let keep = pure $ TS.Tree n $ skip in
347 PlainIref _anchor term -> pure $ TS.Tree PlainIref{anchor=Nothing, term} skip
348 PlainRref _anchor to -> pure $ TS.Tree PlainRref{anchor=Nothing, to} skip
349 PlainSpan attrs -> pure $ TS.Tree n' skip
350 where n' = PlainSpan{attrs = CommonAttrs{ id = Nothing
351 , classes = List.sort $ classes attrs }}
361 PlainEref _to -> keep
365 -- | Return the same hash if 'similarPlain' is applied on the 'Title' before hashing.
366 instance Hashable Title where
367 hashWithSalt salt (Title ps) = hs salt ps
375 PlainIref{..} -> s`hashWithSalt`(0::Int)`hashWithSalt`term
376 PlainRef{..} -> s`hashWithSalt`(1::Int)`hashWithSalt`to
377 PlainSpan{..} -> s`hashWithSalt`(2::Int)`hashWithSalt`List.sort (classes attrs)
378 PlainB -> s`hashWithSalt`(3::Int)
379 PlainCode -> s`hashWithSalt`(4::Int)
380 PlainDel -> s`hashWithSalt`(5::Int)
381 PlainI -> s`hashWithSalt`(6::Int)
382 PlainQ -> s`hashWithSalt`(7::Int)
383 PlainSC -> s`hashWithSalt`(8::Int)
384 PlainSub -> s`hashWithSalt`(9::Int)
385 PlainSup -> s`hashWithSalt`(10::Int)
386 PlainU -> s`hashWithSalt`(11::Int)
387 PlainEref{..} -> s`hashWithSalt`(12::Int)`hashWithSalt`href
388 PlainRref{..} -> s`hashWithSalt`(13::Int)`hashWithSalt`to
389 PlainBreak -> s`hashWithSalt`(14::Int)
390 PlainText t -> s`hashWithSalt`(15::Int)`hashWithSalt`t
404 , org :: Maybe Entity
406 instance Default Entity where
420 instance Semigroup Entity where
424 data Include = Include
427 instance Default Include where
432 -- * Type 'Reference'
433 data Reference = Reference
437 reference :: Ident -> Reference
443 instance Default Reference where
449 , month :: Maybe Nat1
452 instance Default Date where
455 , month = Just (Nat1 01)
456 , day = Just (Nat1 01)
458 instance Semigroup Date where
466 , type_ :: Maybe TL.Text
469 instance Default Link where
482 instance Default Alias where
492 instance Default Serie where
498 -- | Builtins 'URL' recognized from |Serie|'s 'name'.
499 urlSerie :: Serie -> Maybe URL
500 urlSerie Serie{id=id_, name} =
502 "RFC" | TL.all Char.isDigit id_ ->
503 Just $ URL $ "https://tools.ietf.org/html/rfc"<>id_
504 "DOI" -> Just $ URL $ "https://dx.doi.org/"<>id_
511 type Words = [WordOrSpace]
513 -- *** Type 'WordOrSpace'
517 deriving (Eq,Ord,Show,Generic)
518 instance Hashable WordOrSpace
521 type Aliases = [Words]
524 type Terms = [Aliases]