# # # Nim's Runtime Library # (c) Copyright 2012 Andreas Rumpf # # See the file "copying.txt", included in this # distribution, for details about the copyright. # ## This module provides support to handle the Unicode UTF-8 encoding. ## ## There are no specialized ``insert``, ``delete``, ``add`` and ``contains`` ## procedures for ``seq[Rune]`` in this module because the generic variants ## of these procedures in the system module already work with it. ## ## The current version is compatible with Unicode v12.0.0. ## ## **See also:** ## * `strutils module `_ ## * `unidecode module `_ ## * `encodings module `_ {.deadCodeElim: on.} # dce option deprecated include "system/inclrtl" type RuneImpl = int32 # underlying type of Rune Rune* = distinct RuneImpl ## \ ## Type that can hold a single Unicode code point. ## ## A Rune may be composed with other Runes to a character on the screen. template ones(n: untyped): untyped = ((1 shl n)-1) proc runeLen*(s: string): int {.rtl, extern: "nuc$1".} = ## Returns the number of runes of the string ``s``. runnableExamples: let a = "añyóng" doAssert a.runeLen == 6 ## note: a.len == 8 var i = 0 while i < len(s): if uint(s[i]) <= 127: inc(i) elif uint(s[i]) shr 5 == 0b110: inc(i, 2) elif uint(s[i]) shr 4 == 0b1110: inc(i, 3) elif uint(s[i]) shr 3 == 0b11110: inc(i, 4) elif uint(s[i]) shr 2 == 0b111110: inc(i, 5) elif uint(s[i]) shr 1 == 0b1111110: inc(i, 6) else: inc i inc(result) proc runeLenAt*(s: string, i: Natural): int = ## Returns the number of bytes the rune starting at ``s[i]`` takes. ## ## See also: ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ runnableExamples: let a = "añyóng" doAssert a.runeLenAt(0) == 1 doAssert a.runeLenAt(1) == 2 if uint(s[i]) <= 127: result = 1 elif uint(s[i]) shr 5 == 0b110: result = 2 elif uint(s[i]) shr 4 == 0b1110: result = 3 elif uint(s[i]) shr 3 == 0b11110: result = 4 elif uint(s[i]) shr 2 == 0b111110: result = 5 elif uint(s[i]) shr 1 == 0b1111110: result = 6 else: result = 1 const replRune = Rune(0xFFFD) template fastRuneAt*(s: string, i: int, result: untyped, doInc = true) = ## Returns the rune ``s[i]`` in ``result``. ## ## If ``doInc == true`` (default), ``i`` is incremented by the number ## of bytes that have been processed. bind ones if uint(s[i]) <= 127: result = Rune(uint(s[i])) when doInc: inc(i) elif uint(s[i]) shr 5 == 0b110: # assert(uint(s[i+1]) shr 6 == 0b10) if i <= s.len - 2: result = Rune((uint(s[i]) and (ones(5))) shl 6 or (uint(s[i+1]) and ones(6))) when doInc: inc(i, 2) else: result = replRune when doInc: inc(i) elif uint(s[i]) shr 4 == 0b1110: # assert(uint(s[i+1]) shr 6 == 0b10) # assert(uint(s[i+2]) shr 6 == 0b10) if i <= s.len - 3: result = Rune((uint(s[i]) and ones(4)) shl 12 or (uint(s[i+1]) and ones(6)) shl 6 or (uint(s[i+2]) and ones(6))) when doInc: inc(i, 3) else: result = replRune when doInc: inc(i) elif uint(s[i]) shr 3 == 0b11110: # assert(uint(s[i+1]) shr 6 == 0b10) # assert(uint(s[i+2]) shr 6 == 0b10) # assert(uint(s[i+3]) shr 6 == 0b10) if i <= s.len - 4: result = Rune((uint(s[i]) and ones(3)) shl 18 or (uint(s[i+1]) and ones(6)) shl 12 or (uint(s[i+2]) and ones(6)) shl 6 or (uint(s[i+3]) and ones(6))) when doInc: inc(i, 4) else: result = replRune when doInc: inc(i) elif uint(s[i]) shr 2 == 0b111110: # assert(uint(s[i+1]) shr 6 == 0b10) # assert(uint(s[i+2]) shr 6 == 0b10) # assert(uint(s[i+3]) shr 6 == 0b10) # assert(uint(s[i+4]) shr 6 == 0b10) if i <= s.len - 5: result = Rune((uint(s[i]) and ones(2)) shl 24 or (uint(s[i+1]) and ones(6)) shl 18 or (uint(s[i+2]) and ones(6)) shl 12 or (uint(s[i+3]) and ones(6)) shl 6 or (uint(s[i+4]) and ones(6))) when doInc: inc(i, 5) else: result = replRune when doInc: inc(i) elif uint(s[i]) shr 1 == 0b1111110: # assert(uint(s[i+1]) shr 6 == 0b10) # assert(uint(s[i+2]) shr 6 == 0b10) # assert(uint(s[i+3]) shr 6 == 0b10) # assert(uint(s[i+4]) shr 6 == 0b10) # assert(uint(s[i+5]) shr 6 == 0b10) if i <= s.len - 6: result = Rune((uint(s[i]) and ones(1)) shl 30 or (uint(s[i+1]) and ones(6)) shl 24 or (uint(s[i+2]) and ones(6)) shl 18 or (uint(s[i+3]) and ones(6)) shl 12 or (uint(s[i+4]) and ones(6)) shl 6 or (uint(s[i+5]) and ones(6))) when doInc: inc(i, 6) else: result = replRune when doInc: inc(i) else: result = Rune(uint(s[i])) when doInc: inc(i) proc runeAt*(s: string, i: Natural): Rune = ## Returns the rune in ``s`` at **byte index** ``i``. ## ## See also: ## * `runeAtPos proc <#runeAtPos,string,int>`_ ## * `runeStrAtPos proc <#runeStrAtPos,string,Natural>`_ ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ runnableExamples: let a = "añyóng" doAssert a.runeAt(1) == "ñ".runeAt(0) doAssert a.runeAt(2) == "ñ".runeAt(1) doAssert a.runeAt(3) == "y".runeAt(0) fastRuneAt(s, i, result, false) proc validateUtf8*(s: string): int = ## Returns the position of the invalid byte in ``s`` if the string ``s`` does ## not hold valid UTF-8 data. Otherwise ``-1`` is returned. ## ## See also: ## * `toUTF8 proc <#toUTF8,Rune>`_ ## * `$ proc <#$,Rune>`_ alias for `toUTF8` ## * `fastToUTF8Copy template <#fastToUTF8Copy.t,Rune,string,int>`_ var i = 0 let L = s.len while i < L: if uint(s[i]) <= 127: inc(i) elif uint(s[i]) shr 5 == 0b110: if uint(s[i]) < 0xc2: return i # Catch overlong ascii representations. if i+1 < L and uint(s[i+1]) shr 6 == 0b10: inc(i, 2) else: return i elif uint(s[i]) shr 4 == 0b1110: if i+2 < L and uint(s[i+1]) shr 6 == 0b10 and uint(s[i+2]) shr 6 == 0b10: inc i, 3 else: return i elif uint(s[i]) shr 3 == 0b11110: if i+3 < L and uint(s[i+1]) shr 6 == 0b10 and uint(s[i+2]) shr 6 == 0b10 and uint(s[i+3]) shr 6 == 0b10: inc i, 4 else: return i else: return i return -1 template fastToUTF8Copy*(c: Rune, s: var string, pos: int, doInc = true) = ## Copies UTF-8 representation of ``c`` into the preallocated string ``s`` ## starting at position ``pos``. ## ## If ``doInc == true`` (default), ``pos`` is incremented ## by the number of bytes that have been processed. ## ## To be the most efficient, make sure ``s`` is preallocated ## with an additional amount equal to the byte length of ``c``. ## ## See also: ## * `validateUtf8 proc <#validateUtf8,string>`_ ## * `toUTF8 proc <#toUTF8,Rune>`_ ## * `$ proc <#$,Rune>`_ alias for `toUTF8` var i = RuneImpl(c) if i <=% 127: s.setLen(pos+1) s[pos+0] = chr(i) when doInc: inc(pos) elif i <=% 0x07FF: s.setLen(pos+2) s[pos+0] = chr((i shr 6) or 0b110_00000) s[pos+1] = chr((i and ones(6)) or 0b10_0000_00) when doInc: inc(pos, 2) elif i <=% 0xFFFF: s.setLen(pos+3) s[pos+0] = chr(i shr 12 or 0b1110_0000) s[pos+1] = chr(i shr 6 and ones(6) or 0b10_0000_00) s[pos+2] = chr(i and ones(6) or 0b10_0000_00) when doInc: inc(pos, 3) elif i <=% 0x001FFFFF: s.setLen(pos+4) s[pos+0] = chr(i shr 18 or 0b1111_0000) s[pos+1] = chr(i shr 12 and ones(6) or 0b10_0000_00) s[pos+2] = chr(i shr 6 and ones(6) or 0b10_0000_00) s[pos+3] = chr(i and ones(6) or 0b10_0000_00) when doInc: inc(pos, 4) elif i <=% 0x03FFFFFF: s.setLen(pos+5) s[pos+0] = chr(i shr 24 or 0b111110_00) s[pos+1] = chr(i shr 18 and ones(6) or 0b10_0000_00) s[pos+2] = chr(i shr 12 and ones(6) or 0b10_0000_00) s[pos+3] = chr(i shr 6 and ones(6) or 0b10_0000_00) s[pos+4] = chr(i and ones(6) or 0b10_0000_00) when doInc: inc(pos, 5) elif i <=% 0x7FFFFFFF: s.setLen(pos+6) s[pos+0] = chr(i shr 30 or 0b1111110_0) s[pos+1] = chr(i shr 24 and ones(6) or 0b10_0000_00) s[pos+2] = chr(i shr 18 and ones(6) or 0b10_0000_00) s[pos+3] = chr(i shr 12 and ones(6) or 0b10_0000_00) s[pos+4] = chr(i shr 6 and ones(6) or 0b10_0000_00) s[pos+5] = chr(i and ones(6) or 0b10_0000_00) when doInc: inc(pos, 6) else: discard # error, exception? proc toUTF8*(c: Rune): string {.rtl, extern: "nuc$1".} = ## Converts a rune into its UTF-8 representation. ## ## See also: ## * `validateUtf8 proc <#validateUtf8,string>`_ ## * `$ proc <#$,Rune>`_ alias for `toUTF8` ## * `utf8 iterator <#utf8.i,string>`_ ## * `fastToUTF8Copy template <#fastToUTF8Copy.t,Rune,string,int>`_ runnableExamples: let a = "añyóng" doAssert a.runeAt(1).toUTF8 == "ñ" result = "" fastToUTF8Copy(c, result, 0, false) proc add*(s: var string; c: Rune) = ## Adds a rune ``c`` to a string ``s``. runnableExamples: var s = "abc" let c = "ä".runeAt(0) s.add(c) doAssert s == "abcä" let pos = s.len fastToUTF8Copy(c, s, pos, false) proc `$`*(rune: Rune): string = ## An alias for `toUTF8 <#toUTF8,Rune>`_. ## ## See also: ## * `validateUtf8 proc <#validateUtf8,string>`_ ## * `fastToUTF8Copy template <#fastToUTF8Copy.t,Rune,string,int>`_ rune.toUTF8 proc `$`*(runes: seq[Rune]): string = ## Converts a sequence of Runes to a string. ## ## See also: ## * `toRunes <#toRunes,string>`_ for a reverse operation runnableExamples: let someString = "öÑ" someRunes = toRunes(someString) doAssert $someRunes == someString result = "" for rune in runes: result.add rune proc runeOffset*(s: string, pos: Natural, start: Natural = 0): int = ## Returns the byte position of rune ## at position ``pos`` in ``s`` with an optional start byte position. ## Returns the special value -1 if it runs out of the string. ## ## **Beware:** This can lead to unoptimized code and slow execution! ## Most problems can be solved more efficiently by using an iterator ## or conversion to a seq of Rune. ## ## See also: ## * `runeReverseOffset proc <#runeReverseOffset,string,Positive>`_ runnableExamples: let a = "añyóng" doAssert a.runeOffset(1) == 1 doAssert a.runeOffset(3) == 4 doAssert a.runeOffset(4) == 6 var i = 0 o = start while i < pos: o += runeLenAt(s, o) if o >= s.len: return -1 inc i return o proc runeReverseOffset*(s: string, rev: Positive): (int, int) = ## Returns a tuple with the byte offset of the ## rune at position ``rev`` in ``s``, counting ## from the end (starting with 1) and the total ## number of runes in the string. ## ## Returns a negative value for offset if there are to few runes in ## the string to satisfy the request. ## ## **Beware:** This can lead to unoptimized code and slow execution! ## Most problems can be solved more efficiently by using an iterator ## or conversion to a seq of Rune. ## ## See also: ## * `runeOffset proc <#runeOffset,string,Natural,Natural>`_ var a = rev.int o = 0 x = 0 while o < s.len: let r = runeLenAt(s, o) o += r if a < 0: x += r dec a if a > 0: return (-a, rev.int-a) return (x, -a+rev.int) proc runeAtPos*(s: string, pos: int): Rune = ## Returns the rune at position ``pos``. ## ## **Beware:** This can lead to unoptimized code and slow execution! ## Most problems can be solved more efficiently by using an iterator ## or conversion to a seq of Rune. ## ## See also: ## * `runeAt proc <#runeAt,string,Natural>`_ ## * `runeStrAtPos proc <#runeStrAtPos,string,Natural>`_ ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ fastRuneAt(s, runeOffset(s, pos), result, false) proc runeStrAtPos*(s: string, pos: Natural): string = ## Returns the rune at position ``pos`` as UTF8 String. ## ## **Beware:** This can lead to unoptimized code and slow execution! ## Most problems can be solved more efficiently by using an iterator ## or conversion to a seq of Rune. ## ## See also: ## * `runeAt proc <#runeAt,string,Natural>`_ ## * `runeAtPos proc <#runeAtPos,string,int>`_ ## * `fastRuneAt template <#fastRuneAt.t,string,int,untyped>`_ let o = runeOffset(s, pos) s[o .. (o+runeLenAt(s, o)-1)] proc runeSubStr*(s: string, pos: int, len: int = int.high): string = ## Returns the UTF-8 substring starting at code point ``pos`` ## with ``len`` code points. ## ## If ``pos`` or ``len`` is negative they count from ## the end of the string. If ``len`` is not given it means the longest ## possible string. runnableExamples: let s = "Hänsel ««: 10,00€" doAssert(runeSubStr(s, 0, 2) == "Hä") doAssert(runeSubStr(s, 10, 1) == ":") doAssert(runeSubStr(s, -6) == "10,00€") doAssert(runeSubStr(s, 10) == ": 10,00€") doAssert(runeSubStr(s, 12, 5) == "10,00") doAssert(runeSubStr(s, -6, 3) == "10,") if pos < 0: let (o, rl) = runeReverseOffset(s, -pos) if len >= rl: result = s.substr(o, s.len-1) elif len < 0: let e = rl + len if e < 0: result = "" else: result = s.substr(o, runeOffset(s, e-(rl+pos), o)-1) else: result = s.substr(o, runeOffset(s, len, o)-1) else: let o = runeOffset(s, pos) if o < 0: result = "" elif len == int.high: result = s.substr(o, s.len-1) elif len < 0: let (e, rl) = runeReverseOffset(s, -len) discard rl if e <= 0: result = "" else: result = s.substr(o, e-1) else: var e = runeOffset(s, len, o) if e < 0: e = s.len result = s.substr(o, e-1) proc `<=%`*(a, b: Rune): bool = ## Checks if code point of `a` is smaller or equal to code point of `b`. runnableExamples: let a = "ú".runeAt(0) b = "ü".runeAt(0) doAssert a <=% b return int(a) <=% int(b) proc `<%`*(a, b: Rune): bool = ## Checks if code point of `a` is smaller than code point of `b`. runnableExamples: let a = "ú".runeAt(0) b = "ü".runeAt(0) doAssert a <% b return int(a) <% int(b) proc `==`*(a, b: Rune): bool = ## Checks if two runes are equal. return int(a) == int(b) include "includes/unicode_ranges" proc binarySearch(c: RuneImpl, tab: openArray[int], len, stride: int): int = var n = len var t = 0 while n > 1: var m = n div 2 var p = t + m*stride if c >= tab[p]: t = p n = n-m else: n = m if n != 0 and c >= tab[t]: return t return -1 proc toLower*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts ``c`` into lower case. This works for any rune. ## ## If possible, prefer ``toLower`` over ``toUpper``. ## ## See also: ## * `toUpper proc <#toUpper,Rune>`_ ## * `toTitle proc <#toTitle,Rune>`_ ## * `isLower proc <#isLower,Rune>`_ var c = RuneImpl(c) var p = binarySearch(c, toLowerRanges, len(toLowerRanges) div 3, 3) if p >= 0 and c >= toLowerRanges[p] and c <= toLowerRanges[p+1]: return Rune(c + toLowerRanges[p+2] - 500) p = binarySearch(c, toLowerSinglets, len(toLowerSinglets) div 2, 2) if p >= 0 and c == toLowerSinglets[p]: return Rune(c + toLowerSinglets[p+1] - 500) return Rune(c) proc toUpper*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts ``c`` into upper case. This works for any rune. ## ## If possible, prefer ``toLower`` over ``toUpper``. ## ## See also: ## * `toLower proc <#toLower,Rune>`_ ## * `toTitle proc <#toTitle,Rune>`_ ## * `isUpper proc <#isUpper,Rune>`_ var c = RuneImpl(c) var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3) if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]: return Rune(c + toUpperRanges[p+2] - 500) p = binarySearch(c, toUpperSinglets, len(toUpperSinglets) div 2, 2) if p >= 0 and c == toUpperSinglets[p]: return Rune(c + toUpperSinglets[p+1] - 500) return Rune(c) proc toTitle*(c: Rune): Rune {.rtl, extern: "nuc$1", procvar.} = ## Converts ``c`` to title case. ## ## See also: ## * `toLower proc <#toLower,Rune>`_ ## * `toUpper proc <#toUpper,Rune>`_ ## * `isTitle proc <#isTitle,Rune>`_ var c = RuneImpl(c) var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2) if p >= 0 and c == toTitleSinglets[p]: return Rune(c + toTitleSinglets[p+1] - 500) return Rune(c) proc isLower*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a lower case rune. ## ## If possible, prefer ``isLower`` over ``isUpper``. ## ## See also: ## * `toLower proc <#toLower,Rune>`_ ## * `isUpper proc <#isUpper,Rune>`_ ## * `isTitle proc <#isTitle,Rune>`_ var c = RuneImpl(c) # Note: toUpperRanges is correct here! var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3) if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]: return true p = binarySearch(c, toUpperSinglets, len(toUpperSinglets) div 2, 2) if p >= 0 and c == toUpperSinglets[p]: return true proc isUpper*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a upper case rune. ## ## If possible, prefer ``isLower`` over ``isUpper``. ## ## See also: ## * `toUpper proc <#toUpper,Rune>`_ ## * `isLower proc <#isLower,Rune>`_ ## * `isTitle proc <#isTitle,Rune>`_ ## * `isAlpha proc <#isAlpha,Rune>`_ ## * `isWhiteSpace proc <#isWhiteSpace,Rune>`_ var c = RuneImpl(c) # Note: toLowerRanges is correct here! var p = binarySearch(c, toLowerRanges, len(toLowerRanges) div 3, 3) if p >= 0 and c >= toLowerRanges[p] and c <= toLowerRanges[p+1]: return true p = binarySearch(c, toLowerSinglets, len(toLowerSinglets) div 2, 2) if p >= 0 and c == toLowerSinglets[p]: return true proc isAlpha*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is an *alpha* rune (i.e., a letter). ## ## See also: ## * `isLower proc <#isLower,Rune>`_ ## * `isTitle proc <#isTitle,Rune>`_ ## * `isAlpha proc <#isAlpha,Rune>`_ ## * `isWhiteSpace proc <#isWhiteSpace,Rune>`_ ## * `isCombining proc <#isCombining,Rune>`_ if isUpper(c) or isLower(c): return true var c = RuneImpl(c) var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2) if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]: return true p = binarySearch(c, alphaSinglets, len(alphaSinglets), 1) if p >= 0 and c == alphaSinglets[p]: return true proc isTitle*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a Unicode titlecase code point. ## ## See also: ## * `toTitle proc <#toTitle,Rune>`_ ## * `isLower proc <#isLower,Rune>`_ ## * `isUpper proc <#isUpper,Rune>`_ ## * `isAlpha proc <#isAlpha,Rune>`_ ## * `isWhiteSpace proc <#isWhiteSpace,Rune>`_ return isUpper(c) and isLower(c) proc isWhiteSpace*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a Unicode whitespace code point. ## ## See also: ## * `isLower proc <#isLower,Rune>`_ ## * `isUpper proc <#isUpper,Rune>`_ ## * `isTitle proc <#isTitle,Rune>`_ ## * `isAlpha proc <#isAlpha,Rune>`_ var c = RuneImpl(c) var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2) if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]: return true proc isCombining*(c: Rune): bool {.rtl, extern: "nuc$1", procvar.} = ## Returns true if ``c`` is a Unicode combining code unit. ## ## See also: ## * `isLower proc <#isLower,Rune>`_ ## * `isUpper proc <#isUpper,Rune>`_ ## * `isTitle proc <#isTitle,Rune>`_ ## * `isAlpha proc <#isAlpha,Rune>`_ var c = RuneImpl(c) # Optimized to return false immediately for ASCII return c >= 0x0300 and (c <= 0x036f or (c >= 0x1ab0 and c <= 0x1aff) or (c >= 0x1dc0 and c <= 0x1dff) or (c >= 0x20d0 and c <= 0x20ff) or (c >= 0xfe20 and c <= 0xfe2f)) template runeCheck(s, runeProc) = ## Common code for isAlpha and isSpace. result = if len(s) == 0: false else: true var i = 0 rune: Rune while i < len(s) and result: fastRuneAt(s, i, rune, doInc = true) result = runeProc(rune) and result proc isAlpha*(s
Version 0.15.0 released
=======================

