docgen: group by type feature
This commit is contained in:
parent
07fcce6e63
commit
083b31b473
5 changed files with 596 additions and 1 deletions
231
tools/dochack/dochack.nim
Normal file
231
tools/dochack/dochack.nim
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
|
||||
|
||||
import karax
|
||||
|
||||
proc findNodeWith(x: Element; tag, content: cstring): Element =
|
||||
if x.nodeName == tag and x.textContent == content:
|
||||
return x
|
||||
for i in 0..<x.len:
|
||||
let it = x[i]
|
||||
let y = findNodeWith(it, tag, content)
|
||||
if y != nil: return y
|
||||
return nil
|
||||
|
||||
proc clone(e: Element): Element {.importcpp: "#.cloneNode(true)", nodecl.}
|
||||
proc parent(e: Element): Element {.importcpp: "#.parentNode", nodecl.}
|
||||
proc markElement(x: Element) {.importcpp: "#.__karaxMarker__ = true", nodecl.}
|
||||
proc isMarked(x: Element): bool {.
|
||||
importcpp: "#.hasOwnProperty('__karaxMarker__')", nodecl.}
|
||||
proc title(x: Element): cstring {.importcpp: "#.title", nodecl.}
|
||||
|
||||
proc sort[T](x: var openArray[T]; cmp: proc(a, b: T): int) {.importcpp:
|
||||
"#.sort(#)", nodecl.}
|
||||
|
||||
proc parentWith(x: Element; tag: cstring): Element =
|
||||
result = x.parent
|
||||
while result.nodeName != tag:
|
||||
result = result.parent
|
||||
if result == nil: return nil
|
||||
|
||||
proc extractItems(x: Element; items: var seq[Element]) =
|
||||
if x == nil: return
|
||||
if x.nodeName == "A":
|
||||
items.add x
|
||||
else:
|
||||
for i in 0..<x.len:
|
||||
let it = x[i]
|
||||
extractItems(it, items)
|
||||
|
||||
# HTML trees are so shitty we transform the TOC into a decent
|
||||
# data-structure instead and work on that.
|
||||
type
|
||||
TocEntry = ref object
|
||||
heading: Element
|
||||
kids: seq[TocEntry]
|
||||
sortId: int
|
||||
doSort: bool
|
||||
|
||||
proc extractItems(x: TocEntry; heading: cstring;
|
||||
items: var seq[Element]) =
|
||||
if x == nil: return
|
||||
if x.heading != nil and x.heading.textContent == heading:
|
||||
for i in 0..<x.kids.len:
|
||||
items.add x.kids[i].heading
|
||||
else:
|
||||
for i in 0..<x.kids.len:
|
||||
let it = x.kids[i]
|
||||
extractItems(it, heading, items)
|
||||
|
||||
proc toHtml(x: TocEntry; isRoot=false): Element =
|
||||
if x == nil: return nil
|
||||
if x.kids.len == 0:
|
||||
if x.heading == nil: return nil
|
||||
return x.heading.clone
|
||||
result = tree("DIV")
|
||||
if x.heading != nil and not isMarked(x.heading):
|
||||
result.add x.heading.clone
|
||||
let ul = tree("UL")
|
||||
if isRoot:
|
||||
ul.setClass("simple simple-toc")
|
||||
else:
|
||||
ul.setClass("simple")
|
||||
if x.dosort:
|
||||
x.kids.sort(proc(a, b: TocEntry): int =
|
||||
if a.heading != nil and b.heading != nil:
|
||||
let x = a.heading.textContent
|
||||
let y = b.heading.textContent
|
||||
if x < y: return -1
|
||||
if x > y: return 1
|
||||
return 0
|
||||
else:
|
||||
# ensure sorting is stable:
|
||||
return a.sortId - b.sortId
|
||||
)
|
||||
for k in x.kids:
|
||||
let y = toHtml(k)
|
||||
if y != nil:
|
||||
ul.add tree("LI", y)
|
||||
if ul.len != 0: result.add ul
|
||||
if result.len == 0: result = nil
|
||||
|
||||
proc containsWord(a, b: cstring): bool {.asmNoStackFrame.} =
|
||||
{.emit: """
|
||||
var escaped = `b`.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
|
||||
return new RegExp("\\b" + escaped + "\\b").test(`a`);
|
||||
""".}
|
||||
|
||||
proc isWhitespace(text: cstring): bool {.asmNoStackFrame.} =
|
||||
{.emit: """
|
||||
return !/[^\s]/.test(`text`);
|
||||
""".}
|
||||
|
||||
proc isWhitespace(x: Element): bool =
|
||||
x.nodeName == "#text" and x.textContent.isWhitespace or
|
||||
x.nodeName == "#comment"
|
||||
|
||||
proc toToc(x: Element; father: TocEntry) =
|
||||
if x.nodeName == "UL":
|
||||
let f = TocEntry(heading: nil, kids: @[], sortId: father.kids.len)
|
||||
var i = 0
|
||||
while i < x.len:
|
||||
var nxt = i+1
|
||||
while nxt < x.len and x[nxt].isWhitespace:
|
||||
inc nxt
|
||||
if nxt < x.len and x[i].nodeName == "LI" and x[i].len == 1 and
|
||||
x[nxt].nodeName == "UL":
|
||||
let e = TocEntry(heading: x[i][0], kids: @[], sortId: f.kids.len)
|
||||
let it = x[nxt]
|
||||
for j in 0..<it.len:
|
||||
toToc(it[j], e)
|
||||
f.kids.add e
|
||||
i = nxt+1
|
||||
else:
|
||||
toToc(x[i], f)
|
||||
inc i
|
||||
father.kids.add f
|
||||
elif isWhitespace(x):
|
||||
discard
|
||||
elif x.nodeName == "LI":
|
||||
var idx: seq[int] = @[]
|
||||
for i in 0 ..< x.len:
|
||||
if not x[i].isWhitespace: idx.add i
|
||||
if idx.len == 2 and x[idx[1]].nodeName == "UL":
|
||||
let e = TocEntry(heading: x[idx[0]], kids: @[],
|
||||
sortId: father.kids.len)
|
||||
let it = x[idx[1]]
|
||||
for j in 0..<it.len:
|
||||
toToc(it[j], e)
|
||||
father.kids.add e
|
||||
else:
|
||||
for i in 0..<x.len:
|
||||
toToc(x[i], father)
|
||||
else:
|
||||
father.kids.add TocEntry(heading: x, kids: @[],
|
||||
sortId: father.kids.len)
|
||||
|
||||
proc tocul(x: Element): Element =
|
||||
# x is a 'ul' element
|
||||
result = tree("UL")
|
||||
for i in 0..<x.len:
|
||||
let it = x[i]
|
||||
if it.nodeName == "LI":
|
||||
result.add it.clone
|
||||
elif it.nodeName == "UL":
|
||||
result.add tocul(it)
|
||||
|
||||
proc getSection(toc: Element; name: cstring): Element =
|
||||
let sec = findNodeWith(toc, "A", name)
|
||||
if sec != nil:
|
||||
result = sec.parentWith("LI")
|
||||
|
||||
proc uncovered(x: TocEntry): TocEntry =
|
||||
if x.kids.len == 0 and x.heading != nil:
|
||||
return if not isMarked(x.heading): x else: nil
|
||||
result = TocEntry(heading: x.heading, kids: @[], sortId: x.sortId,
|
||||
doSort: x.doSort)
|
||||
for i in 0..<x.kids.len:
|
||||
let y = uncovered(x.kids[i])
|
||||
if y != nil: result.kids.add y
|
||||
if result.kids.len == 0: result = nil
|
||||
|
||||
proc mergeTocs(orig, news: TocEntry): TocEntry =
|
||||
result = uncovered(orig)
|
||||
if result == nil:
|
||||
result = news
|
||||
else:
|
||||
for i in 0..<news.kids.len:
|
||||
result.kids.add news.kids[i]
|
||||
|
||||
proc buildToc(orig: TocEntry; types, procs: seq[Element]): TocEntry =
|
||||
var newStuff = TocEntry(heading: nil, kids: @[], doSort: true)
|
||||
for t in types:
|
||||
let c = TocEntry(heading: t.clone, kids: @[], doSort: true)
|
||||
t.markElement()
|
||||
for p in procs:
|
||||
if not isMarked(p):
|
||||
let xx = karax.getElementsByClass(p.parent, cstring"attachedType")
|
||||
if xx.len == 1 and xx[0].textContent == t.textContent:
|
||||
#kout(cstring"found ", p.nodeName)
|
||||
let q = tree("A", text(p.title))
|
||||
q.setAttr("href", p.getAttribute("href"))
|
||||
c.kids.add TocEntry(heading: q, kids: @[])
|
||||
p.markElement()
|
||||
newStuff.kids.add c
|
||||
result = mergeTocs(orig, newStuff)
|
||||
|
||||
var alternative: Element
|
||||
|
||||
proc togglevis(d: Element) =
|
||||
asm """
|
||||
if (`d`.style.display == 'none')
|
||||
`d`.style.display = 'inline';
|
||||
else
|
||||
`d`.style.display = 'none';
|
||||
"""
|
||||
|
||||
proc groupBy*(value: cstring) {.exportc.} =
|
||||
let toc = getElementById("toc-list")
|
||||
if alternative.isNil:
|
||||
var tt = TocEntry(heading: nil, kids: @[])
|
||||
toToc(toc, tt)
|
||||
tt = tt.kids[0]
|
||||
|
||||
var types: seq[Element] = @[]
|
||||
var procs: seq[Element] = @[]
|
||||
|
||||
extractItems(tt, "Types", types)
|
||||
extractItems(tt, "Procs", procs)
|
||||
extractItems(tt, "Converters", procs)
|
||||
extractItems(tt, "Methods", procs)
|
||||
extractItems(tt, "Templates", procs)
|
||||
extractItems(tt, "Macros", procs)
|
||||
extractItems(tt, "Iterators", procs)
|
||||
|
||||
let ntoc = buildToc(tt, types, procs)
|
||||
let x = toHtml(ntoc, isRoot=true)
|
||||
alternative = tree("DIV", x)
|
||||
if value == "type":
|
||||
replaceById("tocRoot", alternative)
|
||||
else:
|
||||
replaceById("tocRoot", tree("DIV"))
|
||||
togglevis(getElementById"toc-list")
|
||||
Loading…
Add table
Add a link
Reference in a new issue