Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rst: rst2html and doc now have clickable anchors for each paragraph/list element #17251

Closed
wants to merge 29 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion doc/nimdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,20 @@ input:checked + .slider:before {
html {
font-size: 100%;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%; }
-ms-text-size-adjust: 100%;
/*jumping to top is confusing, doesn't show context upwards*/
/*scroll-padding-top: 50%;*/
}

*//*so that anchors are highlighted when selected*/
.nimanchor:target {
background-color: #99ff66;
opacity:1
}

.nimanchor {
opacity:0.1
}

body {
font-family: "Lato", "Helvetica Neue", "HelveticaNeue", Helvetica, Arial, sans-serif;
Expand Down
1 change: 1 addition & 0 deletions lib/packages/docutils/rst.nim
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ type
roSupportRawDirective, ## support the ``raw`` directive (don't support
## it for sandboxing)
roSupportMarkdown ## support additional features of Markdown
roNoGenerateAnchors ## generate anchors for paragraphs, list items, etc.

RstParseOptions* = set[RstParseOption]

Expand Down
2 changes: 2 additions & 0 deletions lib/packages/docutils/rstast.nim
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ type

PRstNode* = ref RstNode ## an RST node
RstNodeSeq* = seq[PRstNode]
RstAnchorKind* = enum raDefault, raVisited, raExplicit, raFromTitle, raInterpolated
RstNode* {.acyclic, final.} = object ## AST node (result of RST parsing)
case kind*: RstNodeKind ## the node's kind
of rnLeaf, rnSmiley:
Expand All @@ -96,6 +97,7 @@ type
discard
anchor*: string ## anchor, internal link target
## (aka HTML id tag, aka Latex label/hypertarget)
anchorKind*: RstAnchorKind ## kind of `anchor`
sons*: RstNodeSeq ## the node's sons

proc len*(n: PRstNode): int =
Expand Down
43 changes: 38 additions & 5 deletions lib/packages/docutils/rstgen.nim
Original file line number Diff line number Diff line change
Expand Up @@ -299,13 +299,15 @@ template idS(txt: string): string =
# we add \label for page number references via \pageref, while
# \hypertarget is for clickable links via \hyperlink.

proc renderAux(d: PDoc, n: PRstNode, html, tex: string, result: var string) =
proc renderAux(d: PDoc, n: PRstNode, html, tex: string, result: var string, useAnchor = false) =
# formats sons of `n` as substitution variable $1 inside strings `html` and
# `tex`, internal target (anchor) is provided as substitute $2.
var tmp = ""
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], tmp)
case d.target
of outHtml: result.addf(html, [tmp, n.anchor.idS])
of outHtml:
let anchor = if useAnchor: n.anchor else: n.anchor.idS
result.addf(html, [tmp, anchor])
of outLatex: result.addf(tex, [tmp, n.anchor.idS])

# ---------------- index handling --------------------------------------------
Expand Down Expand Up @@ -766,7 +768,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
if n2.level < n.level:
sectionPrefix = rstnodeToRefname(n2) & "-"
break
var refname = sectionPrefix & rstnodeToRefname(n)
let refname = sectionPrefix & rstnodeToRefname(n)
if d.hasToc:
var length = len(d.tocPart)
setLen(d.tocPart, length + 1)
Expand Down Expand Up @@ -1136,19 +1138,50 @@ proc renderAdmonition(d: PDoc, n: PRstNode, result: var string) =
"$1\n\\end{mdframed}\n",
result)

proc computeAnchorGen(n: PRstNode) =
var anchorLast = "ROOT"
var idLast = 0
proc impl(n: PRstNode) =
if n == nil: return
n.anchorKind = raVisited # can be over-written below
template update(anchorNew) =
let anchor = anchorNew
n.anchor = anchor
anchorLast = anchor
idLast = 0
if n.anchor.len > 0:
n.anchorKind = raExplicit
update(n.anchor)
elif n.kind in {rnHeadline}:
n.anchorKind = raFromTitle
update(n.rstnodeToRefname)
elif n.kind in {rnParagraph, rnBulletItem, rnEnumItem}:
n.anchorKind = raInterpolated
idLast.inc
n.anchor = "-" & anchorLast & "-" & $idLast
for ai in n.sons: impl(ai)
impl(n)

proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
if n == nil: return
let generateAnchors = roNoGenerateAnchors notin d.options
var anchorLink = ""
if generateAnchors:
anchorLink = """<a class="nimanchor" id="$2" href="#$2">🔗</a> """
if n.anchorKind == raDefault: computeAnchorGen(n)

case n.kind
of rnInner: renderAux(d, n, result)
of rnHeadline, rnMarkdownHeadline: renderHeadline(d, n, result)
of rnOverline: renderOverline(d, n, result)
of rnTransition: renderAux(d, n, "<hr$2 />\n", "\\hrule$2\n", result)
of rnParagraph: renderAux(d, n, "<p$2>$1</p>\n", "$2\n$1\n\n", result)
of rnParagraph:
renderAux(d, n, "<p$$2>$1$$1</p>\n" % anchorLink, "$2\n$1\n\n", result, useAnchor = generateAnchors)
of rnBulletList:
renderAux(d, n, "<ul$2 class=\"simple\">$1</ul>\n",
"\\begin{itemize}\n$2\n$1\\end{itemize}\n", result)
of rnBulletItem, rnEnumItem:
renderAux(d, n, "<li$2>$1</li>\n", "\\item $2$1\n", result)
renderAux(d, n, "<li$$2>$1$$1</li>\n" % anchorLink, "\\item $2$1\n", result, useAnchor = generateAnchors)
of rnEnumList: renderEnumList(d, n, result)
of rnDefList:
renderAux(d, n, "<dl$2 class=\"docutils\">$1</dl>\n",
Expand Down
Loading