.. container:: metadata

  Posted by Dominik Picheta and Andreas Rumpf on 30/09/2016

We're happy to announce that the latest release of Nim, version 0.15.0, is now
available!

As always, you can grab the latest version from the
`downloads page <http://nim-lang.org/download.html>`_.

This release includes almost 180 bug fixes and improvements. To see a full list
of changes, take a look at the detailed changelog
`below <#changelog>`_.

Some of the most significant changes in this release include: improvements to
the documentation, addition of a new ``multisync`` macro, and a new
``HttpClient`` implementation.

Documentation
~~~~~~~~~~~~~

All pages in the documentation now contain a search box and a drop down to
select how procedures should be sorted. This allows you to search for
procedures, types, macros and more from any documentation page.

.. raw::html

  <a href="../assets/news/images/0.15.0/doc_search.gif">
    <img src="../assets/news/images/0.15.0/doc_search.gif" alt="Doc search" style="width:100%"/>
  </a>

Sorting the procedures by type shows a more natural table of contents. This
should also help you to find procedures and other identifiers.

.. raw::html

  <a href="../assets/news/images/0.15.0/doc_sort.gif">
    <img src="../assets/news/images/0.15.0/doc_sort.gif" alt="Doc sort" style="width:100%"/>
  </a>

Multisync macro
~~~~~~~~~~~~~~~

