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' --- .../expected/subdir/subdir_b/utils.html | 1299 +++++++++++++++++++ nimdoc/testproject/expected/testproject.html | 1331 ++++++++++++++++++++ 2 files changed, 2630 insertions(+) create mode 100644 nimdoc/testproject/expected/subdir/subdir_b/utils.html create mode 100644 nimdoc/testproject/expected/testproject.html (limited to 'nimdoc/testproject/expected') 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 + +
+ +
+ +
+
+ +
+ +
+
+
+ + + -- cgit 1.4.1-2-gfad0 From b9ed684dd2188c8d58eafba313d314ec0aa8d4db Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 13 Sep 2018 01:05:51 +0200 Subject: index generation for docgen knows about subdirectories; index knows about enum values; fixes import statement for runnableExamples --- compiler/docgen.nim | 19 +- lib/packages/docutils/rstgen.nim | 80 +- nimdoc/tester.nim | 5 +- nimdoc/testproject/expected/theindex.html | 1266 ++++++++++++++++++++++++++ nimdoc/testproject/subdir/subdir_b/utils.nim | 5 +- nimdoc/testproject/testproject.nim | 3 +- 6 files changed, 1337 insertions(+), 41 deletions(-) create mode 100644 nimdoc/testproject/expected/theindex.html (limited to 'nimdoc/testproject/expected') diff --git a/compiler/docgen.nim b/compiler/docgen.nim index e1ae33cf5..ca3b1ac2d 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -343,6 +343,7 @@ proc testExample(d: PDoc; ex: PNode) = elif isDefined(d.conf, "objc"): "objc" else: "c" if os.execShellCmd(os.getAppFilename() & " " & backend & + " --path:" & quoteShell(d.conf.projectPath) & " --nimcache:" & quoteShell(outputDir) & " -r " & quoteShell(outp)) != 0: quit "[Examples] failed: see " & outp.string @@ -622,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"], @@ -637,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 @@ -847,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, "")) diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index a68ae928c..434d98b06 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -85,8 +85,8 @@ proc init(p: var CodeBlockParams) = proc initRstGenerator*(g: var RstGenerator, target: OutputTarget, config: StringTableRef, filename: string, options: RstParseOptions, - findFile: FindFileHandler=nil, - msgHandler: MsgHandler=nil) = + findFile: FindFileHandler = nil, + msgHandler: MsgHandler = nil) = ## Initializes a ``RstGenerator``. ## ## You need to call this before using a ``RstGenerator`` with any other @@ -255,9 +255,9 @@ proc renderRstToOut*(d: var RstGenerator, n: PRstNode, result: var string) ## .. code-block:: nim ## ## # ...configure gen and rst vars... - ## var generatedHTML = "" - ## renderRstToOut(gen, rst, generatedHTML) - ## echo generatedHTML + ## var generatedHtml = "" + ## renderRstToOut(gen, rst, generatedHtml) + ## echo generatedHtml proc renderAux(d: PDoc, n: PRstNode, result: var string) = for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result) @@ -282,20 +282,26 @@ proc quoteIndexColumn(text: string): string = ## * ``"\\"`` => ``"\\\\"`` ## * ``"\n"`` => ``"\\n"`` ## * ``"\t"`` => ``"\\t"`` - result = text.replace("\\", "\\\\").replace("\n", "\\n").replace("\t", "\\t") + result = newStringOfCap(text.len + 3) + for c in text: + case c + of '\\': result.add "\\" + of '\L': result.add "\\n" + of '\C': discard + of '\t': result.add "\\t" + else: result.add c proc unquoteIndexColumn(text: string): string = ## Returns the unquoted version generated by ``quoteIndexColumn``. - result = text.replace("\\t", "\t").replace("\\n", "\n").replace("\\\\", "\\") + result = text.multiReplace(("\\t", "\t"), ("\\n", "\n"), ("\\\\", "\\")) -proc setIndexTerm*(d: var RstGenerator, id, term: string, +proc setIndexTerm*(d: var RstGenerator, htmlFile, id, term: string, linkTitle, linkDesc = "") = ## Adds a `term` to the index using the specified hyperlink identifier. ## ## A new entry will be added to the index using the format - ## ``termfile#id``. The file part will come from the `filename` - ## parameter used in a previous call to the `initRstGenerator() - ## <#initRstGenerator>`_ proc. + ## ``termfile#id``. The file part will come from the `htmlFile` + ## parameter. ## ## The `id` will be appended with a hash character only if its length is not ## zero, otherwise no specific anchor will be generated. In general you @@ -316,7 +322,6 @@ proc setIndexTerm*(d: var RstGenerator, id, term: string, entry = term isTitle = false entry.add('\t') - let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt) entry.add(htmlFile) if id.len > 0: entry.add('#') @@ -356,7 +361,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) = var term = "" renderAux(d, n, term) - setIndexTerm(d, id, term, d.currentSection) + setIndexTerm(d, "", id, term, d.currentSection) dispA(d.target, result, "$2", "$2\\label{$1}", [id, term]) @@ -364,15 +369,15 @@ type IndexEntry = object keyword: string link: string - linkTitle: string ## If not nil, contains a prettier text for the href - linkDesc: string ## If not nil, the title attribute of the final href + linkTitle: string ## contains a prettier text for the href + linkDesc: string ## the title attribute of the final href IndexedDocs = Table[IndexEntry, seq[IndexEntry]] ## \ ## Contains the index sequences for doc types. ## ## The key is a *fake* IndexEntry which will contain the title of the ## document in the `keyword` field and `link` will contain the html - ## filename for the document. `linkTitle` and `linkDesc` will be nil. + ## filename for the document. `linkTitle` and `linkDesc` will be empty. ## ## The value indexed by this IndexEntry is a sequence with the real index ## entries found in the ``.idx`` file. @@ -433,13 +438,13 @@ proc generateSymbolIndex(symbols: seq[IndexEntry]): string = var i = 0 while i < symbols.len: let keyword = symbols[i].keyword - let cleaned_keyword = keyword.escapeLink + let cleanedKeyword = keyword.escapeLink result.addf("
$1:
    \n", - [keyword, cleaned_keyword]) + [keyword, cleanedKeyword]) var j = i while j < symbols.len and keyword == symbols[j].keyword: let - url = symbols[j].link.escapeLink + url = symbols[j].link #.escapeLink text = if symbols[j].linkTitle.len > 0: symbols[j].linkTitle else: url desc = if symbols[j].linkDesc.len > 0: symbols[j].linkDesc else: "" if desc.len > 0: @@ -462,12 +467,12 @@ proc isDocumentationTitle(hyperlink: string): bool = ## for a more detailed explanation. result = hyperlink.find('#') < 0 -proc stripTOCLevel(s: string): tuple[level: int, text: string] = +proc stripTocLevel(s: string): tuple[level: int, text: string] = ## Returns the *level* of the toc along with the text without it. - for c in 0 .. |
