summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2014-07-22 20:23:28 +0200
committerAraq <rumpf_a@web.de>2014-07-22 20:23:28 +0200
commit821fe72ff55866737c5b1d9f356b8d142f8836c3 (patch)
tree28c3eaaccc8772529e1818f8287854c4e93494b7
parent725cf0e22d4f8185e8b6d182f7e8a959b77e049a (diff)
parent479b2c629610c7377db788b9de6025d02147df45 (diff)
downloadNim-821fe72ff55866737c5b1d9f356b8d142f8836c3.tar.gz
Merge branch 'devel' of https://github.com/Araq/Nimrod into devel
-rw-r--r--doc/manual.txt6
-rw-r--r--lib/pure/collections/sequtils.nim3
-rw-r--r--lib/pure/parsecfg.nim3
-rw-r--r--lib/pure/parseurl.nim4
-rw-r--r--lib/pure/strutils.nim276
-rw-r--r--lib/pure/uri.nim350
-rw-r--r--lib/system.nim26
-rw-r--r--tests/stdlib/testequivalence.nim1
-rw-r--r--web/index.txt2
-rw-r--r--web/news.txt4
-rw-r--r--web/nimrod.ini2
11 files changed, 549 insertions, 128 deletions
diff --git a/doc/manual.txt b/doc/manual.txt
index 32b0541e9..54c1477e8 100644
--- a/doc/manual.txt
+++ b/doc/manual.txt
@@ -4970,9 +4970,9 @@ or ``ref T`` or ``ptr T`` this means no locations are modified. It is a static
 error to mark a proc/iterator to have no side effect if the compiler cannot
 verify this.
 
-As a special semantic rule, the built-in ``debugEcho`` pretends to be free of 
-side effects, so that it can be used for debugging routines marked as
-``noSideEffect``.
+As a special semantic rule, the built-in `debugEcho <system.html#debugEcho>`_
+pretends to be free of side effects, so that it can be used for debugging
+routines marked as ``noSideEffect``.
 
 **Future directions**: ``func`` may become a keyword and syntactic sugar for a
 proc with no side effects:
diff --git a/lib/pure/collections/sequtils.nim b/lib/pure/collections/sequtils.nim
index e760c5e02..c50c4165b 100644
--- a/lib/pure/collections/sequtils.nim
+++ b/lib/pure/collections/sequtils.nim
@@ -186,7 +186,7 @@ proc keepIf*[T](seq1: var seq[T], pred: proc(item: T): bool {.closure.}) =
   ##
   ## .. code-block:: nimrod
   ##   var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
-  ##   filter(floats, proc(x: float): bool = x > 10)
+  ##   keepIf(floats, proc(x: float): bool = x > 10)
   ##   assert floats == @[13.0, 12.5, 10.1]
   var pos = 0
   for i in 0 .. <len(seq1):
@@ -388,6 +388,7 @@ template mapIt*(seq1, typ, pred: expr): expr =
   ##   let
   ##     nums = @[1, 2, 3, 4]
   ##     strings = nums.mapIt(string, $(4 * it))
+  ##   assert strings == @["4", "8", "12", "16"]
   var result {.gensym.}: seq[typ] = @[]
   for it {.inject.} in items(seq1):
     result.add(pred)
diff --git a/lib/pure/parsecfg.nim b/lib/pure/parsecfg.nim
index 727a8efd8..1d61a967b 100644
--- a/lib/pure/parsecfg.nim
+++ b/lib/pure/parsecfg.nim
@@ -350,7 +350,8 @@ proc next*(c: var TCfgParser): TCfgEvent {.rtl, extern: "npc$1".} =
     rawGetTok(c, c.tok)
     if c.tok.kind == tkBracketRi: 
       rawGetTok(c, c.tok)
-    else: 
+    else:
+      reset(result)
       result.kind = cfgError
       result.msg = errorStr(c, "']' expected, but found: " & c.tok.literal)
   of tkInvalid, tkEquals, tkColon, tkBracketRi: 
diff --git a/lib/pure/parseurl.nim b/lib/pure/parseurl.nim
index 357d1df0f..67c6de905 100644
--- a/lib/pure/parseurl.nim
+++ b/lib/pure/parseurl.nim
@@ -20,7 +20,7 @@ type
     scheme, username, password, 
     hostname, port, path, query, anchor: string]
     
-proc parseUrl*(url: string): TUrl =
+proc parseUrl*(url: string): TUrl {.deprecated.} =
   var i = 0
 
   var scheme, username, password: string = ""
@@ -86,7 +86,7 @@ proc parseUrl*(url: string): TUrl =
     
   return (scheme, username, password, hostname, port, path, query, anchor)
 
-proc `$`*(u: TUrl): string =
+proc `$`*(u: TUrl): string {.deprecated.} =
   ## turns the URL `u` into its string representation.
   result = ""
   if u.scheme.len > 0:
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index 51392ba50..6f8924d83 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -48,9 +48,11 @@ const
     ## the set of characters a newline terminator can start with
 
   AllChars* = {'\x00'..'\xFF'}
-    ## A set with all the possible characters. Not very useful by its own, you
-    ## can use it to create *inverted* sets to make the ``find()`` proc find
-    ## **invalid** characters in strings. Example:
+    ## A set with all the possible characters.
+    ##
+    ## Not very useful by its own, you can use it to create *inverted* sets to
+    ## make the `find() proc <#find,string,set[char],int>`_ find **invalid**
+    ## characters in strings.  Example:
     ##
     ## .. code-block:: nimrod
     ##   let invalid = AllChars - Digits
@@ -59,8 +61,11 @@ const
 
 proc toLower*(c: char): char {.noSideEffect, procvar,
   rtl, extern: "nsuToLowerChar".} =
-  ## Converts `c` into lower case. This works only for the letters A-Z.
-  ## See `unicode.toLower` for a version that works for any Unicode character.
+  ## Converts `c` into lower case.
+  ##
+  ## This works only for the letters ``A-Z``. See `unicode.toLower
+  ## <unicode.html#toLower>`_ for a version that works for any Unicode
+  ## character.
   if c in {'A'..'Z'}:
     result = chr(ord(c) + (ord('a') - ord('A')))
   else:
