summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/concurrency/threadpool.nim11
-rw-r--r--lib/pure/httpclient.nim14
-rw-r--r--lib/pure/osproc.nim24
-rw-r--r--lib/pure/strutils.nim4
-rw-r--r--lib/pure/terminal.nim319
-rw-r--r--lib/system.nim55
-rw-r--r--lib/system/dyncalls.nim36
-rw-r--r--lib/system/jssys.nim12
-rw-r--r--lib/system/threads.nim3
-rw-r--r--lib/windows/winlean.nim2
10 files changed, 293 insertions, 187 deletions
diff --git a/lib/pure/concurrency/threadpool.nim b/lib/pure/concurrency/threadpool.nim
index 72e744d52..2603835dd 100644
--- a/lib/pure/concurrency/threadpool.nim
+++ b/lib/pure/concurrency/threadpool.nim
@@ -267,6 +267,17 @@ proc awaitAny*(flowVars: openArray[FlowVarBase]): int =
     result = -1
   destroySemaphore(ai.cv)
 
+proc isReady*(fv: FlowVarBase): bool =
+  ## Determines whether the specified ``FlowVarBase``'s value is available.
+  ##
+  ## If ``true`` awaiting ``fv`` will not block.
+  if fv.usesSemaphore and not fv.awaited:
+    acquire(fv.cv.L)
+    result = fv.cv.counter > 0
+    release(fv.cv.L)
+  else:
+    result = true
+
 proc nimArgsPassingDone(p: pointer) {.compilerProc.} =
   let w = cast[ptr Worker](p)
   signal(w.taskStarted)
diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim
index a5d4ec1a1..8e182e274 100644
--- a/lib/pure/httpclient.nim
+++ b/lib/pure/httpclient.nim
@@ -166,12 +166,12 @@ proc parseChunks(s: Socket, timeout: int): string =
 
 proc parseBody(s: Socket, headers: StringTableRef, timeout: int): string =
   result = ""
-  if headers["Transfer-Encoding"] == "chunked":
+  if headers.getOrDefault"Transfer-Encoding" == "chunked":
     result = parseChunks(s, timeout)
   else:
     # -REGION- Content-Length
     # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
-    var contentLengthHeader = headers["Content-Length"]
+    var contentLengthHeader = headers.getOrDefault"Content-Length"
     if contentLengthHeader != "":
       var length = contentLengthHeader.parseint()
       if length > 0:
@@ -190,7 +190,7 @@ proc parseBody(s: Socket, headers: StringTableRef, timeout: int): string =
 
       # -REGION- Connection: Close
       # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
-      if headers["Connection"] == "close":
+      if headers.getOrDefault"Connection" == "close":
         var buf = ""
         while true:
           buf = newString(4000)
@@ -456,7 +456,7 @@ proc redirection(status: string): bool =
       return true
 
 proc getNewLocation(lastUrl: string, headers: StringTableRef): string =
-  result = headers["Location"]
+  result = headers.getOrDefault"Location"
   if result == "": httpError("location header expected")
   # Relative URLs. (Not part of the spec, but soon will be.)
   let r = parseUri(result)
@@ -679,12 +679,12 @@ proc parseChunks(client: AsyncHttpClient): Future[string] {.async.} =
 proc parseBody(client: AsyncHttpClient,
                headers: StringTableRef): Future[string] {.async.} =
   result = ""
-  if headers["Transfer-Encoding"] == "chunked":
+  if headers.getOrDefault"Transfer-Encoding" == "chunked":
     result = await parseChunks(client)
   else:
     # -REGION- Content-Length
     # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
-    var contentLengthHeader = headers["Content-Length"]
+    var contentLengthHeader = headers.getOrDefault"Content-Length"
     if contentLengthHeader != "":
       var length = contentLengthHeader.parseint()
       if length > 0:
