diff options
author | Grzegorz Adam Hankiewicz <gradha@imap.cc> | 2014-04-21 11:48:18 +0200 |
---|---|---|
committer | Grzegorz Adam Hankiewicz <gradha@imap.cc> | 2014-04-21 21:05:38 +0200 |
commit | 69fb40bd84c5b441e663cabdf072de7d16704eba (patch) | |
tree | 8ebd21c54021eb6c9c79bfe32cfbfd30a0e72d8d /lib/packages/docutils | |
parent | b1f26ae542adbdd7a076779f4aa1eb99f9636f1c (diff) | |
download | Nim-69fb40bd84c5b441e663cabdf072de7d16704eba.tar.gz |
Refactors adhoc table of sequences into TIndexedDocs type.
Diffstat (limited to 'lib/packages/docutils')
-rw-r--r-- | lib/packages/docutils/rstgen.nim | 146 |
1 files changed, 87 insertions, 59 deletions
diff --git a/lib/packages/docutils/rstgen.nim b/lib/packages/docutils/rstgen.nim index 049d78b13..a7745b2a5 100644 --- a/lib/packages/docutils/rstgen.nim +++ b/lib/packages/docutils/rstgen.nim @@ -208,6 +208,9 @@ proc dispA(target: TOutputTarget, dest: var string, if target != outLatex: addf(dest, xml, 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) ## 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 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 = ## Sorts two ``TIndexEntry`` first by `keyword` field, then by `link`. result = cmpIgnoreStyle(a.keyword, b.keyword) if result == 0: 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) = shallowCopy a.keyword, b.keyword shallowCopy a.link, b.link @@ -371,9 +394,6 @@ proc isDocumentationTitle(hyperlink: string): bool = ## for a more detailed explanation. 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] = ## Returns the *level* of the toc along with the text without it. for c in 0 .. <s.len: @@ -395,12 +415,12 @@ proc indentToLevel(level: var int, newLevel: int): string = result = repeatStr(level - newLevel, "</ul>") level = newLevel -proc generateDocumentationTOC(entries: seq[TIndexEntry]): - tuple[toc, titleRef: string] = +proc generateDocumentationTOC(entries: seq[TIndexEntry]): string = ## 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. var + titleRef: string levels: seq[tuple[level: int, text: string]] L = 0 level = 1 @@ -420,73 +440,51 @@ proc generateDocumentationTOC(entries: seq[TIndexEntry]): inc L # Now generate hierarchical lists based on the precalculated levels. - result.toc = "<ul>\n" + result = "<ul>\n" level = 1 L = 0 while L < entries.len: let link = entries[L].link if link.isDocumentationTitle: - result.titleRef = link + titleRef = link else: - result.toc.add(level.indentToLevel(levels[L].level)) - result.toc.add("<li><a href=\"" & link & "\">" & + result.add(level.indentToLevel(levels[L].level)) + result.add("<li><a href=\"" & link & "\">" & levels[L].text & "</a>\n") inc L - result.toc.add(level.indentToLevel(1) & "</ul>\n") - assert(not result.titleRef.isNil, "Can't use this proc on an API index") + result.add(level.indentToLevel(1) & "</ul>\n") + assert(not titleRef.isNil, + "Can't use this proc on an API index, docs always have a title entry") -proc generateDocumentationIndex( - docs: TTable[string, seq[TIndexEntry]]): string = +proc generateDocumentationIndex(docs: TIndexedDocs): string = ## Returns all the documentation TOCs in an HTML hierarchical list. result = "" # Sort the titles to generate their toc in alphabetical order. - var titles = toSeq(keys[string, seq[TIndexEntry]](docs)) - sort(titles, system.cmp) + var titles = toSeq(keys[TIndexEntry, seq[TIndexEntry]](docs)) + sort(titles, cmp) for title in titles: - let (list, titleRef) = generateDocumentationTOC(docs[title]) - result.add("<ul><li><a href=\"" & titleRef & "\">" & - title & "</a>\n" & list & "</ul>\n") + let tocList = generateDocumentationTOC(docs[title]) + result.add("<ul><li><a href=\"" & title.link & "\">" & + title.keyword & "</a>\n" & tocList & "</ul>\n") -proc mergeIndexes*(dir: string): string = - ## Merges all index files in `dir` and returns the generated index as HTML. - ## - ## This proc will first scan `dir` for index files with the ``.idx`` - ## extension previously created by commands like ``nimrod doc|rst2html`` - ## which use the ``--index:on`` switch. These index files are the result of - ## calls to `setIndexTerm() <#setIndexTerm>`_ and `writeIndexFile() - ## <#writeIndexFile>`_, so they are simple tab separated files. +proc readIndexDir(dir: string): + tuple[symbols: seq[TIndexEntry], docs: TIndexedDocs] = + ## Walks `dir` reading ``.idx`` files converting them in TIndexEntry items. ## - ## As convention this proc will split index files into two categories: - ## documentation and API. API indices will be all joined together into a - ## single big sorted index, making the bulk of the final index. This is good - ## for API documentation because many symbols are repated in different - ## modules. On the other hand, documentation indices are essentially table of - ## contents plus a few special markers. These documents will be rendered in a - ## separate section which tries to maintain the order and hierarchy of the - ## symbols in the index file. - ## - ## To differentiate between a documentation and API file a convention is - ## used: indices which contain one entry without the HTML hash character (#) - ## will be considered `documentation`, since this hash-less entry is the - ## explicit title of the document. Indices without this explicit entry will - ## be considered `generated API` extracted out of a source ``.nim`` file. - ## - ## Returns the merged and sorted indices into a single HTML block which can - ## be further embedded into nimdoc templates. - var - symbols: seq[TIndexEntry] - docs = initTable[string, seq[TIndexEntry]](32) - newSeq(symbols, 15_000) - setLen(symbols, 0) + ## 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] - foundTitle = "" + title: TIndexEntry F = 0 newSeq(fileEntries, 500) setLen(fileEntries, 0) @@ -496,9 +494,10 @@ proc mergeIndexes*(dir: string): string = 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 + # 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') @@ -511,13 +510,42 @@ proc mergeIndexes*(dir: string): string = 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) + if title.keyword.isNil: + setLen(result.symbols, L + F) for i in 0 .. <F: - symbols[L] = fileEntries[i] + result.symbols[L] = fileEntries[i] inc L + else: + result.docs[title] = fileEntries + +proc mergeIndexes*(dir: string): string = + ## Merges all index files in `dir` and returns the generated index as HTML. + ## + ## This proc will first scan `dir` for index files with the ``.idx`` + ## extension previously created by commands like ``nimrod doc|rst2html`` + ## which use the ``--index:on`` switch. These index files are the result of + ## calls to `setIndexTerm() <#setIndexTerm>`_ and `writeIndexFile() + ## <#writeIndexFile>`_, so they are simple tab separated files. + ## + ## As convention this proc will split index files into two categories: + ## documentation and API. API indices will be all joined together into a + ## single big sorted index, making the bulk of the final index. This is good + ## for API documentation because many symbols are repated in different + ## modules. On the other hand, documentation indices are essentially table of + ## contents plus a few special markers. These documents will be rendered in a + ## separate section which tries to maintain the order and hierarchy of the + ## symbols in the index file. + ## + ## To differentiate between a documentation and API file a convention is + ## used: indices which contain one entry without the HTML hash character (#) + ## will be considered `documentation`, since this hash-less entry is the + ## explicit title of the document. Indices without this explicit entry will + ## be considered `generated API` extracted out of a source ``.nim`` file. + ## + ## Returns the merged and sorted indices into a single HTML block which can + ## be further embedded into nimdoc templates. + var (symbols, docs) = readIndexDir(dir) + assert(not symbols.isNil) result = "" # Generate the HTML block with API documents. @@ -526,7 +554,7 @@ proc mergeIndexes*(dir: string): string = result.add(generateDocumentationIndex(docs)) # Generate the HTML block with symbols. - if L > 0: + if symbols.len > 0: sortIndex(symbols) result.add("<h2>API symbols</h2>\n") result.add(generateSymbolIndex(symbols)) |