diff options
-rw-r--r-- | changelog.md | 9 | ||||
-rw-r--r-- | compiler/commands.nim | 5 | ||||
-rw-r--r-- | compiler/modulepaths.nim | 201 |
3 files changed, 119 insertions, 96 deletions
diff --git a/changelog.md b/changelog.md index 26adab6e9..463fc5ed9 100644 --- a/changelog.md +++ b/changelog.md @@ -251,3 +251,12 @@ bar() - The ``securehash`` module is now deprecated. Instead import ``std / sha1``. - ``db_mysql`` module: ``DbConn`` is now a ``distinct`` type that doesn't expose the details of the underlying ``PMySQL`` type. +- Standard library modules can now also be imported via the ``std`` pseudo-directory. + This is useful in order to distinguish between standard library and nimble package + imports: + +```nim + +import std / [strutils, os, osproc] +import someNimblePackage / [strutils, os] +``` diff --git a/compiler/commands.nim b/compiler/commands.nim index aa7d13703..766b78798 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -274,9 +274,10 @@ proc testCompileOption*(switch: string, info: TLineInfo): bool = proc processPath(path: string, info: TLineInfo, notRelativeToProj = false): string = - let p = if notRelativeToProj or os.isAbsolute(path) or - '$' in path: + let p = if os.isAbsolute(path) or '$' in path: path + elif notRelativeToProj: + getCurrentDir() / path else: options.gProjectPath / path try: diff --git a/compiler/modulepaths.nim b/compiler/modulepaths.nim index 5d112c6b9..878c22cf8 100644 --- a/compiler/modulepaths.nim +++ b/compiler/modulepaths.nim @@ -11,38 +11,39 @@ import ast, renderer, strutils, msgs, options, idents, os import nimblecmd -const - considerParentDirs = not defined(noParentProjects) - considerNimbleDirs = not defined(noNimbleDirs) +when false: + const + considerParentDirs = not defined(noParentProjects) + considerNimbleDirs = not defined(noNimbleDirs) -proc findInNimbleDir(pkg, subdir, dir: string): string = - var best = "" - var bestv = "" - for k, p in os.walkDir(dir, relative=true): - if k == pcDir and p.len > pkg.len+1 and - p[pkg.len] == '-' and p.startsWith(pkg): - let (_, a) = getPathVersion(p) - if bestv.len == 0 or bestv < a: - bestv = a - best = dir / p + proc findInNimbleDir(pkg, subdir, dir: string): string = + var best = "" + var bestv = "" + for k, p in os.walkDir(dir, relative=true): + if k == pcDir and p.len > pkg.len+1 and + p[pkg.len] == '-' and p.startsWith(pkg): + let (_, a) = getPathVersion(p) + if bestv.len == 0 or bestv < a: + bestv = a + best = dir / p - if best.len > 0: - var f: File - if open(f, best / changeFileExt(pkg, ".nimble-link")): - # the second line contains what we're interested in, see: - # https://github.com/nim-lang/nimble#nimble-link - var override = "" - discard readLine(f, override) - discard readLine(f, override) - close(f) - if not override.isAbsolute(): - best = best / override - else: - best = override - let f = if subdir.len == 0: pkg else: subdir - let res = addFileExt(best / f, "nim") - if best.len > 0 and fileExists(res): - result = res + if best.len > 0: + var f: File + if open(f, best / changeFileExt(pkg, ".nimble-link")): + # the second line contains what we're interested in, see: + # https://github.com/nim-lang/nimble#nimble-link + var override = "" + discard readLine(f, override) + discard readLine(f, override) + close(f) + if not override.isAbsolute(): + best = best / override + else: + best = override + let f = if subdir.len == 0: pkg else: subdir + let res = addFileExt(best / f, "nim") + if best.len > 0 and fileExists(res): + result = res const stdlibDirs = [ "pure", "core", "arch", @@ -51,65 +52,66 @@ const stdlibDirs = [ "wrappers", "wrappers/linenoise", "windows", "posix", "js"] -proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string = - template attempt(a) = - let x = addFileExt(a, "nim") - if fileExists(x): return x +when false: + proc resolveDollar(project, source, pkg, subdir: string; info: TLineInfo): string = + template attempt(a) = + let x = addFileExt(a, "nim") + if fileExists(x): return x - case pkg - of "stdlib": - if subdir.len == 0: - return options.libpath - else: - for candidate in stdlibDirs: - attempt(options.libpath / candidate / subdir) - of "root": - let root = project.splitFile.dir - if subdir.len == 0: - return root + case pkg + of "stdlib": + if subdir.len == 0: + return options.libpath + else: + for candidate in stdlibDirs: + attempt(options.libpath / candidate / subdir) + of "root": + let root = project.splitFile.dir + if subdir.len == 0: + return root + else: + attempt(root / subdir) else: - attempt(root / subdir) - else: - when considerParentDirs: - var p = parentDir(source.splitFile.dir) - # support 'import $karax': - let f = if subdir.len == 0: pkg else: subdir + when considerParentDirs: + var p = parentDir(source.splitFile.dir) + # support 'import $karax': + let f = if subdir.len == 0: pkg else: subdir - while p.len > 0: - let dir = p / pkg - if dirExists(dir): - attempt(dir / f) - # 2nd attempt: try to use 'karax/karax' - attempt(dir / pkg / f) - # 3rd attempt: try to use 'karax/src/karax' - attempt(dir / "src" / f) - attempt(dir / "src" / pkg / f) - p = parentDir(p) + while p.len > 0: + let dir = p / pkg + if dirExists(dir): + attempt(dir / f) + # 2nd attempt: try to use 'karax/karax' + attempt(dir / pkg / f) + # 3rd attempt: try to use 'karax/src/karax' + attempt(dir / "src" / f) + attempt(dir / "src" / pkg / f) + p = parentDir(p) - when considerNimbleDirs: - if not options.gNoNimblePath: - var nimbleDir = getEnv("NIMBLE_DIR") - if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" - result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs") - if result.len > 0: return result - when not defined(windows): - result = findInNimbleDir(pkg, subdir, "/opt/nimble/pkgs") + when considerNimbleDirs: + if not options.gNoNimblePath: + var nimbleDir = getEnv("NIMBLE_DIR") + if nimbleDir.len == 0: nimbleDir = getHomeDir() / ".nimble" + result = findInNimbleDir(pkg, subdir, nimbleDir / "pkgs") if result.len > 0: return result + when not defined(windows): + result = findInNimbleDir(pkg, subdir, "/opt/nimble/pkgs") + if result.len > 0: return result -proc scriptableImport(pkg, sub: string; info: TLineInfo): string = - result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) - if result.isNil: result = "" + proc scriptableImport(pkg, sub: string; info: TLineInfo): string = + result = resolveDollar(gProjectFull, info.toFullPath(), pkg, sub, info) + if result.isNil: result = "" -proc lookupPackage(pkg, subdir: PNode): string = - let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: "" - case pkg.kind - of nkStrLit, nkRStrLit, nkTripleStrLit: - result = scriptableImport(pkg.strVal, sub, pkg.info) - of nkIdent: - result = scriptableImport(pkg.ident.s, sub, pkg.info) - else: - localError(pkg.info, "package name must be an identifier or string literal") - result = "" + proc lookupPackage(pkg, subdir: PNode): string = + let sub = if subdir != nil: renderTree(subdir, {renderNoComments}).replace(" ") else: "" + case pkg.kind + of nkStrLit, nkRStrLit, nkTripleStrLit: + result = scriptableImport(pkg.strVal, sub, pkg.info) + of nkIdent: + result = scriptableImport(pkg.ident.s, sub, pkg.info) + else: + localError(pkg.info, "package name must be an identifier or string literal") + result = "" proc getModuleName*(n: PNode): string = # This returns a short relative module name without the nim extension @@ -136,23 +138,34 @@ proc getModuleName*(n: PNode): string = n.sons[1] = n.sons[2] n.sons.setLen(2) return getModuleName(n.sons[0]) - if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$": - if n0.kind == nkIdent and n0.ident.s == "/": - result = lookupPackage(n1[1], n[2]) - else: - localError(n.info, "only '/' supported with $package notation") - result = "" + when false: + if n1.kind == nkPrefix and n1[0].kind == nkIdent and n1[0].ident.s == "$": + if n0.kind == nkIdent and n0.ident.s == "/": + result = lookupPackage(n1[1], n[2]) + else: + localError(n.info, "only '/' supported with $package notation") + result = "" else: + let modname = getModuleName(n[2]) + if $n1 == "std": + template attempt(a) = + let x = addFileExt(a, "nim") + if fileExists(x): return x + for candidate in stdlibDirs: + attempt(options.libpath / candidate / modname) + # hacky way to implement 'x / y /../ z': result = getModuleName(n1) result.add renderTree(n0, {renderNoComments}) - result.add getModuleName(n[2]) + result.add modname of nkPrefix: - if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$": - result = lookupPackage(n[1], nil) - else: - # hacky way to implement 'x / y /../ z': - result = renderTree(n, {renderNoComments}).replace(" ") + when false: + if n.sons[0].kind == nkIdent and n.sons[0].ident.s == "$": + result = lookupPackage(n[1], nil) + else: + discard + # hacky way to implement 'x / y /../ z': + result = renderTree(n, {renderNoComments}).replace(" ") of nkDotExpr: result = renderTree(n, {renderNoComments}).replace(".", "/") of nkImportAs: |