diff options
-rw-r--r-- | .github/workflows/ci_docs.yml | 24 | ||||
-rw-r--r-- | compiler/docgen.nim | 21 | ||||
-rw-r--r-- | compiler/index.nim | 18 | ||||
-rw-r--r-- | config/nimdoc.cfg | 55 | ||||
-rw-r--r-- | doc/idetools.rst | 2 | ||||
-rw-r--r-- | koch.nim | 7 | ||||
-rw-r--r-- | lib/std/private/globs.nim | 54 | ||||
-rw-r--r-- | tests/misc/trunner.nim | 7 | ||||
-rw-r--r-- | tools/kochdocs.nim | 107 | ||||
-rw-r--r-- | tools/nimblepkglist.nim | 3 |
10 files changed, 171 insertions, 127 deletions
diff --git a/.github/workflows/ci_docs.yml b/.github/workflows/ci_docs.yml index a1e0920b6..c5e23fbed 100644 --- a/.github/workflows/ci_docs.yml +++ b/.github/workflows/ci_docs.yml @@ -1,18 +1,27 @@ name: Nim Docs CI on: push: - # Run only on changes on these files paths: - - 'lib/**.nim' + - 'compiler/docgen.nim' + - 'compiler/renderverbatim.nim' - 'doc/**.rst' - 'doc/nimdoc.css' + - 'lib/**.nim' + - 'nimdoc/testproject/expected/testproject.html' + - 'tools/dochack/dochack.nim' + - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' - pull_request: # Run only on changes on these files paths: - - 'lib/**.nim' + - 'compiler/docgen.nim' + - 'compiler/renderverbatim.nim' - 'doc/**.rst' + - 'doc/nimdoc.css' + - 'lib/**.nim' + - 'nimdoc/testproject/expected/testproject.html' + - 'tools/dochack/dochack.nim' + - 'tools/kochdocs.nim' - '.github/workflows/ci_docs.yml' jobs: @@ -115,13 +124,6 @@ jobs: shell: bash run: ./koch doc --git.commit:devel - - name: 'Prepare documentation for deployment' - if: | - github.event_name == 'push' && github.ref == 'refs/heads/devel' && - matrix.target == 'linux' - shell: bash - run: cp -f doc/html/{overview,index}.html - - name: 'Publish documentation to Github Pages' if: | github.event_name == 'push' && github.ref == 'refs/heads/devel' && diff --git a/compiler/docgen.nim b/compiler/docgen.nim index ffafb1fcb..535b11ce7 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -19,6 +19,8 @@ import typesrenderer, astalgo, lineinfos, intsets, pathutils, trees, tables, nimpaths, renderverbatim +from std/private/globs import nativeToUnixPath + const exportSection = skField docCmdSkip = "skip" @@ -53,12 +55,6 @@ type PDoc* = ref TDocumentor ## Alias to type less. -proc nativeToUnix(path: string): string = - doAssert not path.isAbsolute # absolute files need more care for the drive - when DirSep == '\\': - result = replace(path, '\\', '/') - else: result = path - proc docOutDir(conf: ConfigRef, subdir: RelativeDir = RelativeDir""): AbsoluteDir = if not conf.outDir.isEmpty: conf.outDir else: conf.projectPath / subdir @@ -97,7 +93,7 @@ proc presentationPath*(conf: ConfigRef, file: AbsoluteFile, isTitle = false): Re if isAbsolute(result.string): result = file.string.splitPath()[1].RelativeFile if isTitle: - result = result.string.nativeToUnix.RelativeFile + result = result.string.nativeToUnixPath.RelativeFile else: result = result.string.replace("..", dotdotMangle).RelativeFile doAssert not result.isEmpty @@ -1244,20 +1240,23 @@ 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] - let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnix + let external = presentationPath(d.conf, AbsoluteFile d.filename).changeFileExt(HtmlExt).string.nativeToUnixPath setIndexTerm(d[], external, "", title) else: # Modules get an automatic title for the HTML, but no entry in the index. # better than `extractFilename(changeFileExt(d.filename, ""))` as it disambiguates dups title = $presentationPath(d.conf, AbsoluteFile d.filename, isTitle = true).changeFileExt("") - let bodyname = if d.hasToc and not d.isPureRst: "doc.body_toc_group" + var groupsection = getConfigVar(d.conf, "doc.body_toc_groupsection") + let bodyname = if d.hasToc and not d.isPureRst: + groupsection.setLen 0 + "doc.body_toc_group" elif d.hasToc: "doc.body_toc" else: "doc.body_no_toc" content = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, bodyname), ["title", - "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref"], + "tableofcontents", "moduledesc", "date", "time", "content", "deprecationMsg", "theindexhref", "body_toc_groupsection"], [title.rope, toc, d.modDesc, rope(getDateStr()), - rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile, theindexFname.RelativeFile)]) + rope(getClockStr()), code, d.modDeprecationMsg, relLink(d.conf.outDir, d.destFile, theindexFname.RelativeFile), groupsection.rope]) if optCompileOnly notin d.conf.globalOptions: # XXX what is this hack doing here? 'optCompileOnly' means raw output!? code = ropeFormatNamedVars(d.conf, getConfigVar(d.conf, "doc.file"), [ diff --git a/compiler/index.nim b/compiler/index.nim new file mode 100644 index 000000000..2c2a34fb5 --- /dev/null +++ b/compiler/index.nim @@ -0,0 +1,18 @@ +##[ +This module only exists to generate docs for the compiler. + +## links +* [main docs](../lib.html) +* [compiler user guide](../nimc.html) +* [Internals of the Nim Compiler](../intern.html) +]## + +#[ +note: this is named `index` so that navigating to https://nim-lang.github.io/Nim/compiler/ +will work. + +xxx this should also import other modules, not transitively imported by `compiler/nim.nim`, +eg `evalffi`, otherwise these aren't shown. A glob could be used at CT. +]# + +import nim diff --git a/config/nimdoc.cfg b/config/nimdoc.cfg index 836b19ab6..945a3dc6c 100644 --- a/config/nimdoc.cfg +++ b/config/nimdoc.cfg @@ -81,42 +81,14 @@ $content </ul> """ -doc.body_toc = """ -<div class="row"> - <div class="three columns"> - <div class="theme-switch-wrapper"> - <label class="theme-switch" for="checkbox"> - <input type="checkbox" id="checkbox" /> - <div class="slider round"></div> - </label> - <em>Dark Mode</em> - </div> - <div id="global-links"> - <ul class="simple-boot"> - <li> - <a href="manual.html">Manual</a> - </li> - <li> - <a href="lib.html">Standard library</a> - </li> - <li> - <a href="$theindexhref">Index</a> - </li> - </ul> - </div> - <div id="searchInputDiv"> - Search: <input type="text" id="searchInput" - onkeyup="search()" /> - </div> - $tableofcontents - </div> - <div class="nine columns" id="content"> - <div id="tocRoot"></div> - $deprecationMsg - <p class="module-desc">$moduledesc</p> - $content +doc.body_toc_groupsection = """ + <div class="search-groupby"> + Group by: + <select onchange="groupBy(this.value)"> + <option value="section">Section</option> + <option value="type">Type</option> + </select> </div> -</div> """ @if boot: @@ -145,19 +117,16 @@ doc.body_toc_group = """ <li> <a href="$theindexhref">Index</a> </li> + <li> + <a href="compiler/$theindexhref">Compiler docs</a> + </li> </ul> </div> <div id="searchInputDiv"> Search: <input type="text" id="searchInput" onkeyup="search()" /> </div> - <div class="search-groupby"> - Group by: - <select onchange="groupBy(this.value)"> - <option value="section">Section</option> - <option value="type">Type</option> - </select> - </div> + $body_toc_groupsection $tableofcontents </div> <div class="nine columns" id="content"> @@ -211,6 +180,8 @@ doc.body_toc_group = """ """ @end +doc.body_toc %= "${doc.body_toc_group}" # should only be used for boot + doc.body_no_toc = """ $moduledesc $content diff --git a/doc/idetools.rst b/doc/idetools.rst index ebb140c5c..e83bfe935 100644 --- a/doc/idetools.rst +++ b/doc/idetools.rst @@ -13,6 +13,8 @@ "yes, I'm the creator" -- Araq, 2013-07-26 19:28:32. </p></blockquote> +Note: this is mostly outdated, see instead `nimsuggest <nimsuggest.html>`_ + Nim differs from many other compilers in that it is really fast, and being so fast makes it suited to provide external queries for text editors about the source code being written. Through the diff --git a/koch.nim b/koch.nim index ee7c8006a..c1d8df8da 100644 --- a/koch.nim +++ b/koch.nim @@ -651,6 +651,13 @@ when isMainModule: of "latest": latest = true of "stable": latest = false of "nim": nimExe = op.val.absolutePath # absolute so still works with changeDir + of "docslocal": + # undocumented for now, allows to rebuild local docs in < 40s as follows: + # `./koch --nim:$nimb --docslocal:htmldocs2 --doccmd:skip --warnings:off --hints:off` + # whereas `./koch docs` takes 190s; useful for development. + doAssert op.val.len > 0 + buildDocsDir(op.cmdLineRest, op.val) + break else: showHelp() of cmdArgument: case normalize(op.key) diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim new file mode 100644 index 000000000..e697ca91c --- /dev/null +++ b/lib/std/private/globs.nim @@ -0,0 +1,54 @@ +##[ +unstable API, internal use only for now. +this can eventually be moved to std/os and `walkDirRec` can be implemented in terms of this +to avoid duplication +]## + +import std/[os,strutils] + +type + PathEntry* = object + kind*: PathComponent + path*: string + +iterator walkDirRecFilter*(dir: string, follow: proc(entry: PathEntry): bool = nil, + relative = false, checkDir = true): PathEntry {.tags: [ReadDirEffect].} = + ## Improved `os.walkDirRec`. + #[ + note: a yieldFilter isn't needed because caller can filter at call site, without + loss of generality, unlike `follow`. + + Future work: + * need to document + * add a `sort` option, which can be implemented efficiently only here, not at call site. + * provide a way to do error reporting, which is tricky because iteration cannot be resumed + ]# + var stack = @["."] + var checkDir = checkDir + var entry: PathEntry + while stack.len > 0: + let d = stack.pop() + for k, p in walkDir(dir / d, relative = true, checkDir = checkDir): + let rel = d / p + entry.kind = k + if relative: entry.path = rel + else: entry.path = dir / rel + if k in {pcDir, pcLinkToDir}: + if follow == nil or follow(entry): stack.add rel + yield entry + checkDir = false + # We only check top-level dir, otherwise if a subdir is invalid (eg. wrong + # permissions), it'll abort iteration and there would be no way to + # continue iteration. + +proc nativeToUnixPath*(path: string): string = + # pending https://github.com/nim-lang/Nim/pull/13265 + doAssert not path.isAbsolute # not implemented here; absolute files need more care for the drive + when DirSep == '\\': + result = replace(path, '\\', '/') + else: result = path + +when isMainModule: + import sugar + for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", ".csources", "bin"]): + echo a diff --git a/tests/misc/trunner.nim b/tests/misc/trunner.nim index 566f9f033..382fd35ae 100644 --- a/tests/misc/trunner.nim +++ b/tests/misc/trunner.nim @@ -11,6 +11,7 @@ import std/[strformat,os,osproc,unittest] from std/sequtils import toSeq,mapIt from std/algorithm import sorted import stdtest/[specialpaths, unittest_light] +from std/private/globs import nativeToUnixPath import "$lib/../compiler/nimpaths" @@ -90,11 +91,7 @@ else: # don't run twice the same test removeDir(htmldocsDir) let (outp, exitCode) = execCmdEx(cmd) check exitCode == 0 - proc nativeToUnixPathWorkaround(a: string): string = - # xxx pending https://github.com/nim-lang/Nim/pull/13265 `nativeToUnixPath` - a.replace(DirSep, '/') - - let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPathWorkaround).sorted.join("\n") + let ret = toSeq(walkDirRec(htmldocsDir, relative=true)).mapIt(it.nativeToUnixPath).sorted.join("\n") let context = $(i, ret, cmd) var expected = "" case i diff --git a/tools/kochdocs.nim b/tools/kochdocs.nim index c39a9c448..80aad4fb6 100644 --- a/tools/kochdocs.nim +++ b/tools/kochdocs.nim @@ -1,6 +1,7 @@ ## Part of 'koch' responsible for the documentation generation. import os, strutils, osproc, sets, pathnorm +from std/private/globs import nativeToUnixPath, walkDirRecFilter, PathEntry import "../compiler/nimpaths" const @@ -85,6 +86,16 @@ proc nimCompileFold*(desc, input: string, outputDir = "bin", mode = "c", options let cmd = findNim().quoteShell() & " " & mode & " -o:" & output & " " & options & " " & input execFold(desc, cmd) +proc getRst2html(): seq[string] = + for a in walkDirRecFilter("doc"): + let path = a.path + if a.kind == pcFile and path.splitFile.ext == ".rst" and path.lastPathPart notin + ["docs.rst", "nimfix.rst"]: + # maybe we should still show nimfix, could help reviving it + # `docs` is redundant with `overview`, might as well remove that file? + result.add path + doAssert "doc/manual/var_t_return.rst".unixToNativePath in result # sanity check + const pdf = """ doc/manual.rst @@ -97,39 +108,6 @@ doc/niminst.rst doc/gc.rst """.splitWhitespace() - rst2html = """ -doc/intern.rst -doc/apis.rst -doc/lib.rst -doc/manual.rst -doc/manual_experimental.rst -doc/destructors.rst -doc/tut1.rst -doc/tut2.rst -doc/tut3.rst -doc/nimc.rst -doc/hcr.rst -doc/drnim.rst -doc/overview.rst -doc/filters.rst -doc/tools.rst -doc/niminst.rst -doc/nimgrep.rst -doc/gc.rst -doc/estp.rst -doc/idetools.rst -doc/docgen.rst -doc/koch.rst -doc/backends.rst -doc/nimsuggest.rst -doc/nep1.rst -doc/nims.rst -doc/contributing.rst -doc/codeowners.rst -doc/packaging.rst -doc/manual/var_t_return.rst -""".splitWhitespace() - doc0 = """ lib/system/threads.nim lib/system/channels.nim @@ -185,7 +163,7 @@ proc getDocList(): seq[string] = for a in withoutIndex: docIgnore.incl a for a in ignoredModules: docIgnore.incl a - # don't ignore these even though in lib/system + # don't ignore these even though in lib/system (not include files) const goodSystem = """ lib/system/io.nim lib/system/nimscript.nim @@ -194,14 +172,14 @@ lib/system/iterators.nim lib/system/dollars.nim lib/system/widestrs.nim """.splitWhitespace() - - for a in walkDirRec("lib"): - if a.splitFile.ext != ".nim" or - a.isRelativeTo("lib/pure/includes") or - a.isRelativeTo("lib/genode") or - a.isRelativeTo("lib/deprecated") or - (a.isRelativeTo("lib/system") and a.replace('\\', '/') notin goodSystem) or - a.replace('\\', '/') in docIgnore: + + proc follow(a: PathEntry): bool = + a.path.lastPathPart notin ["nimcache", "htmldocs", "includes", "deprecated", "genode"] + for entry in walkDirRecFilter("lib", follow = follow): + let a = entry.path + if entry.kind != pcFile or a.splitFile.ext != ".nim" or + (a.isRelativeTo("lib/system") and a.nativeToUnixPath notin goodSystem) or + a.nativeToUnixPath in docIgnore: continue result.add a result.add normalizePath("nimsuggest/sexp.nim") @@ -231,16 +209,28 @@ proc buildDocSamples(nimArgs, destPath: string) = [nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"]) proc buildDocPackages(nimArgs, destPath: string) = - # compiler docs, and later, other packages (perhaps tools, testament etc) + # compiler docs; later, other packages (perhaps tools, testament etc) let nim = findNim().quoteShell() - let extra = "-u:boot" # to avoid broken links to manual from compiler dir, but a multi-package # structure could be supported later - exec("$1 doc --project --outdir:$2/compiler $3 --git.url:$4 $5 compiler/nim.nim" % - [nim, destPath, nimArgs, gitUrl, extra]) + + proc docProject(outdir, options, mainproj: string) = + exec("$nim doc --project --outdir:$outdir $nimArgs --git.url:$gitUrl $options $mainproj" % [ + "nim", nim, + "outdir", outdir, + "nimArgs", nimArgs, + "gitUrl", gitUrl, + "options", options, + "mainproj", mainproj, + ]) + let extra = "-u:boot" + # xxx keep in sync with what's in $nim_prs_D/config/nimdoc.cfg, or, rather, + # start using nims instead of nimdoc.cfg + docProject(destPath/"compiler", extra, "compiler/index.nim") proc buildDoc(nimArgs, destPath: string) = # call nim for the documentation: + let rst2html = getRst2html() var commands = newSeq[string](rst2html.len + len(doc0) + len(doc) + withoutIndex.len) i = 0 @@ -305,18 +295,19 @@ proc buildJS(): string = let nim = findNim() exec(nim.quoteShell() & " js -d:release --out:$1 tools/nimblepkglist.nim" % [webUploadOutput / "nimblepkglist.js"]) + # xxx deadcode? and why is it only for webUploadOutput, not for local docs? result = getDocHacksJs(nimr = getCurrentDir(), nim) -proc buildDocs*(args: string) = +proc buildDocsDir*(args: string, dir: string) = + let args = nimArgs & " " & args let docHackJsSource = buildJS() - template fn(args, dir) = - let dir2 = dir - let args2 = args - createDir(dir2) - buildDocSamples(args2, dir2) - buildDoc(args2, dir2) - buildDocPackages(args2, dir2) - copyFile(docHackJsSource, dir2 / docHackJsSource.lastPathPart) - - fn(nimArgs & " " & args, webUploadOutput / NimVersion) - fn(nimArgs, docHtmlOutput) # no `args` to avoid offline docs containing the 'gaCode'! + createDir(dir) + buildDocSamples(args, dir) + buildDoc(args, dir) # bottleneck + copyFile(dir / "overview.html", dir / "index.html") + buildDocPackages(args, dir) + copyFile(docHackJsSource, dir / docHackJsSource.lastPathPart) + +proc buildDocs*(args: string) = + buildDocsDir(args, webUploadOutput / NimVersion) + buildDocsDir("", docHtmlOutput) # no `args` to avoid offline docs containing the 'gaCode'! diff --git a/tools/nimblepkglist.nim b/tools/nimblepkglist.nim index 870944ab0..c4bec4485 100644 --- a/tools/nimblepkglist.nim +++ b/tools/nimblepkglist.nim @@ -1,3 +1,6 @@ +#[ +deadcode? +]# import base64, strutils, json, htmlgen, dom, algorithm type |