From 86556ebfdbbd4b8e9edc9d3085ea21d6c0bae2e2 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 7 Sep 2018 01:53:09 +0200 Subject: compiler refactoring; use typesafe path handing; docgen: render symbols between modules --- compiler/pathutils.nim | 254 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 254 insertions(+) create mode 100644 compiler/pathutils.nim (limited to 'compiler/pathutils.nim') diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim new file mode 100644 index 000000000..f84d964bb --- /dev/null +++ b/compiler/pathutils.nim @@ -0,0 +1,254 @@ +# +# +# The Nim Compiler +# (c) Copyright 2018 Andreas Rumpf +# +# See the file "copying.txt", included in this +# distribution, for details about the copyright. +# + +## Path handling utilities for Nim. Strictly typed code in order +## to avoid the never ending time sink in getting path handling right. +## Might be a candidate for the stdlib later. + +import os, strutils + +type + AbsoluteFile* = distinct string + AbsoluteDir* = distinct string + RelativeFile* = distinct string + RelativeDir* = distinct string + +proc isEmpty*(x: AbsoluteFile): bool {.inline.} = x.string.len == 0 +proc isEmpty*(x: AbsoluteDir): bool {.inline.} = x.string.len == 0 +proc isEmpty*(x: RelativeFile): bool {.inline.} = x.string.len == 0 +proc isEmpty*(x: RelativeDir): bool {.inline.} = x.string.len == 0 + +proc copyFile*(source, dest: AbsoluteFile) = + os.copyFile(source.string, dest.string) + +proc removeFile*(x: AbsoluteFile) {.borrow.} + +proc splitFile*(x: AbsoluteFile): tuple[dir: AbsoluteDir, name, ext: string] = + let (a, b, c) = splitFile(x.string) + result = (dir: AbsoluteDir(a), name: b, ext: c) + +proc extractFilename*(x: AbsoluteFile): string {.borrow.} + +proc fileExists*(x: AbsoluteFile): bool {.borrow.} +proc dirExists*(x: AbsoluteDir): bool {.borrow.} + +proc quoteShell*(x: AbsoluteFile): string {.borrow.} +proc quoteShell*(x: AbsoluteDir): string {.borrow.} + +proc cmpPaths*(x, y: AbsoluteDir): int {.borrow.} + +proc createDir*(x: AbsoluteDir) {.borrow.} + +type + PathIter = object + i, prev: int + notFirst: bool + +proc hasNext(it: PathIter; x: string): bool = + it.i < x.len + +proc next(it: var PathIter; x: string): (int, int) = + it.prev = it.i + if not it.notFirst and x[it.i] in {DirSep, AltSep}: + # absolute path: + inc it.i + else: + while it.i < x.len and x[it.i] notin {DirSep, AltSep}: inc it.i + if it.i > it.prev: + result = (it.prev, it.i-1) + elif hasNext(it, x): + result = next(it, x) + + # skip all separators: + while it.i < x.len and x[it.i] in {DirSep, AltSep}: inc it.i + it.notFirst = true + +iterator dirs(x: string): (int, int) = + var it: PathIter + while hasNext(it, x): yield next(it, x) + +when false: + iterator dirs(x: string): (int, int) = + var i = 0 + var first = true + while i < x.len: + let prev = i + if first and x[i] in {DirSep, AltSep}: + # absolute path: + inc i + else: + while i < x.len and x[i] notin {DirSep, AltSep}: inc i + if i > prev: + yield (prev, i-1) + first = false + # skip all separators: + while i < x.len and x[i] in {DirSep, AltSep}: inc i + +proc isDot(x: string; bounds: (int, int)): bool = + bounds[1] == bounds[0] and x[bounds[0]] == '.' + +proc isDotDot(x: string; bounds: (int, int)): bool = + bounds[1] == bounds[0] + 1 and x[bounds[0]] == '.' and x[bounds[0]+1] == '.' + +proc isSlash(x: string; bounds: (int, int)): bool = + bounds[1] == bounds[0] and x[bounds[0]] in {DirSep, AltSep} + +proc canon(x: string; result: var string; state: var int) = + # state: 0th bit set if isAbsolute path. Other bits count + # the number of path components. + for b in dirs(x): + if (state shr 1 == 0) and isSlash(x, b): + result.add DirSep + state = state or 1 + elif result.len > (state and 1) and isDotDot(x, b): + var d = result.len + # f/.. + while d > (state and 1) and result[d-1] != DirSep: + dec d + setLen(result, d) + elif isDot(x, b): + discard "discard the dot" + else: + if result.len > (state and 1): result.add DirSep + result.add substr(x, b[0], b[1]) + inc state, 2 + +proc canon(x: string): string = + # - Turn multiple slashes into single slashes. + # - Resolve '/foo/../bar' to '/bar'. + # - Remove './' from the path. + result = newStringOfCap(x.len) + var state = 0 + canon(x, result, state) + +when FileSystemCaseSensitive: + template `!=?`(a, b: char): bool = toLowerAscii(a) != toLowerAscii(b) +else: + template `!=?`(a, b: char): bool = a != b + +proc relativeTo(full, base: string; sep = DirSep): string = + if full.len == 0: return "" + var f, b: PathIter + var ff = (0, -1) + var bb = (0, -1) # (int, int) + result = newStringOfCap(full.len) + # skip the common prefix: + while f.hasNext(full) and b.hasNext(base): + ff = next(f, full) + bb = next(b, base) + let diff = ff[1] - ff[0] + if diff != bb[1] - bb[0]: break + var same = true + for i in 0..diff: + if full[i + ff[0]] !=? base[i + bb[0]]: + same = false + break + if not same: break + ff = (0, -1) + bb = (0, -1) + # for i in 0..diff: + # result.add base[i + bb[0]] + + # /foo/bar/xxx/ -- base + # /foo/bar/baz -- full path + # ../baz + # every directory that is in 'base', needs to add '..' + while true: + if bb[1] >= bb[0]: + if result.len > 0 and result[^1] != sep: + result.add sep + result.add ".." + if not b.hasNext(base): break + bb = b.next(base) + + # add the rest of 'full': + while true: + if ff[1] >= ff[0]: + if result.len > 0 and result[^1] != sep: + result.add sep + for i in 0..ff[1] - ff[0]: + result.add full[i + ff[0]] + if not f.hasNext(full): break + ff = f.next(full) + +when true: + proc eqImpl(x, y: string): bool = + when FileSystemCaseSensitive: + result = toLowerAscii(canon x) == toLowerAscii(canon y) + else: + result = canon(x) == canon(y) + + proc `==`*(x, y: AbsoluteFile): bool = eqImpl(x.string, y.string) + proc `==`*(x, y: AbsoluteDir): bool = eqImpl(x.string, y.string) + proc `==`*(x, y: RelativeFile): bool = eqImpl(x.string, y.string) + proc `==`*(x, y: RelativeDir): bool = eqImpl(x.string, y.string) + + proc `/`*(base: AbsoluteDir; f: RelativeFile): AbsoluteFile = + assert isAbsolute(base.string) + assert(not isAbsolute(f.string)) + result = AbsoluteFile newStringOfCap(base.string.len + f.string.len) + var state = 0 + canon(base.string, result.string, state) + canon(f.string, result.string, state) + + proc `/`*(base: AbsoluteDir; f: RelativeDir): AbsoluteDir = + assert isAbsolute(base.string) + assert(not isAbsolute(f.string)) + result = AbsoluteDir newStringOfCap(base.string.len + f.string.len) + var state = 0 + canon(base.string, result.string, state) + canon(f.string, result.string, state) + + proc relativeTo*(fullPath: AbsoluteFile, baseFilename: AbsoluteDir; + sep = DirSep): RelativeFile = + RelativeFile(relativeTo(fullPath.string, baseFilename.string, sep)) + + proc toAbsolute*(file: string; base: AbsoluteDir): AbsoluteFile = + if isAbsolute(file): result = AbsoluteFile(file) + else: result = base / RelativeFile file + + proc changeFileExt*(x: AbsoluteFile; ext: string): AbsoluteFile {.borrow.} + proc changeFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.} + + proc addFileExt*(x: AbsoluteFile; ext: string): AbsoluteFile {.borrow.} + proc addFileExt*(x: RelativeFile; ext: string): RelativeFile {.borrow.} + + proc writeFile*(x: AbsoluteFile; content: string) {.borrow.} + +when isMainModule and defined(posix): + doAssert canon"/foo/../bar" == "/bar" + doAssert canon"foo/../bar" == "bar" + + doAssert canon"/f/../bar///" == "/bar" + doAssert canon"f/..////bar" == "bar" + + doAssert canon"../bar" == "../bar" + doAssert canon"/../bar" == "/../bar" + + doAssert canon("foo/../../bar/") == "../bar" + doAssert canon("./bla/blob/") == "bla/blob" + doAssert canon(".hiddenFile") == ".hiddenFile" + doAssert canon("./bla/../../blob/./zoo.nim") == "../blob/zoo.nim" + + doAssert canon("C:/file/to/this/long") == "C:/file/to/this/long" + doAssert canon("") == "" + doAssert canon("foobar") == "foobar" + doAssert canon("f/////////") == "f" + + doAssert relativeTo("/foo/bar//baz.nim", "/foo") == "bar/baz.nim" + + doAssert relativeTo("/Users/me/bar/z.nim", "/Users/other/bad") == "../../me/bar/z.nim" + + doAssert relativeTo("/Users/me/bar/z.nim", "/Users/other") == "../me/bar/z.nim" + doAssert relativeTo("/Users///me/bar//z.nim", "//Users/") == "me/bar/z.nim" + doAssert relativeTo("/Users/me/bar/z.nim", "/Users/me") == "bar/z.nim" + doAssert relativeTo("", "/users/moo") == "" + doAssert relativeTo("foo", "") == "foo" + + echo string(AbsoluteDir"/Users/me///" / RelativeFile"z.nim") -- cgit 1.4.1-2-gfad0 From b017138c32df2df2799ebb480bf1b8f5a461d300 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Fri, 7 Sep 2018 13:13:35 +0200 Subject: added a test for 'nim doc' --- .travis.yml | 1 + compiler/docgen.nim | 6 +- compiler/msgs.nim | 4 +- compiler/pathutils.nim | 5 +- nimdoc/tester.nim | 29 + .../expected/subdir/subdir_b/utils.html | 1299 +++++++++++++++++++ nimdoc/testproject/expected/testproject.html | 1331 ++++++++++++++++++++ nimdoc/testproject/subdir/subdir_b/utils.nim | 7 + nimdoc/testproject/testproject.nim | 21 + nimdoc/testproject/testproject.nimble | 0 10 files changed, 2696 insertions(+), 7 deletions(-) create mode 100644 nimdoc/tester.nim create mode 100644 nimdoc/testproject/expected/subdir/subdir_b/utils.html create mode 100644 nimdoc/testproject/expected/testproject.html create mode 100644 nimdoc/testproject/subdir/subdir_b/utils.nim create mode 100644 nimdoc/testproject/testproject.nim create mode 100644 nimdoc/testproject/testproject.nimble (limited to 'compiler/pathutils.nim') diff --git a/.travis.yml b/.travis.yml index 0f74c56ac..a0f8765a2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -51,3 +51,4 @@ script: - ./koch csource - ./koch nimsuggest - nim c -r nimsuggest/tester + - nim c -r nimdoc/tester diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 428fcbfe3..4f1070af0 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -670,12 +670,12 @@ proc traceDeps(d: PDoc, it: PNode) = let full = AbsoluteFile toFullPath(d.conf, FileIndex it.sym.position) let tmp = getOutFile2(d.conf, full.relativeTo(d.conf.projectPath), HtmlExt, RelativeDir"htmldocs") - let external = relativeTo(tmp, d.thisDir, '/') + let external = relativeTo(tmp, d.thisDir, '/').string if d.section[k] != nil: add(d.section[k], ", ") dispA(d.conf, d.section[k], "$1", - "$1", [rope esc(d.target, it.sym.name.s), - rope changeFileExt(external, "html").string]) + "$1", [rope esc(d.target, changeFileExt(external, "")), + rope changeFileExt(external, "html")]) proc generateDoc*(d: PDoc, n: PNode) = case n.kind diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 47858f143..d817b2956 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -63,7 +63,7 @@ proc fileInfoKnown*(conf: ConfigRef; filename: AbsoluteFile): bool = canon: AbsoluteFile try: canon = canonicalizePath(conf, filename) - except: + except OSError: canon = filename result = conf.m.filenameToIndexTbl.hasKey(canon.string) @@ -75,7 +75,7 @@ proc fileInfoIdx*(conf: ConfigRef; filename: AbsoluteFile; isKnownFile: var bool try: canon = canonicalizePath(conf, filename) shallow(canon.string) - except: + except OSError: canon = filename # The compiler uses "filenames" such as `command line` or `stdin` # This flag indicates that we are working with such a path here diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index f84d964bb..b27981159 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -180,7 +180,7 @@ proc relativeTo(full, base: string; sep = DirSep): string = when true: proc eqImpl(x, y: string): bool = when FileSystemCaseSensitive: - result = toLowerAscii(canon x) == toLowerAscii(canon y) + result = cmpIgnoreCase(canon x, canon y) == 0 else: result = canon(x) == canon(y) @@ -251,4 +251,5 @@ when isMainModule and defined(posix): doAssert relativeTo("", "/users/moo") == "" doAssert relativeTo("foo", "") == "foo" - echo string(AbsoluteDir"/Users/me///" / RelativeFile"z.nim") + doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" + doAssert relativeTo("/foo/bar.nim", "/foo/") == "bar.nim" diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim new file mode 100644 index 000000000..7ca8b45fe --- /dev/null +++ b/nimdoc/tester.nim @@ -0,0 +1,29 @@ +# Small program that runs the test cases for 'nim doc'. + +import strutils, os + +var + failures = 0 + +proc test(dir: string; fixup = false) = + putEnv("SOURCE_DATE_EPOCH", "100000") + if execShellCmd("nim doc --project -o:$1/htmldocs $1/testproject.nim" % dir) != 0: + quit("FAILURE: nim doc failed") + + for expected in walkDirRec(dir / "expected/"): + let produced = expected.replace("/expected/", "/htmldocs/") + if not fileExists(produced): + echo "FAILURE: files not found: ", produced + inc failures + elif readFile(expected) != readFile(produced): + echo "FAILURE: files differ: ", produced + discard execShellCmd("diff -uNdr " & expected & " " & produced) + inc failures + if fixup: + copyFile(produced, expected) + else: + echo "SUCCESS: files identical: ", produced + removeDir(dir / "htmldocs") + +test("nimdoc/testproject", false) +if failures > 0: quit($failures & " failures occurred.") diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html new file mode 100644 index 000000000..0e09b10cd --- /dev/null +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -0,0 +1,1299 @@ + + + + + + + + + + + + + + + + + +Module utils + + + + + + + + +
+
+

