Refactors adhoc table of sequences into TIndexedDocs type.
This commit is contained in:
parent
b1f26ae542
commit
69fb40bd84
1 changed files with 91 additions and 63 deletions
|
|
@ -208,6 +208,9 @@ proc dispA(target: TOutputTarget, dest: var string,
|
||||||
if target != outLatex: addf(dest, xml, args)
|
if target != outLatex: addf(dest, xml, args)
|
||||||
else: addf(dest, tex, args)
|
else: addf(dest, tex, args)
|
||||||
|
|
||||||
|
proc `or`(x, y: string): string {.inline.} =
|
||||||
|
result = if x.isNil: y else: x
|
||||||
|
|
||||||
proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
|
proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
|
||||||
## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
|
## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
|
||||||
##
|
##
|
||||||
|
|
@ -307,12 +310,32 @@ type
|
||||||
linkTitle: string ## If not nil, contains a prettier text for the href
|
linkTitle: string ## If not nil, contains a prettier text for the href
|
||||||
linkDesc: string ## If not nil, the title attribute of the final href
|
linkDesc: string ## If not nil, the title attribute of the final href
|
||||||
|
|
||||||
|
TIndexedDocs {.pure, final.} = TTable[TIndexEntry, seq[TIndexEntry]] ## \
|
||||||
|
## Contains the index sequences for doc types.
|
||||||
|
##
|
||||||
|
## The key is a *fake* TIndexEntry which will contain the title of the
|
||||||
|
## document in the `keyword` field and `link` will contain the html
|
||||||
|
## filename for the document. `linkTitle` and `linkDesc` will be nil. The
|
||||||
|
## value indexed by this TIndexEntry is a sequence with the real index
|
||||||
|
## entries found in the ``.idx`` file.
|
||||||
|
|
||||||
|
|
||||||
proc cmp(a, b: TIndexEntry): int =
|
proc cmp(a, b: TIndexEntry): int =
|
||||||
## Sorts two ``TIndexEntry`` first by `keyword` field, then by `link`.
|
## Sorts two ``TIndexEntry`` first by `keyword` field, then by `link`.
|
||||||
result = cmpIgnoreStyle(a.keyword, b.keyword)
|
result = cmpIgnoreStyle(a.keyword, b.keyword)
|
||||||
if result == 0:
|
if result == 0:
|
||||||
result = cmpIgnoreStyle(a.link, b.link)
|
result = cmpIgnoreStyle(a.link, b.link)
|
||||||
|
|
||||||
|
proc hash(x: TIndexEntry): int =
|
||||||
|
## Returns the hash for the combined fields of the type.
|
||||||
|
##
|
||||||
|
## The hash is computed as the concatenated string of all available fields.
|
||||||
|
assert(not x.keyword.isNil)
|
||||||
|
assert(not x.link.isNil)
|
||||||
|
let value = x.keyword & x.link & (x.linkTitle or "") & (x.linkDesc or "")
|
||||||
|
result = value.hash
|
||||||
|
|
||||||
|
|
||||||
proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
|
proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
|
||||||
shallowCopy a.keyword, b.keyword
|
shallowCopy a.keyword, b.keyword
|
||||||
shallowCopy a.link, b.link
|
shallowCopy a.link, b.link
|
||||||
|
|
@ -371,9 +394,6 @@ proc isDocumentationTitle(hyperlink: string): bool =
|
||||||
## for a more detailed explanation.
|
## for a more detailed explanation.
|
||||||
result = hyperlink.find('#') < 0
|
result = hyperlink.find('#') < 0
|
||||||
|
|
||||||
proc `or`(x, y: string): string {.inline.} =
|
|
||||||
result = if x.isNil: y else: x
|
|
||||||
|
|
||||||
proc stripTOCLevel(s: string): tuple[level: int, text: string] =
|
proc stripTOCLevel(s: string): tuple[level: int, text: string] =
|
||||||
## Returns the *level* of the toc along with the text without it.
|
## Returns the *level* of the toc along with the text without it.
|
||||||
for c in 0 .. <s.len:
|
for c in 0 .. <s.len:
|
||||||
|
|
@ -395,12 +415,12 @@ proc indentToLevel(level: var int, newLevel: int): string =
|
||||||
result = repeatStr(level - newLevel, "</ul>")
|
result = repeatStr(level - newLevel, "</ul>")
|
||||||
level = newLevel
|
level = newLevel
|
||||||
|
|
||||||
proc generateDocumentationTOC(entries: seq[TIndexEntry]):
|
proc generateDocumentationTOC(entries: seq[TIndexEntry]): string =
|
||||||
tuple[toc, titleRef: string] =
|
|
||||||
## Returns the sequence of index entries in an HTML hierarchical list.
|
## Returns the sequence of index entries in an HTML hierarchical list.
|
||||||
result.toc = ""
|
result = ""
|
||||||
# Build a list of levels and extracted titles to make processing easier.
|
# Build a list of levels and extracted titles to make processing easier.
|
||||||
var
|
var
|
||||||
|
titleRef: string
|
||||||
levels: seq[tuple[level: int, text: string]]
|
levels: seq[tuple[level: int, text: string]]
|
||||||
L = 0
|
L = 0
|
||||||
level = 1
|
level = 1
|
||||||
|
|
@ -420,34 +440,83 @@ proc generateDocumentationTOC(entries: seq[TIndexEntry]):
|
||||||
inc L
|
inc L
|
||||||
|
|
||||||
# Now generate hierarchical lists based on the precalculated levels.
|
# Now generate hierarchical lists based on the precalculated levels.
|
||||||
result.toc = "<ul>\n"
|
result = "<ul>\n"
|
||||||
level = 1
|
level = 1
|
||||||
L = 0
|
L = 0
|
||||||
while L < entries.len:
|
while L < entries.len:
|
||||||
let link = entries[L].link
|
let link = entries[L].link
|
||||||
if link.isDocumentationTitle:
|
if link.isDocumentationTitle:
|
||||||
result.titleRef = link
|
titleRef = link
|
||||||
else:
|
else:
|
||||||
result.toc.add(level.indentToLevel(levels[L].level))
|
result.add(level.indentToLevel(levels[L].level))
|
||||||
result.toc.add("<li><a href=\"" & link & "\">" &
|
result.add("<li><a href=\"" & link & "\">" &
|
||||||
levels[L].text & "</a>\n")
|
levels[L].text & "</a>\n")
|
||||||
inc L
|
inc L
|
||||||
result.toc.add(level.indentToLevel(1) & "</ul>\n")
|
result.add(level.indentToLevel(1) & "</ul>\n")
|
||||||
assert(not result.titleRef.isNil, "Can't use this proc on an API index")
|
assert(not titleRef.isNil,
|
||||||
|
"Can't use this proc on an API index, docs always have a title entry")
|
||||||
|
|
||||||
proc generateDocumentationIndex(
|
proc generateDocumentationIndex(docs: TIndexedDocs): string =
|
||||||
docs: TTable[string, seq[TIndexEntry]]): string =
|
|
||||||
## Returns all the documentation TOCs in an HTML hierarchical list.
|
## Returns all the documentation TOCs in an HTML hierarchical list.
|
||||||
result = ""
|
result = ""
|
||||||
|
|
||||||
# Sort the titles to generate their toc in alphabetical order.
|
# Sort the titles to generate their toc in alphabetical order.
|
||||||
var titles = toSeq(keys[string, seq[TIndexEntry]](docs))
|
var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs))
|
||||||
sort(titles, system.cmp)
|
sort(titles, cmp)
|
||||||
|
|
||||||
for title in titles:
|
for title in titles:
|
||||||
let (list, titleRef) = generateDocumentationTOC(docs[title])
|
let tocList = generateDocumentationTOC(docs[title])
|
||||||
result.add("<ul><li><a href=\"" & titleRef & "\">" &
|
result.add("<ul><li><a href=\"" & title.link & "\">" &
|
||||||
title & "</a>\n" & list & "</ul>\n")
|
title.keyword & "</a>\n" & tocList & "</ul>\n")
|
||||||
|
|
||||||
|
proc readIndexDir(dir: string):
|
||||||
|
tuple[symbols: seq[TIndexEntry], docs: TIndexedDocs] =
|
||||||
|
## Walks `dir` reading ``.idx`` files converting them in TIndexEntry items.
|
||||||
|
##
|
||||||
|
## Returns the list of free symbol entries and the separate documentation
|
||||||
|
## indexes found. See the documentation of ``mergeIndexes`` for details.
|
||||||
|
result.docs = initTable[TIndexEntry, seq[TIndexEntry]](32)
|
||||||
|
newSeq(result.symbols, 15_000)
|
||||||
|
setLen(result.symbols, 0)
|
||||||
|
var L = 0
|
||||||
|
# Scan index files and build the list of symbols.
|
||||||
|
for kind, path in walkDir(dir):
|
||||||
|
if kind == pcFile and path.endsWith(IndexExt):
|
||||||
|
var
|
||||||
|
fileEntries: seq[TIndexEntry]
|
||||||
|
title: TIndexEntry
|
||||||
|
F = 0
|
||||||
|
newSeq(fileEntries, 500)
|
||||||
|
setLen(fileEntries, 0)
|
||||||
|
for line in lines(path):
|
||||||
|
let s = line.find('\t')
|
||||||
|
if s < 0: continue
|
||||||
|
setLen(fileEntries, F+1)
|
||||||
|
fileEntries[F].keyword = line.substr(0, s-1)
|
||||||
|
fileEntries[F].link = line.substr(s+1)
|
||||||
|
# See if we detect a title, a link without a `#foobar` trailing part.
|
||||||
|
if title.keyword.isNil and fileEntries[F].link.isDocumentationTitle:
|
||||||
|
title.keyword = fileEntries[F].keyword
|
||||||
|
title.link = fileEntries[F].link
|
||||||
|
|
||||||
|
if fileEntries[F].link.find('\t') > 0:
|
||||||
|
let extraCols = fileEntries[F].link.split('\t')
|
||||||
|
fileEntries[F].link = extraCols[0]
|
||||||
|
assert extraCols.len == 3
|
||||||
|
fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
|
||||||
|
fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
|
||||||
|
else:
|
||||||
|
fileEntries[F].linkTitle = nil
|
||||||
|
fileEntries[F].linkDesc = nil
|
||||||
|
inc F
|
||||||
|
# Depending on type add this to the list of symbols or table of APIs.
|
||||||
|
if title.keyword.isNil:
|
||||||
|
setLen(result.symbols, L + F)
|
||||||
|
for i in 0 .. <F:
|
||||||
|
result.symbols[L] = fileEntries[i]
|
||||||
|
inc L
|
||||||
|
else:
|
||||||
|
result.docs[title] = fileEntries
|
||||||
|
|
||||||
proc mergeIndexes*(dir: string): string =
|
proc mergeIndexes*(dir: string): string =
|
||||||
## Merges all index files in `dir` and returns the generated index as HTML.
|
## Merges all index files in `dir` and returns the generated index as HTML.
|
||||||
|
|
@ -475,49 +544,8 @@ proc mergeIndexes*(dir: string): string =
|
||||||
##
|
##
|
||||||
## Returns the merged and sorted indices into a single HTML block which can
|
## Returns the merged and sorted indices into a single HTML block which can
|
||||||
## be further embedded into nimdoc templates.
|
## be further embedded into nimdoc templates.
|
||||||
var
|
var (symbols, docs) = readIndexDir(dir)
|
||||||
symbols: seq[TIndexEntry]
|
assert(not symbols.isNil)
|
||||||
docs = initTable[string, seq[TIndexEntry]](32)
|
|
||||||
newSeq(symbols, 15_000)
|
|
||||||
setLen(symbols, 0)
|
|
||||||
var L = 0
|
|
||||||
# Scan index files and build the list of symbols.
|
|
||||||
for kind, path in walkDir(dir):
|
|
||||||
if kind == pcFile and path.endsWith(IndexExt):
|
|
||||||
var
|
|
||||||
fileEntries: seq[TIndexEntry]
|
|
||||||
foundTitle = ""
|
|
||||||
F = 0
|
|
||||||
newSeq(fileEntries, 500)
|
|
||||||
setLen(fileEntries, 0)
|
|
||||||
for line in lines(path):
|
|
||||||
let s = line.find('\t')
|
|
||||||
if s < 0: continue
|
|
||||||
setLen(fileEntries, F+1)
|
|
||||||
fileEntries[F].keyword = line.substr(0, s-1)
|
|
||||||
fileEntries[F].link = line.substr(s+1)
|
|
||||||
# See if we detect a title, a link without a #foobar part.
|
|
||||||
if foundTitle.len < 1 and fileEntries[F].link.isDocumentationTitle:
|
|
||||||
foundTitle = fileEntries[F].keyword
|
|
||||||
|
|
||||||
if fileEntries[F].link.find('\t') > 0:
|
|
||||||
let extraCols = fileEntries[F].link.split('\t')
|
|
||||||
fileEntries[F].link = extraCols[0]
|
|
||||||
assert extraCols.len == 3
|
|
||||||
fileEntries[F].linkTitle = extraCols[1].unquoteIndexColumn
|
|
||||||
fileEntries[F].linkDesc = extraCols[2].unquoteIndexColumn
|
|
||||||
else:
|
|
||||||
fileEntries[F].linkTitle = nil
|
|
||||||
fileEntries[F].linkDesc = nil
|
|
||||||
inc F
|
|
||||||
# Depending on type add this to the list of symbols or table of APIs.
|
|
||||||
if foundTitle.len > 0:
|
|
||||||
docs[foundTitle] = fileEntries
|
|
||||||
else:
|
|
||||||
setLen(symbols, L + F)
|
|
||||||
for i in 0 .. <F:
|
|
||||||
symbols[L] = fileEntries[i]
|
|
||||||
inc L
|
|
||||||
|
|
||||||
result = ""
|
result = ""
|
||||||
# Generate the HTML block with API documents.
|
# Generate the HTML block with API documents.
|
||||||
|
|
@ -526,7 +554,7 @@ proc mergeIndexes*(dir: string): string =
|
||||||
result.add(generateDocumentationIndex(docs))
|
result.add(generateDocumentationIndex(docs))
|
||||||
|
|
||||||
# Generate the HTML block with symbols.
|
# Generate the HTML block with symbols.
|
||||||
if L > 0:
|
if symbols.len > 0:
|
||||||
sortIndex(symbols)
|
sortIndex(symbols)
|
||||||
result.add("<h2>API symbols</h2>\n")
|
result.add("<h2>API symbols</h2>\n")
|
||||||
result.add(generateSymbolIndex(symbols))
|
result.add(generateSymbolIndex(symbols))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue