small bugfixes; documentation generator supports smilies for the forum

This commit is contained in:
Araq 2012-05-01 11:14:29 +02:00
commit e95f155af3
11 changed files with 229 additions and 84 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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)

View file

@ -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)

View file

@ -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.

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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.