Types
We define the types we use in one place.
1 Lilac.Types module
This module defines the core types and some helper functions (those named with a default* prefix). Most of the discussions of the actual types themselves are done in the Org parser, because that module requires these types to perform the parsing (and it is in this capacity that most of these types first come into existence in the system). For this reason, many of the code blocks are defined (and discussed) there.
module Lilac.Types
( Archive (..),
ArchiveOpts (..),
Block (..),
BToken (..),
Cell (..),
Citation (..),
Cite (..),
Command (..),
CompileOpts (..),
Figure (..),
Footnote (..),
GCI (..),
GlobalOpts (..),
GPath,
GTOC (..),
GlossaryTerm (..),
Heading (..),
HtmlHead (..),
InitOpts (..),
LCI (..),
Level (..),
Link (..),
LinkOid (..),
LinkTarget (..),
LintOpts (..),
ListMarker (..),
MathFragment (..),
Object (..),
OID (..),
OrgDoc (..),
OrgParser,
OrgParserConf (..),
OrgParserState (..),
PToken (..),
ProjectConf (..),
PseudoEdge (..),
RawProjectConf (..),
Prose (..),
ServeOpts (..),
Subcommand (..),
Style (..),
StyleMask (..),
StyledText (..),
Table (..),
TangleOpts (..),
WeaveConf (..),
WeaveOpts (..),
decodeGPath,
defaultOrgParserConf,
defaultOrgParserState,
emptyGPath,
emptyProjectConf,
encodeGPath,
Lilac.Types.fromText,
fromWords,
gciToObjCell,
gciToObjPath,
getBlock,
getCellName,
getNamedCells,
getProseContents,
getSectionNumber,
getTangled,
getTangledBlocks,
markingChars,
markingCharsInvisible,
nilOid,
nilOidOrgDocPrefix,
protocolsEmacs,
protocolsWeb,
ptext,
stext,
stripLinks,
stripStyles,
styleMaskFrom,
)
where
import Citeproc qualified as CP
import Citeproc.CslJson (CslJson)
import Data.Aeson
( FromJSON,
FromJSONKey,
FromJSONKeyFunction (FromJSONKeyTextParser),
ToJSON,
ToJSONKey,
fromJSONKey,
parseJSON,
toJSON,
toJSONKey,
)
import Data.Aeson.Types
( Parser,
Value (String),
toJSONKeyText,
withText,
)
import Data.Bits (setBit)
import Data.Bits.Bitwise (toListLE)
import Data.IntMap.Strict (IntMap)
import Data.IntMap.Strict qualified as IntMap
import Data.Map.Strict qualified as M
import Data.Set qualified as Set
import Data.Text qualified as T
import Data.Tree (Tree)
import Data.UUID (UUID, fromText, fromWords64)
import GHC.Generics (Generic)
import Lilac.Types.Internal (GPath (GPath))
import Network.URI qualified as N
import Relude
( Bool (False, True),
Char,
Enum,
Eq,
FilePath,
Hashable,
Identity,
Int,
Map,
Maybe (Just, Nothing),
MonadFail,
Monoid,
Ord,
Semigroup,
Set,
Show,
StateT,
Text,
Type,
Void,
Word64,
Word8,
abs,
catMaybes,
concatMap,
fail,
foldl',
fromEnum,
map,
mapMaybe,
maybe,
mempty,
otherwise,
pure,
reverse,
show,
sort,
toEnum,
zip,
(!!?),
($),
(-),
(.),
(/=),
(<),
(<>),
(>),
)
import Relude.Extra.Map (keys, lookup)
import System.OsPath (OsPath)
import System.OsPath qualified as P
import Text.Megaparsec qualified as MP
import Toml.Schema
( FromValue,
GenericTomlTable (GenericTomlTable),
ToTable,
ToValue,
)
import Prelude qualified (show)
data:BToken
data:Block
data:Cell
f:getTangledBlocks
f:getBlock
f:getTangled
f:getNamedCells
data:Command
data:Figure
data:Heading
f:getProseContents
f:getSectionNumber
data:Level
data:Link
data:LinkOid
instance:ToJSON LinkOid
instance:ToJSONKey LinkOid
instance:FromJSON LinkOid
instance:FromJSONKey LinkOid
instance:Show LinkOid
f:parseJSONLinkOid
data:LinkTarget
data:ListMarker
data:MathFragment
data:OrgDoc
newtype:LCI
data:OrgParserConf
f:defaultOrgParserConf
data:OrgParserState
f:defaultOrgParserState
newtype:Prose
instance:Semigroup Prose
instance:Monoid Prose
data:PToken
data:Style
data:StyledText
f:stext
f:ptext
data:Table
instance:Show Stylemask
newtype:StyleMask
f:styleMaskFrom
data:Footnote
data:GlossaryTerm
data:Citation
data:Cite
newtype:OID
instance:Show OID
f:nilOid
f:nilOidOrgDocPrefix
f:fromWords
f:fromText
newtype:PseudoEdge
type:OrgParser
f:encodeGPath
f:decodeGPath
f:emptyGPath
f:protocolsEmacs
f:protocolsWeb
data:WeaveConf
data:Object
data:Archive
newtype:GCI
f:gciToObjCell
f:gciToObjPath
f:stripLinks
f:stripStyles
f:getCellName
newtype:GTOC
data:ProjectConf
data:HtmlHead
data:RawProjectConf
f:emptyProjectConf
data:GlobalOpts
data:Subcommand
data:ArchiveOpts
data:CompileOpts
data:LintOpts
data:ServeOpts
data:TangleOpts
data:WeaveOpts
data:InitOpts
f:markingChars
f:markingCharsInvisible1.1 Lilac.Types.Internal module
module Lilac.Types.Internal
( GPath (..),
)
where
import Data.Aeson
( FromJSON,
FromJSONKey,
FromJSONKeyFunction (FromJSONKeyTextParser),
ToJSON,
ToJSONKey,
fromJSONKey,
parseJSON,
toJSONKey,
)
import Data.Aeson.Types
( toJSONKeyText,
withText,
)
import Data.Text qualified as T
import GHC.Generics (Generic)
import Relude
( Eq,
FilePath,
Hashable,
Ord,
Show,
Type,
pure,
($),
(.),
)
newtype:GPath
instance:ToJSONKey GPath
instance:FromJSON GPath
instance:FromJSONKey GPath2.1 Org ID (OID)
Org IDs (see newtype:OID, Links, and data:LinkOid) are UUIDs underneath. The functions here manipulate this type.
f:fromWords constructs an OID from two 64-bit words.
fromWords :: Word64 -> Word64 -> OID
fromWords w1 w2 = OID $ fromWords64 w1 w2f:fromText constructs a Maybe OID from text.
fromText :: Text -> Maybe OID
fromText t = case Data.UUID.fromText t of
Just uuid -> Just $ OID uuid
Nothing -> Nothinginstance:Show OID avoids printing the OID text because it's simpler to just have the raw UUID by itself.
instance Show OID where
show (OID uuid) = Prelude.show uuidThe f:nilOid is a special zero-value OID. We use it for things like the f:defaultOrgParserState and also in many of the test cases for parsing.
nilOid :: OID
nilOid = fromWords 0 02.2 GPath, an OsPath wrapper
newtype:GPath is a custom type that guarantees that it can only contain a FilePath which can be converted (without errors) into a valid OsPath. It is named GPath to mean "guaranteed path".
type GPath :: Type
newtype GPath = GPath FilePath
deriving stock (Eq, Ord, Generic, Show)
deriving anyclass (ToJSON)
deriving newtype (Hashable)Similar to instance:ToJSONKey LinkOid, we want to encode and decode GPath values in a succinct way. Because this is a newtype wrapper, by default Data.Aeson will try to write it as "GPath" \"...\"" in JSON, which is ugly. To simplify this we have custom ToJSONKey and FromJSONKey instances.
instance:ToJSONKey GPath tells Data.Aeson to only write the FilePath part of the GPath.
instance ToJSONKey GPath where
toJSONKey = toJSONKeyText $ \(GPath p) -> T.pack pBoth instance:FromJSON GPath and instance:FromJSONKey GPath understand how to parse a GPath from a Text value. The FromJSONKey instance also requires a FromJSON instance, which is why we have both of them here.
instance FromJSONKey GPath where
fromJSONKey = FromJSONKeyTextParser $ \t -> do
pure . GPath $ T.unpack tinstance FromJSON GPath where
parseJSON = withText "GPath" $ \t -> do
pure . GPath $ T.unpack tf:encodeGPath is the only way one is allowed to construct a newtype:GPath.
encodeGPath :: (MonadFail m) => FilePath -> m GPath
encodeGPath fp
| Just osp <- P.encodeUtf fp,
P.isValid osp =
pure $ GPath fp
| otherwise = fail $ "invalid file path: " <> show fpf:decodeGPath takes a GPath and converts it back into the FilePath that it is based on.
decodeGPath :: GPath -> FilePath
decodeGPath (GPath fp) = fpf:emptyGPath is an empty GPath.
emptyGPath :: GPath
emptyGPath = GPath ""2.2.1 Succinct construction
In tests and other scenarios, we want to be able to succinctly construct GPath values without being encumbered by the monadic type of f:encodeGPath. For this purpose we have a separate internal-only module which exposes the GPath constructor.
2.3 Protocols
The f:protocolsWeb are the typical protocols found in links on the internet.
protocolsWeb :: [Text]
protocolsWeb =
[ "http://",
"https://",
"file://",
"ftp://",
"mailto:",
"tel:"
]The f:protocolsEmacs contains protocols that are used as aliases for their more traditional protocols in f:protocolsWeb.
protocolsEmacs :: [Text]
protocolsEmacs =
map
(<> ":")
[ "file"
]2.4 Marking characters
Marking characters are used in Tables as special characters (see this page for more information). See f:tableCellParser and f:weaveTable for how Lilac deals with them.
markingChars :: [Char]
markingChars = "#*" <> markingCharsInvisibleSome marking characters are purely for metadata and signal entire rows that are not meant to be displayed to the user directly. These are defined separately.
markingCharsInvisible :: [Char]
markingCharsInvisible = "!^_$/"