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
167 { opinionsByChoice :: Maybe (MJ.OpinionsByChoice Choice Judge Grade)
170 , importance :: Maybe MJ.Share
171 , question :: Maybe Title
172 , choices :: [Choice]
174 instance Eq Judgment where
176 judges x == judges y &&
177 grades x == grades y &&
178 question x == question y
179 instance Hashable Judgment where
180 hashWithSalt s Judgment{..} =
181 s`hashWithSalt`judges
183 `hashWithSalt`question
188 , title :: Maybe Title
189 , defaultGrades :: [(Ident, Name)]
198 , title :: Maybe Title
203 { title :: Maybe Title
204 , opinions :: [Opinion]
206 instance Eq Choice where
207 (==) = (==)`on`(title::Choice -> Maybe Title)
208 instance Hashable Choice where
209 hashWithSalt s Choice{..} =
213 data Opinion = Opinion
216 , importance :: Maybe MJ.Share
217 , comment :: Maybe Title
222 = ParaItem { item :: ParaItem }
223 | ParaItems { pos :: Pos
224 , attrs :: CommonAttrs
225 , items :: [ParaItem]
229 -- ** Type 'ParaItem'
232 | ParaComment TL.Text
235 | ParaQuote { type_ :: TL.Text
238 | ParaArtwork { type_ :: TL.Text
241 | ParaJudgment Judgment
244 -- *** Type 'ListItem'
245 data ListItem = ListItem
251 type Plain = TS.Trees PlainNode
253 -- ** Type 'PlainNode'
257 | PlainCode -- ^ Code (monospaced)
258 | PlainDel -- ^ Deleted (crossed-over)
260 | PlainGroup -- ^ Group subTrees (neutral)
262 | PlainSC -- ^ Small Caps
263 | PlainSub -- ^ Subscript
264 | PlainSup -- ^ Superscript
265 | PlainU -- ^ Underlined
266 | PlainEref { href :: URL } -- ^ External reference
267 | PlainIref { anchor :: Maybe Anchor -- ^ Set by 'anchorify'.
269 } -- ^ Index reference
270 | PlainRef { to :: Ident }
272 | PlainRref { anchor :: Maybe Anchor -- ^ Set by 'anchorify'.
274 } -- ^ Reference reference
275 | PlainSpan { attrs :: CommonAttrs } -- ^ Neutral node
277 | PlainBreak -- ^ Line break (\n)
279 | PlainNote { number :: Maybe Nat1
286 { pos_Ancestors :: PosPath
287 , pos_AncestorsWithFigureNames :: PosPath
288 , pos_PrecedingSiblings :: Map XmlName Rank
290 instance Ord Pos where
291 compare = compare`on`pos_Ancestors
292 -- | Return only the hash on 'pos_Ancestors',
293 -- which is unique because 'PosPath'
294 -- includes the 'Rank' of each 'XmlNode'.
295 instance Hashable Pos where
296 hashWithSalt s Pos{..} =
297 s`hashWithSalt`pos_Ancestors
298 instance Default Pos where
299 def = Pos mempty mempty mempty
301 -- *** Type 'PosPath'
302 type PosPath = Seq (XmlName,Rank)
305 dropSelfPosPath :: PosPath -> Maybe PosPath
311 -- * Type 'CommonAttrs'
312 data CommonAttrs = CommonAttrs
314 , classes :: [TL.Text]
315 } deriving (Eq,Ord,Show)
316 instance Default CommonAttrs where
326 } deriving (Eq,Ord,Show)
329 newtype Name = Name { unName :: TL.Text }
330 deriving (Eq,Ord,Show,Semigroup,Monoid,Default,IsString,Hashable)
333 newtype Title = Title { unTitle :: Plain }
334 deriving (Show,Semigroup,Monoid,Default)
335 instance Eq Title where
336 (==) = (==) `on` similarPlain . unTitle
337 -- | Return a similar version of a 'Plain' by removing:
339 -- * parsing residues ('PlainGroup'),
340 -- * notes ('PlainNote'),
341 -- * and position specific annotations ('Ident' and 'Anchor').
342 similarPlain :: Plain -> Plain
343 similarPlain = foldMap $ \(TS.Tree n ts) ->
344 let skip = similarPlain ts in
345 let keep = pure $ TS.Tree n $ skip in
349 PlainIref _anchor term -> pure $ TS.Tree PlainIref{anchor=Nothing, term} skip
350 PlainRref _anchor to -> pure $ TS.Tree PlainRref{anchor=Nothing, to} skip
351 PlainSpan attrs -> pure $ TS.Tree n' skip
352 where n' = PlainSpan{attrs = CommonAttrs{ id = Nothing
353 , classes = List.sort $ classes attrs }}
363 PlainEref _to -> keep
367 -- | Return the same hash if 'similarPlain' is applied on the 'Title' before hashing.
368 instance Hashable Title where
369 hashWithSalt salt (Title ps) = hs salt ps
377 PlainIref{..} -> s`hashWithSalt`(0::Int)`hashWithSalt`term
378 PlainRef{..} -> s`hashWithSalt`(1::Int)`hashWithSalt`to
379 PlainSpan{..} -> s`hashWithSalt`(2::Int)`hashWithSalt`List.sort (classes attrs)
380 PlainB -> s`hashWithSalt`(3::Int)
381 PlainCode -> s`hashWithSalt`(4::Int)
382 PlainDel -> s`hashWithSalt`(5::Int)
383 PlainI -> s`hashWithSalt`(6::Int)
384 PlainQ -> s`hashWithSalt`(7::Int)
385 PlainSC -> s`hashWithSalt`(8::Int)
386 PlainSub -> s`hashWithSalt`(9::Int)
387 PlainSup -> s`hashWithSalt`(10::Int)
388 PlainU -> s`hashWithSalt`(11::Int)
389 PlainEref{..} -> s`hashWithSalt`(12::Int)`hashWithSalt`href
390 PlainRref{..} -> s`hashWithSalt`(13::Int)`hashWithSalt`to
391 PlainBreak -> s`hashWithSalt`(14::Int)
392 PlainText t -> s`hashWithSalt`(15::Int)`hashWithSalt`t
406 , org :: Maybe Entity
408 instance Default Entity where
422 instance Semigroup Entity where
426 data Include = Include
429 instance Default Include where
434 -- * Type 'Reference'
435 data Reference = Reference
439 reference :: Ident -> Reference
445 instance Default Reference where
451 , month :: Maybe Nat1
454 instance Default Date where
457 , month = Just (Nat1 01)
458 , day = Just (Nat1 01)
460 instance Semigroup Date where
468 , type_ :: Maybe TL.Text
471 instance Default Link where
484 instance Default Alias where
494 instance Default Serie where
500 -- | Builtins 'URL' recognized from |Serie|'s 'name'.
501 urlSerie :: Serie -> Maybe URL
502 urlSerie Serie{id=id_, name} =
504 "RFC" | TL.all Char.isDigit id_ ->
505 Just $ URL $ "https://tools.ietf.org/html/rfc"<>id_
506 "DOI" -> Just $ URL $ "https://dx.doi.org/"<>id_
513 type Words = [WordOrSpace]
515 -- *** Type 'WordOrSpace'
519 deriving (Eq,Ord,Show,Generic)
520 instance Hashable WordOrSpace
523 type Aliases = [Words]
526 type Terms = [Aliases]