The ``multisync`` macro was implemented to enable you to define both
synchronous and asynchronous IO procedures without having to duplicate a
lot of code.

As an example, consider the ``recvTwice`` procedure below:

.. code-block:: nim
  proc recvTwice(socket: Socket | AsyncSocket): Future[string] {.multisync.} =
    result = ""
    result.add(await socket.recv(25))
    result.add(await socket.recv(20))

The ``multisync`` macro will transform this procedure into the following:

.. code-block:: nim
  proc recvTwice(socket: Socket): string =
    result = ""
    result.add(socket.recv(25))
    result.add(socket.recv(20))

  proc recvTwice(socket: AsyncSocket): Future[string] {.async.} =
    result = ""
    result.add(await socket.recv(25))
    result.add(await socket.recv(20))

Allowing you to use ``recvTwice`` with both synchronous and asynchronous sockets.

HttpClient
~~~~~~~~~~

Many of the ``httpclient`` module's procedures have been deprecated in
favour of a new implementation using the ``multisync`` macro. There are now
two types: ``HttpClient`` and ``AsyncHttpClient``. Both of these implement the
same procedures and functionality, the only difference is timeout support and
whether they are blocking or not.

See the `httpclient <http://nim-lang.org/docs/httpclient.html>`_ module
documentation for more information.