@@ -699,7 +699,7 @@ proc parseBody(client: AsyncHttpClient,
 
       # -REGION- Connection: Close
       # (http://tools.ietf.org/html/rfc2616#section-4.4) NR.5
-      if headers["Connection"] == "close":
+      if headers.getOrDefault"Connection" == "close":
         var buf = ""
         while true:
           buf = await client.socket.recvFull(4000)
diff --git a/lib/pure/osproc.nim b/lib/pure/osproc.nim
index fa20afff0..de9e63909 100644
--- a/lib/pure/osproc.nim
+++ b/lib/pure/osproc.nim
@@ -30,13 +30,14 @@ type
                          ## variable.
                          ## On Windows, this is the default.
     poEvalCommand,       ## Pass `command` directly to the shell, without quoting.
-                         ## Use it only if `command` comes from trused source.
+                         ## Use it only if `command` comes from trusted source.
     poStdErrToStdOut,    ## merge stdout and stderr to the stdout stream
     poParentStreams,     ## use the parent's streams
-    poInteractive        ## optimize the buffer handling for responsiveness for
+    poInteractive,       ## optimize the buffer handling for responsiveness for
                          ## UI applications. Currently this only affects
                          ## Windows: Named pipes are used so that you can peek
                          ## at the process' output streams.
+    poDemon              ## Windows: The program creates no Window.
 
   ProcessObj = object of RootObj
     when defined(windows):
@@ -123,11 +124,21 @@ proc execProcess*(command: string,
   ## and returns its output as a string.
   ## WARNING: this function uses poEvalCommand by default for backward compatibility.
   ## Make sure to pass options explicitly.
+  ##
+  ## .. code-block:: Nim
+  ##
+  ##  let outp = execProcess("nim c -r mytestfile.nim")
+  ##  # Note: outp may have an interleave of text from the nim compile
+  ##  # and any output from mytestfile when it runs
 
 proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [ExecIOEffect].}
   ## Executes ``command`` and returns its error code. Standard input, output,
   ## error streams are inherited from the calling process. This operation
   ## is also often called `system`:idx:.
+  ##
+  ## .. code-block:: Nim
+  ##
+  ##  let errC = execCmd("nim c -r mytestfile.nim")
 
 proc startProcess*(command: string,
                    workingDir: string = "",
@@ -523,8 +534,9 @@ when defined(Windows) and not defined(useNimRtl):
       var tmp = newWideCString(cmdl)
       var ee = newWideCString(e)
       var wwd = newWideCString(wd)
-      success = winlean.createProcessW(nil,
-        tmp, nil, nil, 1, NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT,
+      var flags = NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT
+      if poDemon in options: flags = flags or CREATE_NO_WINDOW
+      success = winlean.createProcessW(nil, tmp, nil, nil, 1, flags,
         ee, wwd, si, procInfo)
     else:
       success = winlean.createProcessA(nil,
@@ -1053,6 +1065,10 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = {
                 exitCode: int] {.tags: [ExecIOEffect, ReadIOEffect], gcsafe.} =
   ## a convenience proc that runs the `command`, grabs all its output and
   ## exit code and returns both.
+  ##
+  ## .. code-block:: Nim
+  ##
+  ##  let (outp, errC) = execCmdEx("nim c -r mytestfile.nim")
   var p = startProcess(command, options=options + {poEvalCommand})
   var outp = outputStream(p)
   result = (TaintedString"", -1)
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index a78fed4b9..b61df6086 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -22,6 +22,8 @@ import parseutils
 
 include "system/inclrtl"
 
+{.pop.}
+
 type
   CharSet* {.deprecated.} = set[char] # for compatibility with Nim
 {.deprecated: [TCharSet: CharSet].}
@@ -1660,7 +1662,7 @@ when isMainModule:
   doAssert isAlpha("Rasp")
   doAssert isAlpha("Args")
   doAssert(not isAlpha("$Tomato"))
-  
+
   doAssert isAlphaNumeric('3')
   doAssert isAlphaNumeric('R')
   doAssert(not isAlphaNumeric('!'))
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index b6d99e429..60f064e7c 100644
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -79,33 +79,51 @@ when defined(windows):
       stdcall, dynlib: "kernel32", importc: "SetConsoleTextAttribute".}
 
   var
-    conHandle: Handle
-  # = createFile("CONOUT$", GENERIC_WRITE, 0, nil, OPEN_ALWAYS, 0, 0)
+    hStdout: Handle # = createFile("CONOUT$", GENERIC_WRITE, 0, nil,
+                    #              OPEN_ALWAYS, 0, 0)
+    hStderr: Handle
 
   block:
-    var hTemp = getStdHandle(STD_OUTPUT_HANDLE)
-    if duplicateHandle(getCurrentProcess(), hTemp, getCurrentProcess(),
-                       addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
-      raiseOSError(osLastError())
+    var hStdoutTemp = getStdHandle(STD_OUTPUT_HANDLE)
+    if duplicateHandle(getCurrentProcess(), hStdoutTemp, getCurrentProcess(),
+                       addr(hStdout), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
+      when defined(consoleapp):
+        raiseOSError(osLastError())
+    var hStderrTemp = getStdHandle(STD_ERROR_HANDLE)
+    if duplicateHandle(getCurrentProcess(), hStderrTemp, getCurrentProcess(),
+                       addr(hStderr), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
+      when defined(consoleapp):
+        raiseOSError(osLastError())
 
-  proc getCursorPos(): tuple [x,y: int] =
+  proc getCursorPos(h: Handle): tuple [x,y: int] =
     var c: CONSOLESCREENBUFFERINFO
-    if getConsoleScreenBufferInfo(conHandle, addr(c)) == 0:
+    if getConsoleScreenBufferInfo(h, addr(c)) == 0:
       raiseOSError(osLastError())
     return (int(c.dwCursorPosition.X), int(c.dwCursorPosition.Y))
 
-  proc getAttributes(): int16 =
+  proc setCursorPos(h: Handle, x, y: int) =
+    var c: COORD
+    c.X = int16(x)
+    c.Y = int16(y)
+    if setConsoleCursorPosition(h, c) == 0:
+      raiseOSError(osLastError())
+
+  proc getAttributes(h: Handle): int16 =
     var c: CONSOLESCREENBUFFERINFO
     # workaround Windows bugs: try several times
-    if getConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
+    if getConsoleScreenBufferInfo(h, addr(c)) != 0:
       return c.wAttributes
     return 0x70'i16 # ERROR: return white background, black text
 
   var
-    oldAttr = getAttributes()
+    oldStdoutAttr = getAttributes(hStdout)
+    oldStderrAttr = getAttributes(hStderr)
+
+  template conHandle(f: File): Handle =
+    if f == stderr: hStderr else: hStdout
 
 else:
-  import termios, unsigned
+  import termios
 
   proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
     var mode: Termios
@@ -119,168 +137,173 @@ else:
     mode.c_cc[VTIME] = 0.cuchar
     discard fd.tcsetattr(time, addr mode)
 
-proc setCursorPos*(x, y: int) =
-  ## sets the terminal's cursor to the (x,y) position. (0,0) is the
-  ## upper left of the screen.
+proc setCursorPos*(f: File, x, y: int) =
+  ## Sets the terminal's cursor to the (x,y) position.
+  ## (0,0) is the upper left of the screen.
   when defined(windows):
-    var c: COORD
-    c.X = int16(x)
-    c.Y = int16(y)
-    if setConsoleCursorPosition(conHandle, c) == 0: raiseOSError(osLastError())
+    let h = conHandle(f)
+    setCursorPos(h, x, y)
   else:
-    stdout.write("\e[" & $y & ';' & $x & 'f')
+    f.write("\e[" & $y & ';' & $x & 'f')
 
-proc setCursorXPos*(x: int) =
-  ## sets the terminal's cursor to the x position. The y position is
-  ## not changed.
+proc setCursorXPos*(f: File, x: int) =
+  ## Sets the terminal's cursor to the x position.
+  ## The y position is not changed.
   when defined(windows):
+    let h = conHandle(f)
     var scrbuf: CONSOLESCREENBUFFERINFO
-    var hStdout = conHandle
-    if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+    if getConsoleScreenBufferInfo(h, addr(scrbuf)) == 0:
       raiseOSError(osLastError())
     var origin = scrbuf.dwCursorPosition
     origin.X = int16(x)
-    if setConsoleCursorPosition(conHandle, origin) == 0:
+    if setConsoleCursorPosition(h, origin) == 0:
       raiseOSError(osLastError())
   else:
-    stdout.write("\e[" & $x & 'G')
+    f.write("\e[" & $x & 'G')
 
 when defined(windows):
-  proc setCursorYPos*(y: int) =
-    ## sets the terminal's cursor to the y position. The x position is
-    ## not changed. **Warning**: This is not supported on UNIX!
+  proc setCursorYPos*(f: File, y: int) =
+    ## Sets the terminal's cursor to the y position.
+    ## The x position is not changed.
+    ## **Warning**: This is not supported on UNIX!
     when defined(windows):
+      let h = conHandle(f)
       var scrbuf: CONSOLESCREENBUFFERINFO
-      var hStdout = conHandle
-      if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+      if getConsoleScreenBufferInfo(h, addr(scrbuf)) == 0:
         raiseOSError(osLastError())
       var origin = scrbuf.dwCursorPosition
       origin.Y = int16(y)
-      if setConsoleCursorPosition(conHandle, origin) == 0:
+      if setConsoleCursorPosition(h, origin) == 0:
         raiseOSError(osLastError())
     else:
       discard
 
-proc cursorUp*(count=1) =
+proc cursorUp*(f: File, count=1) =
   ## Moves the cursor up by `count` rows.
   when defined(windows):
-    var p = getCursorPos()
+    let h = conHandle(f)
+    var p = getCursorPos(h)
     dec(p.y, count)
-    setCursorPos(p.x, p.y)
+    setCursorPos(h, p.x, p.y)
   else:
-    stdout.write("\e[" & $count & 'A')
+    f.write("\e[" & $count & 'A')
 
-proc cursorDown*(count=1) =
+proc cursorDown*(f: File, count=1) =
   ## Moves the cursor down by `count` rows.
   when defined(windows):
-    var p = getCursorPos()
+    let h = conHandle(f)
+    var p = getCursorPos(h)
     inc(p.y, count)
-    setCursorPos(p.x, p.y)
+    setCursorPos(h, p.x, p.y)
   else:
-    stdout.write("\e[" & $count & 'B')
+    f.write("\e[" & $count & 'B')
 
-proc cursorForward*(count=1) =
+proc cursorForward*(f: File, count=1) =
   ## Moves the cursor forward by `count` columns.
   when defined(windows):
-    var p = getCursorPos()
+    let h = conHandle(f)
+    var p = getCursorPos(h)
     inc(p.x, count)
-    setCursorPos(p.x, p.y)
+    setCursorPos(h, p.x, p.y)
   else:
-    stdout.write("\e[" & $count & 'C')
+    f.write("\e[" & $count & 'C')
 
-proc cursorBackward*(count=1) =
+proc cursorBackward*(f: File, count=1) =
   ## Moves the cursor backward by `count` columns.
   when defined(windows):
-    var p = getCursorPos()
+    let h = conHandle(f)
+    var p = getCursorPos(h)
     dec(p.x, count)
-    setCursorPos(p.x, p.y)
+    setCursorPos(h, p.x, p.y)
   else:
-    stdout.write("\e[" & $count & 'D')
+    f.write("\e[" & $count & 'D')
 
 when true:
   discard
 else:
-  proc eraseLineEnd* =
+  proc eraseLineEnd*(f: File) =
     ## Erases from the current cursor position to the end of the current line.
     when defined(windows):
       discard
     else:
-      stdout.write("\e[K")
+      f.write("\e[K")
 
-  proc eraseLineStart* =
+  proc eraseLineStart*(f: File) =
     ## Erases from the current cursor position to the start of the current line.
     when defined(windows):
       discard
     else:
-      stdout.write("\e[1K")
+      f.write("\e[1K")
 
-  proc eraseDown* =
+  proc eraseDown*(f: File) =
     ## Erases the screen from the current line down to the bottom of the screen.
     when defined(windows):
       discard
     else:
-      stdout.write("\e[J")
+      f.write("\e[J")
 
-  proc eraseUp* =
+  proc eraseUp*(f: File) =
     ## Erases the screen from the current line up to the top of the screen.
     when defined(windows):
       discard
     else:
-      stdout.write("\e[1J")
+      f.write("\e[1J")
 
-proc eraseLine* =
+proc eraseLine*(f: File) =
   ## Erases the entire current line.
   when defined(windows):
+    let h = conHandle(f)
     var scrbuf: CONSOLESCREENBUFFERINFO
     var numwrote: DWORD
-    var hStdout = conHandle
-    if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+    if getConsoleScreenBufferInfo(h, addr(scrbuf)) == 0:
       raiseOSError(osLastError())
     var origin = scrbuf.dwCursorPosition
     origin.X = 0'i16
-    if setConsoleCursorPosition(conHandle, origin) == 0:
+    if setConsoleCursorPosition(h, origin) == 0:
       raiseOSError(osLastError())
     var ht = scrbuf.dwSize.Y - origin.Y
     var wt = scrbuf.dwSize.X - origin.X
-    if fillConsoleOutputCharacter(hStdout,' ', ht*wt,
+    if fillConsoleOutputCharacter(h, ' ', ht*wt,
                                   origin, addr(numwrote)) == 0:
       raiseOSError(osLastError())
-    if fillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
+    if fillConsoleOutputAttribute(h, scrbuf.wAttributes, ht * wt,
                                   scrbuf.dwCursorPosition, addr(numwrote)) == 0:
       raiseOSError(osLastError())
   else:
-    stdout.write("\e[2K")
-    setCursorXPos(0)
+    f.write("\e[2K")
+    setCursorXPos(f, 0)
 
-proc eraseScreen* =
+proc eraseScreen*(f: File) =
   ## Erases the screen with the background colour and moves the cursor to home.
   when defined(windows):
+    let h = conHandle(f)
     var scrbuf: CONSOLESCREENBUFFERINFO
     var numwrote: DWORD
     var origin: COORD # is inititalized to 0, 0
-    var hStdout = conHandle
 
-    if getConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0:
+    if getConsoleScreenBufferInfo(h, addr(scrbuf)) == 0:
       raiseOSError(osLastError())
     let numChars = int32(scrbuf.dwSize.X)*int32(scrbuf.dwSize.Y)
 
-    if fillConsoleOutputCharacter(hStdout, ' ', numChars,
+    if fillConsoleOutputCharacter(h, ' ', numChars,
                                   origin, addr(numwrote)) == 0:
       raiseOSError(osLastError())
-    if fillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, numChars,
+    if fillConsoleOutputAttribute(h, scrbuf.wAttributes, numChars,
                                   origin, addr(numwrote)) == 0:
       raiseOSError(osLastError())
-    setCursorXPos(0)
+    setCursorXPos(f, 0)
   else:
-    stdout.write("\e[2J")
+    f.write("\e[2J")
 
-proc resetAttributes* {.noconv.} =
-  ## resets all attributes; it is advisable to register this as a quit proc
-  ## with ``system.addQuitProc(resetAttributes)``.
+proc resetAttributes*(f: File) =
+  ## Resets all attributes.
   when defined(windows):
-    discard setConsoleTextAttribute(conHandle, oldAttr)
+    if f == stderr:
+      discard setConsoleTextAttribute(hStderr, oldStderrAttr)
+    else:
+      discard setConsoleTextAttribute(hStdout, oldStdoutAttr)
   else:
-    stdout.write("\e[0m")
+    f.write("\e[0m")
 
 type
   Style* = enum         ## different styles for text output
@@ -300,30 +323,31 @@ when not defined(windows):
     gFG = 0
     gBG = 0
 
-proc setStyle*(style: set[Style]) =
-  ## sets the terminal style
+proc setStyle*(f: File, style: set[Style]) =
+  ## Sets the terminal style.
   when defined(windows):
+    let h = conHandle(f)
     var a = 0'i16
     if styleBright in style: a = a or int16(FOREGROUND_INTENSITY)
     if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY)
     if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO
     if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE
-    discard setConsoleTextAttribute(conHandle, a)
+    discard setConsoleTextAttribute(h, a)
   else:
     for s in items(style):
-      stdout.write("\e[" & $ord(s) & 'm')
+      f.write("\e[" & $ord(s) & 'm')
 
 proc writeStyled*(txt: string, style: set[Style] = {styleBright}) =
-  ## writes the text `txt` in a given `style`.
+  ## Writes the text `txt` in a given `style` to stdout.
   when defined(windows):
-    var old = getAttributes()
-    setStyle(style)
+    var old = getAttributes(hStdout)
+    stdout.setStyle(style)
     stdout.write(txt)
-    discard setConsoleTextAttribute(conHandle, old)
+    discard setConsoleTextAttribute(hStdout, old)
   else:
-    setStyle(style)
+    stdout.setStyle(style)
     stdout.write(txt)
-    resetAttributes()
+    stdout.resetAttributes()
     if gFG != 0:
       stdout.write("\e[" & $ord(gFG) & 'm')
     if gBG != 0:
@@ -353,10 +377,11 @@ type
 {.deprecated: [TForegroundColor: ForegroundColor,
                TBackgroundColor: BackgroundColor].}
 
-proc setForegroundColor*(fg: ForegroundColor, bright=false) =
-  ## sets the terminal's foreground color
+proc setForegroundColor*(f: File, fg: ForegroundColor, bright=false) =
+  ## Sets the terminal's foreground color.
   when defined(windows):
-    var old = getAttributes() and not 0x0007
+    let h = conHandle(f)
+    var old = getAttributes(h) and not 0x0007
     if bright:
       old = old or FOREGROUND_INTENSITY
     const lookup: array [ForegroundColor, int] = [
@@ -368,16 +393,17 @@ proc setForegroundColor*(fg: ForegroundColor, bright=false) =
       (FOREGROUND_RED or FOREGROUND_BLUE),
       (FOREGROUND_BLUE or FOREGROUND_GREEN),
       (FOREGROUND_BLUE or FOREGROUND_GREEN or FOREGROUND_RED)]
-    discard setConsoleTextAttribute(conHandle, toU16(old or lookup[fg]))
+    discard setConsoleTextAttribute(h, toU16(old or lookup[fg]))
   else:
     gFG = ord(fg)
     if bright: inc(gFG, 60)
-    stdout.write("\e[" & $gFG & 'm')
+    f.write("\e[" & $gFG & 'm')
 
-proc setBackgroundColor*(bg: BackgroundColor, bright=false) =
-  ## sets the terminal's background color
+proc setBackgroundColor*(f: File, bg: BackgroundColor, bright=false) =
+  ## Sets the terminal's background color.
   when defined(windows):
-    var old = getAttributes() and not 0x0070
+    let h = conHandle(f)
+    var old = getAttributes(h) and not 0x0070
     if bright:
       old = old or BACKGROUND_INTENSITY
     const lookup: array [BackgroundColor, int] = [
@@ -389,14 +415,14 @@ proc setBackgroundColor*(bg: BackgroundColor, bright=false) =
       (BACKGROUND_RED or BACKGROUND_BLUE),
       (BACKGROUND_BLUE or BACKGROUND_GREEN),
       (BACKGROUND_BLUE or BACKGROUND_GREEN or BACKGROUND_RED)]
-    discard setConsoleTextAttribute(conHandle, toU16(old or lookup[bg]))
+    discard setConsoleTextAttribute(h, toU16(old or lookup[bg]))
   else:
     gBG = ord(bg)
     if bright: inc(gBG, 60)
-    stdout.write("\e[" & $gBG & 'm')
+    f.write("\e[" & $gBG & 'm')
 
 proc isatty*(f: File): bool =
-  ## returns true if `f` is associated with a terminal device.
+  ## Returns true if `f` is associated with a terminal device.
   when defined(posix):
     proc isatty(fildes: FileHandle): cint {.
       importc: "isatty", header: "<unistd.h>".}
@@ -410,39 +436,62 @@ type
   TerminalCmd* = enum  ## commands that can be expressed as arguments
     resetStyle         ## reset attributes
 
-template styledEchoProcessArg(s: string) = write stdout, s
-template styledEchoProcessArg(style: Style) = setStyle({style})
-template styledEchoProcessArg(style: set[Style]) = setStyle style
-template styledEchoProcessArg(color: ForegroundColor) = setForegroundColor color
-template styledEchoProcessArg(color: BackgroundColor) = setBackgroundColor color
-template styledEchoProcessArg(cmd: TerminalCmd) =
+template styledEchoProcessArg(f: File, s: string) = write f, s
+template styledEchoProcessArg(f: File, style: Style) = setStyle(f, {style})
+template styledEchoProcessArg(f: File, style: set[Style]) = setStyle f, style
+template styledEchoProcessArg(f: File, color: ForegroundColor) =
+  setForegroundColor f, color
+template styledEchoProcessArg(f: File, color: BackgroundColor) =
+  setBackgroundColor f, color
+template styledEchoProcessArg(f: File, cmd: TerminalCmd) =
   when cmd == resetStyle:
-    resetAttributes()
-
-macro styledEcho*(m: varargs[expr]): stmt =
-  ## to be documented.
+    resetAttributes(f)
+
+macro styledWriteLine*(f: File, m: varargs[expr]): stmt =
+  ## Similar to ``writeLine``, but treating terminal style arguments specially.
+  ## When some argument is ``Style``, ``set[Style]``, ``ForegroundColor``,
+  ## ``BackgroundColor`` or ``TerminalCmd`` then it is not sent directly to
+  ## ``f``, but instead corresponding terminal style proc is called.
+  ##
+  ## Example:
+  ##
+  ## .. code-block:: nim
+  ##
+  ##   proc error(msg: string) =
+  ##     styleWriteLine(stderr, fgRed, "Error: ", resetStyle, msg)
+  ##
   let m = callsite()
   var reset = false
   result = newNimNode(nnkStmtList)
 
-  for i in countup(1, m.len - 1):
+  for i in countup(2, m.len - 1):
     let item = m[i]
     case item.kind
     of nnkStrLit..nnkTripleStrLit:
       if i == m.len - 1:
         # optimize if string literal is last, just call writeLine
-        result.add(newCall(bindSym"writeLine", bindSym"stdout", item))
-        if reset: result.add(newCall(bindSym"resetAttributes"))
+        result.add(newCall(bindSym"writeLine", f, item))
+        if reset: result.add(newCall(bindSym"resetAttributes", f))
         return
       else:
         # if it is string literal just call write, do not enable reset
-        result.add(newCall(bindSym"write", bindSym"stdout", item))
+        result.add(newCall(bindSym"write", f, item))
     else:
-      result.add(newCall(bindSym"styledEchoProcessArg", item))
+      result.add(newCall(bindSym"styledEchoProcessArg", f, item))
       reset = true
 
-  result.add(newCall(bindSym"write", bindSym"stdout", newStrLitNode("\n")))
-  if reset: result.add(newCall(bindSym"resetAttributes"))
+  result.add(newCall(bindSym"write", f, newStrLitNode("\n")))
+  if reset: result.add(newCall(bindSym"resetAttributes", f))
+
+macro callStyledEcho(args: varargs[expr]): stmt =
+  result = newCall(bindSym"styledWriteLine")
+  result.add(bindSym"stdout")
+  for arg in children(args[0][1]):
+    result.add(arg)
+
+template styledEcho*(args: varargs[expr]): expr =
+  ## Echoes styles arguments to stdout using ``styledWriteLine``.
+  callStyledEcho(args)
 
 when defined(nimdoc):
   proc getch*(): char =
@@ -462,15 +511,35 @@ elif not defined(windows):
     result = stdin.readChar()
     discard fd.tcsetattr(TCSADRAIN, addr oldMode)
 
+# Wrappers assuming output to stdout:
+template setCursorPos*(x, y: int) = setCursorPos(stdout, x, y)
+template setCursorXPos*(x: int)   = setCursorXPos(stdout, x)
+when defined(windows):
+  template setCursorYPos(x: int)  = setCursorYPos(stdout, x)
+template cursorUp*(count=1)       = cursorUp(stdout, f)
+template cursorDown*(count=1)     = cursorDown(stdout, f)
+template cursorForward*(count=1)  = cursorForward(stdout, f)
+template cursorBackward*(count=1) = cursorBackward(stdout, f)
+template eraseLine*()             = eraseLine(stdout)
+template eraseScreen*()           = eraseScreen(stdout)
+template setStyle*(style: set[Style]) =
+  setStyle(stdout, style)
+template setForegroundColor*(fg: ForegroundColor, bright=false) =
+  setForegroundColor(stdout, fg, bright)
+template setBackgroundColor*(bg: BackgroundColor, bright=false) =
+  setBackgroundColor(stdout, bg, bright)
+proc resetAttributes*() {.noconv.} =
+  ## Resets all attributes on stdout.
+  ## It is advisable to register this as a quit proc with
+  ## ``system.addQuitProc(resetAttributes)``.
+  resetAttributes(stdout)
+
 when not defined(testing) and isMainModule:
-  system.addQuitProc(resetAttributes)
+  #system.addQuitProc(resetAttributes)
   write(stdout, "never mind")
-  eraseLine()
-  #setCursorPos(2, 2)
-  writeStyled("styled text ", {styleBright, styleBlink, styleUnderscore})
-  setBackGroundColor(bgCyan, true)
-  setForeGroundColor(fgBlue)
-  writeLine(stdout, "ordinary text")
-
-  styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})
-
+  stdout.eraseLine()
+  stdout.styledWriteLine("styled text ", {styleBright, styleBlink, styleUnderscore})
+  stdout.setBackGroundColor(bgCyan, true)
+  stdout.setForeGroundColor(fgBlue)
+  stdout.writeLine("ordinary text")
+  stdout.resetAttributes()
diff --git a/lib/system.nim b/lib/system.nim
index 89de08c6f..409691e6a 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -14,14 +14,6 @@
 ## explicitly. Because of this there cannot be a user-defined module named
 ## ``system``.
 ##
-## Exception hierarchy
-## ===================
-##
-## For visual convenience here is the exception inheritance hierarchy
-## represented as a tree:
-##
-## .. include:: ../doc/exception_hierarchy_fragment.txt
-##
 ## Module system
 ## =============
 ##
@@ -151,6 +143,12 @@ proc declaredInScope*(x: expr): bool {.
 proc `addr`*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
   ## Builtin 'addr' operator for taking the address of a memory location.
   ## Cannot be overloaded.
+  ##
+  ## .. code-block:: nim
+  ##  var
+  ##    buf: seq[char] = @['a','b','c']
+  ##    p: pointer = buf[1].addr
+  ##  echo cast[ptr char](p)[]    # b
   discard
 
 proc unsafeAddr*[T](x: var T): ptr T {.magic: "Addr", noSideEffect.} =
@@ -842,6 +840,7 @@ proc `div` *(x, y: int32): int32 {.magic: "DivI", noSideEffect.}
   ##   1 div 2 == 0
   ##   2 div 2 == 1
   ##   3 div 2 == 1
+  ##   7 div 5 == 2
 
 when defined(nimnomagic64):
   proc `div` *(x, y: int64): int64 {.magic: "DivI", noSideEffect.}
@@ -852,8 +851,12 @@ proc `mod` *(x, y: int): int {.magic: "ModI", noSideEffect.}
 proc `mod` *(x, y: int8): int8 {.magic: "ModI", noSideEffect.}
 proc `mod` *(x, y: int16): int16 {.magic: "ModI", noSideEffect.}
 proc `mod` *(x, y: int32): int32 {.magic: "ModI", noSideEffect.}
-  ## computes the integer modulo operation. This is the same as
+  ## computes the integer modulo operation (remainder).
+  ## This is the same as
   ## ``x - (x div y) * y``.
+  ##
+  ## .. code-block:: Nim
+  ##   (7 mod 5) == 2
 
 when defined(nimnomagic64):
   proc `mod` *(x, y: int64): int64 {.magic: "ModI", noSideEffect.}
@@ -878,6 +881,10 @@ proc `shl` *(x, y: int16): int16 {.magic: "ShlI", noSideEffect.}
 proc `shl` *(x, y: int32): int32 {.magic: "ShlI", noSideEffect.}
 proc `shl` *(x, y: int64): int64 {.magic: "ShlI", noSideEffect.}
   ## computes the `shift left` operation of `x` and `y`.
+  ##
+  ## .. code-block:: Nim
+  ##  1'i32 shl 4  == 0x0000_0010
+  ##  1'i64 shl 4  == 0x0000_0000_0000_0010
 
 proc `and` *(x, y: int): int {.magic: "BitandI", noSideEffect.}
 proc `and` *(x, y: int8): int8 {.magic: "BitandI", noSideEffect.}
@@ -885,6 +892,9 @@ proc `and` *(x, y: int16): int16 {.magic: "BitandI", noSideEffect.}
 proc `and` *(x, y: int32): int32 {.magic: "BitandI", noSideEffect.}
 proc `and` *(x, y: int64): int64 {.magic: "BitandI", noSideEffect.}
   ## computes the `bitwise and` of numbers `x` and `y`.
+  ##
+  ## .. code-block:: Nim
+  ##  (0xffff'i16 and 0x0010'i16) == 0x0010
 
 proc `or` *(x, y: int): int {.magic: "BitorI", noSideEffect.}
 proc `or` *(x, y: int8): int8 {.magic: "BitorI", noSideEffect.}
@@ -892,6 +902,9 @@ proc `or` *(x, y: int16): int16 {.magic: "BitorI", noSideEffect.}
 proc `or` *(x, y: int32): int32 {.magic: "BitorI", noSideEffect.}
 proc `or` *(x, y: int64): int64 {.magic: "BitorI", noSideEffect.}
   ## computes the `bitwise or` of numbers `x` and `y`.
+  ##
+  ## .. code-block:: Nim
+  ##  (0x0005'i16 or 0x0010'i16) == 0x0015
 
 proc `xor` *(x, y: int): int {.magic: "BitxorI", noSideEffect.}
 proc `xor` *(x, y: int8): int8 {.magic: "BitxorI", noSideEffect.}
@@ -899,6 +912,9 @@ proc `xor` *(x, y: int16): int16 {.magic: "BitxorI", noSideEffect.}
 proc `xor` *(x, y: int32): int32 {.magic: "BitxorI", noSideEffect.}
 proc `xor` *(x, y: int64): int64 {.magic: "BitxorI", noSideEffect.}
   ## computes the `bitwise xor` of numbers `x` and `y`.
+  ##
+  ## .. code-block:: Nim
+  ##  (0x1011'i16 xor 0x0101'i16) == 0x1110
 
 proc `==` *(x, y: int): bool {.magic: "EqI", noSideEffect.}
 proc `==` *(x, y: int8): bool {.magic: "EqI", noSideEffect.}
@@ -999,10 +1015,17 @@ proc `*`*[T: SomeUnsignedInt](x, y: T): T {.magic: "MulU", noSideEffect.}
 proc `div`*[T: SomeUnsignedInt](x, y: T): T {.magic: "DivU", noSideEffect.}
   ## computes the integer division. This is roughly the same as
   ## ``floor(x/y)``.
+  ##
+  ## .. code-block:: Nim
+  ##  (7 div 5) == 2
 
 proc `mod`*[T: SomeUnsignedInt](x, y: T): T {.magic: "ModU", noSideEffect.}
-  ## computes the integer modulo operation. This is the same as
+  ## computes the integer modulo operation (remainder).
+  ## This is the same as
   ## ``x - (x div y) * y``.
+  ##
+  ## .. code-block:: Nim
+  ##   (7 mod 5) == 2
 
 proc `<=`*[T: SomeUnsignedInt](x, y: T): bool {.magic: "LeU", noSideEffect.}
   ## Returns true iff ``x <= y``.
@@ -1111,6 +1134,10 @@ proc cmp*[T](x, y: T): int {.procvar.} =
   ## and 0 iff x == y. This is useful for writing generic algorithms without
   ## performance loss. This generic implementation uses the `==` and `<`
   ## operators.
+  ##
+  ## .. code-block:: Nim
+  ##  import algorithm
+  ##  echo sorted(@[4,2,6,5,8,7], cmp[int])
   if x == y: return 0
   if x < y: return -1
   return 1
@@ -1138,6 +1165,11 @@ proc setLen*(s: var string, newlen: Natural) {.
   ## If the current length is greater than the new length,
   ## ``s`` will be truncated. `s` cannot be nil! To initialize a string with
   ## a size, use ``newString`` instead.
+  ##
+  ## .. code-block:: Nim
+  ##  var myS = "Nim is great!!"
+  ##  myS.setLen(3)
+  ##  echo myS, " is fantastic!!"
 
 proc newString*(len: Natural): string {.
   magic: "NewString", importc: "mnewString", noSideEffect.}
@@ -1411,7 +1443,8 @@ proc insert*[T](x: var seq[T], item: T, i = 0.Natural) {.noSideEffect.} =
     defaultImpl()
   else:
     when defined(js):
-      {.emit: "`x`[`x`_Idx].splice(`i`, 0, null);".}
+      var it : T
+      {.emit: "`x`[`x`_Idx].splice(`i`, 0, `it`);".}
     else:
       defaultImpl()
   x[i] = item
diff --git a/lib/system/dyncalls.nim b/lib/system/dyncalls.nim
index fe98b1e6f..908aa551b 100644
--- a/lib/system/dyncalls.nim
+++ b/lib/system/dyncalls.nim
@@ -107,42 +107,6 @@ elif defined(windows) or defined(dos):
     result = getProcAddress(cast[THINSTANCE](lib), name)
     if result == nil: procAddrError(name)
 
-elif defined(mac):
-  #
-  # =======================================================================
-  # Native Mac OS X / Darwin Implementation
-  # =======================================================================
-  #
-  {.error: "no implementation for dyncalls yet".}
-
-  proc nimUnloadLibrary(lib: LibHandle) =
-    NSUnLinkModule(NSModule(lib), NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES)
-
-  var
-    dyld_present {.importc: "_dyld_present", header: "<dyld.h>".}: int
-
-  proc nimLoadLibrary(path: string): LibHandle =
-    var
-      img: NSObjectFileImage
-      ret: NSObjectFileImageReturnCode
-      modul: NSModule
-    # this would be a rare case, but prevents crashing if it happens
-    result = nil
-    if dyld_present != 0:
-      ret = NSCreateObjectFileImageFromFile(path, addr(img))
-      if ret == NSObjectFileImageSuccess:
-        modul = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE or
-                                        NSLINKMODULE_OPTION_RETURN_ON_ERROR)
-        NSDestroyObjectFileImage(img)
-        result = LibHandle(modul)
-
-  proc nimGetProcAddr(lib: LibHandle, name: cstring): ProcAddr =
-    var
-      nss: NSSymbol
-    nss = NSLookupSymbolInModule(NSModule(lib), name)
-    result = ProcAddr(NSAddressOfSymbol(nss))
-    if result == nil: ProcAddrError(name)
-
 else:
   {.error: "no implementation for dyncalls".}
 
diff --git a/lib/system/jssys.nim b/lib/system/jssys.nim
index eb6080d38..5bcddc5e6 100644
--- a/lib/system/jssys.nim
+++ b/lib/system/jssys.nim
@@ -532,7 +532,7 @@ proc nimMax(a, b: int): int {.compilerproc.} = return if a >= b: a else: b
 type NimString = string # hack for hti.nim
 include "system/hti"
 
-type JSRef = int # Fake type.
+type JSRef = ref RootObj # Fake type.
 
 proc isFatPointer(ti: PNimType): bool =
   # This has to be consistent with the code generator!
@@ -569,8 +569,14 @@ proc nimCopy(dest, src: JSRef, ti: PNimType): JSRef =
       asm "`result` = [`src`[0], `src`[1]];"
   of tySet:
     asm """
-      `result` = {};
-      for (var key in `src`) { `result`[key] = `src`[key]; }
+      if (`dest` === null || `dest` === undefined) {
+        `dest` = {};
+      }
+      else {
+        for (var key in `dest`) { delete `dest`[key]; }
+      }
+      for (var key in `src`) { `dest`[key] = `src`[key]; }
+      `result` = `dest`;
     """
   of tyTuple, tyObject:
     if ti.base != nil: result = nimCopy(dest, src, ti.base)
diff --git a/lib/system/threads.nim b/lib/system/threads.nim
index c5de841f8..bdb737e35 100644
--- a/lib/system/threads.nim
+++ b/lib/system/threads.nim
@@ -455,6 +455,9 @@ else:
     cpusetIncl(cpu.cint, s)
     setAffinity(t.sys, sizeof(s), s)
 
+proc createThread*(t: var Thread[void], tp: proc () {.thread.}) =
+  createThread[void](t, tp)
+
 proc threadId*[TArg](t: var Thread[TArg]): ThreadId[TArg] {.inline.} =
   ## returns the thread ID of `t`.
   result = addr(t)
diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim
index 89d86c62a..4962186fb 100644
--- a/lib/windows/winlean.nim
+++ b/lib/windows/winlean.nim
@@ -115,6 +115,8 @@ const
   SYNCHRONIZE* = 0x00100000'i32
   FILE_FLAG_WRITE_THROUGH* = 0x80000000'i32
 
+  CREATE_NO_WINDOW* = 0x08000000'i32
+
 proc closeHandle*(hObject: Handle): WINBOOL {.stdcall, dynlib: "kernel32",
     importc: "CloseHandle".}