diff options
author | Ganesh Viswanathan <dev@genotrance.com> | 2018-09-14 18:34:12 -0500 |
---|---|---|
committer | Ganesh Viswanathan <dev@genotrance.com> | 2018-09-14 18:34:12 -0500 |
commit | 9340885251e7791ee5a03f2b75e168f341e231e5 (patch) | |
tree | 86b4a189f01a1c114f5bb9e48d33e09a731953b0 /compiler/docgen.nim | |
parent | 4e305c304014c5ef90413d6cab562f5e2b34e573 (diff) | |
parent | b9dc486db15bb1b4b6f3cef7626733b904d377f7 (diff) | |
download | Nim-9340885251e7791ee5a03f2b75e168f341e231e5.tar.gz |
Merge remote-tracking branch 'upstream/devel' into test-7010
Diffstat (limited to 'compiler/docgen.nim')
-rw-r--r-- | compiler/docgen.nim | 219 |
1 files changed, 136 insertions, 83 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 6f26bcf10..ca3b1ac2d 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -16,7 +16,8 @@ import wordrecg, syntaxes, renderer, lexer, packages/docutils/rstast, packages/docutils/rst, packages/docutils/rstgen, packages/docutils/highlite, sempass2, json, xmltree, cgi, - typesrenderer, astalgo, modulepaths, lineinfos, sequtils, intsets + typesrenderer, astalgo, modulepaths, lineinfos, sequtils, intsets, + pathutils type TSections = array[TSymKind, Rope] @@ -34,6 +35,8 @@ type exampleCounter: int emitted: IntSet # we need to track which symbols have been emitted # already. See bug #3655 + destFile*: AbsoluteFile + thisDir*: AbsoluteDir PDoc* = ref TDocumentor ## Alias to type less. @@ -48,12 +51,12 @@ proc whichType(d: PDoc; n: PNode): PSym = proc attachToType(d: PDoc; p: PSym): PSym = let params = p.ast.sons[paramsPos] - # first check the first parameter, then the return type, - # then the other parameter: template check(i) = result = whichType(d, params[i]) if result != nil: return result + # first check the first parameter, then the return type, + # then the other parameter: if params.len > 1: check(1) if params.len > 0: check(0) for i in 2..<params.len: check(i) @@ -74,10 +77,10 @@ template declareClosures = of mwUnknownSubstitution: k = warnUnknownSubstitutionX of mwUnsupportedLanguage: k = warnLanguageXNotSupported of mwUnsupportedField: k = warnFieldXNotSupported - globalError(conf, newLineInfo(conf, filename, line, col), k, arg) + globalError(conf, newLineInfo(conf, AbsoluteFile filename, line, col), k, arg) proc docgenFindFile(s: string): string {.procvar.} = - result = options.findFile(conf, s) + result = options.findFile(conf, s).string if result.len == 0: result = getCurrentDir() / s if not existsFile(result): result = "" @@ -90,13 +93,29 @@ proc parseRst(text, filename: string, result = rstParse(text, filename, line, column, hasToc, rstOptions, docgenFindFile, compilerMsgHandler) -proc newDocumentor*(filename: string; cache: IdentCache; conf: ConfigRef): PDoc = +proc getOutFile2(conf: ConfigRef; filename: RelativeFile, + 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) + +proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef): PDoc = declareClosures() new(result) result.conf = conf result.cache = cache initRstGenerator(result[], (if conf.cmd != cmdRst2tex: outHtml else: outLatex), - conf.configVars, filename, {roSupportRawDirective}, + conf.configVars, filename.string, {roSupportRawDirective}, docgenFindFile, compilerMsgHandler) if conf.configVars.hasKey("doc.googleAnalytics"): @@ -120,8 +139,12 @@ proc newDocumentor*(filename: string; cache: IdentCache; conf: ConfigRef): PDoc result.jArray = newJArray() initStrTable result.types result.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) = - localError(conf, newLineInfo(conf, d.filename, -1, -1), warnUser, "only 'rst2html' supports the ':test:' attribute") + localError(conf, newLineInfo(conf, AbsoluteFile d.filename, -1, -1), + warnUser, "only 'rst2html' supports the ':test:' attribute") result.emitted = initIntSet() + result.destFile = getOutFile2(conf, relativeTo(filename, conf.projectPath), + HtmlExt, RelativeDir"htmldocs", false) + result.thisDir = result.destFile.splitFile.dir proc dispA(conf: ConfigRef; dest: var Rope, xml, tex: string, args: openArray[Rope]) = if conf.cmd != cmdRst2tex: addf(dest, xml, args) @@ -227,6 +250,10 @@ proc getPlainDocstring(n: PNode): string = result = getPlainDocstring(n.sons[i]) if result.len > 0: return +proc belongsToPackage(conf: ConfigRef; module: PSym): bool = + result = module.kind == skModule and module.owner != nil and + module.owner.id == conf.mainPackageId + proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRenderFlags = {}) = var r: TSrcGen var literal = "" @@ -259,8 +286,22 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe dispA(d.conf, result, "<span class=\"FloatNumber\">$1</span>", "\\spanFloatNumber{$1}", [rope(esc(d.target, literal))]) of tkSymbol: - dispA(d.conf, result, "<span class=\"Identifier\">$1</span>", - "\\spanIdentifier{$1}", [rope(esc(d.target, literal))]) + let s = getTokSym(r) + if s != nil and s.kind == skType and sfExported in s.flags and + s.owner != nil and belongsToPackage(d.conf, s.owner) and + d.target == outHtml: + + let full = AbsoluteFile toFullPath(d.conf, FileIndex s.owner.position) + let tmp = getOutFile2(d.conf, full.relativeTo(d.conf.projectPath), + HtmlExt, RelativeDir"htmldocs", sfMainModule notin s.owner.flags) + + let external = tmp.relativeTo(d.thisDir, '/') + result.addf "<a href=\"$1#$2\"><span class=\"Identifier\">$3</span></a>", + [rope changeFileExt(external, "html").string, rope literal, + rope(esc(d.target, literal))] + else: + dispA(d.conf, result, "<span class=\"Identifier\">$1</span>", + "\\spanIdentifier{$1}", [rope(esc(d.target, literal))]) of tkSpaces, tkInvalid: add(result, literal) of tkCurlyDotLe: @@ -290,23 +331,25 @@ proc nodeToHighlightedHtml(d: PDoc; n: PNode; result: var Rope; renderFlags: TRe proc testExample(d: PDoc; ex: PNode) = if d.conf.errorCounter > 0: return - let outputDir = d.conf.getNimcacheDir / "runnableExamples" + let outputDir = d.conf.getNimcacheDir / RelativeDir"runnableExamples" createDir(outputDir) inc d.exampleCounter - let outp = outputDir / extractFilename(d.filename.changeFileExt"" & - "_examples" & $d.exampleCounter & ".nim") + let outp = outputDir / RelativeFile(extractFilename(d.filename.changeFileExt"" & + "_examples" & $d.exampleCounter & ".nim")) #let nimcache = outp.changeFileExt"" & "_nimcache" - renderModule(ex, d.filename, outp, conf = d.conf) + renderModule(ex, d.filename, outp.string, conf = d.conf) let backend = if isDefined(d.conf, "js"): "js" elif isDefined(d.conf, "cpp"): "cpp" elif isDefined(d.conf, "objc"): "objc" else: "c" if os.execShellCmd(os.getAppFilename() & " " & backend & - " --nimcache:" & outputDir & " -r " & outp) != 0: - quit "[Examples] failed: see " & outp + " --path:" & quoteShell(d.conf.projectPath) & + " --nimcache:" & quoteShell(outputDir) & + " -r " & quoteShell(outp)) != 0: + quit "[Examples] failed: see " & outp.string else: # keep generated source file `outp` to allow inspection. - rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp]) + rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string]) removeFile(outp.changeFileExt(ExeExt)) proc extractImports(n: PNode; result: PNode) = @@ -332,7 +375,8 @@ proc isRunnableExample(n: PNode): bool = result = n.kind == nkSym and n.sym.magic == mRunnableExamples or n.kind == nkIdent and n.ident.s == "runnableExamples" -proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) = +proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope) = + if n.info.fileIndex != orig.info.fileIndex: return case n.kind of nkCallKinds: if isRunnableExample(n[0]) and @@ -357,7 +401,10 @@ proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) = dest.add(d.config.getOrDefault"doc.listing_end" % id) else: discard for i in 0 ..< n.safeLen: - getAllRunnableExamples(d, n[i], dest) + getAllRunnableExamplesRec(d, n[i], orig, dest) + +proc getAllRunnableExamples(d: PDoc; n: PNode; dest: var Rope) = + getAllRunnableExamplesRec(d, n, n, dest) when false: proc findDocComment(n: PNode): PNode = @@ -449,10 +496,8 @@ proc newUniquePlainSymbol(d: PDoc, original: string): string = result = original d.seenSymbols[original] = "" return - # Iterate over possible numeric variants of the original name. var count = 2 - while true: result = original & "_" & $count if not d.seenSymbols.hasKey(result): @@ -460,7 +505,6 @@ proc newUniquePlainSymbol(d: PDoc, original: string): string = break count += 1 - proc complexName(k: TSymKind, n: PNode, baseName: string): string = ## Builds a complex unique href name for the node. ## @@ -482,11 +526,9 @@ proc complexName(k: TSymKind, n: PNode, baseName: string): string = of skTemplate: result.add(".t" & defaultParamSeparator) of skConverter: result.add(".c" & defaultParamSeparator) else: discard - if len(n) > paramsPos and n[paramsPos].kind == nkFormalParams: result.add(renderParamTypes(n[paramsPos])) - proc isCallable(n: PNode): bool = ## Returns true if `n` contains a callable node. case n.kind @@ -495,7 +537,6 @@ proc isCallable(n: PNode): bool = else: result = false - proc docstringSummary(rstText: string): string = ## Returns just the first line or a brief chunk of text from a rst string. ## @@ -523,7 +564,6 @@ proc docstringSummary(rstText: string): string = result.delete(pos, last) result.add("…") - proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = if not isVisible(d, nameNode): return let @@ -545,8 +585,8 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = break plainName.add(literal) - # Render the HTML hyperlink. - nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments, renderDocComments}) + nodeToHighlightedHtml(d, n, result, {renderNoBody, renderNoComments, + renderDocComments, renderSyms}) inc(d.id) let @@ -563,16 +603,18 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = var seeSrcRope: Rope = nil let docItemSeeSrc = getConfigVar(d.conf, "doc.item.seesrc") if docItemSeeSrc.len > 0: - let cwd = canonicalizePath(d.conf, getCurrentDir()) - var path = toFullPath(d.conf, n.info) - if path.startsWith(cwd): - path = path[cwd.len+1 .. ^1].replace('\\', '/') + let path = relativeTo(AbsoluteFile toFullPath(d.conf, n.info), d.conf.projectPath, '/') + when false: + let cwd = canonicalizePath(d.conf, getCurrentDir()) + var path = toFullPath(d.conf, n.info) + if path.startsWith(cwd): + path = path[cwd.len+1 .. ^1].replace('\\', '/') let gitUrl = getConfigVar(d.conf, "git.url") if gitUrl.len > 0: let commit = getConfigVar(d.conf, "git.commit", "master") let develBranch = getConfigVar(d.conf, "git.devel", "devel") dispA(d.conf, seeSrcRope, "$1", "", [ropeFormatNamedVars(d.conf, docItemSeeSrc, - ["path", "line", "url", "commit", "devel"], [rope path, + ["path", "line", "url", "commit", "devel"], [rope path.string, rope($n.info.line), rope gitUrl, rope commit, rope develBranch])]) add(d.section[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item"), @@ -581,11 +623,22 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = [nameRope, result, comm, itemIDRope, plainNameRope, plainSymbolRope, symbolOrIdRope, plainSymbolEncRope, symbolOrIdEncRope, seeSrcRope])) + let external = AbsoluteFile(d.filename).relativeTo(d.conf.projectPath, '/').changeFileExt(HtmlExt).string + var attype: Rope if k in routineKinds and nameNode.kind == nkSym: let att = attachToType(d, nameNode.sym) if att != nil: attype = rope esc(d.target, att.name.s) + elif k == skType and nameNode.kind == nkSym and nameNode.sym.typ.kind in {tyEnum, tyBool}: + let etyp = nameNode.sym.typ + for e in etyp.n: + if e.sym.kind != skEnumField: continue + let plain = renderPlainSymbolName(e) + let symbolOrId = d.newUniquePlainSymbol(plain) + setIndexTerm(d[], external, symbolOrId, plain, nameNode.sym.name.s & '.' & plain, + xmltree.escape(getPlainDocstring(e).docstringSummary)) + add(d.toc[k], ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.item.toc"), ["name", "header", "desc", "itemID", "header_plain", "itemSym", "itemSymOrID", "itemSymEnc", "itemSymOrIDEnc", "attype"], @@ -596,11 +649,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) = # Ironically for types the complexSymbol is *cleaner* than the plainName # because it doesn't include object fields or documentation comments. So we # use the plain one for callable elements, and the complex for the rest. - var linkTitle = changeFileExt(extractFilename(d.filename), "") & " : " + var linkTitle = changeFileExt(extractFilename(d.filename), "") & ": " if n.isCallable: linkTitle.add(xmltree.escape(plainName.strip)) else: linkTitle.add(xmltree.escape(complexSymbol.strip)) - setIndexTerm(d[], symbolOrId, name, linkTitle, + setIndexTerm(d[], external, symbolOrId, name, linkTitle, xmltree.escape(plainDocstring.docstringSummary)) if k == skType and nameNode.kind == nkSym: d.types.strTableAdd nameNode.sym @@ -611,9 +664,7 @@ proc genJsonItem(d: PDoc, n, nameNode: PNode, k: TSymKind): JsonNode = name = getName(d, nameNode) comm = $genRecComment(d, n) r: TSrcGen - initTokRender(r, n, {renderNoBody, renderNoComments, renderDocComments}) - result = %{ "name": %name, "type": %($k), "line": %n.info.line.int, "col": %n.info.col} if comm.len > 0: @@ -626,7 +677,6 @@ proc checkForFalse(n: PNode): bool = proc traceDeps(d: PDoc, it: PNode) = const k = skModule - if it.kind == nkInfix and it.len == 3 and it[2].kind == nkBracket: let sep = it[0] let dir = it[1] @@ -637,13 +687,19 @@ proc traceDeps(d: PDoc, it: PNode) = for x in it[2]: a.sons[2] = x traceDeps(d, a) - else: + 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", 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], - "<a class=\"reference external\" href=\"$1.html\">$1</a>", - "$1", [rope(splitFile(getModuleName(d.conf, it)).name)]) + "<a class=\"reference external\" href=\"$2\">$1</a>", + "$1", [rope esc(d.target, changeFileExt(external, "")), + rope changeFileExt(external, "html")]) -proc generateDoc*(d: PDoc, n: PNode) = +proc generateDoc*(d: PDoc, n, orig: PNode) = + if orig.info.fileIndex != n.info.fileIndex: return case n.kind of nkCommentStmt: add(d.modDesc, genComment(d, n)) of nkProcDef: @@ -670,11 +726,11 @@ proc generateDoc*(d: PDoc, n: PNode) = genItem(d, n.sons[i], n.sons[i].sons[0], succ(skType, ord(n.kind)-ord(nkTypeSection))) of nkStmtList: - for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i]) + for i in countup(0, sonsLen(n) - 1): generateDoc(d, n.sons[i], orig) of nkWhenStmt: # generate documentation for the first branch only: if not checkForFalse(n.sons[0].sons[0]): - generateDoc(d, lastSon(n.sons[0])) + generateDoc(d, lastSon(n.sons[0]), orig) of nkImportStmt: for i in 0 .. sonsLen(n)-1: traceDeps(d, n.sons[i]) of nkFromStmt, nkImportExceptStmt: traceDeps(d, n.sons[0]) @@ -803,7 +859,8 @@ proc genOutFile(d: PDoc): Rope = # Extract the title. Non API modules generate an entry in the index table. if d.meta[metaTitle].len != 0: title = d.meta[metaTitle] - setIndexTerm(d[], "", title) + let external = AbsoluteFile(d.filename).relativeTo(d.conf.projectPath, '/').changeFileExt(HtmlExt).string + setIndexTerm(d[], external, "", title) else: # Modules get an automatic title for the HTML, but no entry in the index. title = "Module " & extractFilename(changeFileExt(d.filename, "")) @@ -829,29 +886,27 @@ proc genOutFile(d: PDoc): Rope = proc generateIndex*(d: PDoc) = if optGenIndex in d.conf.globalOptions: - writeIndexFile(d[], splitFile(d.conf.outFile).dir / - splitFile(d.filename).name & IndexExt) - -proc getOutFile2(conf: ConfigRef; filename, ext, dir: string): string = - if optWholeProject in conf.globalOptions: - let d = if conf.outFile != "": conf.outFile else: dir - createDir(d) - result = d / changeFileExt(filename, ext) - else: - result = getOutFile(conf, filename, ext) - -proc writeOutput*(d: PDoc, filename, outExt: string, useWarning = false) = + 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) = var content = genOutFile(d) if optStdout in d.conf.globalOptions: writeRope(stdout, content) else: - let outfile = getOutFile2(d.conf, filename, outExt, "htmldocs") - createDir(outfile.parentDir) + template outfile: untyped = d.destFile + #let outfile = getOutFile2(d.conf, shortenDir(d.conf, filename), outExt, "htmldocs") + createDir(outfile.splitFile.dir) if not writeRope(content, outfile): - rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, outfile) + rawMessage(d.conf, if useWarning: warnCannotOpenFile else: errCannotOpenFile, + outfile.string) -proc writeOutputJson*(d: PDoc, filename, outExt: string, - useWarning = false) = +proc writeOutputJson*(d: PDoc, useWarning = false) = let content = %*{"orig": d.filename, "nimble": getPackageName(d.conf, d.filename), "entries": d.jArray} @@ -859,8 +914,7 @@ proc writeOutputJson*(d: PDoc, filename, outExt: string, write(stdout, $content) else: var f: File - if open(f, getOutFile2(d.conf, splitFile(filename).name, - outExt, "jsondocs"), fmWrite): + if open(f, d.destFile.string, fmWrite): write(f, $content) close(f) else: @@ -871,27 +925,28 @@ proc commandDoc*(cache: IdentCache, conf: ConfigRef) = if ast == nil: return var d = newDocumentor(conf.projectFull, cache, conf) d.hasToc = true - generateDoc(d, ast) - writeOutput(d, conf.projectFull, HtmlExt) + generateDoc(d, ast, ast) + writeOutput(d) generateIndex(d) -proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string) = +proc commandRstAux(cache: IdentCache, conf: ConfigRef; + filename: AbsoluteFile, outExt: string) = var filen = addFileExt(filename, "txt") var d = newDocumentor(filen, cache, conf) d.onTestSnippet = proc (d: var RstGenerator; filename, cmd: string; status: int; content: string) = - var outp: string + var outp: AbsoluteFile if filename.len == 0: inc(d.id) let nameOnly = splitFile(d.filename).name - let subdir = getNimcacheDir(conf) / nameOnly + let subdir = getNimcacheDir(conf) / RelativeDir(nameOnly) createDir(subdir) - outp = subdir / (nameOnly & "_snippet_" & $d.id & ".nim") + outp = subdir / RelativeFile(nameOnly & "_snippet_" & $d.id & ".nim") elif isAbsolute(filename): - outp = filename + outp = AbsoluteFile filename else: # Nim's convention: every path is relative to the file it was written in: - outp = splitFile(d.filename).dir / filename + outp = splitFile(d.filename).dir.AbsoluteDir / RelativeFile(filename) writeFile(outp, content) let cmd = cmd % quoteShell(outp) rawMessage(conf, hintExecuting, cmd) @@ -899,14 +954,12 @@ proc commandRstAux(cache: IdentCache, conf: ConfigRef; filename, outExt: string) rawMessage(conf, errGenerated, "executing of external program failed: " & cmd) d.isPureRst = true - var rst = parseRst(readFile(filen), filen, 0, 1, d.hasToc, + var rst = parseRst(readFile(filen.string), filen.string, 0, 1, d.hasToc, {roSupportRawDirective}, conf) var modDesc = newStringOfCap(30_000) - #d.modDesc = newMutableRope(30_000) renderRstToOut(d[], rst, modDesc) - #freezeMutableRope(d.modDesc) d.modDesc = rope(modDesc) - writeOutput(d, filename, outExt) + writeOutput(d) generateIndex(d) proc commandRst2Html*(cache: IdentCache, conf: ConfigRef) = @@ -928,9 +981,9 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) = writeRope(stdout, content) else: #echo getOutFile(gProjectFull, JsonExt) - let filename = getOutFile(conf, conf.projectFull, JsonExt) + let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt) if not writeRope(content, filename): - rawMessage(conf, errCannotOpenFile, filename) + rawMessage(conf, errCannotOpenFile, filename.string) proc commandTags*(cache: IdentCache, conf: ConfigRef) = var ast = parseFile(conf.projectMainIdx, cache, conf) @@ -945,12 +998,12 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) = writeRope(stdout, content) else: #echo getOutFile(gProjectFull, TagsExt) - let filename = getOutFile(conf, conf.projectFull, TagsExt) + let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt) if not writeRope(content, filename): - rawMessage(conf, errCannotOpenFile, filename) + rawMessage(conf, errCannotOpenFile, filename.string) proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) = - var content = mergeIndexes(conf.projectFull).rope + var content = mergeIndexes(conf.projectFull.string).rope let code = ropeFormatNamedVars(conf, getConfigVar(conf, "doc.file"), ["title", "tableofcontents", "moduledesc", "date", "time", @@ -958,6 +1011,6 @@ proc commandBuildIndex*(cache: IdentCache, conf: ConfigRef) = ["Index".rope, nil, nil, rope(getDateStr()), rope(getClockStr()), content, nil, nil, nil]) # no analytics because context is not available - let filename = getOutFile(conf, "theindex", HtmlExt) + let filename = getOutFile(conf, RelativeFile"theindex", HtmlExt) if not writeRope(code, filename): - rawMessage(conf, errCannotOpenFile, filename) + rawMessage(conf, errCannotOpenFile, filename.string) |