diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/concurrency/threadpool.nim | 11 | ||||
-rw-r--r-- | lib/pure/httpclient.nim | 14 | ||||
-rw-r--r-- | lib/pure/osproc.nim | 24 | ||||
-rw-r--r-- | lib/pure/strutils.nim | 4 | ||||
-rw-r--r-- | lib/pure/terminal.nim | 319 | ||||
-rw-r--r-- | lib/system.nim | 55 | ||||
-rw-r--r-- | lib/system/dyncalls.nim | 36 | ||||
-rw-r--r-- | lib/system/jssys.nim | 12 | ||||
-rw-r--r-- | lib/system/threads.nim | 3 | ||||
-rw-r--r-- | lib/windows/winlean.nim | 2 |
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".} |