Changelog
~~~~~~~~~

Changes affecting backwards compatibility
-----------------------------------------

- The ``json`` module now uses an ``OrderedTable`` rather than a ``Table``
  for JSON objects.

- The ``split`` `(doc) <http://nim-lang.org/docs/strutils.html#split,string,set[char],int>`_
  procedure in the ``strutils`` module (with a delimiter of type
  ``set[char]``) no longer strips and splits characters out of the target string
  by the entire set of characters. Instead, it now behaves in a
  similar fashion to ``split`` with ``string`` and ``char``
  delimiters. Use ``splitWhitespace`` to get the old behaviour.

- The command invocation syntax will soon apply to open brackets
  and curlies too. This means that code like ``a [i]`` will be
  interpreted as ``a([i])`` and not as ``a[i]`` anymore. Likewise
  ``f (a, b)`` means that the tuple ``(a, b)`` is passed to ``f``.
  The compiler produces a warning for ``a [i]``::

    Warning: a [b] will be parsed as command syntax; spacing is deprecated

  See `Issue #3898 <https://github.com/nim-lang/Nim/issues/3898>`_ for the
  relevant discussion.

- Overloading the special operators ``.``, ``.()``, ``.=``, ``()`` now
  needs to be enabled via the ``{.experimental.}`` pragma.

