diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 2072945973ce7..ddfbeb549847a 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -17,7 +17,7 @@ import packages/docutils/rst, packages/docutils/rstgen, json, xmltree, cgi, trees, types, typesrenderer, astalgo, lineinfos, intsets, - pathutils, trees, tables, nimpaths + pathutils, trees, tables, nimpaths, renderverbatim const exportSection = skField @@ -494,8 +494,8 @@ proc runAllExamples(d: PDoc) = rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string]) # removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove -proc prepareExample(d: PDoc; n: PNode): string = - ## returns `rdoccmd` for this runnableExamples +proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] = + ## returns `rdoccmd` and source code for this runnableExamples var rdoccmd = "" if n.len < 2 or n.len > 3: globalError(d.conf, n.info, "runnableExamples invalid") if n.len == 3: @@ -512,10 +512,11 @@ proc prepareExample(d: PDoc; n: PNode): string = docComment, newTree(nkImportStmt, newStrNode(nkStrLit, d.filename))) runnableExamples.info = n.info - + let ret = extractRunnableExamplesSource(d.conf, n) for a in n.lastSon: runnableExamples.add a + # we could also use `ret` instead here, to keep sources verbatim writeExample(d, runnableExamples, rdoccmd) - result = rdoccmd + result = (rdoccmd, ret) when false: proc extractImports(n: PNode; result: PNode) = if n.kind in {nkImportStmt, nkImportExceptStmt, nkFromStmt}: @@ -561,7 +562,7 @@ proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope, previous if isRunnableExamples(n[0]) and n.len >= 2 and n.lastSon.kind == nkStmtList: previousIsRunnable = true - let rdoccmd = prepareExample(d, n) + let (rdoccmd, code) = prepareExample(d, n) var msg = "Example:" if rdoccmd.len > 0: msg.add " cmd: " & rdoccmd dispA(d.conf, dest, "\n
$1
\n", @@ -569,17 +570,22 @@ proc getAllRunnableExamplesRec(d: PDoc; n, orig: PNode; dest: var Rope, previous inc d.listingCounter let id = $d.listingCounter dest.add(d.config.getOrDefault"doc.listing_start" % [id, "langNim"]) - # this is a rather hacky way to get rid of the initial indentation - # that the renderer currently produces: - var i = 0 - var body = n.lastSon - if body.len == 1 and body.kind == nkStmtList and - body.lastSon.kind == nkStmtList: - body = body.lastSon - for b in body: - if i > 0: dest.add "\n" - inc i - nodeToHighlightedHtml(d, b, dest, {renderRunnableExamples}, nil) + when true: + var dest2 = "" + renderNimCode(dest2, code, isLatex = d.conf.cmd == cmdRst2tex) + dest.add dest2 + else: + # this is a rather hacky way to get rid of the initial indentation + # that the renderer currently produces: + var i = 0 + var body = n.lastSon + if body.len == 1 and body.kind == nkStmtList and + body.lastSon.kind == nkStmtList: + body = body.lastSon + for b in body: + if i > 0: dest.add "\n" + inc i + nodeToHighlightedHtml(d, b, dest, {renderRunnableExamples}, nil) dest.add(d.config.getOrDefault"doc.listing_end" % id) else: previousIsRunnable = false diff --git a/compiler/msgs.nim b/compiler/msgs.nim index a26aa0a3cef67..00efff3aab0a6 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -435,18 +435,21 @@ proc ignoreMsgBecauseOfIdeTools(conf: ConfigRef; msg: TMsgKind): bool = proc addSourceLine(conf: ConfigRef; fileIdx: FileIndex, line: string) = conf.m.fileInfos[fileIdx.int32].lines.add line -proc sourceLine*(conf: ConfigRef; i: TLineInfo): string = - if i.fileIndex.int32 < 0: return "" - - if conf.m.fileInfos[i.fileIndex.int32].lines.len == 0: +proc numLines*(conf: ConfigRef, fileIdx: FileIndex): int = + result = conf.m.fileInfos[fileIdx.int32].lines.len + if result == 0: try: - for line in lines(toFullPathConsiderDirty(conf, i)): - addSourceLine conf, i.fileIndex, line.string + for line in lines(toFullPathConsiderDirty(conf, fileIdx).string): + addSourceLine conf, fileIdx, line.string except IOError: discard - assert i.fileIndex.int32 < conf.m.fileInfos.len + result = conf.m.fileInfos[fileIdx.int32].lines.len + +proc sourceLine*(conf: ConfigRef; i: TLineInfo): string = + if i.fileIndex.int32 < 0: return "" + let num = numLines(conf, i.fileIndex) # can happen if the error points to EOF: - if i.line.int > conf.m.fileInfos[i.fileIndex.int32].lines.len: return "" + if i.line.int > num: return "" result = conf.m.fileInfos[i.fileIndex.int32].lines[i.line.int-1] diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim new file mode 100644 index 0000000000000..9513353cd92ac --- /dev/null +++ b/compiler/renderverbatim.nim @@ -0,0 +1,65 @@ +import strutils +from xmltree import addEscaped + +import ast, options, msgs +import packages/docutils/highlite + +proc lastNodeRec(n: PNode): PNode = + result = n + while result.safeLen > 0: result = result[^1] + +proc isInIndentationBlock(src: string, indent: int): bool = + #[ + we stop at the first de-indentation; there's an inherent ambiguity with non + doc comments since they can have arbitrary indentation, so we just take the + practical route and require a runnableExamples to keep its code (including non + doc comments) to its indentation level. + ]# + for j in 0..This is the top level module.
Example:
-import - subdir / subdir_b / utils - -doAssert bar(3, 4) == 7 -foo(enumValueA, enumValueB) -for x in "xx": - discard+
import subdir / subdir_b / utils +doAssert bar(3, 4) == 7 +foo(enumValueA, enumValueB) +# bug #11078 +for x in "xx": discard
template myfn()
Example:
+import std/strutils +## line doc comment +# bar +doAssert "'foo" == "'foo" +##[ +foo +bar +]## +doAssert: not "foo".startsWith "ba" +block: + discard 0xff # elu par cette crapule +# should be in+ +
template foo(a, b: SomeType)