{-# LANGUAGE DeriveLift #-}

module StrongPath.Internal
  ( Path (..),
    RelPathPrefix (..),
    Abs,
    Rel,
    Dir,
    File,
    Posix,
    Windows,
    System,
    Path',
    File',
    Dir',
    Rel',
    parseRelFileFP,
    parseRelDirFP,
    impossible,
    prefixNumParentDirs,
    relPathNumParentDirs,
    relPathPrefix,
    extractRelPathPrefix,
  )
where

import Control.Monad.Catch (MonadThrow, throwM)
import Language.Haskell.TH.Syntax (Lift)
import qualified Path as P
import qualified Path.Posix as PP
import qualified Path.Windows as PW

-- | Strongly typed file path. Central type of the "StrongPath".
--
--   [@s@]: __Standard__: Posix or windows. Can be fixed ('Posix', 'Windows') or determined by the system ('System').
--
--   [@b@]: __Base__: Absolute ('Abs') or relative ('Rel').
--
--   [@t@]: __Type__: File ('File') or directory ('Dir').
--
-- Some examples:
--
-- > Path System (Dir HomeDir) (File FooFile)
-- > Path System Abs (Dir HomeDir)
-- > Path Posix (Rel ProjectRoot) (File ())
data Path s b t
  = -- NOTE: Relative paths can be sometimes be tricky when being reasoned about in the internal library code,
    --   when reconstructing them and working with them, due to RelPathPrefix and edge cases like ".", "..".
    --
    --   For example if original relative path was "..", we will parse it into RelDir "." ParentDir 1.
    --   Then it is important to be aware that this should be regarded as "..", and not "../.".
    --   In some functions like `basename` it is important to be aware of this.
    --
    --   Also, Path.Path can't hold empty path, so we can count on paths not to be empty.
    --
    --   And Path.Path can't store "." as file, only as dir, so that is also good to know.
    --
    --   I wonder if we could find a better way to represent path internaly, a way which would encode
    --   tricky situations explicitly, or maybe some kind of lower-level interface around it that would encode
    --   things like "paths can't be empty", "dir can be '.' but file can't", and similar.
    --   But maybe the solution would just be too complicated.
    -- System
    RelDir (P.Path P.Rel P.Dir) RelPathPrefix
  | RelFile (P.Path P.Rel P.File) RelPathPrefix
  | AbsDir (P.Path P.Abs P.Dir)
  | AbsFile (P.Path P.Abs P.File)
  | -- Windows
    RelDirW (PW.Path PW.Rel PW.Dir) RelPathPrefix
  | RelFileW (PW.Path PW.Rel PW.File) RelPathPrefix
  | AbsDirW (PW.Path PW.Abs PW.Dir)
  | AbsFileW (PW.Path PW.Abs PW.File)
  | -- Posix
    RelDirP (PP.Path PP.Rel PP.Dir) RelPathPrefix
  | RelFileP (PP.Path PP.Rel PP.File) RelPathPrefix
  | AbsDirP (PP.Path PP.Abs PP.Dir)
  | AbsFileP (PP.Path PP.Abs PP.File)
  deriving (Int -> Path s b t -> ShowS
[Path s b t] -> ShowS
Path s b t -> [Char]
(Int -> Path s b t -> ShowS)
-> (Path s b t -> [Char])
-> ([Path s b t] -> ShowS)
-> Show (Path s b t)
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
forall s b t. Int -> Path s b t -> ShowS
forall s b t. [Path s b t] -> ShowS
forall s b t. Path s b t -> [Char]
showList :: [Path s b t] -> ShowS
$cshowList :: forall s b t. [Path s b t] -> ShowS
show :: Path s b t -> [Char]
$cshow :: forall s b t. Path s b t -> [Char]
showsPrec :: Int -> Path s b t -> ShowS
$cshowsPrec :: forall s b t. Int -> Path s b t -> ShowS
Show, Path s b t -> Path s b t -> Bool
(Path s b t -> Path s b t -> Bool)
-> (Path s b t -> Path s b t -> Bool) -> Eq (Path s b t)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall s b t. Path s b t -> Path s b t -> Bool
/= :: Path s b t -> Path s b t -> Bool
$c/= :: forall s b t. Path s b t -> Path s b t -> Bool
== :: Path s b t -> Path s b t -> Bool
$c== :: forall s b t. Path s b t -> Path s b t -> Bool
Eq, (forall (m :: * -> *). Quote m => Path s b t -> m Exp)
-> (forall (m :: * -> *).
    Quote m =>
    Path s b t -> Code m (Path s b t))
-> Lift (Path s b t)
forall s b t (m :: * -> *). Quote m => Path s b t -> m Exp
forall s b t (m :: * -> *).
Quote m =>
Path s b t -> Code m (Path s b t)
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Path s b t -> m Exp
forall (m :: * -> *). Quote m => Path s b t -> Code m (Path s b t)
liftTyped :: forall (m :: * -> *). Quote m => Path s b t -> Code m (Path s b t)
$cliftTyped :: forall s b t (m :: * -> *).
Quote m =>
Path s b t -> Code m (Path s b t)
lift :: forall (m :: * -> *). Quote m => Path s b t -> m Exp
$clift :: forall s b t (m :: * -> *). Quote m => Path s b t -> m Exp
Lift)

data RelPathPrefix
  = -- | ../, Int saying how many times it repeats.
    ParentDir Int
  | NoPrefix
  deriving (Int -> RelPathPrefix -> ShowS
[RelPathPrefix] -> ShowS
RelPathPrefix -> [Char]
(Int -> RelPathPrefix -> ShowS)
-> (RelPathPrefix -> [Char])
-> ([RelPathPrefix] -> ShowS)
-> Show RelPathPrefix
forall a.
(Int -> a -> ShowS) -> (a -> [Char]) -> ([a] -> ShowS) -> Show a
showList :: [RelPathPrefix] -> ShowS
$cshowList :: [RelPathPrefix] -> ShowS
show :: RelPathPrefix -> [Char]
$cshow :: RelPathPrefix -> [Char]
showsPrec :: Int -> RelPathPrefix -> ShowS
$cshowsPrec :: Int -> RelPathPrefix -> ShowS
Show, RelPathPrefix -> RelPathPrefix -> Bool
(RelPathPrefix -> RelPathPrefix -> Bool)
-> (RelPathPrefix -> RelPathPrefix -> Bool) -> Eq RelPathPrefix
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: RelPathPrefix -> RelPathPrefix -> Bool
$c/= :: RelPathPrefix -> RelPathPrefix -> Bool
== :: RelPathPrefix -> RelPathPrefix -> Bool
$c== :: RelPathPrefix -> RelPathPrefix -> Bool
Eq, (forall (m :: * -> *). Quote m => RelPathPrefix -> m Exp)
-> (forall (m :: * -> *).
    Quote m =>
    RelPathPrefix -> Code m RelPathPrefix)
-> Lift RelPathPrefix
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => RelPathPrefix -> m Exp
forall (m :: * -> *).
Quote m =>
RelPathPrefix -> Code m RelPathPrefix
liftTyped :: forall (m :: * -> *).
Quote m =>
RelPathPrefix -> Code m RelPathPrefix
$cliftTyped :: forall (m :: * -> *).
Quote m =>
RelPathPrefix -> Code m RelPathPrefix
lift :: forall (m :: * -> *). Quote m => RelPathPrefix -> m Exp
$clift :: forall (m :: * -> *). Quote m => RelPathPrefix -> m Exp
Lift)

-- | Describes 'Path' base as absolute.
data Abs deriving ((forall (m :: * -> *). Quote m => Abs -> m Exp)
-> (forall (m :: * -> *). Quote m => Abs -> Code m Abs) -> Lift Abs
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Abs -> m Exp
forall (m :: * -> *). Quote m => Abs -> Code m Abs
liftTyped :: forall (m :: * -> *). Quote m => Abs -> Code m Abs
$cliftTyped :: forall (m :: * -> *). Quote m => Abs -> Code m Abs
lift :: forall (m :: * -> *). Quote m => Abs -> m Exp
$clift :: forall (m :: * -> *). Quote m => Abs -> m Exp
Lift)

-- | Describes 'Path' base as relative to the directory @dir@.
data Rel dir deriving ((forall (m :: * -> *). Quote m => Rel dir -> m Exp)
-> (forall (m :: * -> *). Quote m => Rel dir -> Code m (Rel dir))
-> Lift (Rel dir)
forall dir (m :: * -> *). Quote m => Rel dir -> m Exp
forall dir (m :: * -> *). Quote m => Rel dir -> Code m (Rel dir)
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Rel dir -> m Exp
forall (m :: * -> *). Quote m => Rel dir -> Code m (Rel dir)
liftTyped :: forall (m :: * -> *). Quote m => Rel dir -> Code m (Rel dir)
$cliftTyped :: forall dir (m :: * -> *). Quote m => Rel dir -> Code m (Rel dir)
lift :: forall (m :: * -> *). Quote m => Rel dir -> m Exp
$clift :: forall dir (m :: * -> *). Quote m => Rel dir -> m Exp
Lift)

-- | Means that path points to a directory @dir@.
-- To use as a type in place of @dir@, we recommend creating an empty
-- data type representing the specific directory, e.g. @data ProjectRootDir@.
data Dir dir deriving ((forall (m :: * -> *). Quote m => Dir dir -> m Exp)
-> (forall (m :: * -> *). Quote m => Dir dir -> Code m (Dir dir))
-> Lift (Dir dir)
forall dir (m :: * -> *). Quote m => Dir dir -> m Exp
forall dir (m :: * -> *). Quote m => Dir dir -> Code m (Dir dir)
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Dir dir -> m Exp
forall (m :: * -> *). Quote m => Dir dir -> Code m (Dir dir)
liftTyped :: forall (m :: * -> *). Quote m => Dir dir -> Code m (Dir dir)
$cliftTyped :: forall dir (m :: * -> *). Quote m => Dir dir -> Code m (Dir dir)
lift :: forall (m :: * -> *). Quote m => Dir dir -> m Exp
$clift :: forall dir (m :: * -> *). Quote m => Dir dir -> m Exp
Lift)

-- | Means that path points to a file @file@.
-- To use as a type in place of @file@, we recommend creating an empty
-- data type representing the specific file, e.g. @data ProjectManifestFile@.
data File file deriving ((forall (m :: * -> *). Quote m => File file -> m Exp)
-> (forall (m :: * -> *).
    Quote m =>
    File file -> Code m (File file))
-> Lift (File file)
forall file (m :: * -> *). Quote m => File file -> m Exp
forall file (m :: * -> *).
Quote m =>
File file -> Code m (File file)
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => File file -> m Exp
forall (m :: * -> *). Quote m => File file -> Code m (File file)
liftTyped :: forall (m :: * -> *). Quote m => File file -> Code m (File file)
$cliftTyped :: forall file (m :: * -> *).
Quote m =>
File file -> Code m (File file)
lift :: forall (m :: * -> *). Quote m => File file -> m Exp
$clift :: forall file (m :: * -> *). Quote m => File file -> m Exp
Lift)

-- | Describes 'Path' standard as posix (e.g. @\/path\/to\/foobar@).
-- This makes 'Path' behave in system-independent fashion: code behaves the same
-- regardless of the system it is running on.
-- You will normally want to use it when dealing with paths from some external source,
-- or with paths that have explicitely fixed standard.
-- For example, if you are running your Haskell program on Windows and parsing logs which
-- were obtained from the Linux server, or maybe you are parsing Javascript import statements,
-- you will want to use 'Posix'.
data Posix deriving ((forall (m :: * -> *). Quote m => Posix -> m Exp)
-> (forall (m :: * -> *). Quote m => Posix -> Code m Posix)
-> Lift Posix
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Posix -> m Exp
forall (m :: * -> *). Quote m => Posix -> Code m Posix
liftTyped :: forall (m :: * -> *). Quote m => Posix -> Code m Posix
$cliftTyped :: forall (m :: * -> *). Quote m => Posix -> Code m Posix
lift :: forall (m :: * -> *). Quote m => Posix -> m Exp
$clift :: forall (m :: * -> *). Quote m => Posix -> m Exp
Lift)

-- | Describes 'Path' standard as windows (e.g. @C:\\path\\to\\foobar@).
-- Check 'Posix' for more details, everything is analogous.
data Windows deriving ((forall (m :: * -> *). Quote m => Windows -> m Exp)
-> (forall (m :: * -> *). Quote m => Windows -> Code m Windows)
-> Lift Windows
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => Windows -> m Exp
forall (m :: * -> *). Quote m => Windows -> Code m Windows
liftTyped :: forall (m :: * -> *). Quote m => Windows -> Code m Windows
$cliftTyped :: forall (m :: * -> *). Quote m => Windows -> Code m Windows
lift :: forall (m :: * -> *). Quote m => Windows -> m Exp
$clift :: forall (m :: * -> *). Quote m => Windows -> m Exp
Lift)

-- | Describes 'Path' standard to be determined by the system/OS.
--
-- If the system is Windows, it will resolve to 'Windows' internally, and if not,
-- it will resolve to 'Posix'.
--
-- However, keep in mind that even if running on Windows, @Path Windows b t@
-- and @Path System b t@ are still considered to be different types,
-- even though @Path System b t @ internally uses Windows standard.
--
-- You will normally want to use 'System' if you are dealing with the paths on the disk of the host OS
-- (where your code is running), for example if user is providing you with the path to the file on the disk
-- that you will be doing something with.
-- Keep in mind that 'System' causes the behaviour of 'Path' to be system/platform-dependant.
data System deriving ((forall (m :: * -> *). Quote m => System -> m Exp)
-> (forall (m :: * -> *). Quote m => System -> Code m System)
-> Lift System
forall t.
(forall (m :: * -> *). Quote m => t -> m Exp)
-> (forall (m :: * -> *). Quote m => t -> Code m t) -> Lift t
forall (m :: * -> *). Quote m => System -> m Exp
forall (m :: * -> *). Quote m => System -> Code m System
liftTyped :: forall (m :: * -> *). Quote m => System -> Code m System
$cliftTyped :: forall (m :: * -> *). Quote m => System -> Code m System
lift :: forall (m :: * -> *). Quote m => System -> m Exp
$clift :: forall (m :: * -> *). Quote m => System -> m Exp
Lift) -- Depends on the platform, it is either Posix or Windows.

-- | 'System' is the most commonly used standard, so we provide you with a type alias for it.
type Path' = Path System

-- | When you don't want your path to be relative to anything specific,
-- it is convenient to use unit @()@.
type Rel' = Rel ()

-- | When you don't want your directory path to be named,
-- it is convenient to use unit @()@.
type Dir' = Dir ()

-- | When you don't want your file path to be named,
-- it is convenient to use unit @()@.
type File' = File ()

-- TODO: Extract `parseRelFileFP`, `parseRelDirFP`, `parseRelFP` and `extractRelPathPrefix` into StrongPath.FilePath.Internals?

parseRelFileFP ::
  MonadThrow m =>
  (p -> RelPathPrefix -> Path s (Rel d) (File f)) ->
  [Char] ->
  (FilePath -> m p) ->
  FilePath ->
  m (Path s (Rel d) (File f))
parseRelFileFP :: forall (m :: * -> *) p s d f.
MonadThrow m =>
(p -> RelPathPrefix -> Path s (Rel d) (File f))
-> [Char]
-> ([Char] -> m p)
-> [Char]
-> m (Path s (Rel d) (File f))
parseRelFileFP p -> RelPathPrefix -> Path s (Rel d) (File f)
_ [Char]
_ [Char] -> m p
_ [Char]
"" = PathException -> m (Path s (Rel d) (File f))
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM ([Char] -> PathException
P.InvalidRelFile [Char]
"")
parseRelFileFP p -> RelPathPrefix -> Path s (Rel d) (File f)
constructor [Char]
validSeparators [Char] -> m p
pathParser [Char]
fp = (p -> RelPathPrefix -> Path s (Rel d) (File f))
-> [Char]
-> ([Char] -> m p)
-> [Char]
-> m (Path s (Rel d) (File f))
forall (m :: * -> *) p s d1 t.
MonadThrow m =>
(p -> RelPathPrefix -> Path s (Rel d1) t)
-> [Char] -> ([Char] -> m p) -> [Char] -> m (Path s (Rel d1) t)
parseRelFP p -> RelPathPrefix -> Path s (Rel d) (File f)
constructor [Char]
validSeparators [Char] -> m p
pathParser [Char]
fp

parseRelDirFP ::
  MonadThrow m =>
  (p -> RelPathPrefix -> Path s (Rel d1) (Dir d2)) ->
  [Char] ->
  (FilePath -> m p) ->
  FilePath ->
  m (Path s (Rel d1) (Dir d2))
parseRelDirFP :: forall (m :: * -> *) p s d1 d2.
MonadThrow m =>
(p -> RelPathPrefix -> Path s (Rel d1) (Dir d2))
-> [Char]
-> ([Char] -> m p)
-> [Char]
-> m (Path s (Rel d1) (Dir d2))
parseRelDirFP p -> RelPathPrefix -> Path s (Rel d1) (Dir d2)
_ [Char]
_ [Char] -> m p
_ [Char]
"" = PathException -> m (Path s (Rel d1) (Dir d2))
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM ([Char] -> PathException
P.InvalidRelDir [Char]
"")
parseRelDirFP p -> RelPathPrefix -> Path s (Rel d1) (Dir d2)
constructor [Char]
validSeparators [Char] -> m p
pathParser [Char]
fp = (p -> RelPathPrefix -> Path s (Rel d1) (Dir d2))
-> [Char]
-> ([Char] -> m p)
-> [Char]
-> m (Path s (Rel d1) (Dir d2))
forall (m :: * -> *) p s d1 t.
MonadThrow m =>
(p -> RelPathPrefix -> Path s (Rel d1) t)
-> [Char] -> ([Char] -> m p) -> [Char] -> m (Path s (Rel d1) t)
parseRelFP p -> RelPathPrefix -> Path s (Rel d1) (Dir d2)
constructor [Char]
validSeparators [Char] -> m p
pathParser [Char]
fp

-- Helper function for the parseRelFileFP and parseRelDirFP, should not be used called directly but only
-- by parseRelFileFP and parseRelDirFP.
parseRelFP ::
  MonadThrow m =>
  (p -> RelPathPrefix -> Path s (Rel d1) t) ->
  [Char] ->
  (FilePath -> m p) ->
  FilePath ->
  m (Path s (Rel d1) t)
parseRelFP :: forall (m :: * -> *) p s d1 t.
MonadThrow m =>
(p -> RelPathPrefix -> Path s (Rel d1) t)
-> [Char] -> ([Char] -> m p) -> [Char] -> m (Path s (Rel d1) t)
parseRelFP p -> RelPathPrefix -> Path s (Rel d1) t
_ [Char]
_ [Char] -> m p
_ [Char]
"" = [Char] -> m (Path s (Rel d1) t)
forall a. HasCallStack => [Char] -> a
error [Char]
"can't parse empty path"
parseRelFP p -> RelPathPrefix -> Path s (Rel d1) t
constructor [Char]
validSeparators [Char] -> m p
pathParser [Char]
fp = do
  let (RelPathPrefix
prefix, [Char]
fp') = [Char] -> [Char] -> (RelPathPrefix, [Char])
extractRelPathPrefix [Char]
validSeparators [Char]
fp
      fp'' :: [Char]
fp'' = if [Char]
fp' [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char]
"" then [Char]
"." else [Char]
fp' -- Because Path Rel parsers can't handle just "".
  (\p
p -> p -> RelPathPrefix -> Path s (Rel d1) t
constructor p
p RelPathPrefix
prefix) (p -> Path s (Rel d1) t) -> m p -> m (Path s (Rel d1) t)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [Char] -> m p
pathParser [Char]
fp''

-- | Extracts a multiple "../" from start of the file path.
--   If path is completely ../../.., also handles the last one.
--   NOTE: We don't normalize path in any way.
extractRelPathPrefix :: [Char] -> FilePath -> (RelPathPrefix, FilePath)
extractRelPathPrefix :: [Char] -> [Char] -> (RelPathPrefix, [Char])
extractRelPathPrefix [Char]
validSeparators [Char]
path =
  let (Int
n, [Char]
path') = [Char] -> (Int, [Char])
dropParentDirs [Char]
path
   in (if Int
n Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
0 then RelPathPrefix
NoPrefix else Int -> RelPathPrefix
ParentDir Int
n, [Char]
path')
  where
    parentDirStrings :: [String]
    parentDirStrings :: [[Char]]
parentDirStrings = [[Char
'.', Char
'.', Char
s] | Char
s <- [Char]
validSeparators]

    pathStartsWithParentDir :: FilePath -> Bool
    pathStartsWithParentDir :: [Char] -> Bool
pathStartsWithParentDir [Char]
p = Int -> ShowS
forall a. Int -> [a] -> [a]
take Int
3 [Char]
p [Char] -> [[Char]] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [[Char]]
parentDirStrings

    dropParentDirs :: FilePath -> (Int, FilePath)
    dropParentDirs :: [Char] -> (Int, [Char])
dropParentDirs [Char]
p
      | [Char] -> Bool
pathStartsWithParentDir [Char]
p =
        let (Int
n, [Char]
p') = [Char] -> (Int, [Char])
dropParentDirs (Int -> ShowS
forall a. Int -> [a] -> [a]
drop Int
3 [Char]
p)
         in (Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n, [Char]
p')
      | [Char]
p [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char]
".." = (Int
1, [Char]
"")
      | Bool
otherwise = (Int
0, [Char]
p)

prefixNumParentDirs :: RelPathPrefix -> Int
prefixNumParentDirs :: RelPathPrefix -> Int
prefixNumParentDirs RelPathPrefix
NoPrefix = Int
0
prefixNumParentDirs (ParentDir Int
n) = Int
n

relPathNumParentDirs :: Path s (Rel r) t -> Int
relPathNumParentDirs :: forall s r t. Path s (Rel r) t -> Int
relPathNumParentDirs = RelPathPrefix -> Int
prefixNumParentDirs (RelPathPrefix -> Int)
-> (Path s (Rel r) t -> RelPathPrefix) -> Path s (Rel r) t -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Path s (Rel r) t -> RelPathPrefix
forall s r t. Path s (Rel r) t -> RelPathPrefix
relPathPrefix

relPathPrefix :: Path s (Rel r) t -> RelPathPrefix
relPathPrefix :: forall s r t. Path s (Rel r) t -> RelPathPrefix
relPathPrefix Path s (Rel r) t
sp = case Path s (Rel r) t
sp of
  RelDir Path Rel Dir
_ RelPathPrefix
pr -> RelPathPrefix
pr
  RelFile Path Rel File
_ RelPathPrefix
pr -> RelPathPrefix
pr
  RelDirW Path Rel Dir
_ RelPathPrefix
pr -> RelPathPrefix
pr
  RelFileW Path Rel File
_ RelPathPrefix
pr -> RelPathPrefix
pr
  RelDirP Path Rel Dir
_ RelPathPrefix
pr -> RelPathPrefix
pr
  RelFileP Path Rel File
_ RelPathPrefix
pr -> RelPathPrefix
pr
  Path s (Rel r) t
_ -> RelPathPrefix
forall a. a
impossible

impossible :: a
impossible :: forall a. a
impossible = [Char] -> a
forall a. HasCallStack => [Char] -> a
error [Char]
"This should be impossible."