diff --git a/compiler/docgen.nim b/compiler/docgen.nim index 8cb36cc4662ef..0d4e68e17a740 100644 --- a/compiler/docgen.nim +++ b/compiler/docgen.nim @@ -17,7 +17,8 @@ import packages/docutils/rst, packages/docutils/rstgen, json, xmltree, cgi, trees, types, typesrenderer, astalgo, lineinfos, intsets, - pathutils, trees, tables + pathutils, trees, tables, + renderverbatim const exportSection = skField @@ -492,91 +493,6 @@ proc runAllExamples(d: PDoc) = rawMessage(d.conf, hintSuccess, ["runnableExamples: " & outp.string]) # removeFile(outp.changeFileExt(ExeExt)) # it's in nimcache, no need to remove -proc lastNodeRec(n: PNode): PNode = - # MOVE - result = n - while result.safeLen > 0: - result = result[^1] - -proc isInIndentationBlock(src: string, indent: int): bool = - #[ - MOVE - returns whether source code line `src` is indented within indentation block - indented at `indent`, taking care of comments, - Limitation: following extreme edge case isn't supported, it's trivial - to work around it. As a benefit, we dont miss comments after the last - declaration inside runnableExamples, which alternative implementations would. - - TODO: handle nested comments properly - - runnableExamples: - echo [ - 1, - # this comment works fine - 2, - #[ -sneaky_indentation # this comment won't work - ]# - ] # this will be wrongly skipped because of previous edge case - ]# - - for j in 0.. last.line and not isInIndentationBlock(src, indent): - # if line > last.line: - break - if line > first.line: ret.add "\n" - if src.len > indent: - ret.add src[indent..^1] - lastNonemptyPos = ret.len - ret = ret[0..$1", "\\spanStringLit{$1}", [escLit]) - # result.add "$2" % [class, val] - result.add "$2" % [class, buf] - - while true: - getNextToken(toknizr, langNim) - case toknizr.kind - of gtEof: break # End Of File (or string) - else: - # TODO: avoid alloc; maybe toOpenArray - append(toknizr.kind, substr(code, toknizr.start, toknizr.length + toknizr.start - 1)) - proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] = ## returns `rdoccmd` and source code for this runnableExamples var rdoccmd = "" @@ -594,10 +510,9 @@ proc prepareExample(d: PDoc; n: PNode): tuple[rdoccmd: string, code: string] = docComment, newTree(nkImportStmt, newStrNode(nkStrLit, d.filename))) runnableExamples.info = n.info - let ret = extractRunnableExamplesSource(d, n) - echo ret + let ret = extractRunnableExamplesSource(d.conf, n) for a in n.lastSon: runnableExamples.add a - # TODO: use ret instead here too? + # we could also use `ret` instead here, to keep sources verbatim writeExample(d, runnableExamples, rdoccmd) result = (rdoccmd, ret) when false: diff --git a/compiler/renderverbatim.nim b/compiler/renderverbatim.nim new file mode 100644 index 0000000000000..ed493bf9c48f2 --- /dev/null +++ b/compiler/renderverbatim.nim @@ -0,0 +1,67 @@ +import strutils +from xmltree import addEscaped + +import ast, options, msgs +import packages/docutils/highlite + +proc lastNodeRec(n: PNode): PNode = + # MOVE + 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.. last.line and not isInIndentationBlock(src, indent): + break + if line > first.line: ret.add "\n" + if src.len > indent: + ret.add src[indent..^1] + lastNonemptyPos = ret.len + ret = ret[0..$1", "\\spanStringLit{$1}", [escLit]) + # result.add "$2" % [class, val] + result.add "$2" % [class, buf] + + while true: + getNextToken(toknizr, langNim) + case toknizr.kind + of gtEof: break # End Of File (or string) + else: + # TODO: avoid alloc; maybe toOpenArray + append(toknizr.kind, substr(code, toknizr.start, toknizr.length + toknizr.start - 1)) diff --git a/nimdoc/testproject/expected/testproject.html b/nimdoc/testproject/expected/testproject.html index 4eb8ed44ca89e..ff7263f52acfd 100644 --- a/nimdoc/testproject/expected/testproject.html +++ b/nimdoc/testproject/expected/testproject.html @@ -170,7 +170,9 @@

testproject

  • Templates @@ -184,13 +186,11 @@

    testproject

    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

    Imports

    @@ -328,6 +328,26 @@

    Macros

    Templates

    + +
    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)
    diff --git a/nimdoc/testproject/expected/theindex.html b/nimdoc/testproject/expected/theindex.html index a76f5961f6b88..f78be11eeef16 100644 --- a/nimdoc/testproject/expected/theindex.html +++ b/nimdoc/testproject/expected/theindex.html @@ -143,6 +143,10 @@

    Index

  • testproject: isValid[T](x: T): bool
  • +
    myfn:
    someFunc:
    • testproject: someFunc()
    • diff --git a/nimdoc/testproject/testproject.nim b/nimdoc/testproject/testproject.nim index d1fcf58cd83e4..b2976fe9a5495 100644 --- a/nimdoc/testproject/testproject.nim +++ b/nimdoc/testproject/testproject.nim @@ -9,6 +9,22 @@ runnableExamples: # bug #11078 for x in "xx": discard +template myfn*() = + runnableExamples: + 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 + # should be out + const C_A* = 0x7FF0000000000000'f64 C_B* = 0o377'i8