@@ -68,16 +73,22 @@ proc toLower*(c: char): char {.noSideEffect, procvar,
 
 proc toLower*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuToLowerStr".} =
-  ## Converts `s` into lower case. This works only for the letters A-Z.
-  ## See `unicode.toLower` for a version that works for any Unicode character.
+  ## Converts `s` into lower case.
+  ##
+  ## This works only for the letters ``A-Z``. See `unicode.toLower
+  ## <unicode.html#toLower>`_ for a version that works for any Unicode
+  ## character.
   result = newString(len(s))
   for i in 0..len(s) - 1:
     result[i] = toLower(s[i])
 
 proc toUpper*(c: char): char {.noSideEffect, procvar,
   rtl, extern: "nsuToUpperChar".} =
-  ## Converts `c` into upper case. This works only for the letters a-z.
-  ## See `unicode.toUpper` for a version that works for any Unicode character.
+  ## Converts `c` into upper case.
+  ##
+  ## This works only for the letters ``A-Z``.  See `unicode.toUpper
+  ## <unicode.html#toUpper>`_ for a version that works for any Unicode
+  ## character.
   if c in {'a'..'z'}:
     result = chr(ord(c) - (ord('a') - ord('A')))
   else:
@@ -85,8 +96,11 @@ proc toUpper*(c: char): char {.noSideEffect, procvar,
 
 proc toUpper*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuToUpperStr".} =
-  ## Converts `s` into upper case. This works only for the letters a-z.
-  ## See `unicode.toUpper` for a version that works for any Unicode character.
+  ## Converts `s` into upper case.
+  ##
+  ## This works only for the letters ``A-Z``.  See `unicode.toUpper
+  ## <unicode.html#toUpper>`_ for a version that works for any Unicode
+  ## character.
   result = newString(len(s))
   for i in 0..len(s) - 1:
     result[i] = toUpper(s[i])
@@ -94,13 +108,16 @@ proc toUpper*(s: string): string {.noSideEffect, procvar,
 proc capitalize*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuCapitalize".} =
   ## Converts the first character of `s` into upper case.
-  ## This works only for the letters a-z.
+  ##
+  ## This works only for the letters ``A-Z``.
   result = toUpper(s[0]) & substr(s, 1)
 
 proc normalize*(s: string): string {.noSideEffect, procvar,
   rtl, extern: "nsuNormalize".} =
-  ## Normalizes the string `s`. That means to convert it to lower case and
-  ## remove any '_'. This is needed for Nimrod identifiers for example.
+  ## Normalizes the string `s`.
+  ##
+  ## That means to convert it to lower case and remove any '_'. This is needed
+  ## for Nimrod identifiers for example.
   result = newString(s.len)
   var j = 0
   for i in 0..len(s) - 1:
@@ -155,6 +172,7 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
 proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
   rtl, extern: "nsuStrip", operator: 5.} =
   ## Strips whitespace from `s` and returns the resulting string.
+  ##
   ## If `leading` is true, leading whitespace is stripped.
   ## If `trailing` is true, trailing whitespace is stripped.
   const
@@ -169,8 +187,10 @@ proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
   result = substr(s, first, last)
 
 proc toOctal*(c: char): string {.noSideEffect, rtl, extern: "nsuToOctal".} =
-  ## Converts a character `c` to its octal representation. The resulting
-  ## string may not have a leading zero. Its length is always exactly 3.
+  ## Converts a character `c` to its octal representation.
+  ##
+  ## The resulting string may not have a leading zero. Its length is always
+  ## exactly 3.
   result = newString(3)
   var val = ord(c)
   for i in countdown(2, 0):
@@ -280,9 +300,11 @@ iterator split*(s: string, sep: string): string =
       inc(last, sep.len)
 
 iterator splitLines*(s: string): string =
-  ## Splits the string `s` into its containing lines. Every newline
-  ## combination (CR, LF, CR-LF) is supported. The result strings contain
-  ## no trailing ``\n``.
+  ## Splits the string `s` into its containing lines.
+  ##
+  ## Every `character literal <manual.html#character-literals>`_ newline
+  ## combination (CR, LF, CR-LF) is supported. The result strings contain no
+  ## trailing ``\n``.
   ##
   ## Example:
   ##
@@ -315,13 +337,25 @@ iterator splitLines*(s: string): string =
 
 proc splitLines*(s: string): seq[string] {.noSideEffect,
   rtl, extern: "nsuSplitLines".} =
-  ## The same as the `splitLines` iterator, but is a proc that returns a
-  ## sequence of substrings.
+  ## The same as the `splitLines <#splitLines.i,string>`_ iterator, but is a
+  ## proc that returns a sequence of substrings.
   accumulateResult(splitLines(s))
 
 proc countLines*(s: string): int {.noSideEffect,
   rtl, extern: "nsuCountLines".} =
-  ## same as ``len(splitLines(s))``, but much more efficient.
+  ## Returns the number of new line separators in the string `s`.
+  ##
+  ## This is the same as ``len(splitLines(s))``, but much more efficient
+  ## because it doesn't modify the string creating temporal objects. Every
+  ## `character literal <manual.html#character-literals>`_ newline combination
+  ## (CR, LF, CR-LF) is supported.
+  ##
+  ## Despite its name this proc might not actually return the *number of lines*
+  ## in `s` because the concept of what a line is can vary. For example, a
+  ## string like ``Hello world`` is a line of text, but the proc will return a
+  ## value of zero because there are no newline separators.  Also, text editors
+  ## usually don't count trailing newline characters in a text file as a new
+  ## empty line, but this proc will.
   var i = 0
   while i < s.len:
     case s[i]
@@ -334,28 +368,30 @@ proc countLines*(s: string): int {.noSideEffect,
 
 proc split*(s: string, seps: set[char] = Whitespace): seq[string] {.
   noSideEffect, rtl, extern: "nsuSplitCharSet".} =
-  ## The same as the `split` iterator, but is a proc that returns a
-  ## sequence of substrings.
+  ## The same as the `split iterator <#split.i,string,set[char]>`_, but is a
+  ## proc that returns a sequence of substrings.
   accumulateResult(split(s, seps))
 
 proc split*(s: string, sep: char): seq[string] {.noSideEffect,
   rtl, extern: "nsuSplitChar".} =
-  ## The same as the `split` iterator, but is a proc that returns a sequence
-  ## of substrings.
+  ## The same as the `split iterator <#split.i,string,char>`_, but is a proc
+  ## that returns a sequence of substrings.
   accumulateResult(split(s, sep))
 
 proc split*(s: string, sep: string): seq[string] {.noSideEffect,
   rtl, extern: "nsuSplitString".} =
   ## Splits the string `s` into substrings using a string separator.
   ##
-  ## Substrings are separated by the string `sep`.
+  ## Substrings are separated by the string `sep`. This is a wrapper around the
+  ## `split iterator <#split.i,string,string>`_.
   accumulateResult(split(s, sep))
 
 proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
   rtl, extern: "nsuToHex".} =
-  ## Converts `x` to its hexadecimal representation. The resulting string
-  ## will be exactly `len` characters long. No prefix like ``0x``
-  ## is generated. `x` is treated as an unsigned value.
+  ## Converts `x` to its hexadecimal representation.
+  ##
+  ## The resulting string will be exactly `len` characters long. No prefix like
+  ## ``0x`` is generated. `x` is treated as an unsigned value.
   const
     HexChars = "0123456789ABCDEF"
   var
@@ -367,9 +403,10 @@ proc toHex*(x: BiggestInt, len: int): string {.noSideEffect,
 
 proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,
   rtl, extern: "nsuIntToStr".} =
-  ## Converts `x` to its decimal representation. The resulting string
-  ## will be minimally `minchars` characters long. This is achieved by
-  ## adding leading zeros.
+  ## Converts `x` to its decimal representation.
+  ##
+  ## The resulting string will be minimally `minchars` characters long. This is
+  ## achieved by adding leading zeros.
   result = $abs(x)
   for i in 1 .. minchars - len(result):
     result = '0' & result
@@ -378,16 +415,18 @@ proc intToStr*(x: int, minchars: int = 1): string {.noSideEffect,
 
 proc parseInt*(s: string): int {.noSideEffect, procvar,
   rtl, extern: "nsuParseInt".} =
-  ## Parses a decimal integer value contained in `s`. If `s` is not
-  ## a valid integer, `EInvalidValue` is raised.
+  ## Parses a decimal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `EInvalidValue` is raised.
   var L = parseutils.parseInt(s, result, 0)
   if L != s.len or L == 0:
     raise newException(EInvalidValue, "invalid integer: " & s)
 
 proc parseBiggestInt*(s: string): BiggestInt {.noSideEffect, procvar,
   rtl, extern: "nsuParseBiggestInt".} =
-  ## Parses a decimal integer value contained in `s`. If `s` is not
-  ## a valid integer, `EInvalidValue` is raised.
+  ## Parses a decimal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `EInvalidValue` is raised.
   var L = parseutils.parseBiggestInt(s, result, 0)
   if L != s.len or L == 0:
     raise newException(EInvalidValue, "invalid integer: " & s)
@@ -403,10 +442,11 @@ proc parseFloat*(s: string): float {.noSideEffect, procvar,
 
 proc parseHexInt*(s: string): int {.noSideEffect, procvar,
   rtl, extern: "nsuParseHexInt".} =
-  ## Parses a hexadecimal integer value contained in `s`. If `s` is not
-  ## a valid integer, `EInvalidValue` is raised. `s` can have one of the
-  ## following optional prefixes: ``0x``, ``0X``, ``#``.
-  ## Underscores within `s` are ignored.
+  ## Parses a hexadecimal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `EInvalidValue` is raised. `s` can have one
+  ## of the following optional prefixes: ``0x``, ``0X``, ``#``.  Underscores
+  ## within `s` are ignored.
   var i = 0
   if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
   elif s[i] == '#': inc(i)
@@ -426,26 +466,32 @@ proc parseHexInt*(s: string): int {.noSideEffect, procvar,
     else: raise newException(EInvalidValue, "invalid integer: " & s)
 
 proc parseBool*(s: string): bool =
-  ## Parses a value into a `bool`. If ``s`` is one of the following values:
-  ## ``y, yes, true, 1, on``, then returns `true`. If ``s`` is one of the
-  ## following values: ``n, no, false, 0, off``, then returns `false`.
-  ## If ``s`` is something else a ``EInvalidValue`` exception is raised.
+  ## Parses a value into a `bool`.
+  ##
+  ## If ``s`` is one of the following values: ``y, yes, true, 1, on``, then
+  ## returns `true`. If ``s`` is one of the following values: ``n, no, false,
+  ## 0, off``, then returns `false`.  If ``s`` is something else a
+  ## ``EInvalidValue`` exception is raised.
   case normalize(s)
   of "y", "yes", "true", "1", "on": result = true
   of "n", "no", "false", "0", "off": result = false
   else: raise newException(EInvalidValue, "cannot interpret as a bool: " & s)
 
 proc parseEnum*[T: enum](s: string): T =
-  ## parses an enum ``T``. Raises ``EInvalidValue`` for an invalid value in 
-  ## `s`. The comparison is done in a style insensitive way.
+  ## Parses an enum ``T``.
+  ##
+  ## Raises ``EInvalidValue`` for an invalid value in `s`. The comparison is
+  ## done in a style insensitive way.
   for e in low(T)..high(T):
     if cmpIgnoreStyle(s, $e) == 0:
       return e
   raise newException(EInvalidValue, "invalid enum value: " & s)
 
 proc parseEnum*[T: enum](s: string, default: T): T =
-  ## parses an enum ``T``. Uses `default` for an invalid value in 
-  ## `s`. The comparison is done in a style insensitive way.
+  ## Parses an enum ``T``.
+  ##
+  ## Uses `default` for an invalid value in `s`. The comparison is done in a
+  ## style insensitive way.
   for e in low(T)..high(T):
     if cmpIgnoreStyle(s, $e) == 0:
       return e
@@ -475,10 +521,11 @@ proc repeatStr*(count: int, s: string): string {.noSideEffect,
 proc align*(s: string, count: int, padding = ' '): string {.
   noSideEffect, rtl, extern: "nsuAlignString".} =
   ## Aligns a string `s` with `padding`, so that is of length `count`.
+  ##
   ## `padding` characters (by default spaces) are added before `s` resulting in
   ## right alignment. If ``s.len >= count``, no spaces are added and `s` is
-  ## returned unchanged. If you need to left align a string use the
-  ## ``repeatChar`` proc. Example:
+  ## returned unchanged. If you need to left align a string use the `repeatChar
+  ## proc <#repeatChar>`_. Example:
   ##
   ## .. code-block:: nimrod
   ##   assert align("abc", 4) == " abc"
@@ -532,7 +579,7 @@ proc wordWrap*(s: string, maxLineWidth = 80,
                seps: set[char] = Whitespace,
                newLine = "\n"): string {.
                noSideEffect, rtl, extern: "nsuWordWrap".} =
-  ## word wraps `s`.
+  ## Word wraps `s`.
   result = newStringOfCap(s.len + s.len shr 6)
   var spaceLeft = maxLineWidth
   var lastSep = ""
@@ -564,7 +611,7 @@ proc wordWrap*(s: string, maxLineWidth = 80,
 
 proc unindent*(s: string, eatAllIndent = false): string {.
                noSideEffect, rtl, extern: "nsuUnindent".} =
-  ## unindents `s`.
+  ## Unindents `s`.
   result = newStringOfCap(s.len)
   var i = 0
   var pattern = true
@@ -592,6 +639,7 @@ proc unindent*(s: string, eatAllIndent = false): string {.
 proc startsWith*(s, prefix: string): bool {.noSideEffect,
   rtl, extern: "nsuStartsWith".} =
   ## Returns true iff ``s`` starts with ``prefix``.
+  ##
   ## If ``prefix == ""`` true is returned.
   var i = 0
   while true:
@@ -602,6 +650,7 @@ proc startsWith*(s, prefix: string): bool {.noSideEffect,
 proc endsWith*(s, suffix: string): bool {.noSideEffect,
   rtl, extern: "nsuEndsWith".} =
   ## Returns true iff ``s`` ends with ``suffix``.
+  ##
   ## If ``suffix == ""`` true is returned.
   var i = 0
   var j = len(s) - len(suffix)
@@ -613,6 +662,7 @@ proc endsWith*(s, suffix: string): bool {.noSideEffect,
 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:
@@ -622,6 +672,8 @@ proc continuesWith*(s, substr: string, start: int): bool {.noSideEffect,
 
 proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
                                                            inline.} =
+  ## Adds a separator to `dest` only if its length is bigger than `startLen`.
+  ##
   ## A shorthand for:
   ##
   ## .. code-block:: nimrod
@@ -641,15 +693,15 @@ proc addSep*(dest: var string, sep = ", ", startLen = 0) {.noSideEffect,
   if dest.len > startLen: add(dest, sep)
 
 proc allCharsInSet*(s: string, theSet: TCharSet): bool =
-  ## returns true iff each character of `s` is in the set `theSet`.
+  ## Returns true iff each character of `s` is in the set `theSet`.
   for c in items(s):
     if c notin theSet: return false
   return true
 
 proc abbrev*(s: string, possibilities: openArray[string]): int =
-  ## returns the index of the first item in `possibilities` if not
-  ## ambiguous; -1 if no item has been found; -2 if multiple items
-  ## match.
+  ## Returns the index of the first item in `possibilities` if not ambiguous.
+  ##
+  ## Returns -1 if no item has been found and -2 if multiple items match.
   result = -1 # none found
   for i in 0..possibilities.len-1:
     if possibilities[i].startsWith(s):
@@ -663,7 +715,7 @@ proc abbrev*(s: string, possibilities: openArray[string]): int =
 
 proc join*(a: openArray[string], sep: string): string {.
   noSideEffect, rtl, extern: "nsuJoinSep".} =
-  ## concatenates all strings in `a` separating them with `sep`.
+  ## Concatenates all strings in `a` separating them with `sep`.
   if len(a) > 0:
     var L = sep.len * (a.len-1)
     for i in 0..high(a): inc(L, a[i].len)
@@ -677,7 +729,7 @@ proc join*(a: openArray[string], sep: string): string {.
 
 proc join*(a: openArray[string]): string {.
   noSideEffect, rtl, extern: "nsuJoin".} =
-  ## concatenates all strings in `a`.
+  ## Concatenates all strings in `a`.
   if len(a) > 0:
     var L = 0
     for i in 0..high(a): inc(L, a[i].len)
@@ -695,7 +747,7 @@ proc preprocessSub(sub: string, a: var TSkipTable) =
   for i in 0..m-1: a[sub[i]] = m-i
 
 proc findAux(s, sub: string, start: int, a: TSkipTable): int =
-  # fast "quick search" algorithm:
+  # Fast "quick search" algorithm:
   var
     m = len(sub)
     n = len(s)
@@ -711,32 +763,36 @@ proc findAux(s, sub: string, start: int, a: TSkipTable): int =
 
 proc find*(s, sub: string, start: int = 0): int {.noSideEffect,
   rtl, extern: "nsuFindStr", operator: 6.} =
-  ## Searches for `sub` in `s` starting at position `start`. Searching is
-  ## case-sensitive. If `sub` is not in `s`, -1 is returned.
+  ## Searches for `sub` in `s` starting at position `start`.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
   var a {.noinit.}: TSkipTable
   preprocessSub(sub, a)
   result = findAux(s, sub, start, a)
 
 proc find*(s: string, sub: char, start: int = 0): int {.noSideEffect,
   rtl, extern: "nsuFindChar".} =
-  ## Searches for `sub` in `s` starting at position `start`. Searching is
-  ## case-sensitive. If `sub` is not in `s`, -1 is returned.
+  ## Searches for `sub` in `s` starting at position `start`.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
   for i in start..len(s)-1:
     if sub == s[i]: return i
   return -1
 
 proc find*(s: string, chars: set[char], start: int = 0): int {.noSideEffect,
   rtl, extern: "nsuFindCharSet".} =
-  ## Searches for `chars` in `s` starting at position `start`. If `s` contains
-  ## none of the characters in `chars`, -1 is returned.
+  ## Searches for `chars` in `s` starting at position `start`.
+  ##
+  ## If `s` contains none of the characters in `chars`, -1 is returned.
   for i in start..s.len-1:
     if s[i] in chars: return i
   return -1
 
 proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
   ## Searches for `sub` in `s` in reverse, starting at `start` and going
-  ## backwards to 0. Searching is case-sensitive. If `sub` is not in `s`, -1 is
-  ## returned.
+  ## backwards to 0.
+  ##
+  ## Searching is case-sensitive. If `sub` is not in `s`, -1 is returned.
   let realStart = if start == -1: s.len else: start
   for i in countdown(realStart-sub.len, 0):
     for j in 0..sub.len-1:
@@ -748,10 +804,11 @@ proc rfind*(s, sub: string, start: int = -1): int {.noSideEffect.} =
   return -1
 
 proc quoteIfContainsWhite*(s: string): string {.deprecated.} =
-  ## returns ``'"' & s & '"'`` if `s` contains a space and does not
-  ## start with a quote, else returns `s`
-  ## DEPRECATED as it was confused for shell quoting function.
-  ## For this application use osproc.quoteShell.
+  ## Returns ``'"' & s & '"'`` if `s` contains a space and does not
+  ## start with a quote, else returns `s`.
+  ##
+  ## **DEPRECATED** as it was confused for shell quoting function.  For this
+  ## application use `osproc.quoteShell <osproc.html#quoteShell>`_.
   if find(s, {' ', '\t'}) >= 0 and s[0] != '"':
     result = '"' & s & '"'
   else:
@@ -787,7 +844,9 @@ proc replace*(s, sub: string, by = ""): string {.noSideEffect,
 
 proc replace*(s: string, sub, by: char): string {.noSideEffect,
   rtl, extern: "nsuReplaceChar".} =
-  ## optimized version for characters.
+  ## Replaces `sub` in `s` by the character `by`.
+  ##
+  ## Optimized version of `replace <#replace,string,string>`_ for characters.
   result = newString(s.len)
   var i = 0
   while i < s.len:
@@ -797,9 +856,11 @@ proc replace*(s: string, sub, by: char): string {.noSideEffect,
 
 proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
   rtl, extern: "nsuReplaceWord".} =
-  ## Replaces `sub` in `s` by the string `by`. Each occurance of `sub`
-  ## has to be surrounded by word boundaries (comparable to ``\\w`` in
-  ## regular expressions), otherwise it is not replaced.
+  ## Replaces `sub` in `s` by the string `by`.
+  ##
+  ## Each occurance of `sub` has to be surrounded by word boundaries
+  ## (comparable to ``\\w`` in regular expressions), otherwise it is not
+  ## replaced.
   const wordChars = {'a'..'z', 'A'..'Z', '0'..'9', '_', '\128'..'\255'}
   var a {.noinit.}: TSkipTable
   result = ""
@@ -822,8 +883,9 @@ proc replaceWord*(s, sub: string, by = ""): string {.noSideEffect,
 
 proc delete*(s: var string, first, last: int) {.noSideEffect,
   rtl, extern: "nsuDelete".} =
-  ## Deletes in `s` the characters at position `first` .. `last`. This modifies
-  ## `s` itself, it does not return a copy.
+  ## Deletes in `s` the characters at position `first` .. `last`.
+  ##
+  ## This modifies `s` itself, it does not return a copy.
   var i = first
   var j = last+1
   var newLen = len(s)-j+i
@@ -835,10 +897,11 @@ proc delete*(s: var string, first, last: int) {.noSideEffect,
 
 proc parseOctInt*(s: string): int {.noSideEffect,
   rtl, extern: "nsuParseOctInt".} =
-  ## Parses an octal integer value contained in `s`. If `s` is not
-  ## a valid integer, `EInvalidValue` is raised. `s` can have one of the
-  ## following optional prefixes: ``0o``, ``0O``.
-  ## Underscores within `s` are ignored.
+  ## Parses an octal integer value contained in `s`.
+  ##
+  ## If `s` is not a valid integer, `EInvalidValue` is raised. `s` can have one
+  ## of the following optional prefixes: ``0o``, ``0O``.  Underscores within
+  ## `s` are ignored.
   var i = 0
   if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
   while true:
@@ -852,8 +915,10 @@ proc parseOctInt*(s: string): int {.noSideEffect,
 
 proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
   rtl, extern: "nsuToOct".} =
-  ## converts `x` into its octal representation. The resulting string is
-  ## always `len` characters long. No leading ``0o`` prefix is generated.
+  ## Converts `x` into its octal representation.
+  ##
+  ## The resulting string is always `len` characters long. No leading ``0o``
+  ## prefix is generated.
   var
     mask: BiggestInt = 7
     shift: BiggestInt = 0
@@ -866,8 +931,10 @@ proc toOct*(x: BiggestInt, len: int): string {.noSideEffect,
 
 proc toBin*(x: BiggestInt, len: int): string {.noSideEffect,
   rtl, extern: "nsuToBin".} =
-  ## converts `x` into its binary representation. The resulting string is
-  ## always `len` characters long. No leading ``0b`` prefix is generated.
+  ## Converts `x` into its binary representation.
+  ##
+  ## The resulting string is always `len` characters long. No leading ``0b``
+  ## prefix is generated.
   var
     mask: BiggestInt = 1
     shift: BiggestInt = 0
@@ -880,7 +947,8 @@ proc toBin*(x: BiggestInt, len: int): string {.noSideEffect,
 
 proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect,
   rtl, extern: "nsuInsertSep".} =
-  ## inserts the separator `sep` after `digits` digits from right to left.
+  ## Inserts the separator `sep` after `digits` digits from right to left.
+  ##
   ## Even though the algorithm works with any string `s`, it is only useful
   ## if `s` contains a number.
   ## Example: ``insertSep("1000000") == "1_000_000"``
@@ -899,7 +967,9 @@ proc insertSep*(s: string, sep = '_', digits = 3): string {.noSideEffect,
 
 proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   rtl, extern: "nsuEscape".} =
-  ## Escapes a string `s`. This does these operations (at the same time):
+  ## Escapes a string `s`.
+  ##
+  ## This does these operations (at the same time):
   ## * replaces any ``\`` by ``\\``
   ## * replaces any ``'`` by ``\'``
   ## * replaces any ``"`` by ``\"``
@@ -923,11 +993,13 @@ proc escape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
 
 proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
   rtl, extern: "nsuUnescape".} =
-  ## Unescapes a string `s`. This complements ``escape`` as it performs the
-  ## opposite operations.
+  ## Unescapes a string `s`.
+  ##
+  ## This complements `escape <#escape>`_ as it performs the opposite
+  ## operations.
   ##
-  ## If `s` does not begin with ``prefix`` and end with ``suffix`` a EInvalidValue
-  ## exception will be raised.
+  ## If `s` does not begin with ``prefix`` and end with ``suffix`` a
+  ## EInvalidValue exception will be raised.
   result = newStringOfCap(s.len)
   var i = 0
   if s[0 .. prefix.len-1] != prefix:
@@ -961,9 +1033,10 @@ proc unescape*(s: string, prefix = "\"", suffix = "\""): string {.noSideEffect,
 
 proc validIdentifier*(s: string): bool {.noSideEffect,
   rtl, extern: "nsuValidIdentifier".} =
-  ## returns true if `s` is a valid identifier. A valid identifier starts
-  ## with a character of the set `IdentStartChars` and is followed by any
-  ## number of characters of the set `IdentChars`.
+  ## Returns true if `s` is a valid identifier.
+  ##
+  ## A valid identifier starts with a character of the set `IdentStartChars`
+  ## and is followed by any number of characters of the set `IdentChars`.
   if s[0] in IdentStartChars:
     for i in 1..s.len-1:
       if s[i] notin IdentChars: return false
@@ -971,9 +1044,10 @@ proc validIdentifier*(s: string): bool {.noSideEffect,
 
 proc editDistance*(a, b: string): int {.noSideEffect,
   rtl, extern: "nsuEditDistance".} =
-  ## returns the edit distance between `a` and `b`. This uses the 
-  ## `Levenshtein`:idx: distance algorithm with only a linear memory overhead.
-  ## This implementation is highly optimized!
+  ## Returns the edit distance between `a` and `b`.
+  ##
+  ## This uses the `Levenshtein`:idx: distance algorithm with only a linear
+  ## memory overhead.  This implementation is highly optimized!
   var len1 = a.len
   var len2 = b.len
   if len1 > len2:
@@ -1072,7 +1146,7 @@ type
 proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
                          precision: range[0..32] = 16): string {.
                          noSideEffect, operator: 2, rtl, extern: "nsu$1".} =
-  ## converts a floating point value `f` to a string.
+  ## Converts a floating point value `f` to a string.
   ##
   ## If ``format == ffDecimal`` then precision is the number of digits to
   ## be printed after the decimal point.
@@ -1103,7 +1177,7 @@ proc formatBiggestFloat*(f: BiggestFloat, format: TFloatFormat = ffDefault,
 proc formatFloat*(f: float, format: TFloatFormat = ffDefault,
                   precision: range[0..32] = 16): string {.
                   noSideEffect, operator: 2, rtl, extern: "nsu$1".} =
-  ## converts a floating point value `f` to a string.
+  ## Converts a floating point value `f` to a string.
   ##
   ## If ``format == ffDecimal`` then precision is the number of digits to
   ## be printed after the decimal point.
@@ -1198,6 +1272,8 @@ proc addf*(s: var string, formatstr: string, a: varargs[string, `$`]) {.
 
 proc `%` *(formatstr: string, a: openArray[string]): string {.noSideEffect,
   rtl, extern: "nsuFormatOpenArray".} =
+  ## Interpolates a format string with the values from `a`.
+  ##
   ## The `substitution`:idx: operator performs string substitutions in
   ## `formatstr` and returns a modified `formatstr`. This is often called
   ## `string interpolation`:idx:.
diff --git a/lib/pure/uri.nim b/lib/pure/uri.nim
index ee1226a35..7ec823033 100644
--- a/lib/pure/uri.nim
+++ b/lib/pure/uri.nim
@@ -7,17 +7,24 @@
 #    distribution, for details about the copyright.
 #
 
-## **Note**: This module will be deprecated in the future and merged into a
-## new ``url`` module.
+## This module implements URI parsing as specified by RFC 3986.
 
-import strutils
+import strutils, parseutils
 type
   TUrl* = distinct string
 
-proc `$`*(url: TUrl): string = return string(url)
+  TUri* = object
+    scheme*, username*, password*: string 
+    hostname*, port*, path*, query*, anchor*: string
 
-proc `/`*(a, b: TUrl): TUrl =
+proc `$`*(url: TUrl): string {.deprecated.} =
+  ## **Deprecated since 0.9.6**: Use ``TUri`` instead.
+  return string(url)
+
+proc `/`*(a, b: TUrl): TUrl {.deprecated.} =
   ## Joins two URLs together, separating them with / if needed.
+  ##
+  ## **Deprecated since 0.9.6**: Use ``TUri`` instead.
   var urlS = $a
   var bS = $b
   if urlS == "": return b
@@ -29,9 +36,338 @@ proc `/`*(a, b: TUrl): TUrl =
     urlS.add(bs)
   result = TUrl(urlS)
 
-proc add*(url: var TUrl, a: TUrl) =
+proc add*(url: var TUrl, a: TUrl) {.deprecated.} =
   ## Appends url to url.
+  ##
+  ## **Deprecated since 0.9.6**: Use ``TUri`` instead.
   url = url / a
 
+proc parseAuthority(authority: string, result: var TUri) =
+  var i = 0
+  var inPort = false
+  while true:
+    case authority[i]
+    of '@':
+      result.password = result.port
+      result.port = ""
+      result.username = result.hostname
+      result.hostname = ""
+      inPort = false
+    of ':':
+      inPort = true
+    of '\0': break
+    else:
+      if inPort:
+        result.port.add(authority[i])
+      else:
+        result.hostname.add(authority[i])
+    i.inc
+
+proc parsePath(uri: string, i: var int, result: var TUri) =
+  
+  i.inc parseUntil(uri, result.path, {'?', '#'}, i)
+
+  # The 'mailto' scheme's PATH actually contains the hostname/username
+  if result.scheme.ToLower() == "mailto":
+    parseAuthority(result.path, result)
+    result.path = ""
+
+  if uri[i] == '?':
+    i.inc # Skip '?'
+    i.inc parseUntil(uri, result.query, {'#'}, i)
+
+  if uri[i] == '#':
+    i.inc # Skip '#'
+    i.inc parseUntil(uri, result.anchor, {}, i)
+
+proc initUri(): TUri =
+  result = TUri(scheme: "", username: "", password: "", hostname: "", port: "",
+                path: "", query: "", anchor: "")
+
+proc parseUri*(uri: string): TUri =
+  ## Parses a URI.
+  result = initUri()
+
+  var i = 0
+
+  # Check if this is a reference URI (relative URI)
+  if uri[i] == '/':
+    parsePath(uri, i, result)
+    return
+
+  # Scheme
+  i.inc parseWhile(uri, result.scheme, Letters + Digits + {'+', '-', '.'}, i)
+  if uri[i] != ':':
+    # Assume this is a reference URI (relative URI)
+    i = 0
+    result.scheme = ""
+    parsePath(uri, i, result)
+    return
+  i.inc # Skip ':'
+
+  # Authority
+  if uri[i] == '/' and uri[i+1] == '/':
+    i.inc(2) # Skip //
+    var authority = ""
+    i.inc parseUntil(uri, authority, {'/', '?', '#'}, i)
+    if authority == "":
+      raise newException(EInvalidValue, "Expected authority got nothing.")
+    parseAuthority(authority, result)
+
+  # Path
+  parsePath(uri, i, result)
+
+proc removeDotSegments(path: string): string =
+  var collection: seq[string] = @[]
+  let endsWithSlash = path[path.len-1] == '/'
+  var i = 0
+  var currentSegment = ""
+  while true:
+    case path[i]
+    of '/':
+      collection.add(currentSegment)
+      currentSegment = ""
+    of '.':
+      if path[i+1] == '.' and path[i+2] == '/':
+        if collection.len > 0:
+          discard collection.pop()
+          i.inc 3
+          continue
+      elif path[i+1] == '/':
+        i.inc 2
+        continue
+      currentSegment.add path[i]
+    of '\0':
+      if currentSegment != "":
+        collection.add currentSegment
+      break
+    else:
+      currentSegment.add path[i]
+    i.inc
+
+  result = collection.join("/")
+  if endsWithSlash: result.add '/'
+
+proc merge(base, reference: TUri): string =
+  # http://tools.ietf.org/html/rfc3986#section-5.2.3
+  if base.hostname != "" and base.path == "":
+    '/' & reference.path
+  else:
+    let lastSegment = rfind(base.path, "/")
+    if lastSegment == -1:
+      reference.path
+    else:
+      base.path[0 .. lastSegment] & reference.path
+
+proc combine*(base: TUri, reference: TUri): TUri =
+  ## Combines a base URI with a reference URI.
+  ##
+  ## This uses the algorithm specified in
+  ## `section 5.2.2 of RFC 3986 <http://tools.ietf.org/html/rfc3986#section-5.2.2>`_.
+  ##
+  ## This means that the slashes inside the base URI's path as well as reference
+  ## URI's path affect the resulting URI.
+  ##
+  ## For building URIs you may wish to use \`/\` instead.
+  ##
+  ## Examples:
+  ##
+  ## .. code-block:: nimrod
+  ##   let foo = combine(parseUri("http://example.com/foo/bar"), parseUri("/baz"))
+  ##   assert foo.path == "/baz"
+  ##
+  ##   let bar = combine(parseUri("http://example.com/foo/bar"), parseUri("baz"))
+  ##   assert foo.path == "/foo/baz"
+  ##
+  ##   let bar = combine(parseUri("http://example.com/foo/bar/"), parseUri("baz"))
+  ##   assert foo.path == "/foo/bar/baz"
+  
+  template setAuthority(dest, src: expr): stmt =
+    dest.hostname = src.hostname
+    dest.username = src.username
+    dest.port = src.port
+    dest.password = src.password
+
+  result = initUri()
+  if reference.scheme != base.scheme and reference.scheme != "":
+    result = reference
+    result.path = removeDotSegments(result.path)
+  else:
+    if reference.hostname != "":
+      setAuthority(result, reference)
+      result.path = removeDotSegments(reference.path)
+      result.query = reference.query
+    else:
+      if reference.path == "":
+        result.path = base.path
+        if reference.query != "":
+          result.query = reference.query
+        else:
+          result.query = base.query
+      else:
+        if reference.path.startsWith("/"):
+          result.path = removeDotSegments(reference.path)
+        else:
+          result.path = removeDotSegments(merge(base, reference))
+        result.query = reference.query
+      setAuthority(result, base)
+    result.scheme = base.scheme
+  result.anchor = reference.anchor
+
+proc combine*(uris: varargs[TUri]): TUri =
+  ## Combines multiple URIs together.
+  result = uris[0]
+  for i in 1 .. <uris.len:
+    result = combine(result, uris[i])
+
+proc `/`*(x: TUri, path: string): TUri =
+  ## Concatenates the path specified to the specified URI's path.
+  ##
+  ## Contrary to the ``combine`` procedure you do not have to worry about
+  ## the slashes at the beginning and end of the path and URI's path
+  ## respectively.
+  ##
+  ## Examples:
+  ##
+  ## .. code-block:: nimrod
+  ##   let foo = parseUri("http://example.com/foo/bar") / parseUri("/baz")
+  ##   assert foo.path == "/foo/bar/baz"
+  ##
+  ##   let bar = parseUri("http://example.com/foo/bar") / parseUri("baz")
+  ##   assert foo.path == "/foo/bar/baz"
+  ##
+  ##   let bar = parseUri("http://example.com/foo/bar/") / parseUri("baz")
+  ##   assert foo.path == "/foo/bar/baz"
+  result = x
+  if result.path[result.path.len-1] == '/':
+    if path[0] == '/':
+      result.path.add(path[1 .. path.len-1])
+    else:
+      result.path.add(path)
+  else:
+    if path[0] != '/':
+      result.path.add '/'
+    result.path.add(path)
+
+proc `$`*(u: TUri): string =
+  ## Returns the string representation of the specified URI object.
+  result = ""
+  if u.scheme.len > 0:
+    result.add(u.scheme)
+    result.add("://")
+  if u.username.len > 0:
+    result.add(u.username)
+    if u.password.len > 0:
+      result.add(":")
+      result.add(u.password)
+    result.add("@")
+  result.add(u.hostname)
+  if u.port.len > 0:
+    result.add(":")
+    result.add(u.port)
+  if u.path.len > 0:
+    if u.path[0] != '/': result.add("/")
+    result.add(u.path)
+  result.add(u.query)
+  result.add(u.anchor)
+
 when isMainModule:
-  assert($("http://".TUrl / "localhost:5000".TUrl) == "http://localhost:5000")
+  block:
+    let test = parseUri("http://localhost:8080/test")
+    doAssert test.scheme == "http"
+    doAssert test.port == "8080"
+    doAssert test.path == "/test"
+    doAssert test.hostname == "localhost"
+
+  block:
+    let test = parseUri("foo://username:password@example.com:8042/over/there" &
+                        "/index.dtb?type=animal&name=narwhal#nose")
+    doAssert test.scheme == "foo"
+    doAssert test.username == "username"
+    doAssert test.password == "password"
+    doAssert test.hostname == "example.com"
+    doAssert test.port == "8042"
+    doAssert test.path == "/over/there/index.dtb"
+    doAssert test.query == "type=animal&name=narwhal"
+    doAssert test.anchor == "nose"
+
+  block:
+    let test = parseUri("urn:example:animal:ferret:nose")
+    doAssert test.scheme == "urn"
+    doAssert test.path == "example:animal:ferret:nose"
+
+  block:
+    let test = parseUri("mailto:username@example.com?subject=Topic")
+    doAssert test.scheme == "mailto"
+    doAssert test.username == "username"
+    doAssert test.hostname == "example.com"
+    doAssert test.query == "subject=Topic"
+
+  block:
+    let test = parseUri("magnet:?xt=urn:sha1:72hsga62ba515sbd62&dn=foobar")
+    doAssert test.scheme == "magnet"
+    doAssert test.query == "xt=urn:sha1:72hsga62ba515sbd62&dn=foobar"
+
+  block:
+    let test = parseUri("/test/foo/bar?q=2#asdf")
+    doAssert test.scheme == ""
+    doAssert test.path == "/test/foo/bar"
+    doAssert test.query == "q=2"
+    doAssert test.anchor == "asdf"
+
+  block:
+    let test = parseUri("test/no/slash")
+    doAssert test.path == "test/no/slash"
+
+  # Remove dot segments tests
+  block:
+    doAssert removeDotSegments("/foo/bar/baz") == "/foo/bar/baz"
+
+  # Combine tests
+  block:
+    let concat = combine(parseUri("http://google.com/foo/bar/"), parseUri("baz"))
+    doAssert concat.path == "/foo/bar/baz"
+    doAssert concat.hostname == "google.com"
+    doAssert concat.scheme == "http"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo"), parseUri("/baz"))
+    doAssert concat.path == "/baz"
+    doAssert concat.hostname == "google.com"
+    doAssert concat.scheme == "http"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+    doAssert concat.path == "/foo/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test"), parseUri("/bar"))
+    doAssert concat.path == "/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test"), parseUri("bar"))
+    doAssert concat.path == "/foo/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar"))
+    doAssert concat.path == "/foo/test/bar"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"))
+    doAssert concat.path == "/foo/test/bar/"
+
+  block:
+    let concat = combine(parseUri("http://google.com/foo/test/"), parseUri("bar/"),
+                         parseUri("baz"))
+    doAssert concat.path == "/foo/test/bar/baz"
+
+  # `/` tests
+  block:
+    let test = parseUri("http://example.com/foo") / "bar/asd"
+    doAssert test.path == "/foo/bar/asd"
+
+  block:
+    let test = parseUri("http://example.com/foo/") / "/bar/asd"
+    doAssert test.path == "/foo/bar/asd"
+
+  
diff --git a/lib/system.nim b/lib/system.nim
index 0a16efbb5..753205777 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -783,7 +783,7 @@ proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} =
   result = s.a <= value and value <= s.b
 
 template `in` * (x, y: expr): expr {.immediate.} = contains(y, x)
-  ## Suger for contains
+  ## Sugar for contains
   ##
   ## .. code-block:: Nimrod
   ##   assert(1 in (1..3) == true)
@@ -1052,7 +1052,7 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
   ## containers should also call their adding proc `add` for consistency.
   ## Generic code becomes much easier to write if the Nimrod naming scheme is
   ## respected.
-  var xl = x.len
+  let xl = x.len
   setLen(x, xl + y.len)
   for i in 0..high(y): x[xl+i] = y[i]
 
@@ -1066,20 +1066,20 @@ proc shallowCopy*[T](x: var T, y: T) {.noSideEffect, magic: "ShallowCopy".}
 proc del*[T](x: var seq[T], i: int) {.noSideEffect.} = 
   ## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
   ## This is an O(1) operation.
-  var xl = x.len
+  let xl = x.len
   shallowCopy(x[i], x[xl-1])
   setLen(x, xl-1)
   
 proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} = 
   ## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
   ## This is an O(n) operation.
-  var xl = x.len
+  let xl = x.len
   for j in i..xl-2: shallowCopy(x[j], x[j+1]) 
   setLen(x, xl-1)
   
 proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} = 
   ## inserts `item` into `x` at position `i`.
-  var xl = x.len
+  let xl = x.len
   setLen(x, xl+1)
   var j = xl-1
   while j >= i:
@@ -2026,19 +2026,25 @@ elif hostOS != "standalone":
   {.pop.}
 
 proc echo*[T](x: varargs[T, `$`]) {.magic: "Echo", tags: [FWriteIO], gcsafe.}
-  ## special built-in that takes a variable number of arguments. Each argument
+  ## Writes and flushes the parameters to the standard output.
+  ##
+  ## Special built-in that takes a variable number of arguments. Each argument
   ## is converted to a string via ``$``, so it works for user-defined
   ## types that have an overloaded ``$`` operator.
   ## It is roughly equivalent to ``writeln(stdout, x); flush(stdout)``, but
   ## available for the JavaScript target too.
+  ##
   ## Unlike other IO operations this is guaranteed to be thread-safe as
-  ## ``echo`` is very often used for debugging convenience.
+  ## ``echo`` is very often used for debugging convenience. If you want to use
+  ## ``echo`` inside a `proc without side effects
+  ## <manual.html#nosideeffect-pragma>`_ you can use `debugEcho <#debugEcho>`_
+  ## instead.
 
 proc debugEcho*[T](x: varargs[T, `$`]) {.magic: "Echo", noSideEffect, 
                                          tags: [], raises: [].}
-  ## Same as ``echo``, but as a special semantic rule, ``debugEcho`` pretends
-  ## to be free of side effects, so that it can be used for debugging routines
-  ## marked as ``noSideEffect``.
+  ## Same as `echo <#echo>`_, but as a special semantic rule, ``debugEcho``
+  ## pretends to be free of side effects, so that it can be used for debugging
+  ## routines marked as `noSideEffect <manual.html#nosideeffect-pragma>`_.
 
 template newException*(exceptn: typedesc, message: string): expr =
   ## creates an exception object of type ``exceptn`` and sets its ``msg`` field
diff --git a/tests/stdlib/testequivalence.nim b/tests/stdlib/testequivalence.nim
index 7c5d9e3e9..7acaad340 100644
--- a/tests/stdlib/testequivalence.nim
+++ b/tests/stdlib/testequivalence.nim
@@ -1,7 +1,6 @@
 discard """
   output: ''''''
 """
-import unittest
 import sets
 
 doAssert(toSet(@[1,2,3]) <= toSet(@[1,2,3,4]), "equivalent or subset")
diff --git a/web/index.txt b/web/index.txt
index c3459d56b..947ebb706 100644
--- a/web/index.txt
+++ b/web/index.txt
@@ -101,5 +101,5 @@ Roadmap to 1.0
 ==============
 
 Please have a look at
-this `wiki page <https://github.com/Araq/Nimrod/wiki/Feature-Matrix>`_ for
+this `wiki page <https://github.com/Araq/Nimrod/wiki/Roadmap>`_ for
 an up-to-date overview.
diff --git a/web/news.txt b/web/news.txt
index a913c94ad..62a923dcd 100644
--- a/web/news.txt
+++ b/web/news.txt
@@ -18,6 +18,8 @@ News
   - ``pas2nim`` moved into its own repository and is now a Babel 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
+    of the new ``TUri`` type in the ``uri`` module.
 
   Library Additions
   -----------------
@@ -26,7 +28,7 @@ News
   - Added module ``threadpool``.
   - ``sequtils.distnct`` has been renamed to ``sequtils.deduplicate``.
   - Added ``algorithm.reversed``
-
+  - Added ``uri.combine`` and ``uri.parseUri``.
 
 2014-04-21 Version 0.9.4 released
 =================================
diff --git a/web/nimrod.ini b/web/nimrod.ini
index 7b0a91c19..544446b11 100644
--- a/web/nimrod.ini
+++ b/web/nimrod.ini
@@ -37,7 +37,7 @@ UNIX. We don't believe this to be a coincidence. - Jeremy S. Anderson."""
 
 [Documentation]
 doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters"
-doc: "tools;c2nim;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
+doc: "tools;niminst;nimgrep;gc;estp;idetools;docgen;koch;backends.txt"
 pdf: "manual;lib;tut1;tut2;nimrodc;niminst;gc"
 srcdoc2: "system.nim;impure/graphics;wrappers/sdl"
 srcdoc2: "core/macros;pure/marshal;core/typeinfo;core/unsigned"