- ``immediate`` templates and macros are now deprecated.
  Use ``untyped`` `(doc) <http://nim-lang.org/docs/manual.html#templates-typed-vs-untyped-parameters>`_
  parameters instead.

- The metatype ``expr`` is deprecated. Use ``untyped``
  `(doc) <http://nim-lang.org/docs/manual.html#templates-typed-vs-untyped-parameters>`_ instead.

- The metatype ``stmt`` is deprecated. Use ``typed``
  `(doc) <http://nim-lang.org/docs/manual.html#templates-typed-vs-untyped-parameters>`_ instead.

- The compiler is now more picky when it comes to ``tuple`` types. The
  following code used to compile, now it's rejected:

.. code-block:: nim

  import tables
  var rocketaims = initOrderedTable[string, Table[tuple[k: int8, v: int8], int64]]()
  rocketaims["hi"] = {(-1.int8, 0.int8): 0.int64}.toTable()

Instead be consistent in your tuple usage and use tuple names for named tuples:

.. code-block:: nim

  import tables
  var rocketaims = initOrderedTable[string, Table[tuple[k: int8, v: int8], int64]]()
  rocketaims["hi"] = {(k: -1.int8, v: 0.int8): 0.int64}.toTable()

- Now when you compile console applications for Windows, console output
  encoding is automatically set to UTF-8.

