summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/docgen.nim4
-rw-r--r--lib/pure/asyncdispatch.nim77
-rw-r--r--lib/pure/asyncfile.nim34
-rw-r--r--lib/pure/asynchttpserver.nim1
-rw-r--r--lib/pure/asyncio.nim1
-rw-r--r--lib/pure/cgi.nim13
-rw-r--r--lib/system.nim6
-rw-r--r--tests/async/tasyncawait.nim21
-rw-r--r--tests/async/tasyncdiscard.nim4
-rw-r--r--tests/async/tasyncexceptions.nim6
-rw-r--r--tests/async/tasyncfile.nim2
-rw-r--r--tests/async/tasynctry.nim51
-rw-r--r--tests/async/tnestedpfuturetypeparam.nim4
-rw-r--r--tests/testament/htmlgen.nim2
-rw-r--r--tests/vm/tasmparser.nim2
-rw-r--r--web/download.txt4
-rw-r--r--web/news.txt18
17 files changed, 153 insertions, 97 deletions
diff --git a/compiler/docgen.nim b/compiler/docgen.nim
index 4e576867b..c34332b57 100644
--- a/compiler/docgen.nim
+++ b/compiler/docgen.nim
@@ -374,11 +374,11 @@ proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind) =
     cleanPlainSymbol = renderPlainSymbolName(nameNode)
     complexSymbol = complexName(k, n, cleanPlainSymbol)
     plainSymbolRope = toRope(cleanPlainSymbol)
-    plainSymbolEncRope = toRope(URLencode(cleanPlainSymbol))
+    plainSymbolEncRope = toRope(urlEncode(cleanPlainSymbol))
     itemIDRope = toRope(d.id)
     symbolOrId = d.newUniquePlainSymbol(complexSymbol)
     symbolOrIdRope = symbolOrId.toRope
-    symbolOrIdEncRope = URLencode(symbolOrId).toRope
+    symbolOrIdEncRope = urlEncode(symbolOrId).toRope
 
   var seeSrcRope: PRope = nil
   let docItemSeeSrc = getConfigVar("doc.item.seesrc")
diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim
index e521b8e64..5363d8862 100644
--- a/lib/pure/asyncdispatch.nim
+++ b/lib/pure/asyncdispatch.nim
@@ -796,6 +796,7 @@ else:
       else:
         # FD no longer a part of the selector. Likely been closed
         # (e.g. socket disconnected).
+        discard
 
     processTimers(p)
   
@@ -972,29 +973,50 @@ template createCb*(retFutureSym, iteratorNameSym,
   cb()
   #{.pop.}
 proc generateExceptionCheck(futSym,
-    exceptBranch, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} =
-  if exceptBranch == nil:
+    tryStmt, rootReceiver, fromNode: PNimrodNode): PNimrodNode {.compileTime.} =
+  if tryStmt.kind == nnkNilLit:
     result = rootReceiver
   else:
-    if exceptBranch[0].kind == nnkStmtList:
-      result = newIfStmt(
-        (newDotExpr(futSym, newIdentNode("failed")),
-           exceptBranch[0]
-         )
-      )
-    else:
-      expectKind(exceptBranch[1], nnkStmtList)
-      result = newIfStmt(
-        (newDotExpr(futSym, newIdentNode("failed")),
-           newIfStmt(
-             (infix(newDotExpr(futSym, newIdentNode("error")), "of", exceptBranch[0]),
-              exceptBranch[1])
-           )
-         )
-      )
+    var exceptionChecks: seq[tuple[cond, body: PNimrodNode]] = @[]
+    let errorNode = newDotExpr(futSym, newIdentNode("error"))
+    for i in 1 .. <tryStmt.len:
+      let exceptBranch = tryStmt[i]
+      if exceptBranch[0].kind == nnkStmtList:
+        exceptionChecks.add((newIdentNode("true"), exceptBranch[0]))
+      else:
+        var exceptIdentCount = 0
+        var ifCond: PNimrodNode
+        for i in 0 .. <exceptBranch.len:
+          let child = exceptBranch[i]
+          if child.kind == nnkIdent:
+            let cond = infix(errorNode, "of", child)
+            if exceptIdentCount == 0:
+              ifCond = cond
+            else:
+              ifCond = infix(ifCond, "or", cond)
+          else:
+            break
+          exceptIdentCount.inc
+
+        expectKind(exceptBranch[exceptIdentCount], nnkStmtList)
+        exceptionChecks.add((ifCond, exceptBranch[exceptIdentCount]))
+    # -> -> else: raise futSym.error
+    exceptionChecks.add((newIdentNode("true"),
+        newNimNode(nnkRaiseStmt).add(errorNode)))
+    # Read the future if there is no error.
+    # -> else: futSym.read
     let elseNode = newNimNode(nnkElse, fromNode)
     elseNode.add newNimNode(nnkStmtList, fromNode)
     elseNode[0].add rootReceiver