characters to switch to `newLevel`. @@ -483,7 +488,7 @@ proc indentToLevel(level: var int, newLevel: int): string = result = repeat("", level - newLevel) level = newLevel -proc generateDocumentationTOC(entries: seq[IndexEntry]): string = +proc generateDocumentationToc(entries: seq[IndexEntry]): string = ## Returns the sequence of index entries in an HTML hierarchical list. result = "" # Build a list of levels and extracted titles to make processing easier. @@ -495,7 +500,7 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = level = 1 levels.newSeq(entries.len) for entry in entries: - let (rawLevel, rawText) = stripTOCLevel(entry.linkTitle or entry.keyword) + let (rawLevel, rawText) = stripTocLevel(entry.linkTitle or entry.keyword) if rawLevel < 1: # This is a normal symbol, push it *inside* one level from the last one. levels[L].level = level + 1 @@ -519,9 +524,9 @@ proc generateDocumentationTOC(entries: seq[IndexEntry]): string = titleTag = levels[L].text else: result.add(level.indentToLevel(levels[L].level)) - result.addf("""
  • + result.addf("""
  • $3
  • - """, [titleTag & " : " & levels[L].text, link, levels[L].text]) + """, [titleTag, levels[L].text, link, levels[L].text]) inc L result.add(level.indentToLevel(1) & "\n") @@ -534,7 +539,7 @@ proc generateDocumentationIndex(docs: IndexedDocs): string = sort(titles, cmp) for title in titles: - let tocList = generateDocumentationTOC(docs.getOrDefault(title)) + let tocList = generateDocumentationToc(docs.getOrDefault(title)) result.add("\n") @@ -575,8 +580,8 @@ proc readIndexDir(dir: string): setLen(result.symbols, 0) var L = 0 # Scan index files and build the list of symbols. - for kind, path in walkDir(dir): - if kind == pcFile and path.endsWith(IndexExt): + for path in walkDirRec(dir): + if path.endsWith(IndexExt): var fileEntries: seq[IndexEntry] title: IndexEntry @@ -606,7 +611,7 @@ proc readIndexDir(dir: string): inc F # Depending on type add this to the list of symbols or table of APIs. if title.keyword.len == 0: - for i in 0 .. 0 and toc[0] == ' ': @@ -615,7 +620,12 @@ proc readIndexDir(dir: string): setLen(result.symbols, L + 1) result.symbols[L] = fileEntries[i] inc L - result.modules.add(path.splitFile.name) + if fileEntries.len > 0: + var x = fileEntries[0].link + let i = find(x, '#') + if i > 0: + x = x.substr(0, i-1) + result.modules.add(x.changeFileExt("")) else: # Generate the symbolic anchor for index quickjumps. title.linkTitle = "doc_toc_" & $result.docs.len @@ -676,7 +686,7 @@ proc mergeIndexes*(dir: string): string = # ---------------------------------------------------------------------------- -proc stripTOCHTML(s: string): string = +proc stripTocHtml(s: string): string = ## Ugly quick hack to remove HTML tags from TOC titles. ## ## A TocEntry.header field already contains rendered HTML tags. Instead of @@ -724,7 +734,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) = # Generate index entry using spaces to indicate TOC level for the output HTML. assert n.level >= 0 - setIndexTerm(d, refname, tmp.stripTOCHTML, + setIndexTerm(d, "", refname, tmp.stripTocHtml, spaces(max(0, n.level)) & tmp) proc renderOverline(d: PDoc, n: PRstNode, result: var string) = @@ -872,7 +882,7 @@ proc parseCodeBlockParams(d: PDoc, n: PRstNode): CodeBlockParams = if result.langStr != "": result.lang = getSourceLanguage(result.langStr) -proc buildLinesHTMLTable(d: PDoc; params: CodeBlockParams, code: string): +proc buildLinesHtmlTable(d: PDoc; params: CodeBlockParams, code: string): tuple[beginTable, endTable: string] = ## Returns the necessary tags to start/end a code block in HTML. ## @@ -922,7 +932,7 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) = if params.testCmd.len > 0 and d.onTestSnippet != nil: d.onTestSnippet(d, params.filename, params.testCmd, params.status, m.text) - let (blockStart, blockEnd) = buildLinesHTMLTable(d, params, m.text) + let (blockStart, blockEnd) = buildLinesHtmlTable(d, params, m.text) dispA(d.target, result, blockStart, "\\begin{rstpre}\n", []) if params.lang == langNone: diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index 7ca8b45fe..58117987b 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -7,9 +7,12 @@ var proc test(dir: string; fixup = false) = putEnv("SOURCE_DATE_EPOCH", "100000") - if execShellCmd("nim doc --project -o:$1/htmldocs $1/testproject.nim" % dir) != 0: + if execShellCmd("nim doc --project --index:on -o:$1/htmldocs $1/testproject.nim" % dir) != 0: quit("FAILURE: nim doc failed") + if execShellCmd("nim buildIndex -o:$1/htmldocs/theindex.html $1/htmldocs" % [dir]) != 0: + quit("FAILURE: nim buildIndex failed") + for expected in walkDirRec(dir / "expected/"): let produced = expected.replace("/expected/", "/htmldocs/") if not fileExists(produced): diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html new file mode 100644 index 000000000..7e4f8d397 --- /dev/null +++ b/nimdoc/testproject/expected/theindex.html @@ -0,0 +1,1266 @@ + + + + + + + + + + + + + + + + + +Index + + + + + + + + + + + + diff --git a/nimdoc/testproject/subdir/subdir_b/utils.nim b/nimdoc/testproject/subdir/subdir_b/utils.nim index 31e066751..d7d82b3cd 100644 --- a/nimdoc/testproject/subdir/subdir_b/utils.nim +++ b/nimdoc/testproject/subdir/subdir_b/utils.nim @@ -1,6 +1,9 @@ type - SomeType* = int + SomeType* = enum + enumValueA, + enumValueB, + enumValueC proc someType*(): SomeType = ## constructor. diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index 697a2ab3c..b4f6a58fb 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -3,8 +3,9 @@ import subdir / subdir_b / utils ## This is the top level module. runnableExamples: + import subdir / subdir_b / utils doAssert bar(3, 4) == 7 - foo(1, 2) + foo(enumValueA, enumValueB) template foo*(a, b: SomeType) = -- cgit 1.4.1-2-gfad0 From 9b29436f629b85301e1cfce8c0a502d45a2ad6fe Mon Sep 17 00:00:00 2001 From: Araq Date: Thu, 13 Sep 2018 23:18:51 +0200 Subject: make documentation generator tests green again --- .gitignore | 2 +- nimdoc/tester.nim | 2 +- nimdoc/testproject/expected/subdir/subdir_b/utils.html | 6 ++++-- nimdoc/testproject/expected/testproject.html | 7 +++++-- 4 files changed, 11 insertions(+), 6 deletions(-) (limited to 'nimdoc/testproject/expected') diff --git a/.gitignore b/.gitignore index eb29dfc04..8cd092639 100644 --- a/.gitignore +++ b/.gitignore @@ -45,7 +45,7 @@ xcuserdata/ # Generated files. /compile.json -/compiler/nimrod.dot +/compiler/nim.dot /reject.json /run.json # for `nim doc foo.nim` diff --git a/nimdoc/tester.nim b/nimdoc/tester.nim index 58117987b..e0afe6b94 100644 --- a/nimdoc/tester.nim +++ b/nimdoc/tester.nim @@ -14,7 +14,7 @@ proc test(dir: string; fixup = false) = quit("FAILURE: nim buildIndex failed") for expected in walkDirRec(dir / "expected/"): - let produced = expected.replace("/expected/", "/htmldocs/") + let produced = expected.replace('\\', '/').replace("/expected/", "/htmldocs/") if not fileExists(produced): echo "FAILURE: files not found: ", produced inc failures diff --git a/nimdoc/testproject/expected/subdir/subdir_b/utils.html b/nimdoc/testproject/expected/subdir/subdir_b/utils.html index 0e09b10cd..285d09d5c 100644 --- a/nimdoc/testproject/expected/subdir/subdir_b/utils.html +++ b/nimdoc/testproject/expected/subdir/subdir_b/utils.html @@ -1242,7 +1242,8 @@ function main() { Types
    • SomeType
    • + title="SomeType = enum + enumValueA, enumValueB, enumValueC">SomeType
    @@ -1264,7 +1265,8 @@ function main() {

    Types

    -
    SomeType = int
    +
    SomeType = enum
    +  enumValueA, enumValueB, enumValueC
    diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index b1f8489f1..784fbe9b7 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -1276,8 +1276,11 @@ function main() {

    This is the top level module.

    Examples:

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

    +
    import
    +  subdir / subdir_b / utils
    +
    +doAssert bar(3, 4) == 7
    +foo(enumValueA, enumValueB)

    Imports

    -- cgit 1.4.1-2-gfad0