- Unhandled exceptions in JavaScript are now thrown regardless of whether
  ``noUnhandledHandler`` is defined. But the stack traces should be much more
  readable now.

- In JavaScript, the ``system.alert`` procedure has been deprecated.
  Use ``dom.alert`` instead.

- De-deprecated ``re.nim`` because there is too much code using it
  and it got the basic API right.

- The type of ``headers`` field in the ``AsyncHttpClient`` type
  `(doc) <http://nim-lang.org/docs/httpclient.html#AsyncHttpClient>`_
  has been changed
  from a string table to the specialised ``HttpHeaders`` type.

- The ``httpclient.request``
  `(doc) <http://nim-lang.org/docs/httpclient.html#request,AsyncHttpClient,string,string,string>`_
  procedure which takes the ``httpMethod`` as a string
  value no longer requires it to be prefixed with ``"http"``
  (or similar).

- Converting a ``HttpMethod``
  `(doc) <nim-lang.org/docs/httpcore.html#HttpMethod>`_
  value to a string using the ``$`` operator will
  give string values without the ``"Http"`` prefix now.

- The ``Request``
  `(doc) <http://nim-lang.org/docs/asynchttpserver.html#Request>`_
  object defined in the ``asynchttpserver`` module now uses
  the ``HttpMethod`` type for the request method.