+
+    let ifBody = newStmtList()
+    ifBody.add newCall(newIdentNode("setCurrentException"), errorNode)
+    ifBody.add newIfStmt(exceptionChecks)
+    ifBody.add newCall(newIdentNode("setCurrentException"), newNilLit())
+
+    result = newIfStmt(
+      (newDotExpr(futSym, newIdentNode("failed")), ifBody)
+    )
     result.add elseNode
 
 template createVar(result: var PNimrodNode, futSymName: string,
@@ -1006,11 +1028,11 @@ template createVar(result: var PNimrodNode, futSymName: string,
   result.add newVarStmt(futSym, asyncProc) # -> var future<x> = y
   result.add newNimNode(nnkYieldStmt, fromNode).add(futSym) # -> yield future<x>
   valueReceiver = newDotExpr(futSym, newIdentNode("read")) # -> future<x>.read
-  result.add generateExceptionCheck(futSym, exceptBranch, rootReceiver, fromNode)
+  result.add generateExceptionCheck(futSym, tryStmt, rootReceiver, fromNode)
 
 proc processBody(node, retFutureSym: PNimrodNode,
                  subTypeIsVoid: bool,
-                 exceptBranch: PNimrodNode): PNimrodNode {.compileTime.} =
+                 tryStmt: PNimrodNode): PNimrodNode {.compileTime.} =
   #echo(node.treeRepr)
   result = node
   case node.kind
@@ -1024,7 +1046,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
         result.add newCall(newIdentNode("complete"), retFutureSym)
     else:
       result.add newCall(newIdentNode("complete"), retFutureSym,
-        node[0].processBody(retFutureSym, subTypeIsVoid, exceptBranch))
+        node[0].processBody(retFutureSym, subTypeIsVoid, tryStmt))
 
     result.add newNimNode(nnkReturnStmt, node).add(newNilLit())
     return # Don't process the children of this return stmt
@@ -1079,7 +1101,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
                        res: PNimrodNode): bool {.compileTime.} =
       result = false
       while i < n[0].len:
-        var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n[1])
+        var processed = processBody(n[0][i], retFutureSym, subTypeIsVoid, n)
         if processed.kind != n[0][i].kind or processed.len != n[0][i].len:
           expectKind(processed, nnkStmtList)
           expectKind(processed[2][1], nnkElse)
@@ -1099,7 +1121,7 @@ proc processBody(node, retFutureSym: PNimrodNode,
   else: discard
 
   for i in 0 .. <result.len:
-    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, exceptBranch)
+    result[i] = processBody(result[i], retFutureSym, subTypeIsVoid, tryStmt)
 
 proc getName(node: PNimrodNode): string {.compileTime.} =
   case node.kind
@@ -1193,7 +1215,7 @@ macro async*(prc: stmt): stmt {.immediate.} =
   result[6] = outerProcBody
 
   #echo(treeRepr(result))
-  #if prc[0].getName == "getFile":
+  #if prc[0].getName == "catch":
   #  echo(toStrLit(result))
 
 proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
@@ -1209,6 +1231,8 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
   ## If the socket is disconnected in the middle of a line (before ``\r\L``
   ## is read) then line will be set to ``""``.
   ## The partial line **will be lost**.
+  ##
+  ## **Warning**: This assumes that lines are delimited by ``\r\l``.
   
   template addNLIfEmpty(): stmt =
     if result.len == 0:
@@ -1221,9 +1245,8 @@ proc recvLine*(socket: TAsyncFD): Future[string] {.async.} =
     if c.len == 0:
       return ""
     if c == "\r":
-      c = await recv(socket, 1, {SocketFlag.SafeDisconn, SocketFlag.Peek})
-      if c.len > 0 and c == "\L":
-        discard await recv(socket, 1)
+      c = await recv(socket, 1)
+      assert c == "\l"
       addNLIfEmpty()
       return
     elif c == "\L":
diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim
index 6c8a87184..e861c6e48 100644
--- a/lib/pure/asyncfile.nim
+++ b/lib/pure/asyncfile.nim
@@ -34,26 +34,7 @@ type
     fd: TAsyncFd
     offset: int64
 
-# TODO: These will be nil in other threads?
-var
-  asyncStdin* {.threadvar.}: AsyncFile ## Asynchronous stdin handle
-  asyncStdout* {.threadvar.}: AsyncFile ## Asynchronous stdout handle
-  asyncStderr* {.threadvar.}: AsyncFile ## Asynchronous stderr handle
-
 when defined(windows):
-  asyncStdin = AsyncFile(
-      fd: getStdHandle(STD_INPUT_HANDLE).TAsyncFd,
-      offset: 0
-    )
-  asyncStdout = AsyncFile(
-      fd: getStdHandle(STD_OUTPUT_HANDLE).TAsyncFd,
-      offset: 0
-    )
-  asyncStderr = AsyncFile(
-      fd: getStdHandle(STD_ERROR_HANDLE).TAsyncFd,
-      offset: 0
-    )
-
   proc getDesiredAccess(mode: TFileMode): int32 =
     case mode
     of fmRead:
@@ -73,19 +54,6 @@ when defined(windows):
       else:
         CREATE_NEW
 else:
-  asyncStdin = AsyncFile(
-      fd: STDIN_FILENO.TAsyncFd,
-      offset: 0
-    )
-  asyncStdout = AsyncFile(
-      fd: STDOUT_FILENO.TAsyncFd,
-      offset: 0
-    )
-  asyncStderr = AsyncFile(
-      fd: STDERR_FILENO.TAsyncFd,
-      offset: 0
-    )
-
   proc getPosixFlags(mode: TFileMode): cint =
     case mode
     of fmRead:
@@ -100,7 +68,7 @@ else:
       result = O_RDWR
     result = result or O_NONBLOCK
 
-proc getFileSize*(f: AsyncFile): int64 =
+proc getFileSize(f: AsyncFile): int64 =
   ## Retrieves the specified file's size.
   when defined(windows):
     var high: DWord
