small bugfixes; documentation generator supports smilies for the forum
This commit is contained in:
parent
ccae314635
commit
e95f155af3
11 changed files with 229 additions and 84 deletions
|
|
@ -28,7 +28,8 @@ type
|
||||||
TSections = array[TSymKind, PRope]
|
TSections = array[TSymKind, PRope]
|
||||||
TMetaEnum = enum
|
TMetaEnum = enum
|
||||||
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
|
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
|
||||||
TDocumentor{.final.} = object # contains a module's documentation
|
TDocumentor {.final.} = object # contains a module's documentation
|
||||||
|
options: TRstParseOptions
|
||||||
filename*: string # filename of the source file; without extension
|
filename*: string # filename of the source file; without extension
|
||||||
basedir*: string # base directory (where to put the documentation)
|
basedir*: string # base directory (where to put the documentation)
|
||||||
modDesc*: PRope # module description
|
modDesc*: PRope # module description
|
||||||
|
|
@ -70,8 +71,8 @@ proc initIndexFile(d: PDoc) =
|
||||||
gIndexFile = addFileExt(gIndexFile, "txt")
|
gIndexFile = addFileExt(gIndexFile, "txt")
|
||||||
d.indexValFilename = changeFileExt(extractFilename(d.filename), HtmlExt)
|
d.indexValFilename = changeFileExt(extractFilename(d.filename), HtmlExt)
|
||||||
if ExistsFile(gIndexFile):
|
if ExistsFile(gIndexFile):
|
||||||
d.indexFile = rstParse(readFile(gIndexFile), false, gIndexFile, 0, 1,
|
d.indexFile = rstParse(readFile(gIndexFile), gIndexFile, 0, 1,
|
||||||
dummyHasToc)
|
dummyHasToc, {})
|
||||||
d.theIndex = findIndexNode(d.indexFile)
|
d.theIndex = findIndexNode(d.indexFile)
|
||||||
if (d.theIndex == nil) or (d.theIndex.kind != rnDefList):
|
if (d.theIndex == nil) or (d.theIndex.kind != rnDefList):
|
||||||
rawMessage(errXisNoValidIndexFile, gIndexFile)
|
rawMessage(errXisNoValidIndexFile, gIndexFile)
|
||||||
|
|
@ -265,9 +266,10 @@ proc renderIndexTerm(d: PDoc, n: PRstNode): PRope =
|
||||||
proc genComment(d: PDoc, n: PNode): PRope =
|
proc genComment(d: PDoc, n: PNode): PRope =
|
||||||
var dummyHasToc: bool
|
var dummyHasToc: bool
|
||||||
if n.comment != nil and startsWith(n.comment, "##"):
|
if n.comment != nil and startsWith(n.comment, "##"):
|
||||||
result = renderRstToOut(d, rstParse(n.comment, true, toFilename(n.info),
|
result = renderRstToOut(d, rstParse(n.comment, toFilename(n.info),
|
||||||
toLineNumber(n.info), toColumn(n.info),
|
toLineNumber(n.info), toColumn(n.info),
|
||||||
dummyHasToc))
|
dummyHasToc,
|
||||||
|
d.options + {roSkipPounds}))
|
||||||
|
|
||||||
proc genRecComment(d: PDoc, n: PNode): PRope =
|
proc genRecComment(d: PDoc, n: PNode): PRope =
|
||||||
if n == nil: return nil
|
if n == nil: return nil
|
||||||
|
|
@ -357,15 +359,15 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
|
||||||
of tkSymbol:
|
of tkSymbol:
|
||||||
dispA(result, "<span class=\"Identifier\">$1</span>",
|
dispA(result, "<span class=\"Identifier\">$1</span>",
|
||||||
"\\spanIdentifier{$1}", [toRope(esc(literal))])
|
"\\spanIdentifier{$1}", [toRope(esc(literal))])
|
||||||
of tkInd, tkSad, tkDed, tkSpaces:
|
of tkInd, tkSad, tkDed, tkSpaces, tkInvalid:
|
||||||
app(result, literal)
|
app(result, literal)
|
||||||
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
of tkParLe, tkParRi, tkBracketLe, tkBracketRi, tkCurlyLe, tkCurlyRi,
|
||||||
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
tkBracketDotLe, tkBracketDotRi, tkCurlyDotLe, tkCurlyDotRi, tkParDotLe,
|
||||||
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
tkParDotRi, tkComma, tkSemiColon, tkColon, tkEquals, tkDot, tkDotDot,
|
||||||
tkAccent:
|
tkAccent, tkColonColon,
|
||||||
|
tkGStrLit, tkGTripleStrLit, tkInfixOpr, tkPrefixOpr, tkPostfixOpr:
|
||||||
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
dispA(result, "<span class=\"Other\">$1</span>", "\\spanOther{$1}",
|
||||||
[toRope(esc(literal))])
|
[toRope(esc(literal))])
|
||||||
else: InternalError(n.info, "docgen.genThing(" & toktypeToStr[kind] & ')')
|
|
||||||
inc(d.id)
|
inc(d.id)
|
||||||
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
app(d.section[k], ropeFormatNamedVars(getConfigVar("doc.item"),
|
||||||
["name", "header", "desc", "itemID"],
|
["name", "header", "desc", "itemID"],
|
||||||
|
|
@ -498,6 +500,9 @@ proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
|
||||||
of rnStrongEmphasis:
|
of rnStrongEmphasis:
|
||||||
result = renderRstSons(d, n)
|
result = renderRstSons(d, n)
|
||||||
result = ropef("**$1**", [result])
|
result = ropef("**$1**", [result])
|
||||||
|
of rnTripleEmphasis:
|
||||||
|
result = renderRstSons(d, n)
|
||||||
|
result = ropef("***$1***", [result])
|
||||||
of rnInterpretedText:
|
of rnInterpretedText:
|
||||||
result = renderRstSons(d, n)
|
result = renderRstSons(d, n)
|
||||||
result = ropef("`$1`", [result])
|
result = ropef("`$1`", [result])
|
||||||
|
|
@ -506,6 +511,8 @@ proc renderRstToRst(d: PDoc, n: PRstNode): PRope =
|
||||||
result = renderRstSons(d, n)
|
result = renderRstSons(d, n)
|
||||||
result = ropef("``$1``", [result])
|
result = ropef("``$1``", [result])
|
||||||
dec(d.verbatim)
|
dec(d.verbatim)
|
||||||
|
of rnSmiley:
|
||||||
|
result = toRope(n.text)
|
||||||
of rnLeaf:
|
of rnLeaf:
|
||||||
if (d.verbatim == 0) and (n.text == "\\"):
|
if (d.verbatim == 0) and (n.text == "\\"):
|
||||||
result = toRope("\\\\") # XXX: escape more special characters!
|
result = toRope("\\\\") # XXX: escape more special characters!
|
||||||
|
|
@ -560,6 +567,12 @@ proc renderImage(d: PDoc, n: PRstNode): PRope =
|
||||||
[toRope(getArgument(n)), options])
|
[toRope(getArgument(n)), options])
|
||||||
if rsonsLen(n) >= 3: app(result, renderRstToOut(d, n.sons[2]))
|
if rsonsLen(n) >= 3: app(result, renderRstToOut(d, n.sons[2]))
|
||||||
|
|
||||||
|
proc renderSmiley(d: PDoc, n: PRstNode): PRope =
|
||||||
|
result = dispF(
|
||||||
|
"""<img src="images/smilies/$1.gif" width="15"
|
||||||
|
height="17" hspace="2" vspace="2" />""",
|
||||||
|
"\\includegraphics{$1}", [toRope(n.text)])
|
||||||
|
|
||||||
proc renderCodeBlock(d: PDoc, n: PRstNode): PRope =
|
proc renderCodeBlock(d: PDoc, n: PRstNode): PRope =
|
||||||
result = nil
|
result = nil
|
||||||
if n.sons[2] == nil: return
|
if n.sons[2] == nil: return
|
||||||
|
|
@ -741,6 +754,9 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
|
||||||
of rnEmphasis: result = renderAux(d, n, disp("<em>$1</em>", "\\emph{$1}"))
|
of rnEmphasis: result = renderAux(d, n, disp("<em>$1</em>", "\\emph{$1}"))
|
||||||
of rnStrongEmphasis:
|
of rnStrongEmphasis:
|
||||||
result = renderAux(d, n, disp("<strong>$1</strong>", "\\textbf{$1}"))
|
result = renderAux(d, n, disp("<strong>$1</strong>", "\\textbf{$1}"))
|
||||||
|
of rnTripleEmphasis:
|
||||||
|
result = renderAux(d, n, disp("<strong><em>$1</em></strong>",
|
||||||
|
"\\textbf{emph{$1}}"))
|
||||||
of rnInterpretedText:
|
of rnInterpretedText:
|
||||||
result = renderAux(d, n, disp("<cite>$1</cite>", "\\emph{$1}"))
|
result = renderAux(d, n, disp("<cite>$1</cite>", "\\emph{$1}"))
|
||||||
of rnIdx:
|
of rnIdx:
|
||||||
|
|
@ -752,10 +768,10 @@ proc renderRstToOut(d: PDoc, n: PRstNode): PRope =
|
||||||
result = renderAux(d, n, disp(
|
result = renderAux(d, n, disp(
|
||||||
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
||||||
"\\texttt{$1}"))
|
"\\texttt{$1}"))
|
||||||
|
of rnSmiley: result = renderSmiley(d, n)
|
||||||
of rnLeaf: result = toRope(esc(n.text))
|
of rnLeaf: result = toRope(esc(n.text))
|
||||||
of rnContents: d.hasToc = true
|
of rnContents: d.hasToc = true
|
||||||
of rnTitle: d.meta[metaTitle] = renderRstToOut(d, n.sons[0])
|
of rnTitle: d.meta[metaTitle] = renderRstToOut(d, n.sons[0])
|
||||||
else: InternalError("renderRstToOut")
|
|
||||||
|
|
||||||
proc checkForFalse(n: PNode): bool =
|
proc checkForFalse(n: PNode): bool =
|
||||||
result = n.kind == nkIdent and IdentEq(n.ident, "false")
|
result = n.kind == nkIdent and IdentEq(n.ident, "false")
|
||||||
|
|
@ -869,7 +885,7 @@ proc CommandRstAux(filename, outExt: string) =
|
||||||
var filen = addFileExt(filename, "txt")
|
var filen = addFileExt(filename, "txt")
|
||||||
var d = newDocumentor(filen)
|
var d = newDocumentor(filen)
|
||||||
initIndexFile(d)
|
initIndexFile(d)
|
||||||
var rst = rstParse(readFile(filen), false, filen, 0, 1, d.hasToc)
|
var rst = rstParse(readFile(filen), filen, 0, 1, d.hasToc, {})
|
||||||
d.modDesc = renderRstToOut(d, rst)
|
d.modDesc = renderRstToOut(d, rst)
|
||||||
writeOutput(d, filename, outExt)
|
writeOutput(d, filename, outExt)
|
||||||
generateIndex(d)
|
generateIndex(d)
|
||||||
|
|
@ -926,12 +942,13 @@ $content
|
||||||
setConfigVar("doc.body_no_toc", "$moduledesc $content")
|
setConfigVar("doc.body_no_toc", "$moduledesc $content")
|
||||||
setConfigVar("doc.file", "$content")
|
setConfigVar("doc.file", "$content")
|
||||||
|
|
||||||
proc rstToHtml*(s: string): string =
|
proc rstToHtml*(s: string, options: TRstParseOptions): string =
|
||||||
## exported for *nimforum*.
|
## exported for *nimforum*.
|
||||||
const filen = "input"
|
const filen = "input"
|
||||||
var d = newDocumentor(filen)
|
var d = newDocumentor(filen)
|
||||||
|
d.options = options
|
||||||
var dummyHasToc = false
|
var dummyHasToc = false
|
||||||
var rst = rstParse(s, false, filen, 0, 1, dummyHasToc)
|
var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
|
||||||
d.modDesc = renderRstToOut(d, rst)
|
d.modDesc = renderRstToOut(d, rst)
|
||||||
let res = genOutFile(d)
|
let res = genOutFile(d)
|
||||||
result = res.ropeToStr
|
result = res.ropeToStr
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,10 @@ type
|
||||||
gtReference, gtOther
|
gtReference, gtOther
|
||||||
TGeneralTokenizer* = object of TObject
|
TGeneralTokenizer* = object of TObject
|
||||||
kind*: TTokenClass
|
kind*: TTokenClass
|
||||||
start*, length*: int # private:
|
start*, length*: int
|
||||||
buf*: cstring
|
buf: cstring
|
||||||
pos*: int
|
pos: int
|
||||||
state*: TTokenClass
|
state: TTokenClass
|
||||||
|
|
||||||
TSourceLanguage* = enum
|
TSourceLanguage* = enum
|
||||||
langNone, langNimrod, langCpp, langCsharp, langC, langJava
|
langNone, langNimrod, langCpp, langCsharp, langC, langJava
|
||||||
|
|
|
||||||
218
compiler/rst.nim
218
compiler/rst.nim
|
|
@ -11,7 +11,7 @@
|
||||||
# subset is provided.
|
# subset is provided.
|
||||||
|
|
||||||
import
|
import
|
||||||
os, msgs, strutils, platform, hashes, ropes, options
|
os, msgs, strutils, hashes, options
|
||||||
|
|
||||||
type
|
type
|
||||||
TRstNodeKind* = enum
|
TRstNodeKind* = enum
|
||||||
|
|
@ -52,15 +52,25 @@ type
|
||||||
# * `file#id <file#id>'_
|
# * `file#id <file#id>'_
|
||||||
rnSubstitutionDef, # a definition of a substitution
|
rnSubstitutionDef, # a definition of a substitution
|
||||||
rnGeneralRole, # Inline markup:
|
rnGeneralRole, # Inline markup:
|
||||||
rnSub, rnSup, rnIdx, rnEmphasis, # "*"
|
rnSub, rnSup, rnIdx,
|
||||||
|
rnEmphasis, # "*"
|
||||||
rnStrongEmphasis, # "**"
|
rnStrongEmphasis, # "**"
|
||||||
|
rnTripleEmphasis, # "***"
|
||||||
rnInterpretedText, # "`"
|
rnInterpretedText, # "`"
|
||||||
rnInlineLiteral, # "``"
|
rnInlineLiteral, # "``"
|
||||||
rnSubstitutionReferences, # "|"
|
rnSubstitutionReferences, # "|"
|
||||||
|
rnSmiley, # some smiley
|
||||||
rnLeaf # a leaf; the node's text field contains the
|
rnLeaf # a leaf; the node's text field contains the
|
||||||
# leaf val
|
# leaf val
|
||||||
|
|
||||||
type # the syntax tree of RST:
|
type
|
||||||
|
TRstParseOption* = enum ## options for the RST parser
|
||||||
|
roSkipPounds, ## skip ``#`` at line beginning (documentation
|
||||||
|
## embedded in Nimrod comments)
|
||||||
|
roSupportSmilies, ## make the RST parser support smilies like ``:)``
|
||||||
|
|
||||||
|
TRstParseOptions* = set[TRstParseOption]
|
||||||
|
|
||||||
PRSTNode* = ref TRstNode
|
PRSTNode* = ref TRstNode
|
||||||
TRstNodeSeq* = seq[PRstNode]
|
TRstNodeSeq* = seq[PRstNode]
|
||||||
TRSTNode*{.acyclic, final.} = object
|
TRSTNode*{.acyclic, final.} = object
|
||||||
|
|
@ -71,9 +81,9 @@ type # the syntax tree of RST:
|
||||||
sons*: TRstNodeSeq # the node's sons
|
sons*: TRstNodeSeq # the node's sons
|
||||||
|
|
||||||
|
|
||||||
proc rstParse*(text: string, # the text to be parsed
|
proc rstParse*(text, filename: string,
|
||||||
skipPounds: bool, filename: string, # for error messages
|
line, column: int, hasToc: var bool,
|
||||||
line, column: int, hasToc: var bool): PRstNode
|
options: TRstParseOptions): PRstNode
|
||||||
proc rsonsLen*(n: PRstNode): int
|
proc rsonsLen*(n: PRstNode): int
|
||||||
proc newRstNode*(kind: TRstNodeKind): PRstNode
|
proc newRstNode*(kind: TRstNodeKind): PRstNode
|
||||||
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode
|
proc newRstNode*(kind: TRstNodeKind, s: string): PRstNode
|
||||||
|
|
@ -91,6 +101,44 @@ proc clearIndex*(index: PRstNode, filename: string)
|
||||||
|
|
||||||
const
|
const
|
||||||
SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
SymChars: TCharSet = {'a'..'z', 'A'..'Z', '0'..'9', '\x80'..'\xFF'}
|
||||||
|
SmileyStartChars: TCharSet = {':', ';', '8'}
|
||||||
|
Smilies = {
|
||||||
|
":D": "icon_e_biggrin",
|
||||||
|
":-D": "icon_e_biggrin",
|
||||||
|
":)": "icon_e_smile",
|
||||||
|
":-)": "icon_e_smile",
|
||||||
|
";)": "icon_e_wink",
|
||||||
|
";-)": "icon_e_wink",
|
||||||
|
":(": "icon_e_sad",
|
||||||
|
":-(": "icon_e_sad",
|
||||||
|
":o": "icon_e_surprised",
|
||||||
|
":-o": "icon_e_surprised",
|
||||||
|
":shock:": "icon_eek",
|
||||||
|
":?": "icon_e_confused",
|
||||||
|
":-?": "icon_e_confused",
|
||||||
|
"8-)": "icon_cool",
|
||||||
|
|
||||||
|
":lol:": "icon_lol",
|
||||||
|
":x": "icon_mad",
|
||||||
|
":-x": "icon_mad",
|
||||||
|
":P": "icon_razz",
|
||||||
|
":-P": "icon_razz",
|
||||||
|
":oops:": "icon_redface",
|
||||||
|
":cry:": "icon_cry",
|
||||||
|
":evil:": "icon_evil",
|
||||||
|
":twisted:": "icon_twisted",
|
||||||
|
":roll:": "icon_rolleyes",
|
||||||
|
":!:": "icon_exclaim",
|
||||||
|
|
||||||
|
":?:": "icon_question",
|
||||||
|
":idea:": "icon_idea",
|
||||||
|
":arrow:": "icon_arrow",
|
||||||
|
":|": "icon_neutral",
|
||||||
|
":-|": "icon_neutral",
|
||||||
|
":mrgreen:": "icon_mrgreen",
|
||||||
|
":geek:": "icon_e_geek",
|
||||||
|
":ugeek:": "icon_e_ugeek"
|
||||||
|
}
|
||||||
|
|
||||||
type
|
type
|
||||||
TTokType = enum
|
TTokType = enum
|
||||||
|
|
@ -117,7 +165,7 @@ proc getThing(L: var TLexer, tok: var TToken, s: TCharSet) =
|
||||||
while True:
|
while True:
|
||||||
add(tok.symbol, L.buf[pos])
|
add(tok.symbol, L.buf[pos])
|
||||||
inc(pos)
|
inc(pos)
|
||||||
if not (L.buf[pos] in s): break
|
if L.buf[pos] notin s: break
|
||||||
inc(L.col, pos - L.bufpos)
|
inc(L.col, pos - L.bufpos)
|
||||||
L.bufpos = pos
|
L.bufpos = pos
|
||||||
|
|
||||||
|
|
@ -256,7 +304,8 @@ type
|
||||||
key*: string
|
key*: string
|
||||||
value*: PRstNode
|
value*: PRstNode
|
||||||
|
|
||||||
TSharedState{.final.} = object
|
TSharedState {.final.} = object
|
||||||
|
options: TRstParseOptions # parsing options
|
||||||
uLevel*, oLevel*: int # counters for the section levels
|
uLevel*, oLevel*: int # counters for the section levels
|
||||||
subs*: seq[TSubstitution] # substitutions
|
subs*: seq[TSubstitution] # substitutions
|
||||||
refs*: seq[TSubstitution] # references
|
refs*: seq[TSubstitution] # references
|
||||||
|
|
@ -280,10 +329,11 @@ type
|
||||||
hasToc*: bool
|
hasToc*: bool
|
||||||
|
|
||||||
|
|
||||||
proc newSharedState(): PSharedState =
|
proc newSharedState(options: TRstParseOptions): PSharedState =
|
||||||
new(result)
|
new(result)
|
||||||
result.subs = @[]
|
result.subs = @[]
|
||||||
result.refs = @[]
|
result.refs = @[]
|
||||||
|
result.options = options
|
||||||
|
|
||||||
proc tokInfo(p: TRstParser, tok: TToken): TLineInfo =
|
proc tokInfo(p: TRstParser, tok: TToken): TLineInfo =
|
||||||
result = newLineInfo(p.filename, p.line + tok.line, p.col + tok.col)
|
result = newLineInfo(p.filename, p.line + tok.line, p.col + tok.col)
|
||||||
|
|
@ -325,7 +375,7 @@ proc addNodes(n: PRstNode): string =
|
||||||
|
|
||||||
proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
|
proc rstnodeToRefnameAux(n: PRstNode, r: var string, b: var bool) =
|
||||||
if n.kind == rnLeaf:
|
if n.kind == rnLeaf:
|
||||||
for i in countup(0, len(n.text) + 0 - 1):
|
for i in countup(0, len(n.text) - 1):
|
||||||
case n.text[i]
|
case n.text[i]
|
||||||
of '0'..'9':
|
of '0'..'9':
|
||||||
if b:
|
if b:
|
||||||
|
|
@ -440,15 +490,14 @@ proc matchesHyperlink(h: PRstNode, filename: string): bool =
|
||||||
|
|
||||||
proc clearIndex(index: PRstNode, filename: string) =
|
proc clearIndex(index: PRstNode, filename: string) =
|
||||||
var
|
var
|
||||||
k, items, lastItem: int
|
lastItem: int
|
||||||
val: PRstNode
|
|
||||||
assert(index.kind == rnDefList)
|
assert(index.kind == rnDefList)
|
||||||
for i in countup(0, rsonsLen(index) - 1):
|
for i in countup(0, rsonsLen(index) - 1):
|
||||||
assert(index.sons[i].sons[1].kind == rnDefBody)
|
assert(index.sons[i].sons[1].kind == rnDefBody)
|
||||||
val = index.sons[i].sons[1].sons[0]
|
var val = index.sons[i].sons[1].sons[0]
|
||||||
if val.kind == rnInner: val = val.sons[0]
|
if val.kind == rnInner: val = val.sons[0]
|
||||||
if val.kind == rnBulletList:
|
if val.kind == rnBulletList:
|
||||||
items = rsonsLen(val)
|
var items = rsonsLen(val)
|
||||||
lastItem = - 1 # save the last valid item index
|
lastItem = - 1 # save the last valid item index
|
||||||
for j in countup(0, rsonsLen(val) - 1):
|
for j in countup(0, rsonsLen(val) - 1):
|
||||||
if val.sons[j] == nil:
|
if val.sons[j] == nil:
|
||||||
|
|
@ -464,7 +513,7 @@ proc clearIndex(index: PRstNode, filename: string) =
|
||||||
index.sons[i] = nil
|
index.sons[i] = nil
|
||||||
elif matchesHyperlink(val, filename):
|
elif matchesHyperlink(val, filename):
|
||||||
index.sons[i] = nil
|
index.sons[i] = nil
|
||||||
k = 0
|
var k = 0
|
||||||
for i in countup(0, rsonsLen(index) - 1):
|
for i in countup(0, rsonsLen(index) - 1):
|
||||||
if index.sons[i] != nil:
|
if index.sons[i] != nil:
|
||||||
if k != i: index.sons[k] = index.sons[i]
|
if k != i: index.sons[k] = index.sons[i]
|
||||||
|
|
@ -574,20 +623,6 @@ proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
|
||||||
else: d = '\0'
|
else: d = '\0'
|
||||||
if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
|
if d != '\0': result = p.tok[p.idx + 1].symbol[0] != d
|
||||||
|
|
||||||
proc parseBackslash(p: var TRstParser, father: PRstNode) =
|
|
||||||
assert(p.tok[p.idx].kind == tkPunct)
|
|
||||||
if p.tok[p.idx].symbol == "\\\\":
|
|
||||||
addSon(father, newRstNode(rnLeaf, "\\"))
|
|
||||||
inc(p.idx)
|
|
||||||
elif p.tok[p.idx].symbol == "\\":
|
|
||||||
# XXX: Unicode?
|
|
||||||
inc(p.idx)
|
|
||||||
if p.tok[p.idx].kind != tkWhite: addSon(father, newLeaf(p))
|
|
||||||
inc(p.idx)
|
|
||||||
else:
|
|
||||||
addSon(father, newLeaf(p))
|
|
||||||
inc(p.idx)
|
|
||||||
|
|
||||||
proc match(p: TRstParser, start: int, expr: string): bool =
|
proc match(p: TRstParser, start: int, expr: string): bool =
|
||||||
# regular expressions are:
|
# regular expressions are:
|
||||||
# special char exact match
|
# special char exact match
|
||||||
|
|
@ -601,7 +636,7 @@ proc match(p: TRstParser, start: int, expr: string): bool =
|
||||||
# 'e' tkWord or '#' (for enumeration lists)
|
# 'e' tkWord or '#' (for enumeration lists)
|
||||||
var i = 0
|
var i = 0
|
||||||
var j = start
|
var j = start
|
||||||
var last = len(expr) + 0 - 1
|
var last = len(expr) - 1
|
||||||
while i <= last:
|
while i <= last:
|
||||||
case expr[i]
|
case expr[i]
|
||||||
of 'w': result = p.tok[j].kind == tkWord
|
of 'w': result = p.tok[j].kind == tkWord
|
||||||
|
|
@ -687,21 +722,37 @@ proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
|
||||||
addSon(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
|
addSon(result, newRstNode(rnLeaf, p.tok[p.idx + 1].symbol))
|
||||||
inc(p.idx, 3)
|
inc(p.idx, 3)
|
||||||
|
|
||||||
|
proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
|
||||||
|
result = start
|
||||||
|
var j = 0
|
||||||
|
while j < expr.len and continuesWith(expr, p.tok[result].symbol, j):
|
||||||
|
inc j, p.tok[result].symbol.len
|
||||||
|
inc result
|
||||||
|
if j < expr.len: result = 0
|
||||||
|
|
||||||
|
proc parseSmiley(p: var TRstParser): PRstNode =
|
||||||
|
if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
|
||||||
|
for key, val in items(smilies):
|
||||||
|
let m = matchVerbatim(p, p.idx, key)
|
||||||
|
if m > 0:
|
||||||
|
p.idx = m
|
||||||
|
result = newRstNode(rnSmiley)
|
||||||
|
result.text = val
|
||||||
|
return
|
||||||
|
|
||||||
proc isURL(p: TRstParser, i: int): bool =
|
proc isURL(p: TRstParser, i: int): bool =
|
||||||
result = (p.tok[i + 1].symbol == ":") and (p.tok[i + 2].symbol == "//") and
|
result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
|
||||||
(p.tok[i + 3].kind == tkWord) and (p.tok[i + 4].symbol == ".")
|
(p.tok[i+3].kind == tkWord) and (p.tok[i+4].symbol == ".")
|
||||||
|
|
||||||
proc parseURL(p: var TRstParser, father: PRstNode) =
|
proc parseURL(p: var TRstParser, father: PRstNode) =
|
||||||
#if p.tok[p.idx].symbol[strStart] = '<' then begin
|
#if p.tok[p.idx].symbol[strStart] == '<':
|
||||||
if isURL(p, p.idx):
|
if isURL(p, p.idx):
|
||||||
var n = newRstNode(rnStandaloneHyperlink)
|
var n = newRstNode(rnStandaloneHyperlink)
|
||||||
while true:
|
while true:
|
||||||
case p.tok[p.idx].kind
|
case p.tok[p.idx].kind
|
||||||
of tkWord, tkAdornment, tkOther:
|
of tkWord, tkAdornment, tkOther: nil
|
||||||
nil
|
|
||||||
of tkPunct:
|
of tkPunct:
|
||||||
if not (p.tok[p.idx + 1].kind in
|
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
|
||||||
{tkWord, tkAdornment, tkOther, tkPunct}):
|
|
||||||
break
|
break
|
||||||
else: break
|
else: break
|
||||||
addSon(n, newLeaf(p))
|
addSon(n, newLeaf(p))
|
||||||
|
|
@ -713,6 +764,44 @@ proc parseURL(p: var TRstParser, father: PRstNode) =
|
||||||
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
|
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
|
||||||
addSon(father, n)
|
addSon(father, n)
|
||||||
|
|
||||||
|
proc parseBackslash(p: var TRstParser, father: PRstNode) =
|
||||||
|
assert(p.tok[p.idx].kind == tkPunct)
|
||||||
|
if p.tok[p.idx].symbol == "\\\\":
|
||||||
|
addSon(father, newRstNode(rnLeaf, "\\"))
|
||||||
|
inc(p.idx)
|
||||||
|
elif p.tok[p.idx].symbol == "\\":
|
||||||
|
# XXX: Unicode?
|
||||||
|
inc(p.idx)
|
||||||
|
if p.tok[p.idx].kind != tkWhite: addSon(father, newLeaf(p))
|
||||||
|
inc(p.idx)
|
||||||
|
else:
|
||||||
|
addSon(father, newLeaf(p))
|
||||||
|
inc(p.idx)
|
||||||
|
|
||||||
|
when false:
|
||||||
|
proc parseAdhoc(p: var TRstParser, father: PRstNode, verbatim: bool) =
|
||||||
|
if not verbatim and isURL(p, p.idx):
|
||||||
|
var n = newRstNode(rnStandaloneHyperlink)
|
||||||
|
while true:
|
||||||
|
case p.tok[p.idx].kind
|
||||||
|
of tkWord, tkAdornment, tkOther: nil
|
||||||
|
of tkPunct:
|
||||||
|
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
|
||||||
|
break
|
||||||
|
else: break
|
||||||
|
addSon(n, newLeaf(p))
|
||||||
|
inc(p.idx)
|
||||||
|
addSon(father, n)
|
||||||
|
elif not verbatim and roSupportSmilies in p.shared.options:
|
||||||
|
let n = parseSmiley(p)
|
||||||
|
if s != nil:
|
||||||
|
addSon(father, n)
|
||||||
|
else:
|
||||||
|
var n = newLeaf(p)
|
||||||
|
inc(p.idx)
|
||||||
|
if p.tok[p.idx].symbol == "_": n = parsePostfix(p, n)
|
||||||
|
addSon(father, n)
|
||||||
|
|
||||||
proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
|
proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
|
||||||
interpretBackslash: bool) =
|
interpretBackslash: bool) =
|
||||||
while true:
|
while true:
|
||||||
|
|
@ -743,7 +832,12 @@ proc parseUntil(p: var TRstParser, father: PRstNode, postfix: string,
|
||||||
proc parseInline(p: var TRstParser, father: PRstNode) =
|
proc parseInline(p: var TRstParser, father: PRstNode) =
|
||||||
case p.tok[p.idx].kind
|
case p.tok[p.idx].kind
|
||||||
of tkPunct:
|
of tkPunct:
|
||||||
if isInlineMarkupStart(p, "**"):
|
if isInlineMarkupStart(p, "***"):
|
||||||
|
inc(p.idx)
|
||||||
|
var n = newRstNode(rnTripleEmphasis)
|
||||||
|
parseUntil(p, n, "***", true)
|
||||||
|
addSon(father, n)
|
||||||
|
elif isInlineMarkupStart(p, "**"):
|
||||||
inc(p.idx)
|
inc(p.idx)
|
||||||
var n = newRstNode(rnStrongEmphasis)
|
var n = newRstNode(rnStrongEmphasis)
|
||||||
parseUntil(p, n, "**", true)
|
parseUntil(p, n, "**", true)
|
||||||
|
|
@ -770,10 +864,25 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
|
||||||
parseUntil(p, n, "|", false)
|
parseUntil(p, n, "|", false)
|
||||||
addSon(father, n)
|
addSon(father, n)
|
||||||
else:
|
else:
|
||||||
|
if roSupportSmilies in p.s.options:
|
||||||
|
let n = parseSmiley(p)
|
||||||
|
if n != nil:
|
||||||
|
addSon(father, n)
|
||||||
|
return
|
||||||
parseBackslash(p, father)
|
parseBackslash(p, father)
|
||||||
of tkWord:
|
of tkWord:
|
||||||
|
if roSupportSmilies in p.s.options:
|
||||||
|
let n = parseSmiley(p)
|
||||||
|
if n != nil:
|
||||||
|
addSon(father, n)
|
||||||
|
return
|
||||||
parseURL(p, father)
|
parseURL(p, father)
|
||||||
of tkAdornment, tkOther, tkWhite:
|
of tkAdornment, tkOther, tkWhite:
|
||||||
|
if roSupportSmilies in p.s.options:
|
||||||
|
let n = parseSmiley(p)
|
||||||
|
if n != nil:
|
||||||
|
addSon(father, n)
|
||||||
|
return
|
||||||
addSon(father, newLeaf(p))
|
addSon(father, newLeaf(p))
|
||||||
inc(p.idx)
|
inc(p.idx)
|
||||||
else: nil
|
else: nil
|
||||||
|
|
@ -878,7 +987,9 @@ proc getFieldValue(n: PRstNode, fieldname: string): string =
|
||||||
result = ""
|
result = ""
|
||||||
if n.sons[1] == nil: return
|
if n.sons[1] == nil: return
|
||||||
if (n.sons[1].kind != rnFieldList):
|
if (n.sons[1].kind != rnFieldList):
|
||||||
InternalError("getFieldValue (2): " & $n.sons[1].kind)
|
#InternalError("getFieldValue (2): " & $n.sons[1].kind)
|
||||||
|
# We don't like internal errors here anymore as that would break the forum!
|
||||||
|
return
|
||||||
for i in countup(0, rsonsLen(n.sons[1]) - 1):
|
for i in countup(0, rsonsLen(n.sons[1]) - 1):
|
||||||
var f = n.sons[1].sons[i]
|
var f = n.sons[1].sons[i]
|
||||||
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
|
if cmpIgnoreStyle(addNodes(f.sons[0]), fieldname) == 0:
|
||||||
|
|
@ -975,7 +1086,8 @@ proc whichSection(p: TRstParser): TRstNodeKind =
|
||||||
result = rnLineBlock
|
result = rnLineBlock
|
||||||
elif (p.tok[p.idx].symbol == "..") and predNL(p):
|
elif (p.tok[p.idx].symbol == "..") and predNL(p):
|
||||||
result = rnDirective
|
result = rnDirective
|
||||||
elif (p.tok[p.idx].symbol == ":") and predNL(p):
|
elif match(p, p.idx, ":w:") and predNL(p):
|
||||||
|
# (p.tok[p.idx].symbol == ":")
|
||||||
result = rnFieldList
|
result = rnFieldList
|
||||||
elif match(p, p.idx, "(e) "):
|
elif match(p, p.idx, "(e) "):
|
||||||
result = rnEnumList
|
result = rnEnumList
|
||||||
|
|
@ -1317,13 +1429,14 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
|
||||||
of rnOverline: a = parseOverline(p)
|
of rnOverline: a = parseOverline(p)
|
||||||
of rnTable: a = parseSimpleTable(p)
|
of rnTable: a = parseSimpleTable(p)
|
||||||
of rnOptionList: a = parseOptionList(p)
|
of rnOptionList: a = parseOptionList(p)
|
||||||
else: InternalError("rst.parseSection()")
|
else:
|
||||||
if (a == nil) and (k != rnDirective):
|
#InternalError("rst.parseSection()")
|
||||||
|
nil
|
||||||
|
if a == nil and k != rnDirective:
|
||||||
a = newRstNode(rnParagraph)
|
a = newRstNode(rnParagraph)
|
||||||
parseParagraph(p, a)
|
parseParagraph(p, a)
|
||||||
addSonIfNotNil(result, a)
|
addSonIfNotNil(result, a)
|
||||||
if (sonKind(result, 0) == rnParagraph) and
|
if sonKind(result, 0) == rnParagraph and sonKind(result, 1) != rnParagraph:
|
||||||
(sonKind(result, 1) != rnParagraph):
|
|
||||||
result.sons[0].kind = rnInner
|
result.sons[0].kind = rnInner
|
||||||
|
|
||||||
proc parseSectionWrapper(p: var TRstParser): PRstNode =
|
proc parseSectionWrapper(p: var TRstParser): PRstNode =
|
||||||
|
|
@ -1423,9 +1536,10 @@ proc dirInclude(p: var TRstParser): PRstNode =
|
||||||
var q: TRstParser
|
var q: TRstParser
|
||||||
initParser(q, p.s)
|
initParser(q, p.s)
|
||||||
q.filename = filename
|
q.filename = filename
|
||||||
getTokens(readFile(path), false, q.tok) # workaround a GCC bug:
|
getTokens(readFile(path), false, q.tok)
|
||||||
if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0:
|
# workaround a GCC bug; more like the interior pointer bug?
|
||||||
InternalError("Too many binary zeros in include file")
|
#if find(q.tok[high(q.tok)].symbol, "\0\x01\x02") > 0:
|
||||||
|
# InternalError("Too many binary zeros in include file")
|
||||||
result = parseDoc(q)
|
result = parseDoc(q)
|
||||||
|
|
||||||
proc dirCodeBlock(p: var TRstParser): PRstNode =
|
proc dirCodeBlock(p: var TRstParser): PRstNode =
|
||||||
|
|
@ -1580,15 +1694,15 @@ proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
|
||||||
else:
|
else:
|
||||||
for i in countup(0, rsonsLen(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
|
for i in countup(0, rsonsLen(n) - 1): n.sons[i] = resolveSubs(p, n.sons[i])
|
||||||
|
|
||||||
proc rstParse(text: string, # the text to be parsed
|
proc rstParse(text, filename: string,
|
||||||
skipPounds: bool, filename: string, # for error messages
|
line, column: int, hasToc: var bool,
|
||||||
line, column: int, hasToc: var bool): PRstNode =
|
options: TRstParseOptions): PRstNode =
|
||||||
var p: TRstParser
|
var p: TRstParser
|
||||||
if isNil(text): rawMessage(errCannotOpenFile, filename)
|
if isNil(text): rawMessage(errCannotOpenFile, filename)
|
||||||
initParser(p, newSharedState())
|
initParser(p, newSharedState(options))
|
||||||
p.filename = filename
|
p.filename = filename
|
||||||
p.line = line
|
p.line = line
|
||||||
p.col = column
|
p.col = column
|
||||||
getTokens(text, skipPounds, p.tok)
|
getTokens(text, roSkipPounds in options, p.tok)
|
||||||
result = resolveSubs(p, parseDoc(p))
|
result = resolveSubs(p, parseDoc(p))
|
||||||
hasToc = p.hasToc
|
hasToc = p.hasToc
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
var sqlres = mysql.UseResult(db)
|
var sqlres = mysql.UseResult(db)
|
||||||
if sqlres != nil:
|
if sqlres != nil:
|
||||||
var L = int(mysql.NumFields(sqlres))
|
var L = int(mysql.NumFields(sqlres))
|
||||||
var result = newRow(L)
|
result = newRow(L)
|
||||||
var row = mysql.FetchRow(sqlres)
|
var row = mysql.FetchRow(sqlres)
|
||||||
if row != nil:
|
if row != nil:
|
||||||
for i in 0..L-1:
|
for i in 0..L-1:
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
## retrieves a single row.
|
## retrieves a single row.
|
||||||
var res = setupQuery(db, query, args)
|
var res = setupQuery(db, query, args)
|
||||||
var L = int(PQnfields(res))
|
var L = int(PQnfields(res))
|
||||||
var result = newRow(L)
|
result = newRow(L)
|
||||||
setRow(res, result, 0, L)
|
setRow(res, result, 0, L)
|
||||||
PQclear(res)
|
PQclear(res)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
|
||||||
## retrieves a single row.
|
## retrieves a single row.
|
||||||
var stmt = setupQuery(db, query, args)
|
var stmt = setupQuery(db, query, args)
|
||||||
var L = int(columnCount(stmt))
|
var L = int(columnCount(stmt))
|
||||||
var result = newRow(L)
|
result = newRow(L)
|
||||||
if step(stmt) == SQLITE_ROW:
|
if step(stmt) == SQLITE_ROW:
|
||||||
setRow(stmt, result, L)
|
setRow(stmt, result, L)
|
||||||
if finalize(stmt) != SQLITE_OK: dbError(db)
|
if finalize(stmt) != SQLITE_OK: dbError(db)
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ macro head*(e: expr): expr =
|
||||||
|
|
||||||
macro html*(e: expr): expr =
|
macro html*(e: expr): expr =
|
||||||
## generates the HTML ``html`` element.
|
## generates the HTML ``html`` element.
|
||||||
result = xmlCheckedTag(e, "html", "", "xmlns")
|
result = xmlCheckedTag(e, "html", "xmlns", "")
|
||||||
|
|
||||||
macro hr*(e: expr): expr =
|
macro hr*(e: expr): expr =
|
||||||
## generates the HTML ``hr`` element.
|
## generates the HTML ``hr`` element.
|
||||||
|
|
|
||||||
|
|
@ -532,6 +532,16 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
|
||||||
inc(i)
|
inc(i)
|
||||||
if suffix[i] == '\0': return true
|
if suffix[i] == '\0': return true
|
||||||
|
|
||||||
|
proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
|
||||||
|
rtl, extern: "nsuContinuesWith".} =
|
||||||
|
## Returns true iff ``s`` continues with ``substr`` at position ``start``.
|
||||||
|
## If ``substr == ""`` true is returned.
|
||||||
|
var i = 0
|
||||||
|
while true:
|
||||||
|
if substr[i] == '\0': return true
|
||||||
|
if s[i+start] != substr[i]: return false
|
||||||
|
inc(i)
|
||||||
|
|
||||||
proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
|
proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
|
||||||
inline.} =
|
inline.} =
|
||||||
## A shorthand for:
|
## A shorthand for:
|
||||||
|
|
|
||||||
1
todo.txt
1
todo.txt
|
|
@ -2,6 +2,7 @@ version 0.9.0
|
||||||
=============
|
=============
|
||||||
|
|
||||||
- make templates hygienic by default
|
- make templates hygienic by default
|
||||||
|
- ``bind`` for overloaded symbols does not work apparently
|
||||||
- ``=`` should be overloadable; requires specialization for ``=``
|
- ``=`` should be overloadable; requires specialization for ``=``
|
||||||
- fix remaining generics bugs
|
- fix remaining generics bugs
|
||||||
- fix remaining closure bugs:
|
- fix remaining closure bugs:
|
||||||
|
|
|
||||||
|
|
@ -203,8 +203,10 @@ proc main(c: var TConfigData) =
|
||||||
if c.ticker.len > 0:
|
if c.ticker.len > 0:
|
||||||
Exec(cmd % [c.nimrodArgs, c.ticker])
|
Exec(cmd % [c.nimrodArgs, c.ticker])
|
||||||
var temp = "web" / changeFileExt(c.ticker, "temp")
|
var temp = "web" / changeFileExt(c.ticker, "temp")
|
||||||
|
try:
|
||||||
c.ticker = readFile(temp)
|
c.ticker = readFile(temp)
|
||||||
if isNil(c.ticker): quit("[Error] cannot open:" & temp)
|
except EIO:
|
||||||
|
quit("[Error] cannot open: " & temp)
|
||||||
RemoveFile(temp)
|
RemoveFile(temp)
|
||||||
for i in 0..c.tabs.len-1:
|
for i in 0..c.tabs.len-1:
|
||||||
var file = c.tabs[i].val
|
var file = c.tabs[i].val
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ Library Additions
|
||||||
- Added ``system.TInteger`` and ``system.TNumber`` type classes matching
|
- Added ``system.TInteger`` and ``system.TNumber`` type classes matching
|
||||||
any of the corresponding type available in nimrod.
|
any of the corresponding type available in nimrod.
|
||||||
- Added ``system.clamp`` to limit a value within an interval ``[a, b]``.
|
- Added ``system.clamp`` to limit a value within an interval ``[a, b]``.
|
||||||
|
- Added ``strutils.continuesWith``.
|
||||||
- The GC supports (soft) realtime systems via ``GC_setMaxPause``
|
- The GC supports (soft) realtime systems via ``GC_setMaxPause``
|
||||||
and ``GC_step`` procs.
|
and ``GC_step`` procs.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue