diff options
-rw-r--r-- | doc/docgen.md | 6 | ||||
-rw-r--r-- | koch.nim | 14 | ||||
-rw-r--r-- | readme.md | 2 | ||||
-rw-r--r-- | tools/nimweb.nim | 556 | ||||
-rw-r--r-- | tools/website.nimf | 266 |
5 files changed, 2 insertions, 842 deletions
diff --git a/doc/docgen.md b/doc/docgen.md index 268087cfc..27530737a 100644 --- a/doc/docgen.md +++ b/doc/docgen.md @@ -463,11 +463,7 @@ You can edit ``config/nimdoc.cfg`` and modify the ``doc.item.seesrc`` value with a hyperlink to your own code repository. In the case of Nim's own documentation, the `commit` value is just a commit -hash to append to a formatted URL to https://github.com/nim-lang/Nim. The -``tools/nimweb.nim`` helper queries the current git commit hash during the doc -generation, but since you might be working on an unpublished repository, it -also allows specifying a `githash` value in ``web/website.ini`` to force a -specific commit in the output. +hash to append to a formatted URL to https://github.com/nim-lang/Nim. Other Input Formats diff --git a/koch.nim b/koch.nim index 2564456c9..e3e2cb098 100644 --- a/koch.nim +++ b/koch.nim @@ -251,20 +251,6 @@ proc install(args: string) = geninstall() exec("sh ./install.sh $#" % args) -when false: - proc web(args: string) = - nimexec("js tools/dochack/dochack.nim") - nimexec("cc -r tools/nimweb.nim $# web/website.ini --putenv:nimversion=$#" % - [args, VersionAsString]) - - proc website(args: string) = - nimexec("cc -r tools/nimweb.nim $# --website web/website.ini --putenv:nimversion=$#" % - [args, VersionAsString]) - - proc pdf(args="") = - exec("$# cc -r tools/nimweb.nim $# --pdf web/website.ini --putenv:nimversion=$#" % - [findNim().quoteShell(), args, VersionAsString], additionalPATH=findNim().splitFile.dir) - # -------------- boot --------------------------------------------------------- proc findStartNim: string = diff --git a/readme.md b/readme.md index 6c14b738f..3d32bcf87 100644 --- a/readme.md +++ b/readme.md @@ -141,7 +141,7 @@ you should familiarize yourself with the following repository structure: dependencies written in other languages. * ``wrappers/`` - modules that wrap dependencies written in other languages. * ``tests/`` - contains categorized tests for the compiler and standard library. -* ``tools/`` - the tools including ``niminst`` and ``nimweb`` (mostly invoked via +* ``tools/`` - the tools including ``niminst`` (mostly invoked via ``koch``). * ``koch.nim`` - the tool used to bootstrap Nim, generate C sources, build the website, and generate the documentation. diff --git a/tools/nimweb.nim b/tools/nimweb.nim deleted file mode 100644 index ccc80dfcf..000000000 --- a/tools/nimweb.nim +++ /dev/null @@ -1,556 +0,0 @@ -# -# -# Nim Website Generator -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -import - os, strutils, times, parseopt, parsecfg, streams, strtabs, tables, - re, htmlgen, macros, md5, osproc, parsecsv, algorithm - -from xmltree import escape - -type - TKeyValPair = tuple[key, id, val: string] - TConfigData = object of RootObj - tabs, links: seq[TKeyValPair] - doc, srcdoc, srcdoc2, webdoc, pdf: seq[string] - authors, projectName, projectTitle, logo, infile, ticker: string - vars: StringTableRef - nimCompiler: string - nimArgs: string - gitURL: string - docHTMLOutput: string - webUploadOutput: string - quotations: Table[string, tuple[quote, author: string]] - numProcessors: int # Set by parallelBuild:n, only works for values > 0. - gaId: string # google analytics ID, nil means analytics are disabled - TRssItem = object - year, month, day, title, url, content: string - TAction = enum - actAll, actOnlyWebsite, actPdf, actJson2, actOnlyDocs - - Sponsor = object - logo: string - name: string - url: string - thisMonth: int - allTime: int - since: string - level: int - -var action: TAction - -proc initConfigData(c: var TConfigData) = - c.tabs = @[] - c.links = @[] - c.doc = @[] - c.srcdoc = @[] - c.srcdoc2 = @[] - c.webdoc = @[] - c.pdf = @[] - c.infile = "" - c.nimArgs = "--hint:Conf:off --hint:Path:off --hint:Processing:off -d:boot " - c.gitURL = "https://github.com/nim-lang/Nim" - c.docHTMLOutput = "doc/html" - c.webUploadOutput = "web/upload" - c.authors = "" - c.projectTitle = "" - c.projectName = "" - c.logo = "" - c.ticker = "" - c.vars = newStringTable(modeStyleInsensitive) - c.numProcessors = countProcessors() - # Attempts to obtain the git current commit. - when false: - let (output, code) = execCmdEx("git log -n 1 --format=%H") - if code == 0 and output.strip.len == 40: - c.gitCommit = output.strip - c.quotations = initTable[string, tuple[quote, author: string]]() - -include "website.nimf" - -# ------------------------- configuration file ------------------------------- - -const - version = "0.8" - usage = "nimweb - Nim Website Generator Version " & version & """ - - (c) 2015 Andreas Rumpf -Usage: - nimweb [options] ini-file[.ini] [compile_options] -Options: - -h, --help shows this help - -v, --version shows the version - -o, --output overrides output directory instead of default - web/upload and doc/html - --nimCompiler overrides nim compiler; default = bin/nim - --var:name=value set the value of a variable - --website only build the website, not the full documentation - --pdf build the PDF version of the documentation - --json2 build JSON of the documentation - --onlyDocs build only the documentation - --git.url override base url in generated doc links - --git.commit override commit/branch in generated doc links 'source' - --git.devel override devel branch in generated doc links 'edit' -Compile_options: - will be passed to the Nim compiler -""" - - rYearMonthDay = r"on\s+(\d{2})\/(\d{2})\/(\d{4})" - rssUrl = "http://nim-lang.org/news.xml" - rssNewsUrl = "http://nim-lang.org/news.html" - activeSponsors = "web/sponsors.csv" - inactiveSponsors = "web/inactive_sponsors.csv" - validAnchorCharacters = Letters + Digits - - -macro id(e: untyped): untyped = - ## generates the rss xml ``id`` element. - let e = callsite() - result = xmlCheckedTag(e, "id") - -macro updated(e: varargs[untyped]): untyped = - ## generates the rss xml ``updated`` element. - let e = callsite() - result = xmlCheckedTag(e, "updated") - -proc updatedDate(year, month, day: string): string = - ## wrapper around the update macro with easy input. - result = updated("$1-$2-$3T00:00:00Z" % [year, - repeat("0", 2 - len(month)) & month, - repeat("0", 2 - len(day)) & day]) - -macro entry(e: varargs[untyped]): untyped = - ## generates the rss xml ``entry`` element. - let e = callsite() - result = xmlCheckedTag(e, "entry") - -macro content(e: varargs[untyped]): untyped = - ## generates the rss xml ``content`` element. - let e = callsite() - result = xmlCheckedTag(e, "content", reqAttr = "type") - -proc parseCmdLine(c: var TConfigData) = - var p = initOptParser() - while true: - next(p) - var kind = p.kind - var key = p.key - var val = p.val - case kind - of cmdArgument: - c.infile = addFileExt(key, "ini") - c.nimArgs.add(cmdLineRest(p)) - break - of cmdLongOption, cmdShortOption: - case normalize(key) - of "help", "h": - stdout.write(usage) - quit(0) - of "version", "v": - stdout.write(version & "\n") - quit(0) - of "output", "o": - c.webUploadOutput = val - c.docHTMLOutput = val / "docs" - of "nimcompiler": - c.nimCompiler = val - of "parallelbuild": - try: - let num = parseInt(val) - if num != 0: c.numProcessors = num - except ValueError: - quit("invalid numeric value for --parallelBuild") - of "var": - var idx = val.find('=') - if idx < 0: quit("invalid command line") - c.vars[substr(val, 0, idx-1)] = substr(val, idx+1) - of "website": action = actOnlyWebsite - of "pdf": action = actPdf - of "json2": action = actJson2 - of "onlydocs": action = actOnlyDocs - of "googleanalytics": - c.gaId = val - c.nimArgs.add("--doc.googleAnalytics:" & val & " ") - of "git.url": - c.gitURL = val - of "git.commit": - c.nimArgs.add("--git.commit:" & val & " ") - of "git.devel": - c.nimArgs.add("--git.devel:" & val & " ") - else: - echo("Invalid argument '$1'" % [key]) - quit(usage) - of cmdEnd: break - if c.infile.len == 0: quit(usage) - -proc walkDirRecursively(s: var seq[string], root, ext: string) = - for k, f in walkDir(root): - case k - of pcFile, pcLinkToFile: - if cmpIgnoreCase(ext, splitFile(f).ext) == 0: - add(s, f) - of pcDir: walkDirRecursively(s, f, ext) - of pcLinkToDir: discard - -proc addFiles(s: var seq[string], dir, ext: string, patterns: seq[string]) = - for p in items(patterns): - if fileExists(dir / addFileExt(p, ext)): - s.add(dir / addFileExt(p, ext)) - if dirExists(dir / p): - walkDirRecursively(s, dir / p, ext) - -proc parseIniFile(c: var TConfigData) = - var - p: CfgParser - section: string # current section - var input = newFileStream(c.infile, fmRead) - if input == nil: quit("cannot open: " & c.infile) - open(p, input, c.infile) - while true: - var k = next(p) - case k.kind - of cfgEof: break - of cfgSectionStart: - section = normalize(k.section) - case section - of "project", "links", "tabs", "ticker", "documentation", "var": discard - else: echo("[Warning] Skipping unknown section: " & section) - - of cfgKeyValuePair: - var v = k.value % c.vars - c.vars[k.key] = v - - case section - of "project": - case normalize(k.key) - of "name": c.projectName = v - of "title": c.projectTitle = v - of "logo": c.logo = v - of "authors": c.authors = v - else: quit(errorStr(p, "unknown variable: " & k.key)) - of "var": discard - of "links": - let valID = v.split(';') - add(c.links, (k.key.replace('_', ' '), valID[1], valID[0])) - of "tabs": add(c.tabs, (k.key, "", v)) - of "ticker": c.ticker = v - of "documentation": - case normalize(k.key) - of "doc": addFiles(c.doc, "doc", ".rst", split(v, {';'})) - of "pdf": addFiles(c.pdf, "doc", ".rst", split(v, {';'})) - of "srcdoc": addFiles(c.srcdoc, "lib", ".nim", split(v, {';'})) - of "srcdoc2": addFiles(c.srcdoc2, "lib", ".nim", split(v, {';'})) - of "webdoc": addFiles(c.webdoc, "lib", ".nim", split(v, {';'})) - of "parallelbuild": - try: - let num = parseInt(v) - if num != 0: c.numProcessors = num - except ValueError: - quit("invalid numeric value for --parallelBuild in config") - else: quit(errorStr(p, "unknown variable: " & k.key)) - of "quotations": - let vSplit = v.split('-') - doAssert vSplit.len == 2 - c.quotations[k.key.normalize] = (vSplit[0], vSplit[1]) - else: discard - of cfgOption: quit(errorStr(p, "syntax error")) - of cfgError: quit(errorStr(p, k.msg)) - close(p) - if c.projectName.len == 0: - c.projectName = changeFileExt(extractFilename(c.infile), "") - -# ------------------- main ---------------------------------------------------- - - -proc exe(f: string): string = return addFileExt(f, ExeExt) - -proc findNim(c: TConfigData): string = - if c.nimCompiler.len > 0: return c.nimCompiler - var nim = "nim".exe - result = "bin" / nim - if fileExists(result): return - for dir in split(getEnv("PATH"), PathSep): - if fileExists(dir / nim): return dir / nim - # assume there is a symlink to the exe or something: - return nim - -proc exec(cmd: string) = - echo(cmd) - let (outp, exitCode) = osproc.execCmdEx(cmd) - if exitCode != 0: quit outp - -proc sexec(cmds: openarray[string]) = - ## Serial queue wrapper around exec. - for cmd in cmds: exec(cmd) - -proc mexec(cmds: openarray[string], processors: int) = - ## Multiprocessor version of exec - doAssert processors > 0, "nimweb needs at least one processor" - if processors == 1: - sexec(cmds) - return - let r = execProcesses(cmds, {poStdErrToStdOut, poParentStreams, poEchoCmd}, - n = processors) - if r != 0: - echo "external program failed, retrying serial work queue for logs!" - sexec(cmds) - -proc buildDocSamples(c: var TConfigData, destPath: string) = - ## Special case documentation sample proc. - ## - ## TODO: consider integrating into the existing generic documentation builders - ## now that we have a single `doc` command. - exec(findNim(c) & " doc $# -o:$# $#" % - [c.nimArgs, destPath / "docgen_sample.html", "doc" / "docgen_sample.nim"]) - -proc pathPart(d: string): string = splitFile(d).dir.replace('\\', '/') - -proc buildDoc(c: var TConfigData, destPath: string) = - # call nim for the documentation: - var - commands = newSeq[string](len(c.doc) + len(c.srcdoc) + len(c.srcdoc2)) - i = 0 - for d in items(c.doc): - commands[i] = findNim(c) & " rst2html $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, c.gitURL, - destPath / changeFileExt(splitFile(d).name, "html"), d] - i.inc - for d in items(c.srcdoc): - commands[i] = findNim(c) & " doc0 $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, c.gitURL, - destPath / changeFileExt(splitFile(d).name, "html"), d] - i.inc - for d in items(c.srcdoc2): - commands[i] = findNim(c) & " doc $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, c.gitURL, - destPath / changeFileExt(splitFile(d).name, "html"), d] - i.inc - - mexec(commands, c.numProcessors) - exec(findNim(c) & " buildIndex -o:$1/theindex.html $1" % [destPath]) - -proc buildPdfDoc(c: var TConfigData, destPath: string) = - createDir(destPath) - if os.execShellCmd("pdflatex -version") != 0: - echo "pdflatex not found; no PDF documentation generated" - else: - const pdflatexcmd = "pdflatex -interaction=nonstopmode " - for d in items(c.pdf): - exec(findNim(c) & " rst2tex $# $#" % [c.nimArgs, d]) - # call LaTeX twice to get cross references right: - exec(pdflatexcmd & changeFileExt(d, "tex")) - exec(pdflatexcmd & changeFileExt(d, "tex")) - # delete all the crappy temporary files: - let pdf = splitFile(d).name & ".pdf" - let dest = destPath / pdf - removeFile(dest) - moveFile(dest=dest, source=pdf) - removeFile(changeFileExt(pdf, "aux")) - if fileExists(changeFileExt(pdf, "toc")): - removeFile(changeFileExt(pdf, "toc")) - removeFile(changeFileExt(pdf, "log")) - removeFile(changeFileExt(pdf, "out")) - removeFile(changeFileExt(d, "tex")) - -proc buildAddDoc(c: var TConfigData, destPath: string) = - # build additional documentation (without the index): - var commands = newSeq[string](c.webdoc.len) - for i, doc in pairs(c.webdoc): - commands[i] = findNim(c) & " doc $# --git.url:$# -o:$# $#" % - [c.nimArgs, c.gitURL, - destPath / changeFileExt(splitFile(doc).name, "html"), doc] - mexec(commands, c.numProcessors) - -proc parseNewsTitles(inputFilename: string): seq[TRssItem] = - # Goes through each news file, returns its date/title. - result = @[] - var matches: array[3, string] - let reYearMonthDay = re(rYearMonthDay) - for kind, path in walkDir(inputFilename): - let (dir, name, ext) = path.splitFile - if ext == ".rst": - let content = readFile(path) - let title = content.splitLines()[0] - let urlPath = "news/" & name & ".html" - if content.find(reYearMonthDay, matches) >= 0: - result.add(TRssItem(year: matches[2], month: matches[1], day: matches[0], - title: title, url: "http://nim-lang.org/" & urlPath, - content: content)) - result.reverse() - -proc genUUID(text: string): string = - # Returns a valid RSS uuid, which is basically md5 with dashes and a prefix. - result = getMD5(text) - result.insert("-", 20) - result.insert("-", 16) - result.insert("-", 12) - result.insert("-", 8) - result.insert("urn:uuid:") - -proc genNewsLink(title: string): string = - # Mangles a title string into an expected news.html anchor. - result = title - result.insert("Z") - for i in 1..len(result)-1: - let letter = result[i].toLowerAscii() - if letter in validAnchorCharacters: - result[i] = letter - else: - result[i] = '-' - result.insert(rssNewsUrl & "#") - -proc generateRss(outputFilename: string, news: seq[TRssItem]) = - # Given a list of rss items generates an rss overwriting destination. - var - output: File - - if not open(output, outputFilename, mode = fmWrite): - quit("Could not write to $1 for rss generation" % [outputFilename]) - defer: output.close() - - output.write("""<?xml version="1.0" encoding="utf-8"?> -<feed xmlns="http://www.w3.org/2005/Atom"> -""") - output.write(title("Nim website news")) - output.write(link(href = rssUrl, rel = "self")) - output.write(link(href = rssNewsUrl)) - output.write(id(rssNewsUrl)) - - let now = utc(getTime()) - output.write(updatedDate($now.year, $(int(now.month) + 1), $now.monthday)) - - for rss in news: - output.write(entry( - title(xmltree.escape(rss.title)), - id(genUUID(rss.title)), - link(`type` = "text/html", rel = "alternate", - href = rss.url), - updatedDate(rss.year, rss.month, rss.day), - "<author><name>Nim</name></author>", - content(xmltree.escape(rss.content), `type` = "text") - )) - - output.write("""</feed>""") - -proc buildNewsRss(c: var TConfigData, destPath: string) = - # generates an xml feed from the web/news.rst file - let - srcFilename = "web" / "news" - destFilename = destPath / changeFileExt(splitFile(srcFilename).name, "xml") - - generateRss(destFilename, parseNewsTitles(srcFilename)) - -proc readSponsors(sponsorsFile: string): seq[Sponsor] = - result = @[] - var fileStream = newFileStream(sponsorsFile, fmRead) - if fileStream == nil: quit("Cannot open sponsors.csv file: " & sponsorsFile) - var parser: CsvParser - open(parser, fileStream, sponsorsFile) - discard readRow(parser) # Skip the header row. - while readRow(parser): - result.add(Sponsor(logo: parser.row[0], name: parser.row[1], - url: parser.row[2], thisMonth: parser.row[3].parseInt, - allTime: parser.row[4].parseInt, - since: parser.row[5], level: parser.row[6].parseInt)) - parser.close() - -proc buildSponsors(c: var TConfigData, outputDir: string) = - let sponsors = generateSponsorsPage(readSponsors(activeSponsors), - readSponsors(inactiveSponsors)) - let outFile = outputDir / "sponsors.html" - var f: File - if open(f, outFile, fmWrite): - writeLine(f, generateHtmlPage(c, "", "Our Sponsors", sponsors, "")) - close(f) - else: - quit("[Error] Cannot write file: " & outFile) - -const - cmdRst2Html = " rst2html --compileonly $1 -o:web/$2.temp web/$2.rst" - -proc buildPage(c: var TConfigData, file, title, rss: string, assetDir = "") = - exec(findNim(c) & cmdRst2Html % [c.nimArgs, file]) - var temp = "web" / changeFileExt(file, "temp") - var content: string - try: - content = readFile(temp) - except IOError: - quit("[Error] cannot open: " & temp) - var f: File - var outfile = c.webUploadOutput / "$#.html" % file - if not dirExists(outfile.splitFile.dir): - createDir(outfile.splitFile.dir) - if open(f, outfile, fmWrite): - writeLine(f, generateHTMLPage(c, file, title, content, rss, assetDir)) - close(f) - else: - quit("[Error] cannot write file: " & outfile) - removeFile(temp) - -proc buildNews(c: var TConfigData, newsDir: string, outputDir: string) = - for kind, path in walkDir(newsDir): - let (dir, name, ext) = path.splitFile - if ext == ".rst": - let title = readFile(path).splitLines()[0] - buildPage(c, tailDir(dir) / name, title, "", "../") - else: - echo("Skipping file in news directory: ", path) - -proc buildWebsite(c: var TConfigData) = - if c.ticker.len > 0: - try: - c.ticker = readFile("web" / c.ticker) - except IOError: - quit("[Error] cannot open: " & c.ticker) - for i in 0..c.tabs.len-1: - var file = c.tabs[i].val - let rss = if file in ["news", "index"]: extractFilename(rssUrl) else: "" - if '.' in file: continue - buildPage(c, file, if file == "question": "FAQ" else: file, rss) - copyDir("web/assets", c.webUploadOutput / "assets") - buildNewsRss(c, c.webUploadOutput) - buildSponsors(c, c.webUploadOutput) - buildNews(c, "web/news", c.webUploadOutput / "news") - -proc onlyDocs(c: var TConfigData) = - createDir(c.docHTMLOutput) - buildDocSamples(c, c.docHTMLOutput) - buildDoc(c, c.docHTMLOutput) - -proc main(c: var TConfigData) = - buildWebsite(c) - let docup = c.webUploadOutput / NimVersion - createDir(docup) - buildAddDoc(c, docup) - buildDocSamples(c, docup) - buildDoc(c, docup) - onlyDocs(c) - -proc json2(c: var TConfigData) = - const destPath = "web/json2" - var commands = newSeq[string](c.srcdoc2.len) - var i = 0 - for d in items(c.srcdoc2): - createDir(destPath / splitFile(d).dir) - commands[i] = findNim(c) & " jsondoc $# --git.url:$# -o:$# --index:on $#" % - [c.nimArgs, c.gitURL, - destPath / changeFileExt(d, "json"), d] - i.inc - - mexec(commands, c.numProcessors) - -var c: TConfigData -initConfigData(c) -parseCmdLine(c) -parseIniFile(c) -case action -of actOnlyWebsite: buildWebsite(c) -of actPdf: buildPdfDoc(c, "doc/pdf") -of actOnlyDocs: onlyDocs(c) -of actAll: main(c) -of actJson2: json2(c) diff --git a/tools/website.nimf b/tools/website.nimf deleted file mode 100644 index cea30f74f..000000000 --- a/tools/website.nimf +++ /dev/null @@ -1,266 +0,0 @@ -#? stdtmpl | standard -#proc generateHTMLPage(c: var TConfigData, currentTab, title, content, rss, -# rootDir = ""): string = -# result = "" -<!DOCTYPE html> -<html> - <head> - <meta http-equiv="content-type" content="text/html; charset=utf-8"> - <title>${title} - $c.projectTitle</title> - <link rel="stylesheet" type="text/css" href="${rootDir}assets/style.css?t=2320" /> - <link rel="shortcut icon" href="${rootDir}assets/images/favicon.ico"> - #if len(rss) > 0: - <link href="$rss" title="Recent changes" type="application/atom+xml" rel="alternate"> - #end if - </head> - <body> - <div id="bountysource"> - <a href="https://salt.bountysource.com/teams/nim"> - <div class="page-layout" style="padding: 2pt 2pt 2pt 30pt"> - <img src="${rootDir}assets/bountysource/bountysource.png" style="width: 20px; float: left;"> - <span style="margin-left: 10pt; float: left; margin-top: 2pt;">Fund Nim and help us develop it further!</span> - <img src="https://api.bountysource.com/badge/team?team_id=19072&style=raised" style="margin-top: 2pt; margin-left: 10pt"/> - </div> - </a> - </div> - - <header id="head"> - <div class="page-layout tall"> - <div id="head-logo"></div> - <a id="head-logo-link" href="${rootDir}index.html"></a> - <nav id="head-links"> - #for i in 0.. c.tabs.len-1: - # let t = c.tabs[i].val - # if t != "index" and t != "community" and t != "news": - # let name = c.tabs[i].key - # if currentTab == t: - <a class="active" - # else: - <a - # end if - # if t.contains('.'): - href="${t}" title = "$c.projectName - $name">$name</a> - # else: - href="${rootDir}${t}.html" title = "$c.projectName - $name">$name</a> - # end if - # end if - #end for - </nav> - </div> - </header> - -# if currentTab == "index": - <section id="neck" class="home"> -# else: - <section id="neck"> -# end - <div class="page-layout tall"> - <div id="glow-arrow"></div> - -# if currentTab == "index": - <div id="slideshow"> - <!-- slides --> - <div id="slide0" class="active codeslide2"> - <div> - <h2>Nim is simple..</h2> -<pre> -<span class="cmt"># compute average line length</span> -<span class="kwd">var</span> -<span class="tab"> </span>sum = <span class="val">0</span> -<span class="tab end"> </span>count = <span class="val">0</span> - -<span class="kwd">for</span> line <span class="kwd">in</span> stdin.lines: -<span class="tab"> </span>sum += line.len -<span class="tab end"> </span>count += <span class="val">1</span> - -echo(<span class="val">"Average line length: "</span>, - <span class="kwd">if</span> count > <span class="val">0</span>: sum / count <span class="kwd">else</span>: <span class="val">0</span>) -</pre> - </div> - <div> - <h2>..and type safe...</h2> -<pre> -<span class="cmt"># create and greet someone</span> -<span class="kwd">type</span> <span class="def">Person</span> = <span class="kwd">object</span> -<span class="tab"> </span>name: <span class="typ">string</span> -<span class="tab end"> </span>age: <span class="typ">int</span> - -<span class="kwd">proc</span> <span class="def">greet</span>(p: <span class="typ">Person</span>) = -<span class="tab"> </span>echo <span class="val">"Hi, I'm "</span>, p.name, <span class="val">"."</span> -<span class="tab end"> </span>echo <span class="val">"I am "</span>, p.age, <span class="val">" years old."</span> - -<span class="kwd">let</span> p = <span class="typ">Person</span>(name:<span class="val">"Jon"</span>, age:<span class="val">18</span>) -p.greet() <span class="cmt"># or greet(p)</span> -</pre> - </div> - </div> - <div id="slide1" class="codeslide3"> - <div> - <h2>C FFI is easy in Nim..</h2> -<pre> -<span class="cmt"># declare a C procedure..</span> -<span class="kwd">proc</span> <span class="def">unsafeScanf</span>(f: <span class="typ">File</span>, s: <span class="typ">cstring</span>) -<span class="tab"> </span>{.varargs, -<span class="tab"> </span>importc: <span class="val">"fscanf"</span>, -<span class="tab end"> </span>header: <span class="val">"<stdio.h>"</span>.} - -<span class="cmt"># ..and use it...</span> -<span class="kwd">var</span> x: <span class="typ">cint</span> -stdin.unsafeScanf(<span class="val">"%d"</span>, <span class="kwd">addr</span> x) -</pre> - <p><span class="desc"><b>Compile and run with:</b><br> $ nim c -r example.nim</span></p> - </div> - <div> - <h2>..and DSLs are too...</h2> -<pre> -<span class="cmt"># a simple html server</span> -<span class="kwd">import</span> - jester, asyncdispatch, htmlgen - -<span class="kwd">routes</span>: -<span class="tab"> </span><span class="kwd">get</span> <span class="val">"/"</span>: -<span class="tab end"> <span class="tab end"> </span></span><span class="kwd">resp</span> h1(<span class="val">"Hello world"</span>) - -runForever() -</pre> - <p><span class="desc"><b>View in browser at:</b><br> localhost:5000</span></p> - </div> - </div> - <div id="slide2" class="niaslide"> - <a href="news/e030_nim_in_action_in_production.html"> - <img src="${rootDir}assets/niminaction/banner2.png" alt="A printed copy of Nim in Action should be available in March 2017!"/> - </a> - </div> - <div id="slide3" class="niaslide"> - <a href="sponsors.html"> - <img src="${rootDir}assets/bountysource/meet_sponsors.png" alt="Meet our BountySource sponsors!"/> - </a> - </div> - </div> - <div id="slideshow-nav"> - <div id="slideControl0" onclick="slideshow_click(0)" class="active"></div> - <div id="slideControl1" onclick="slideshow_click(1)"></div> - <div id="slideControl2" onclick="slideshow_click(2)"></div> - <div id="slideControl3" onclick="slideshow_click(3)"></div> - </div> -# end - <aside id="sidebar"> - -# if len(c.links) > 0: - <h3>More Links</h3> - <div id="sidebar-links"> -# for i in 0..c.links.len-1: - <a href="${c.links[i].val}" id="${c.links[i].id}">${c.links[i].key}</a> -# end for - </div> -# end if -# if len(c.ticker) > 0: - <h3 class="blue">Latest News</h3> - <div id="sidebar-news"> - ${c.ticker % rootDir} - </div> -# end if - </aside> - </div> - </section> - - <section id="body"> - <div id="body-border"></div> - <div id="glow-line"></div> - <div class="page-layout"> - <article id="content" class="page"> - $content - </article> - </div> - </section> - - <!--- #foot ---> - <footer id="foot" class="home"> - <div class="page-layout tall"> - <div id="foot-links"> - <div> - <h4>Documentation</h4> - <a href="${rootDir}documentation.html">Stable Documentation</a> - <a href="${rootDir}learn.html">Learning Resources</a> - <!-- <a href="">Development Documentation</a> --> - <a href="https://github.com/nim-lang/nim">Issues & Requests</a> - </div> - <div> - <h4>Community</h4> - <a href="https://forum.nim-lang.org">User Forum</a> - <a href="https://web.libera.chat/#nim">Online IRC</a> - <a href="https://irclogs.nim-lang.org/">IRC Logs</a> - </div> - </div> - <div id="foot-legal"> - <h4>Written in Nim - Powered by <a href="https://github.com/dom96/jester">Jester</a></h4> - Web Design by <a href="http://reign-studios.net/philipwitte/">Philip Witte</a> & <a href="http://picheta.me/">Dominik Picheta</a><br> - Copyright © 2017 - <a href="https://nim-lang.org/blog/">Andreas Rumpf</a> & <a href="https://github.com/nim-lang/nim/graphs/contributors">Contributors</a> - </div> - </div> - </footer> - -# if currentTab == "index": - <script src="${rootDir}assets/index.js"></script> -# end if -# if c.gaId.len != 0: - <script> - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', '${c.gaId}', 'nim-lang.org'); - ga('send', 'pageview'); - </script> -# end if -</body> -</html> -#end proc -# -# -#proc generateSponsors(sponsors: seq[Sponsor]): string = -#result = "" -#for sponsor in sponsors: - <dt class="level-${sponsor.level}"> - #if sponsor.url.len > 0: - <a href="${sponsor.url}" target="_blank">${sponsor.name}</a> - #else: - ${sponsor.name} - #end if - </dt> - <dd class="logo"> - #if sponsor.logo.len > 0: - <a href="${sponsor.url}" target="_blank"> - <img alt="${sponsor.name}'s logo" src="${sponsor.logo}"/> - </a> - #end if - </dd> - <dd class="this_month"> - Donated <b>$$${sponsor.thisMonth}</b> this month - </dd> - <dd class="legend"> - Donated $$${sponsor.allTime} in total since ${sponsor.since} - </dd> -#end for -#end proc -#proc generateSponsorsPage(activeSponsors, inactiveSponsors: seq[Sponsor]): string = -#result = "" -<h1 id="our-current-sponsors">Our Current Sponsors</h1> -<p>This section lists the companies and individuals that are, very kindly, contributing a -monthly amount to help sustain Nim's development. For more details take a -look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campaign</a>.</p> -<p class="lastUpdate">Last updated: ${getTime().utc().format("dd/MM/yyyy")}</p> -<dl> -${generateSponsors(activeSponsors)} -</dl> -# -<h1 id="our-past-sponsors">Our Past Sponsors</h1> -<p>This section lists the companies and individuals that have contributed -money in the past to help sustain Nim's development. For more details take a -look at the <a href="https://salt.bountysource.com/teams/nim">Bountysource campaign</a>.</p> -<dl> -${generateSponsors(inactiveSponsors)} -</dl> -# -#end proc |