diff --git a/lib/pure/asynchttpserver.nim b/lib/pure/asynchttpserver.nim
index 70a865ed5..931a0c15a 100644
--- a/lib/pure/asynchttpserver.nim
+++ b/lib/pure/asynchttpserver.nim
@@ -183,6 +183,7 @@ proc processClient(client: PAsyncSocket, address: string,
       # header states otherwise.
       # In HTTP 1.0 we assume that the connection should not be persistent.
       # Unless the connection header states otherwise.
+      discard
     else:
       request.client.close()
       break
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index 5e757a03b..3de947dca 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -247,6 +247,7 @@ proc asyncSockHandleWrite(h: RootRef) =
           # Apparently the socket cannot be written to. Even though select
           # just told us that it can be... This used to be an assert. Just
           # do nothing instead.
+          discard
         elif bytesSent != sock.sendBuffer.len:
           sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
         elif bytesSent == sock.sendBuffer.len:
diff --git a/lib/pure/cgi.nim b/lib/pure/cgi.nim
index b30f8dd33..d5690bf51 100644
--- a/lib/pure/cgi.nim
+++ b/lib/pure/cgi.nim
@@ -31,7 +31,7 @@
 
 import strutils, os, strtabs, cookies
 
-proc URLencode*(s: string): string =
+proc urlEncode*(s: string): string =
   ## Encodes a value to be HTTP safe: This means that characters in the set
   ## ``{'A'..'Z', 'a'..'z', '0'..'9', '_'}`` are carried over to the result,
   ## a space is converted to ``'+'`` and every other character is encoded as
@@ -52,7 +52,7 @@ proc handleHexChar(c: char, x: var int) {.inline.} =
   of 'A'..'F': x = (x shl 4) or (ord(c) - ord('A') + 10)
   else: assert(false)
 
-proc URLdecode*(s: string): string =
+proc urlDecode*(s: string): string =
   ## Decodes a value from its HTTP representation: This means that a ``'+'``
   ## is converted to a space, ``'%xx'`` (where ``xx`` denotes a hexadecimal
   ## value) is converted to the character with ordinal number ``xx``, and
@@ -82,7 +82,7 @@ proc addXmlChar(dest: var string, c: char) {.inline.} =
   of '\"': add(dest, "&quot;")
   else: add(dest, c)
 
-proc XMLencode*(s: string): string =
+proc xmlEncode*(s: string): string =
   ## Encodes a value to be XML safe:
   ## * ``"`` is replaced by ``&quot;``
   ## * ``<`` is replaced by ``&lt;``
@@ -99,7 +99,8 @@ type
     methodPost,          ## query uses the POST method
     methodGet            ## query uses the GET method
 
-{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError].}
+{.deprecated: [TRequestMethod: RequestMethod, ECgi: CgiError,
+  URLencode: urlEncode, XMLencode: xmlEncode, URLdecode: urlDecode].}
 
 proc cgiError*(msg: string) {.noreturn.} =
   ## raises an ECgi exception with message `msg`.
@@ -331,9 +332,9 @@ proc setTestData*(keysvalues: varargs[string]) =
   var i = 0
   var query = ""
   while i < keysvalues.len:
-    add(query, URLencode(keysvalues[i]))
+    add(query, urlEncode(keysvalues[i]))
     add(query, '=')
-    add(query, URLencode(keysvalues[i+1]))
+    add(query, urlEncode(keysvalues[i+1]))
     add(query, '&')
     inc(i, 2)
   putEnv("QUERY_STRING", query)
diff --git a/lib/system.nim b/lib/system.nim
index fe94ce95d..da49386ed 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2631,6 +2631,12 @@ when not defined(JS): #and not defined(NimrodVM):
         excHandler.hasRaiseAction = true
         excHandler.raiseAction = action
 
+    proc setCurrentException*(exc: ref Exception) {.inline, gcsafe.} =
+      ## sets the current exception.
+      ##
+      ## **Warning**: Only use this if you know what you are doing.
+      currException = exc
+
   {.push stack_trace: off, profiler:off.}
   when defined(endb) and not defined(NimrodVM):
     include "system/debugger"
diff --git a/tests/async/tasyncawait.nim b/tests/async/tasyncawait.nim
index ec05a0386..5165b0f06 100644
--- a/tests/async/tasyncawait.nim
+++ b/tests/async/tasyncawait.nim
@@ -21,15 +21,8 @@ proc launchSwarm(port: TPort) {.async.} =
     var sock = newAsyncRawSocket()
 
     await connect(sock, "localhost", port)
-    when true:
-      await sendMessages(sock)
-      closeSocket(sock)
-    else:
-      # Issue #932: https://github.com/Araq/Nim/issues/932
-      var msgFut = sendMessages(sock)
-      msgFut.callback =
-        proc () =
-          closeSocket(sock)
+    await sendMessages(sock)
+    closeSocket(sock)
 
 proc readMessages(client: TAsyncFD) {.async.} =
   while true:
@@ -47,18 +40,18 @@ proc readMessages(client: TAsyncFD) {.async.} =
 proc createServer(port: TPort) {.async.} =
   var server = newAsyncRawSocket()
   block:
-    var name: TSockaddr_in
+    var name: Sockaddr_in
     when defined(windows):
       name.sin_family = toInt(AF_INET).int16
     else:
       name.sin_family = toInt(AF_INET)
     name.sin_port = htons(int16(port))
     name.sin_addr.s_addr = htonl(INADDR_ANY)
