{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
module Test.Tasty.Sugar.Candidates
(
candidateToPath
, findCandidates
, makeCandidate
, candidateMatchPrefix
, candidateMatchSuffix
)
where
import Control.Monad ( filterM, guard )
import Data.Bifunctor ( first )
import qualified Data.List as DL
import Data.Maybe ( fromMaybe, isNothing )
import Numeric.Natural
import System.Directory ( doesDirectoryExist, getCurrentDirectory
, listDirectory, doesDirectoryExist )
import System.FilePath ( (</>), isRelative, makeRelative
, splitPath, takeDirectory, takeFileName)
import Test.Tasty.Sugar.Iterations
import Test.Tasty.Sugar.Types
findCandidates :: CUBE -> FilePath -> IO ([Either String CandidateFile])
findCandidates :: CUBE -> FilePath -> IO [Either FilePath CandidateFile]
findCandidates CUBE
cube FilePath
inDir =
let collectDirEntries :: FilePath -> IO [Either FilePath CandidateFile]
collectDirEntries FilePath
d =
let recurse :: Bool
recurse = FilePath -> FilePath
takeFileName FilePath
d forall a. Eq a => a -> a -> Bool
== FilePath
"*"
top :: Maybe FilePath
top = if Bool
recurse then forall a. a -> Maybe a
Just (FilePath -> FilePath
takeDirectory FilePath
d) else forall a. Maybe a
Nothing
start :: FilePath
start = if Bool
recurse then FilePath -> FilePath
takeDirectory FilePath
d else FilePath
d
in Maybe FilePath -> FilePath -> IO [Either FilePath CandidateFile]
dirListWithPaths Maybe FilePath
top FilePath
start
dirListWithPaths :: Maybe FilePath -> FilePath -> IO [Either FilePath CandidateFile]
dirListWithPaths Maybe FilePath
topDir FilePath
d =
FilePath -> IO Bool
doesDirectoryExist FilePath
d forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Bool
True ->
do [FilePath]
dirContents <- FilePath -> IO [FilePath]
listDirectory FilePath
d
case Maybe FilePath
topDir of
Maybe FilePath
Nothing -> do
let mkC :: FilePath -> CandidateFile
mkC = CUBE -> FilePath -> [FilePath] -> FilePath -> CandidateFile
makeCandidate CUBE
cube FilePath
d []
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> CandidateFile
mkC forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilePath]
dirContents)
Just FilePath
topdir -> do
let subs :: [FilePath]
subs = forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => t a -> Bool
null)
(forall a. [a] -> [a]
init
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. [a] -> [a]
init (FilePath -> [FilePath]
splitPath
forall a b. (a -> b) -> a -> b
$ FilePath -> FilePath -> FilePath
makeRelative FilePath
topdir (FilePath
d FilePath -> FilePath -> FilePath
</> FilePath
"x")))
let mkC :: FilePath -> CandidateFile
mkC = CUBE -> FilePath -> [FilePath] -> FilePath -> CandidateFile
makeCandidate CUBE
cube FilePath
topdir [FilePath]
subs
[FilePath]
subdirs <- forall (m :: * -> *) a.
Applicative m =>
(a -> m Bool) -> [a] -> m [a]
filterM (FilePath -> IO Bool
doesDirectoryExist forall b c a. (b -> c) -> (a -> b) -> a -> c
. (FilePath
d FilePath -> FilePath -> FilePath
</>)) [FilePath]
dirContents
let here :: [Either a CandidateFile]
here = forall a b. b -> Either a b
Right forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> CandidateFile
mkC forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath]
subdirs)) [FilePath]
dirContents)
[[Either FilePath CandidateFile]]
subCandidates <- forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Maybe FilePath -> FilePath -> IO [Either FilePath CandidateFile]
dirListWithPaths Maybe FilePath
topDir)
((FilePath
d FilePath -> FilePath -> FilePath
</>) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [FilePath]
subdirs)
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall {a}. [Either a CandidateFile]
here forall a. Semigroup a => a -> a -> a
<> (forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [[Either FilePath CandidateFile]]
subCandidates)
Bool
False -> do
FilePath
showD <- case FilePath -> Bool
isRelative FilePath
d of
Bool
True -> do FilePath
cwd <- IO FilePath
getCurrentDirectory
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ FilePath
"[" forall a. Semigroup a => a -> a -> a
<> FilePath
cwd forall a. Semigroup a => a -> a -> a
<> FilePath
"/]" forall a. Semigroup a => a -> a -> a
<> FilePath
d
Bool
False -> forall (m :: * -> *) a. Monad m => a -> m a
return FilePath
d
forall (m :: * -> *) a. Monad m => a -> m a
return [forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ FilePath
showD forall a. Semigroup a => a -> a -> a
<> FilePath
" does not exist"]
in FilePath -> IO [Either FilePath CandidateFile]
collectDirEntries FilePath
inDir
makeCandidate :: CUBE -> FilePath -> [String] -> FilePath -> CandidateFile
makeCandidate :: CUBE -> FilePath -> [FilePath] -> FilePath -> CandidateFile
makeCandidate CUBE
cube FilePath
topDir [FilePath]
subPath FilePath
fName =
let fl :: Int
fl = forall (t :: * -> *) a. Foldable t => t a -> Int
DL.length FilePath
fName
isSep :: Char -> Bool
isSep = (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` CUBE -> FilePath
separators CUBE
cube)
firstSep :: Int
firstSep = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
fl (forall a. Num a => a -> a -> a
+Int
1) forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> Maybe Int
DL.findIndex Char -> Bool
isSep FilePath
fName
fle :: Int
fle = forall b a. b -> (a -> b) -> Maybe a -> b
maybe Int
fl (Int
flforall a. Num a => a -> a -> a
-) forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> Maybe Int
DL.findIndex Char -> Bool
isSep forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
DL.reverse FilePath
fName
pmatches :: [(NamedParamMatch, (Natural, Int))]
pmatches = forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall a. LogicI a -> ([a], IterStat)
observeIAll
forall a b. (a -> b) -> a -> b
$ do ParameterPattern
p <- forall a. Text -> [a] -> LogicI a
eachFrom Text
"param for candidate" forall a b. (a -> b) -> a -> b
$ CUBE -> [ParameterPattern]
validParams CUBE
cube
FilePath
v <- forall a. Text -> [a] -> LogicI a
eachFrom Text
"value for param" (forall a. a -> Maybe a -> a
fromMaybe [] (forall a b. (a, b) -> b
snd ParameterPattern
p))
let vl :: Int
vl = forall (t :: * -> *) a. Foldable t => t a -> Int
DL.length FilePath
v
Int
i <- forall a. Text -> [a] -> LogicI a
eachFrom Text
"param starts"
forall a b. (a -> b) -> a -> b
$ forall a. (a -> Bool) -> [a] -> [Int]
DL.findIndices (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (CUBE -> FilePath
separators CUBE
cube)) FilePath
fName
let vs :: Int
vs = Int
i forall a. Num a => a -> a -> a
+ Int
1
let ve :: Int
ve = Int
vs forall a. Num a => a -> a -> a
+ Int
vl
if forall (t :: * -> *). Foldable t => t Bool -> Bool
and [ Int
ve forall a. Num a => a -> a -> a
+ Int
1 forall a. Ord a => a -> a -> Bool
< Int
fl
, FilePath
v forall a. Eq a => a -> a -> Bool
== forall a. Int -> [a] -> [a]
DL.take Int
vl (forall a. Int -> [a] -> [a]
DL.drop Int
vs FilePath
fName)
, forall a. [a] -> a
head (forall a. Int -> [a] -> [a]
DL.drop Int
ve FilePath
fName) forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` (CUBE -> FilePath
separators CUBE
cube)
]
then forall (m :: * -> *) a. Monad m => a -> m a
return ((forall a b. (a, b) -> a
fst ParameterPattern
p, FilePath -> ParamMatch
Explicit FilePath
v), (forall a. Enum a => Int -> a
toEnum Int
vs, Int
ve))
else do forall (f :: * -> *). Alternative f => Bool -> f ()
guard forall a b. (a -> b) -> a -> b
$ FilePath
v forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [FilePath]
subPath
forall (m :: * -> *) a. Monad m => a -> m a
return ((forall a b. (a, b) -> a
fst ParameterPattern
p, FilePath -> ParamMatch
Explicit FilePath
v), (Natural
0, Int
0))
pmatchArbitrary :: [(NamedParamMatch, (Natural, Int))]
pmatchArbitrary =
case forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
DL.find (forall a. Maybe a -> Bool
isNothing forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) forall a b. (a -> b) -> a -> b
$ CUBE -> [ParameterPattern]
validParams CUBE
cube of
Maybe ParameterPattern
Nothing -> []
Just (FilePath
p,Maybe [FilePath]
_) ->
let chkRange :: [(Int, Int)]
chkRange = [(Int
firstSep, Int
fle)]
arbs :: [(Natural, Int)]
arbs = [(Int, Int)] -> [(Natural, Int)] -> [(Natural, Int)]
holes [(Int, Int)]
chkRange (forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(NamedParamMatch, (Natural, Int))]
pmatches)
getRange :: (a, Int) -> FilePath
getRange (a
s,Int
e) = let s' :: Int
s' = forall a. Enum a => a -> Int
fromEnum a
s
in forall a. Int -> [a] -> [a]
DL.take (Int
e forall a. Num a => a -> a -> a
- Int
s' forall a. Num a => a -> a -> a
- Int
1) forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
DL.drop Int
s' FilePath
fName
holeVals :: [(FilePath, (Natural, Int))]
holeVals = let neither :: (t -> Bool) -> t -> t -> Bool
neither t -> Bool
f t
a t
b = Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *). Foldable t => t Bool -> Bool
or [t -> Bool
f t
a, t -> Bool
f t
b]
splitBySep :: FilePath -> [FilePath]
splitBySep = forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isSep)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> a -> Bool) -> [a] -> [[a]]
DL.groupBy (forall {t}. (t -> Bool) -> t -> t -> Bool
neither Char -> Bool
isSep)
rangeVals :: (a, Int) -> [(FilePath, (a, Int))]
rangeVals (a, Int)
r = (,(a, Int)
r) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (FilePath -> [FilePath]
splitBySep forall a b. (a -> b) -> a -> b
$ forall {a}. Enum a => (a, Int) -> FilePath
getRange (a, Int)
r)
in
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap forall {a}. Enum a => (a, Int) -> [(FilePath, (a, Int))]
rangeVals [(Natural, Int)]
arbs
dirVals :: [(FilePath, (Natural, Int))]
dirVals =
let pvals :: [Maybe FilePath]
pvals = ParamMatch -> Maybe FilePath
getParamVal forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(NamedParamMatch, (Natural, Int))]
pmatches
in (, (Natural
0,Int
0)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. (a -> Bool) -> [a] -> [a]
filter (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Maybe FilePath]
pvals) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just) [FilePath]
subPath
in (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ((FilePath
p,) forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePath -> ParamMatch
Explicit)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ([(FilePath, (Natural, Int))]
holeVals forall a. Semigroup a => a -> a -> a
<> [(FilePath, (Natural, Int))]
dirVals)
pAll :: [(NamedParamMatch, (Natural, Int))]
pAll = [(NamedParamMatch, (Natural, Int))]
pmatches forall a. Semigroup a => a -> a -> a
<> [(NamedParamMatch, (Natural, Int))]
pmatchArbitrary
dropSeps :: a -> a
dropSeps a
i =
let lst :: FilePath
lst = forall a. [a] -> a
last forall a b. (a -> b) -> a -> b
$ forall a. Eq a => [a] -> [[a]]
DL.group forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
DL.take (forall a. Enum a => a -> Int
fromEnum a
i) FilePath
fName
in if Char -> Bool
isSep forall a b. (a -> b) -> a -> b
$ forall a. [a] -> a
head FilePath
lst
then a
i forall a. Num a => a -> a -> a
- (forall a. Enum a => Int -> a
toEnum (forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
lst) forall a. Num a => a -> a -> a
- a
1)
else a
i
mtchIdx :: Natural
mtchIdx = forall {a}. (Num a, Enum a) => a -> a
dropSeps
forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) a. (Foldable t, Ord a) => t a -> a
minimum
forall a b. (a -> b) -> a -> b
$ forall a. Enum a => Int -> a
toEnum Int
fle
forall a. a -> [a] -> [a]
: forall a. (a -> Bool) -> [a] -> [a]
filter (forall a. Eq a => a -> a -> Bool
/= Natural
0) (forall a b. (a, b) -> a
fst forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(NamedParamMatch, (Natural, Int))]
pAll)
in CandidateFile { candidateDir :: FilePath
candidateDir = FilePath
topDir
, candidateSubdirs :: [FilePath]
candidateSubdirs = [FilePath]
subPath
, candidateFile :: FilePath
candidateFile = FilePath
fName
, candidatePMatch :: [NamedParamMatch]
candidatePMatch = forall a. Eq a => [a] -> [a]
DL.nub forall a b. (a -> b) -> a -> b
$ forall a. Ord a => [a] -> [a]
DL.sort forall a b. (a -> b) -> a -> b
$ (forall a b. (a, b) -> a
fst forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(NamedParamMatch, (Natural, Int))]
pAll)
, candidateMatchIdx :: Natural
candidateMatchIdx = Natural
mtchIdx
}
holes :: [(Int,Int)] -> [(Natural,Int)] -> [(Natural,Int)]
holes :: [(Int, Int)] -> [(Natural, Int)] -> [(Natural, Int)]
holes [(Int, Int)]
chkRange [(Natural, Int)]
present =
let rmvKnown :: (a, Int) -> [(a, Int)] -> [(a, Int)]
rmvKnown (a, Int)
_ [] = []
rmvKnown p :: (a, Int)
p@(a
ps,Int
pe) ((a
s,Int
e):[(a, Int)]
rs) =
if forall a. Num a => a -> a
abs(forall a. Enum a => a -> Int
fromEnum a
ps forall a. Num a => a -> a -> a
- forall a. Enum a => a -> Int
fromEnum a
s) forall a. Ord a => a -> a -> Bool
<= Int
1
then if Int
pe forall a. Ord a => a -> a -> Bool
> Int
e
then (a, Int) -> [(a, Int)] -> [(a, Int)]
rmvKnown (forall a. Enum a => Int -> a
toEnum Int
e,Int
pe) [(a, Int)]
rs
else if forall a. Num a => a -> a
abs(Int
peforall a. Num a => a -> a -> a
-Int
e) forall a. Ord a => a -> a -> Bool
<= Int
1
then [(a, Int)]
rs
else (forall a. Enum a => Int -> a
toEnum Int
pe forall a. Num a => a -> a -> a
+ a
1, Int
e) forall a. a -> [a] -> [a]
: [(a, Int)]
rs
else if a
ps forall a. Ord a => a -> a -> Bool
>= a
s Bool -> Bool -> Bool
&& forall a. Enum a => a -> Int
fromEnum a
ps forall a. Ord a => a -> a -> Bool
< Int
e
then if forall a. Num a => a -> a
abs(Int
pe forall a. Num a => a -> a -> a
- Int
e) forall a. Ord a => a -> a -> Bool
<= Int
1
then (a
s, forall a. Enum a => a -> Int
fromEnum a
ps) forall a. a -> [a] -> [a]
: [(a, Int)]
rs
else if Int
pe forall a. Ord a => a -> a -> Bool
< Int
e
then (a
s, forall a. Enum a => a -> Int
fromEnum a
ps) forall a. a -> [a] -> [a]
: (forall a. Enum a => Int -> a
toEnum Int
pe, Int
e) forall a. a -> [a] -> [a]
: [(a, Int)]
rs
else (a
s, forall a. Enum a => a -> Int
fromEnum a
ps) forall a. a -> [a] -> [a]
: (a, Int) -> [(a, Int)] -> [(a, Int)]
rmvKnown (forall a. Enum a => Int -> a
toEnum Int
e, Int
pe) [(a, Int)]
rs
else (a, Int) -> [(a, Int)] -> [(a, Int)]
rmvKnown (a, Int)
p [(a, Int)]
rs
r' :: [(Int, Int)]
r' = forall a. (a -> Bool) -> [a] -> [a]
filter (\(Int, Int)
x -> forall a b. (a, b) -> a
fst (Int, Int)
x forall a. Eq a => a -> a -> Bool
/= forall a b. (a, b) -> b
snd (Int, Int)
x) [(Int, Int)]
chkRange
p' :: [(Natural, Int)]
p' = forall a. (a -> Bool) -> [a] -> [a]
filter (\(Natural
x,Int
y) -> Bool -> Bool
not forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *). Foldable t => t Bool -> Bool
and [ Natural
x forall a. Eq a => a -> a -> Bool
== Natural
0, Int
y forall a. Eq a => a -> a -> Bool
== Int
0 ]) [(Natural, Int)]
present
in forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall {a}.
(Enum a, Num a, Ord a) =>
(a, Int) -> [(a, Int)] -> [(a, Int)]
rmvKnown (forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first forall a. Enum a => Int -> a
toEnum forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [(Int, Int)]
r') (forall a. Ord a => [a] -> [a]
DL.sort [(Natural, Int)]
p')
candidateToPath :: CandidateFile -> FilePath
candidateToPath :: CandidateFile -> FilePath
candidateToPath CandidateFile
c =
CandidateFile -> FilePath
candidateDir CandidateFile
c FilePath -> FilePath -> FilePath
</> forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr FilePath -> FilePath -> FilePath
(</>) (CandidateFile -> FilePath
candidateFile CandidateFile
c) (CandidateFile -> [FilePath]
candidateSubdirs CandidateFile
c)
candidateMatchPrefix :: Separators -> CandidateFile -> CandidateFile -> Bool
candidateMatchPrefix :: FilePath -> CandidateFile -> CandidateFile -> Bool
candidateMatchPrefix FilePath
seps CandidateFile
mf CandidateFile
cf =
let mStart :: FilePath
mStart = CandidateFile -> FilePath
candidateFile CandidateFile
mf
mStartLen :: Int
mStartLen = forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
mStart
f :: FilePath
f = CandidateFile -> FilePath
candidateFile CandidateFile
cf
pfxlen :: Natural
pfxlen = let cl :: Natural
cl = CandidateFile -> Natural
candidateMatchIdx CandidateFile
cf
in if forall a. Enum a => a -> Int
fromEnum Natural
cl forall a. Eq a => a -> a -> Bool
== forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
f
then if forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
seps then forall a. Enum a => Int -> a
toEnum Int
mStartLen else Natural
cl
else Natural
cl forall a. Num a => a -> a -> a
- Natural
1
in FilePath
mStart forall a. Eq a => a -> a -> Bool
== forall a. Int -> [a] -> [a]
DL.take (forall a. Enum a => a -> Int
fromEnum Natural
pfxlen) FilePath
f
candidateMatchSuffix :: Separators -> FileSuffix -> CandidateFile
-> CandidateFile -> Bool
candidateMatchSuffix :: FilePath -> FilePath -> CandidateFile -> CandidateFile -> Bool
candidateMatchSuffix FilePath
seps FilePath
sfx CandidateFile
rootf CandidateFile
cf =
let f :: FilePath
f = CandidateFile -> FilePath
candidateFile CandidateFile
cf
sfxsep :: Bool
sfxsep = Bool -> Bool
not (forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
sfx) Bool -> Bool -> Bool
&& forall a. [a] -> a
head FilePath
sfx forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` FilePath
seps
in if forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
sfx
then FilePath
f forall a. Eq a => a -> a -> Bool
== forall a. (a -> Bool) -> [a] -> [a]
DL.takeWhile (Bool -> Bool
not forall b c a. (b -> c) -> (a -> b) -> a -> c
. (forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` FilePath
seps)) FilePath
f
else forall (t :: * -> *). Foldable t => t Bool -> Bool
and [ forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
f forall a. Ord a => a -> a -> Bool
>= (forall (t :: * -> *) a. Foldable t => t a -> Int
length (CandidateFile -> FilePath
candidateFile CandidateFile
rootf) forall a. Num a => a -> a -> a
+ forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
sfx)
, FilePath
sfx forall a. Eq a => [a] -> [a] -> Bool
`DL.isSuffixOf` FilePath
f
, if forall (t :: * -> *) a. Foldable t => t a -> Bool
null FilePath
seps
then forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
f forall a. Eq a => a -> a -> Bool
== forall (t :: * -> *) a. Foldable t => t a -> Int
length (CandidateFile -> FilePath
candidateFile CandidateFile
rootf) forall a. Num a => a -> a -> a
+ forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
sfx
else if Bool
sfxsep
then Bool
True
else forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False ((forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` FilePath
seps) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> a
fst)
forall a b. (a -> b) -> a -> b
$ forall a. [a] -> Maybe (a, [a])
DL.uncons
forall a b. (a -> b) -> a -> b
$ forall a. Int -> [a] -> [a]
DL.drop (forall (t :: * -> *) a. Foldable t => t a -> Int
length FilePath
sfx)
forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a]
reverse FilePath
f
]