Library Additions
-----------------

- Added ``readHeaderRow`` and ``rowEntry`` to the ``parsecsv``
  `(doc) <http://nim-lang.org/docs/parsecsv.html>`_ module
  to provide
  a lightweight alternative to python's ``csv.DictReader``.

- Added ``setStdIoUnbuffered`` proc to the ``system`` module to enable
  unbuffered I/O.

- Added ``center`` and ``rsplit`` to the ``strutils``
  `(doc) <http://nim-lang.org/docs/strutils.html>`_ module
  to provide similar Python functionality for Nim's strings.

- Added ``isTitle``, ``title``, ``swapCase``, ``isUpper``, ``toUpper``,
  ``isLower``, ``toLower``, ``isAlpha``, ``isSpace``, and ``capitalize``
  to the ``unicode.nim``
  `(doc) <http://nim-lang.org/docs/unicode.html>`_ module
  to provide unicode aware case manipulation and case
  testing.

- Added a new module ``strmisc``
  `(doc) <http://nim-lang.org/docs/strmisc.html>`_
  to hold uncommon string
  operations. Currently contains ``partition``, ``rpartition``
  and ``expandTabs``.

- Split out ``walkFiles`` in the ``os``
  `(doc) <http://nim-lang.org/docs/os.html>`_ module to three separate procs
  in order to make a clear distinction of functionality. ``walkPattern`` iterates
  over both files and directories, while ``walkFiles`` now only iterates
  over files and ``walkDirs`` only iterates over directories.