-    if bindAddr(server.TSocketHandle, cast[ptr TSockAddr](addr(name)),
-                sizeof(name).TSocklen) < 0'i32:
-      osError(osLastError())
+    if bindAddr(server.SocketHandle, cast[ptr SockAddr](addr(name)),
+                sizeof(name).Socklen) < 0'i32:
+      raiseOSError(osLastError())
   
-  discard server.TSocketHandle.listen()
+  discard server.SocketHandle.listen()
   while true:
     var client = await accept(server)
     asyncCheck readMessages(client)
diff --git a/tests/async/tasyncdiscard.nim b/tests/async/tasyncdiscard.nim
index 966851acc..71aba29e2 100644
--- a/tests/async/tasyncdiscard.nim
+++ b/tests/async/tasyncdiscard.nim
@@ -13,7 +13,7 @@ discard """
 import asyncio, asyncdispatch, asyncnet
 
 proc main {.async.} =
-  proc f: PFuture[int] {.async.} =
+  proc f: Future[int] {.async.} =
     discard
     echo 1
     discard
@@ -24,7 +24,7 @@ proc main {.async.} =
   echo x
   echo 3
 
-  proc g: PFuture[int] {.async.} =
+  proc g: Future[int] {.async.} =
     discard
     echo 4
     discard
diff --git a/tests/async/tasyncexceptions.nim b/tests/async/tasyncexceptions.nim
index ca73c6a3d..30ef41756 100644
--- a/tests/async/tasyncexceptions.nim
+++ b/tests/async/tasyncexceptions.nim
@@ -1,15 +1,15 @@
 discard """
   file: "tasyncexceptions.nim"
   exitcode: 1
-  outputsub: "Error: unhandled exception: foobar [E_Base]"
+  outputsub: "Error: unhandled exception: foobar [Exception]"
 """
 import asyncdispatch
 
-proc accept(): PFuture[int] {.async.} =
+proc accept(): Future[int] {.async.} =
   await sleepAsync(100)
   result = 4
 
-proc recvLine(fd: int): PFuture[string] {.async.} =
+proc recvLine(fd: int): Future[string] {.async.} =
   await sleepAsync(100)
   return "get"
 
diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim
index 78738de4e..c3cf33512 100644
--- a/tests/async/tasyncfile.nim
+++ b/tests/async/tasyncfile.nim
@@ -1,5 +1,5 @@
 discard """
