packages feed

org-parser-0.1.0.0: src/Org/Compare.hs

{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}

{- | This module implements comparasion of Org contents, using multiwalk. You
 should use this instead of the default Ord instances when you want to compare
 Org content semantically.
-}
module Org.Compare (compareContent, compareContents, toAtoms, Atom) where

import Data.Text qualified as T
import Org.Types
import Org.Walk

data Atom
  = Separator
  | Word Text
  | Literal Text
  | Time DateTime
  deriving (Eq, Ord)

compareContent :: MultiWalk MWTag a => a -> a -> Ordering
compareContent = comparing toAtoms

compareContents :: MultiWalk MWTag a => [a] -> [a] -> Ordering
compareContents = comparing (foldMap toAtoms)

toAtoms :: MultiWalk MWTag a => a -> [Atom]
toAtoms = buildMultiQ \f l ->
  l ?> objToAtoms f ?> elmToAtoms f

elmToAtoms :: Query [Atom] -> OrgElementData -> [Atom]
elmToAtoms f = (Separator :) . \case
  ExportBlock _ t -> [Literal t]
  ExampleBlock _ t -> [Literal $ srcLinesToText t]
  SrcBlock {..} -> [Literal $ srcLinesToText srcBlkLines]
  LaTeXEnvironment _ t -> [Literal t]
  x -> f x

objToAtoms :: Query [Atom] -> OrgObject -> [Atom]
objToAtoms f = \case
  Plain t -> Word <$> T.words t
  Code t -> [Literal t]
  Verbatim t -> [Literal t]
  Timestamp (TimestampData _ t) -> [Time t]
  Timestamp (TimestampRange _ t s) -> [Time t, Time s]
  Entity t -> [Literal t]
  LaTeXFragment _ t -> [Literal t]
  ExportSnippet _ t -> [Literal t]
  FootnoteRef {} -> []
  Cite (Citation {..}) ->
    (citationPrefix >>= toAtoms)
      ++ ( citationReferences >>= \CiteReference {..} ->
            (refPrefix >>= toAtoms)
              ++ [Literal refId]
              ++ (refSuffix >>= toAtoms)
         )
      ++ (citationSuffix >>= toAtoms)
  Src _ _ t -> [Literal t]
  x -> f x