diff options
Diffstat (limited to 'compiler/pathutils.nim')
-rw-r--r-- | compiler/pathutils.nim | 73 |
1 files changed, 57 insertions, 16 deletions
diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index e3dd69628..5f6212bb2 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -10,7 +10,10 @@ ## Path handling utilities for Nim. Strictly typed code in order ## to avoid the never ending time sink in getting path handling right. -import os, pathnorm +import std/[os, pathnorm, strutils] + +when defined(nimPreviewSlimSystem): + import std/[syncio, assertions] type AbsoluteFile* = distinct string @@ -67,7 +70,7 @@ when true: proc `/`*(base: AbsoluteDir; f: RelativeFile): AbsoluteFile = let base = postProcessBase(base) - assert(not isAbsolute(f.string)) + assert(not isAbsolute(f.string), f.string) result = AbsoluteFile newStringOfCap(base.string.len + f.string.len) var state = 0 addNormalizePath(base.string, result.string, state) @@ -83,7 +86,10 @@ when true: proc relativeTo*(fullPath: AbsoluteFile, baseFilename: AbsoluteDir; sep = DirSep): RelativeFile = - RelativeFile(relativePath(fullPath.string, baseFilename.string, sep)) + # this currently fails for `tests/compilerapi/tcompilerapi.nim` + # it's needed otherwise would returns an absolute path + # assert not baseFilename.isEmpty, $fullPath + result = RelativeFile(relativePath(fullPath.string, baseFilename.string, sep)) proc toAbsolute*(file: string; base: AbsoluteDir): AbsoluteFile = if isAbsolute(file): result = AbsoluteFile(file) @@ -97,16 +103,51 @@ when true: proc writeFile*(x: AbsoluteFile; content: string) {.borrow.} -when isMainModule: - doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" - doAssert relativePath("/foo/bar.nim", "/foo/", '/') == "bar.nim" - doAssert $RelativeDir"foo/bar" == "foo/bar" - doAssert RelativeDir"foo/bar" == RelativeDir"foo/bar" - doAssert RelativeFile"foo/bar".changeFileExt(".txt") == RelativeFile"foo/bar.txt" - doAssert RelativeFile"foo/bar".addFileExt(".txt") == RelativeFile"foo/bar.txt" - doAssert not RelativeDir"foo/bar".isEmpty - doAssert RelativeDir"".isEmpty - -when isMainModule and defined(windows): - let nasty = string(AbsoluteDir(r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\linkedPkgs\pkgB-#head\../../simplePkgs/pkgB-#head/") / RelativeFile"pkgA/module.nim") - doAssert nasty.replace('/', '\\') == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim" +proc skipHomeDir(x: string): int = + when defined(windows): + if x.continuesWith("Users/", len("C:/")): + result = 3 + else: + result = 0 + else: + if x.startsWith("/home/") or x.startsWith("/Users/"): + result = 3 + elif x.startsWith("/mnt/") and x.continuesWith("/Users/", len("/mnt/c")): + result = 5 + else: + result = 0 + +proc relevantPart(s: string; afterSlashX: int): string = + result = newStringOfCap(s.len - 8) + var slashes = afterSlashX + for i in 0..<s.len: + if slashes == 0: + result.add s[i] + elif s[i] == '/': + dec slashes + +template canonSlashes(x: string): string = + when defined(windows): + x.replace('\\', '/') + else: + x + +proc customPathImpl(x: string): string = + # Idea: Encode a "protocol" via "//protocol/path" which is not ambiguous + # as path canonicalization would have removed the double slashes. + # /mnt/X/Users/Y + # X:\\Users\Y + # /home/Y + # --> + # //user/ + if not isAbsolute(x): + result = customPathImpl(canonSlashes(getCurrentDir() / x)) + else: + let slashes = skipHomeDir(x) + if slashes > 0: + result = "//user/" & relevantPart(x, slashes) + else: + result = x + +proc customPath*(x: string): string = + customPathImpl canonSlashes x |