-  file: "tasyncexceptions.nim"
+  file: "tasyncfile.nim"
   exitcode: 0
 """
 import asyncfile, asyncdispatch, os
diff --git a/tests/async/tasynctry.nim b/tests/async/tasynctry.nim
new file mode 100644
index 000000000..66ea40d49
--- /dev/null
+++ b/tests/async/tasynctry.nim
@@ -0,0 +1,51 @@
+discard """
+  file: "tasynctry.nim"
+  exitcode: 0
+  output: '''
+Generic except: Test
+Specific except
+Multiple idents in except
+Multiple except branches
+Multiple except branches 2
+'''
+"""
+import asyncdispatch
+
+# Here we are testing the ability to catch exceptions.
+
+proc foobar() {.async.} =
+  if 5 == 5:
+    raise newException(EInvalidIndex, "Test")
+
+proc catch() {.async.} =
+  # TODO: Create a test for when exceptions are not caught.
+  try:
+    await foobar()
+  except:
+    echo("Generic except: ", getCurrentExceptionMsg())
+
+  try:
+    await foobar()
+  except EInvalidIndex:
+    echo("Specific except")
+
+  try:
+    await foobar()
+  except OSError, EInvalidField, EInvalidIndex:
+    echo("Multiple idents in except")
+
+  try:
+    await foobar()
+  except OSError, EInvalidField:
+    assert false
+  except EInvalidIndex:
+    echo("Multiple except branches")
+
+  try:
+    await foobar()
+  except EInvalidIndex:
+    echo("Multiple except branches 2")
+  except OSError, EInvalidField:
+    assert false
+
+asyncCheck catch()
diff --git a/tests/async/tnestedpfuturetypeparam.nim b/tests/async/tnestedpfuturetypeparam.nim
index 1db442170..bf346ff8e 100644
--- a/tests/async/tnestedpfuturetypeparam.nim
+++ b/tests/async/tnestedpfuturetypeparam.nim
@@ -1,8 +1,8 @@
 import asyncdispatch, asyncnet
 
 proc main {.async.} =
-  proc f: PFuture[seq[int]] {.async.} =
-    await newAsyncSocket().connect("www.google.com", TPort(80))
+  proc f: Future[seq[int]] {.async.} =
+    await newAsyncSocket().connect("www.google.com", Port(80))
   let x = await f()
 
 asyncCheck main()
diff --git a/tests/testament/htmlgen.nim b/tests/testament/htmlgen.nim
index d863bd411..b9eda5383 100644
--- a/tests/testament/htmlgen.nim
+++ b/tests/testament/htmlgen.nim
@@ -107,7 +107,7 @@ div.tabContent.hide { display: none; }
   HtmlEnd = "</body></html>"
 
 proc td(s: string): string =
-  result = "<td>" & s.substr(0, 200).XMLEncode & "</td>"
+  result = "<td>" & s.substr(0, 200).xmlEncode & "</td>"
 
 proc getCommit(db: TDbConn, c: int): string =
   var commit = c
diff --git a/tests/vm/tasmparser.nim b/tests/vm/tasmparser.nim
index 24ccb2ec8..67313c858 100644
--- a/tests/vm/tasmparser.nim
+++ b/tests/vm/tasmparser.nim
@@ -37,7 +37,7 @@ proc asmx64 () {.compileTime} =
 
 
   proc abortAsmParse (err:string) =
-    #
+    discard
 
   let codeLen = code.len
   #let codeEnd = codeLen-1
diff --git a/web/download.txt b/web/download.txt
index 557788217..6d860b332 100644
--- a/web/download.txt
+++ b/web/download.txt
@@ -121,8 +121,8 @@ Bleeding edge binaries are available from the `Nimrod build farm <http://build.n
 Source
 ======
 
-Starting with 0.9.4 we now advise people to build directly from the
-github `master <https://github.com/Araq/Nimrod#compiling>`_ branch::
+Use the following commands to build the compiler from source.
+Change the branch to suit your needs::
 
   git clone -b master git://github.com/Araq/Nimrod.git
   cd Nimrod
diff --git a/web/news.txt b/web/news.txt
index 3b48140e5..0b4c98b73 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -14,8 +14,12 @@ News
     ``threadpool``.
   - The symbol binding rules in generics changed: ``bar`` in ``foo.bar`` is
     now considered for implicit early binding.
-  - ``c2nim`` moved into its own repository and is now a Babel package.
-  - ``pas2nim`` moved into its own repository and is now a Babel package.
+  - ``c2nim`` moved into its own
+    `repository <https://github.com/nimrod-code/c2nim>`_
+    and is now a Nimble package.
+  - ``pas2nim`` moved into its own
+    `repository <https://github.com/nimrod-code/pas2nim>`_
+    and is now a Nimble package.
   - ``system.$`` for floating point types now produces a human friendly string
     representation.
   - ``uri.TUrl`` as well as the ``parseurl`` module are now deprecated in favour
@@ -31,7 +35,15 @@ News
     will disappear soon!
   - ``system.fileHandle`` has been renamed to ``system.getFileHandle`` to
     prevent name conflicts with the new type ``FileHandle``.
-  
+  - Comments are now not part of the AST, as such you cannot use them in place
+    of ``discard``.
+  - The ``irc`` module has been moved into its own
+    `repository <https://github.com/nimrod-code/irc>`_
+    and is now a Nimble package.
+  - Many wrappers have been moved into their own repositories and are now
+    Nimble packages including ``lua``, ``opengl``, ``x11``, ``nim-zmq``,
+    ``gtk2``, ``mongo``, ``cairo``, ``tcl`` and ``python``. They can be
+    found under the `nim-code <https://github.com/nimrod-code>`_ organisation.
 
   Language Additions
   ------------------