Module utils

+
+
+ +
+ Search: +
+
+ Group by: + +
+ + +
+
+
+

+
+

Types

+
+
SomeType = int
+
+ + +
+ +
+
+

Procs

+
+
proc someType(): SomeType {...}{.raises: [], tags: [].}
+
+constructor. + +
+ +
+ +
+
+ +
+ +
+
+
+ + + diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html new file mode 100644 index 000000000..b1f8489f1 --- /dev/null +++ b/nimdoc/testproject/expected/testproject.html @@ -0,0 +1,1331 @@ + + + + + + + + + + + + + + + + + +Module testproject + + + + + + + + +
+
+

Module testproject

+
+
+ +
+ Search: +
+
+ Group by: + +
+ + +
+
+
+

This is the top level module. +

Examples:

+
doAssert bar(3, 4) == 7
+foo(1, 2)

+ +
+

Procs

+
+
proc bar[T](a, b: T): T
+
+ + +
+ +
+
+

Macros

+
+
macro bar(): untyped
+
+ + +
+ +
+
+

Templates

+
+
template foo(a, b: SomeType)
+
+This does nothing + +
+ +
+ +
+
+ +
+ +
+
+
+ + + diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim new file mode 100644 index 000000000..31e066751 --- /dev/null +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -0,0 +1,7 @@ + +type + SomeType* = int + +proc someType*(): SomeType = + ## constructor. + SomeType(2) diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim new file mode 100644 index 000000000..697a2ab3c --- /dev/null +++ b/nimdoc/testproject/testproject.nim @@ -0,0 +1,21 @@ + +import subdir / subdir_b / utils + +## This is the top level module. +runnableExamples: + doAssert bar(3, 4) == 7 + foo(1, 2) + + +template foo*(a, b: SomeType) = + ## This does nothing + ## + discard + +proc bar*[T](a, b: T): T = + result = a + b + +import std/macros + +macro bar*(): untyped = + result = newStmtList() diff --git a/nimdoc/testproject/testproject.nimble b/nimdoc/testproject/testproject.nimble new file mode 100644 index 000000000..e69de29bb -- cgit 1.4.1-2-gfad0 From f078f272e5080d2b0983b53750e9d0b2d63c5e02 Mon Sep 17 00:00:00 2001 From: Araq Date: Fri, 7 Sep 2018 19:20:44 +0200 Subject: make tests green again --- appveyor.yml | 1 + compiler/layouter.nim | 7 ++++--- compiler/pathutils.nim | 11 ++++++++--- nimpretty/nimpretty.nim | 6 +++--- 4 files changed, 16 insertions(+), 9 deletions(-) (limited to 'compiler/pathutils.nim') diff --git a/appveyor.yml b/appveyor.yml index cb4ac9e00..001c7c98f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -59,6 +59,7 @@ build_script: test_script: - tests\testament\tester --pedantic all -d:nimCoroutines + - nim c -r nimdoc\tester # - koch csource # - koch zip diff --git a/compiler/layouter.nim b/compiler/layouter.nim index 36ad08696..cc6ec48b7 100644 --- a/compiler/layouter.nim +++ b/compiler/layouter.nim @@ -9,7 +9,8 @@ ## Layouter for nimpretty. -import idents, lexer, lineinfos, llstream, options, msgs, strutils +import idents, lexer, lineinfos, llstream, options, msgs, strutils, + pathutils from os import changeFileExt const @@ -39,7 +40,7 @@ type proc openEmitter*(em: var Emitter, cache: IdentCache; config: ConfigRef, fileIdx: FileIndex) = - let fullPath = config.toFullPath(fileIdx) + let fullPath = Absolutefile config.toFullPath(fileIdx) em.indWidth = getIndentWidth(fileIdx, llStreamOpen(fullPath, fmRead), cache, config) if em.indWidth == 0: em.indWidth = 2 @@ -55,7 +56,7 @@ proc openEmitter*(em: var Emitter, cache: IdentCache; proc closeEmitter*(em: var Emitter) = var f = llStreamOpen(em.config.outFile, fmWrite) if f == nil: - rawMessage(em.config, errGenerated, "cannot open file: " & em.config.outFile) + rawMessage(em.config, errGenerated, "cannot open file: " & em.config.outFile.string) f.llStreamWrite em.content llStreamClose(f) diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index b27981159..e5317d5c3 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -111,11 +111,12 @@ proc canon(x: string; result: var string; state: var int) = # f/.. while d > (state and 1) and result[d-1] != DirSep: dec d - setLen(result, d) + setLen(result, d-1) elif isDot(x, b): discard "discard the dot" - else: - if result.len > (state and 1): result.add DirSep + elif b[1] > b[0]: + if result.len > 0 and result[^1] != DirSep: + result.add DirSep result.add substr(x, b[0], b[1]) inc state, 2 @@ -253,3 +254,7 @@ when isMainModule and defined(posix): doAssert AbsoluteDir"/Users/me///" / RelativeFile"z.nim" == AbsoluteFile"/Users/me/z.nim" doAssert relativeTo("/foo/bar.nim", "/foo/") == "bar.nim" + +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 == r"C:\Users\rumpf\projects\nim\tests\nimble\nimbleDir\simplePkgs\pkgB-#head\pkgA\module.nim" diff --git a/nimpretty/nimpretty.nim b/nimpretty/nimpretty.nim index aa9756c45..fb2b8637f 100644 --- a/nimpretty/nimpretty.nim +++ b/nimpretty/nimpretty.nim @@ -12,7 +12,7 @@ when not defined(nimpretty): {.error: "This needs to be compiled with --define:nimPretty".} -import ../compiler / [idents, msgs, ast, syntaxes, renderer, options] +import ../compiler / [idents, msgs, ast, syntaxes, renderer, options, pathutils] import parseopt, strutils, os @@ -42,8 +42,8 @@ proc writeVersion() = proc prettyPrint(infile, outfile: string) = var conf = newConfigRef() - let fileIdx = fileInfoIdx(conf, infile) - conf.outFile = outfile + let fileIdx = fileInfoIdx(conf, AbsoluteFile infile) + conf.outFile = AbsoluteFile outfile when defined(nimpretty2): discard parseFile(fileIdx, newIdentCache(), conf) else: -- cgit 1.4.1-2-gfad0 From ca77f9388a9b1a580314aa5898e581461a07bc39 Mon Sep 17 00:00:00 2001 From: Araq Date: Sat, 8 Sep 2018 10:04:22 +0200 Subject: 'nim doc': fixes index generation regression --- compiler/docgen.nim | 8 ++++++-- compiler/pathutils.nim | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'compiler/pathutils.nim') diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 4f1070af0..209cd9d92 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -863,8 +863,12 @@ proc genOutFile(d: PDoc): Rope = proc generateIndex*(d: PDoc) = if optGenIndex in d.conf.globalOptions: - let dest = getOutFile2(d.conf, relativeTo(AbsoluteFile d.filename, d.conf.projectPath), - IndexExt, RelativeDir"index") + let dir = if d.conf.outFile.isEmpty: d.conf.projectPath / RelativeDir"htmldocs" + elif optWholeProject in d.conf.globalOptions: AbsoluteDir(d.conf.outFile) + else: AbsoluteDir(d.conf.outFile.string.splitFile.dir) + createDir(dir) + let dest = dir / changeFileExt(relativeTo(AbsoluteFile d.filename, + d.conf.projectPath), IndexExt) writeIndexFile(d[], dest.string) proc writeOutput*(d: PDoc, useWarning = false) = diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index e5317d5c3..b71caf314 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -191,7 +191,7 @@ when true: proc `==`*(x, y: RelativeDir): bool = eqImpl(x.string, y.string) proc `/`*(base: AbsoluteDir; f: RelativeFile): AbsoluteFile = - assert isAbsolute(base.string) + #assert isAbsolute(base.string) assert(not isAbsolute(f.string)) result = AbsoluteFile newStringOfCap(base.string.len + f.string.len) var state = 0 @@ -199,7 +199,7 @@ when true: canon(f.string, result.string, state) proc `/`*(base: AbsoluteDir; f: RelativeDir): AbsoluteDir = - assert isAbsolute(base.string) + #assert isAbsolute(base.string) assert(not isAbsolute(f.string)) result = AbsoluteDir newStringOfCap(base.string.len + f.string.len) var state = 0 -- cgit 1.4.1-2-gfad0 From f14f5544354b9731417e5eeea0a42bbfd42739fb Mon Sep 17 00:00:00 2001 From: Araq Date: Mon, 10 Sep 2018 23:27:45 +0200 Subject: nim doc: fixes cross-link generation when --out is used --- compiler/docgen.nim | 13 +++++++++---- compiler/pathutils.nim | 2 +- 2 files changed, 10 insertions(+), 5 deletions(-) (limited to 'compiler/pathutils.nim') diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6095745be..e1ae33cf5 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -94,13 +94,18 @@ proc parseRst(text, filename: string, docgenFindFile, compilerMsgHandler) proc getOutFile2(conf: ConfigRef; filename: RelativeFile, - ext: string, dir: RelativeDir): AbsoluteFile = + ext: string, dir: RelativeDir; guessTarget: bool): AbsoluteFile = if optWholeProject in conf.globalOptions: # This is correct, for 'nim doc --project' we interpret the '--out' option as an # absolute directory, not as a filename! let d = if conf.outFile.isEmpty: conf.projectPath / dir else: AbsoluteDir(conf.outFile) createDir(d) result = d / changeFileExt(filename, ext) + elif guessTarget: + let d = if not conf.outFile.isEmpty: splitFile(conf.outFile).dir + else: conf.projectPath + createDir(d) + result = d / changeFileExt(filename, ext) else: result = getOutFile(conf, filename, ext) @@ -138,7 +143,7 @@ proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef): warnUser, "only 'rst2html' supports the ':test:' attribute") result.emitted = initIntSet() result.destFile = getOutFile2(conf, relativeTo(filename, conf.projectPath), - HtmlExt, RelativeDir"htmldocs") + HtmlExt, RelativeDir"htmldocs", false) result.thisDir = result.destFile.splitFile.dir proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) = @@ -288,7 +293,7 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe let full = AbsoluteFile toFullPath(d.conf, FileIndex s.owner.position) let tmp = getOutFile2(d.conf, full.relativeTo(d.conf.projectPath), - HtmlExt, RelativeDir"htmldocs") + HtmlExt, RelativeDir"htmldocs", sfMainModule notin s.owner.flags) let external = tmp.relativeTo(d.thisDir, '/') result.addf "$3", @@ -673,7 +678,7 @@ proc traceDeps(d: PDoc, it: PNode) = elif it.kind == nkSym and belongsToPackage(d.conf, it.sym): let full = AbsoluteFile toFullPath(d.conf, FileIndex it.sym.position) let tmp = getOutFile2(d.conf, full.relativeTo(d.conf.projectPath), HtmlExt, - RelativeDir"htmldocs") + RelativeDir"htmldocs", sfMainModule notin it.sym.flags) let external = relativeTo(tmp, d.thisDir, '/').string if d.section[k] != nil: add(d.section[k], ", ") dispA(d.conf, d.section[k], diff --git a/compiler/pathutils.nim b/compiler/pathutils.nim index b71caf314..ef0fa4abd 100644 --- a/compiler/pathutils.nim +++ b/compiler/pathutils.nim @@ -111,7 +111,7 @@ proc canon(x: string; result: var string; state: var int) = # f/.. while d > (state and 1) and result[d-1] != DirSep: dec d - setLen(result, d-1) + if d > 0: setLen(result, d-1) elif isDot(x, b): discard "discard the dot" elif b[1] > b[0]: -- cgit 1.4.1-2-gfad0