Skip to content
This repository was archived by the owner on Apr 1, 2025. It is now read-only.

Commit 867455a

Browse files
author
Patrick Thomson
authored
Merge pull request #547 from zhujinxuan/joinpaths
Refactor joinPaths to use pathtype
2 parents 09b5e49 + eebc484 commit 867455a

File tree

2 files changed

+32
-24
lines changed

2 files changed

+32
-24
lines changed

src/Data/Abstract/Path.hs

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,43 @@ module Data.Abstract.Path
22
( dropRelativePrefix
33
, joinPaths
44
, stripQuotes
5-
, joinUntypedPaths
65
) where
76

87
import Data.Text (Text)
98
import qualified Data.Text as T
10-
import System.FilePath.Posix
119
import qualified System.Path as Path
12-
import System.Path.PartClass (FileDir)
10+
import System.Path.PartClass (FileDir(..))
1311

1412
-- | Join two paths a and b. Handles walking up relative directories in b. e.g.
1513
--
1614
-- joinPaths "a/b" "../c" == "a/c"
1715
-- joinPaths "a/b" "./c" == "a/b/c"
1816
--
1917
-- Walking beyond the beginning of a just stops when you get to the root of a.
20-
joinUntypedPaths :: FilePath -> FilePath -> FilePath
21-
joinUntypedPaths a b = let bs = splitPath (normalise b)
22-
n = length (filter (== "../") bs)
23-
in normalise $ walkup n a </> joinPath (drop n bs)
18+
joinPaths :: FileDir fd => Path.AbsRelDir -> Path.Rel fd -> Path.AbsRel fd
19+
joinPaths = runJP $ switchFileDir (JP joinFilePaths) (JP joinDirPaths) (JP joinFDPaths)
20+
21+
newtype JP fd = JP {runJP :: Path.AbsRelDir -> Path.Rel fd -> Path.AbsRel fd }
22+
23+
joinDirPaths :: Path.AbsRelDir -> Path.RelDir -> Path.AbsRelDir
24+
joinDirPaths x y = result isAbs
2425
where
25-
walkup 0 str = str
26-
walkup n str = walkup (pred n) (takeDirectory str)
26+
(isAbs, rels, _) = Path.splitPath (Path.normalise $ x Path.</> y)
27+
(_, fRel) = foldr go (0, Path.currentDir) rels
28+
go :: Path.RelDir -> (Integer, Path.RelDir) -> (Integer, Path.RelDir)
29+
go rel (i, r)
30+
| rel == Path.rel ".." = (i + 1, r)
31+
| i == 0 = (0, rel Path.</> r)
32+
| otherwise = (i - 1, r)
33+
result True = Path.toAbsRel $ Path.rootDir Path.</> fRel
34+
result False = Path.toAbsRel $ fRel
2735

28-
-- | Join two paths a and b. Handles walking up relative directories in b. e.g.
29-
--
30-
-- joinPaths "a/b" "../c" == "a/c"
31-
-- joinPaths "a/b" "./c" == "a/b/c"
32-
--
33-
-- Walking beyond the beginning of a just stops when you get to the root of a.
34-
-- TODO: Rewrite it with pathtype
35-
joinPaths :: FileDir fd => Path.AbsRelDir -> Path.Rel fd -> Path.AbsRel fd
36-
joinPaths x y= Path.path $ joinUntypedPaths (Path.toString x) (Path.toString y)
36+
37+
joinFilePaths :: Path.AbsRelDir -> Path.RelFile -> Path.AbsRelFile
38+
joinFilePaths x y = let (d, f) = Path.splitFileName y in joinDirPaths x d Path.</> f
39+
40+
joinFDPaths :: Path.AbsRelDir -> Path.RelFileDir -> Path.AbsRelFileDir
41+
joinFDPaths x = Path.toFileDir . joinDirPaths x . Path.dirFromFileDir
3742

3843

3944
stripQuotes :: Text -> Text

test/Data/Abstract/Path/Spec.hs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,22 @@ module Data.Abstract.Path.Spec(spec) where
22

33
import Data.Abstract.Path
44
import SpecHelpers
5+
import qualified System.Path as Path
56

67
spec :: Spec
78
spec = parallel $
89
describe "joinPaths" $ do
910
it "joins empty paths" $
10-
joinUntypedPaths "" "" `shouldBe` "."
11+
go Path.currentDir Path.currentDir $ Path.currentDir
1112
it "joins relative paths" $
12-
joinUntypedPaths "a/b" "./c" `shouldBe` "a/b/c"
13+
go (Path.relDir "a/b") (Path.relFile "./c") $ Path.relFile "a/b/c"
1314
it "joins absolute paths" $
14-
joinUntypedPaths "/a/b" "c" `shouldBe` "/a/b/c"
15+
go (Path.absDir "/a/b") (Path.relDir "c" ) $ Path.absDir "/a/b/c"
1516
it "walks up directories for ../" $
16-
joinUntypedPaths "a/b" "../c" `shouldBe` "a/c"
17+
go (Path.relDir "a/b") (Path.relFile "../c") $ Path.relFile "a/c"
1718
it "walks up directories for multiple ../" $
18-
joinUntypedPaths "a/b" "../../c" `shouldBe` "c"
19+
go (Path.relDir "a/b") (Path.relFile "../../c") $ Path.relFile "c"
1920
it "stops walking at top directory" $
20-
joinUntypedPaths "a/b" "../../../c" `shouldBe` "c"
21+
go (Path.relDir "a/b") (Path.relFile "../../../c" ) $ Path.relFile "c"
22+
where
23+
go x y z = joinPaths (Path.toAbsRel x) y `shouldBe` Path.toAbsRel z

0 commit comments

Comments
 (0)