neuron-1.0.0.0: src/lib/Neuron/Zettelkasten/Zettel.hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Neuron.Zettelkasten.Zettel where
import Data.Aeson
import Data.Aeson.GADT.TH
import Data.Dependent.Sum.Orphans ()
import Data.GADT.Compare.TH
import Data.GADT.Show.TH
import Data.Graph.Labelled (Vertex (..))
import Data.Some
import Data.TagTree (Tag, TagPattern (..))
import Data.Time.DateMayTime (DateMayTime)
import Neuron.Reader.Type
import Neuron.Zettelkasten.Connection
import Neuron.Zettelkasten.ID
import Neuron.Zettelkasten.Query.Error
import Neuron.Zettelkasten.Query.Theme
import Relude hiding (show)
import Text.Pandoc.Definition (Pandoc (..))
import Text.Show (Show (show))
-- | ZettelQuery queries individual zettels.
--
-- It does not care about the relationship *between* those zettels; for that use `GraphQuery`.
data ZettelQuery r where
ZettelQuery_ZettelByID :: ZettelID -> Connection -> ZettelQuery Zettel
ZettelQuery_ZettelsByTag :: [TagPattern] -> Connection -> ZettelsView -> ZettelQuery [Zettel]
ZettelQuery_Tags :: [TagPattern] -> ZettelQuery (Map Tag Natural)
ZettelQuery_TagZettel :: Tag -> ZettelQuery ()
-- | A zettel note
--
-- The metadata could have been inferred from the content.
data ZettelT content = Zettel
{ zettelID :: ZettelID,
zettelFormat :: ZettelFormat,
-- | Relative path to this zettel in the zettelkasten directory
zettelPath :: FilePath,
zettelTitle :: Text,
-- | Whether the title was infered from the body
zettelTitleInBody :: Bool,
zettelTags :: [Tag],
-- | Date associated with the zettel if any
zettelDate :: Maybe DateMayTime,
zettelUnlisted :: Bool,
-- | List of all queries in the zettel
zettelQueries :: [Some ZettelQuery],
zettelError :: ContentError content,
zettelContent :: content
}
deriving (Generic)
newtype MetadataOnly = MetadataOnly ()
deriving (Generic, ToJSON, FromJSON)
type family ContentError c where
-- The list of queries that failed to parse.
ContentError Pandoc = [QueryParseError]
-- When a zettel fails to parse, we use its raw text along with its parse error.
ContentError Text = ZettelParseError
-- When working with zettel sans content, we gather both kinds of errors (above)
ContentError MetadataOnly = Either (ContentError Text) (ContentError Pandoc)
-- | All possible errors in a zettel
--
-- NOTE: Unlike `ContentError MetadataOnly` this also includes QueryResultError
-- (which can be determined only after *evaluating* the queries).
data ZettelError
= ZettelError_ParseError ZettelParseError
| ZettelError_QueryErrors (NonEmpty QueryError)
| ZettelError_AmbiguousFiles (NonEmpty FilePath)
deriving (Eq, Show, Generic, ToJSON, FromJSON)
-- | Zettel without its content
type Zettel = ZettelT MetadataOnly
-- | Zettel with its content (Pandoc or raw text)
type ZettelC = Either (ZettelT Text) (ZettelT Pandoc)
sansContent :: ZettelC -> Zettel
sansContent = \case
Left z ->
z
{ zettelError = Left $ zettelError z,
zettelContent = MetadataOnly ()
}
Right z ->
z
{ zettelError = Right $ zettelError z,
zettelContent = MetadataOnly ()
}
instance Eq (ZettelT c) where
(==) = (==) `on` zettelID
instance Ord (ZettelT c) where
compare = compare `on` zettelID
instance Show (ZettelT c) where
show Zettel {..} = "Zettel:" <> show zettelID
instance Vertex (ZettelT c) where
type VertexID (ZettelT c) = ZettelID
vertexID = zettelID
sortZettelsReverseChronological :: [Zettel] -> [Zettel]
sortZettelsReverseChronological =
sortOn (Down . zettelDate)
deriveJSONGADT ''ZettelQuery
deriveGEq ''ZettelQuery
deriveGShow ''ZettelQuery
deriving instance Show (ZettelQuery (Maybe Zettel))
deriving instance Show (ZettelQuery [Zettel])
deriving instance Show (ZettelQuery (Map Tag Natural))
deriving instance Eq (ZettelQuery (Maybe Zettel))
deriving instance Eq (ZettelQuery [Zettel])
deriving instance Eq (ZettelQuery (Map Tag Natural))
deriving instance ToJSON Zettel
deriving instance FromJSON Zettel