- Added a synchronous ``HttpClient`` in the ``httpclient``
  `(doc) <http://nim-lang.org/docs/httpclient.html>`_
  module. The old
  ``get``, ``post`` and similar procedures are now deprecated in favour of it.

- Added a new macro called ``multisync`` allowing you to write procedures for
  synchronous and asynchronous sockets with no duplication.

- The ``async`` macro will now complete ``FutureVar[T]`` parameters
  automatically unless they have been completed already.

Tool Additions
--------------

- The documentation is now searchable and sortable by type.
- Pragmas are now hidden by default in the documentation to reduce noise.
- Edit links are now present in the documentation.


Compiler Additions
------------------

- The ``-d/--define`` flag can now optionally take a value to be used
  by code at compile time.
  `(doc) <http://nim-lang.org/docs/manual.html#implementation-specific-pragmas-compile-time-define-pragmas>`_

Nimscript Additions
-------------------

- It's possible to enable and disable specific hints and warnings in
  Nimscript via the ``warning`` and ``hint`` procedures.

- Nimscript exports  a proc named ``patchFile`` which can be used to
  patch modules or include files for different Nimble packages, including
  the ``stdlib`` package.

Language Additions
------------------

- Added ``{.intdefine.}`` and ``{.strdefine.}`` macros to make use of
  (optional) compile time defines.
  `(doc) <http://nim-lang.org/docs/manual.html#implementation-specific-pragmas-compile-time-define-pragmas>`_

- If the first statement is an ``import system`` statement then ``system``
  is not imported implicitly anymore. This allows for code like
  ``import system except echo`` or ``from system import nil``.

Bugfixes
--------

The list below has been generated based on the commits in Nim's git
repository. As such it lists only the issues which have been closed
via a commit, for a full list see
`this link on Github <https://github.com/nim-lang/Nim/issues?utf8=%E2%9C%93&q=is%3Aissue+closed%3A%222016-06-22+..+2016-09-30%22+>`_.

- Fixed "RFC: should startsWith and endsWith work with characters?"
  (`#4252 <https://github.com/nim-lang/Nim/issues/4252>`_)

- Fixed "Feature request: unbuffered I/O"
  (`#2146 <https://github.com/nim-lang/Nim/issues/2146>`_)
- Fixed "clear() not implemented for CountTableRef"
  (`#4325 <https://github.com/nim-lang/Nim/issues/4325>`_)
- Fixed "Cannot close file opened async"
  (`#4334 <https://github.com/nim-lang/Nim/issues/4334>`_)
- Fixed "Feature Request: IDNA support"
  (`#3045 <https://github.com/nim-lang/Nim/issues/3045>`_)
- Fixed "Async: wrong behavior of boolean operations on futures"
  (`#4333 <https://github.com/nim-lang/Nim/issues/4333>`_)
- Fixed "os.walkFiles yields directories"
  (`#4280 <https://github.com/nim-lang/Nim/issues/4280>`_)
- Fixed "Fix #4392 and progress on #4170"
  (`#4393 <https://github.com/nim-lang/Nim/issues/4393>`_)
- Fixed "Await unable to wait futures from objects fields"
  (`#4390 <https://github.com/nim-lang/Nim/issues/4390>`_)
- Fixed "TMP variable name generation should be more stable"
  (`#4364 <https://github.com/nim-lang/Nim/issues/4364>`_)
- Fixed "nativesockets doesn't compile for Android 4.x (API v19 or older) because of gethostbyaddr"
  (`#4376 <https://github.com/nim-lang/Nim/issues/4376>`_)
- Fixed "no generic parameters allowed for ref"
  (`#4395 <https://github.com/nim-lang/Nim/issues/4395>`_)
- Fixed "split proc in strutils inconsistent for set[char]"
  (`#4305 <https://github.com/nim-lang/Nim/issues/4305>`_)
- Fixed "Problem with sets in devel"
  (`#4412 <https://github.com/n