module Data.OrgMode.OrgDocView (
OrgDocView(..), generateDocView, getRawElements,
updateDoc, NodeUpdate(..)
) where
import Data.OrgMode.Doc
import Data.OrgMode.Text
import Data.Set (Set(..), member, lookupLE)
import Data.Maybe (mapMaybe, fromJust, catMaybes)
data OrgDocView a = OrgDocView
{ ovElements :: [(a, Node)]
, ovDocument :: OrgDoc
}
class (Eq a) => NodeUpdate a where
findItemInNode :: Node -> Maybe a
updateNodeLine :: a -> Node -> Maybe Node
mergeSorted :: (Ord a) => [a] -> [a] -> [a]
mergeSorted [] [] = []
mergeSorted xs [] = xs
mergeSorted [] ys = ys
mergeSorted xl@(x:xs) yl@(y:ys) =
case compare x y of
EQ -> x:(mergeSorted xs yl)
LT -> x:(mergeSorted xs yl)
GT -> y:(mergeSorted xl ys)
instance TextLineSource OrgDoc where
getTextLines doc =
let docLines = concatMap getTextLines $ odNodes doc
propLines = concatMap getTextLines $ odProperties doc
in mergeSorted docLines propLines
instance TextLineSource (OrgDocView a) where
getTextLines = getTextLines . ovDocument
generateDocView :: (NodeUpdate a) => OrgDoc -> OrgDocView a
generateDocView doc =
let childNode (ChildNode n) = Just n
childNode _ = Nothing
childNodes n = mapMaybe childNode $ nChildren n
scanNode :: (Node -> Maybe a) -> Node -> [(a, Node)]
scanNode fn n = let hd = fn n
entry = maybe [] (\a -> [(a,n)]) hd
rest = (concatMap (scanNode fn) $ childNodes n)
in (entry++rest)
scanOrgForest :: (NodeUpdate a) => [Node] -> [(a, Node)]
scanOrgForest forest =
concatMap (scanNode findItemInNode) forest
forest = odNodes doc
elements = scanOrgForest forest
in OrgDocView elements doc
getRawElements :: OrgDocView a -> [a]
getRawElements docview =
map fst $ ovElements docview
updateElementList :: (NodeUpdate a) => [Node] -> [(a, Node)]
updateElementList nodes =
let nodeChildScan (ChildNode nd) = nodeScan nd
nodeChildScan _ = []
nodeScan nd =
let children = concatMap nodeChildScan (nChildren nd)
in case findItemInNode nd of
Just item -> (item, nd):children
Nothing -> children
in concatMap nodeScan nodes
updateDoc :: (Ord a, NodeUpdate a) => Set a -> OrgDocView a -> OrgDocView a
updateDoc new_items doc =
let nodeUpdater node =
case findItemInNode node of
Just item ->
if member item new_items
then let new_item = fromJust $ lookupLE item new_items
in updateNodeLine new_item node
else Nothing
Nothing -> Nothing
new_nodes =
map (updateNode nodeUpdater) $ odNodes $ ovDocument doc
new_doc = (ovDocument doc) { odNodes = new_nodes }
in doc { ovDocument = new_doc }