{-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} module Annotations.MultiRec.Positional where import Annotations.Bounds import Annotations.ExploreHints import Annotations.MultiRec.Annotated import Annotations.MultiRec.Zipper import Annotations.MultiRec.ZipperFix import Generics.MultiRec.Base import Generics.MultiRec.HFunctor import Data.Maybe import Data.List import Data.Ord import Control.Applicative -- | Find the deepest node whose bounds match the given range. See 'rangeInBounds'. selectByRange :: Zipper phi (PF phi) => phi ix -> Range -> AnnFix Bounds phi ix -> Maybe (AnnZipper phi Bounds ix) selectByRange p range@(left, _) = listToMaybe . reverse . explore p hints where hints bounds@(Bounds _ (ir, _)) = ExploreHints { matchHere = range `rangeInBounds` bounds , exploreDown = range `rangeInRange` outerRange bounds , exploreRight = left >= ir } selectByPos :: (Zipper phi (PF phi)) => phi ix -> Int -> AnnFix Bounds phi ix -> Maybe (AnnZipper phi Bounds ix) selectByPos p pos = findLeftmostDeepest p (posInRange pos . innerRange) repairBy :: (Ord dist, HFunctor phi (PF phi)) => phi ix -> (Range -> Range -> dist) -> AnnFix Bounds phi ix -> Range -> Bounds repairBy p cost tree range = head (sortOn (cost range . innerRange) (allAnnotations p tree)) -- | Defined as @'repairBy' 'distRange'@. repair :: HFunctor phi (PF phi) => phi ix -> AnnFix Bounds phi ix -> Range -> Bounds repair p = repairBy p distRange sortOn :: Ord b => (a -> b) -> [a] -> [a] sortOn = sortBy . comparing -- | Move around in a tree according to the 'Nav', expressed in tree selections. Although a 'Range' is required as input, a 'Bounds' is returned, providing information about all the valid text selections that would select the particular tree node. moveSelection :: Zipper phi (PF phi) => phi ix -> AnnFix Bounds phi ix -> Nav -> Range -> Maybe Bounds moveSelection p tree nav range = focusAnn <$> (selectByRange p range tree >>= nav)