summary refs log tree commit diff stats
path: root/lib/std
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/cmdline.nim14
-rw-r--r--lib/std/decls.nim2
-rw-r--r--lib/std/dirs.nim2
-rw-r--r--lib/std/editdistance.nim4
-rw-r--r--lib/std/effecttraits.nim2
-rw-r--r--lib/std/enumerate.nim2
-rw-r--r--lib/std/enumutils.nim17
-rw-r--r--lib/std/envvars.nim2
-rw-r--r--lib/std/exitprocs.nim18
-rw-r--r--lib/std/files.nim2
-rw-r--r--lib/std/formatfloat.nim37
-rw-r--r--lib/std/genasts.nim2
-rw-r--r--lib/std/jsonutils.nim8
-rw-r--r--lib/std/monotimes.nim4
-rw-r--r--lib/std/oserrors.nim2
-rw-r--r--lib/std/outparams.nim2
-rw-r--r--lib/std/packedsets.nim2
-rw-r--r--lib/std/paths.nim12
-rw-r--r--lib/std/private/gitutils.nim13
-rw-r--r--lib/std/private/globs.nim6
-rw-r--r--lib/std/private/jsutils.nim6
-rw-r--r--lib/std/private/oscommon.nim4
-rw-r--r--lib/std/private/osdirs.nim25
-rw-r--r--lib/std/private/osfiles.nim35
-rw-r--r--lib/std/private/ospaths2.nim22
-rw-r--r--lib/std/private/ossymlinks.nim22
-rw-r--r--lib/std/private/syslocks.nim28
-rw-r--r--lib/std/private/underscored_calls.nim2
-rw-r--r--lib/std/setutils.nim2
-rw-r--r--lib/std/sha1.nim4
-rw-r--r--lib/std/socketstreams.nim2
-rw-r--r--lib/std/symlinks.nim2
-rw-r--r--lib/std/syncio.nim30
-rw-r--r--lib/std/sysatomics.nim4
-rw-r--r--lib/std/sysrand.nim2
-rw-r--r--lib/std/tasks.nim27
-rw-r--r--lib/std/tempfiles.nim6
-rw-r--r--lib/std/time_t.nim4
-rw-r--r--lib/std/typedthreads.nim94
-rw-r--r--lib/std/varints.nim12
-rw-r--r--lib/std/widestrs.nim4
-rw-r--r--lib/std/with.nim2
-rw-r--r--lib/std/wordwrap.nim2
-rw-r--r--lib/std/wrapnils.nim4
44 files changed, 295 insertions, 203 deletions
diff --git a/lib/std/cmdline.nim b/lib/std/cmdline.nim
index e545ac599..0ba4619e5 100644
--- a/lib/std/cmdline.nim
+++ b/lib/std/cmdline.nim
@@ -30,9 +30,9 @@ const weirdTarget = defined(nimscript) or defined(js)
 when weirdTarget:

   discard

 elif defined(windows):

-  import winlean

+  import std/winlean

 elif defined(posix):

-  import posix

+  import std/posix

 else:

   {.error: "The cmdline module has not been implemented for the target platform.".}

 

@@ -138,7 +138,7 @@ proc parseCmdLine*(c: string): seq[string] {.
         while i < c.len and c[i] > ' ':

           add(a, c[i])

           inc(i)

-    add(result, a)

+    add(result, move a)

 

 when defined(nimdoc):

   # Common forward declaration docstring block for parameter retrieval procs.

@@ -181,7 +181,7 @@ when defined(nimdoc):
     ## Similarly to `argv`:idx: in C,

     ## it is possible to call `paramStr(0)` but this will return OS specific

     ## contents (usually the name of the invoked executable). You should avoid

-    ## this and call `getAppFilename()`_ instead.

+    ## this and call `getAppFilename() <os.html#getAppFilename>`_ instead.

     ##

     ## **Availability**: When generating a dynamic library (see `--app:lib`) on

     ## Posix this proc is not defined.

@@ -192,7 +192,7 @@ when defined(nimdoc):
     ## * `parseCmdLine proc`_

     ## * `paramCount proc`_

     ## * `commandLineParams proc`_

-    ## * `getAppFilename proc`_

+    ## * `getAppFilename proc <os.html#getAppFilename>`_

     ##

     ## **Examples:**

     ##

@@ -282,7 +282,7 @@ when declared(paramCount) or defined(nimdoc):
     ## Convenience proc which returns the command line parameters.

     ##

     ## This returns **only** the parameters. If you want to get the application

-    ## executable filename, call `getAppFilename()`_.

+    ## executable filename, call `getAppFilename() <os.html#getAppFilename>`_.

     ##

     ## **Availability**: On Posix there is no portable way to get the command

     ## line from a DLL and thus the proc isn't defined in this environment. You

@@ -294,7 +294,7 @@ when declared(paramCount) or defined(nimdoc):
     ## * `parseCmdLine proc`_

     ## * `paramCount proc`_

     ## * `paramStr proc`_

-    ## * `getAppFilename proc`_

+    ## * `getAppFilename proc <os.html#getAppFilename>`_

     ##

     ## **Examples:**

     ##

diff --git a/lib/std/decls.nim b/lib/std/decls.nim
index 3f774cd08..bb7ec3593 100644
--- a/lib/std/decls.nim
+++ b/lib/std/decls.nim
@@ -1,6 +1,6 @@
 ## This module implements syntax sugar for some declarations.
 
-import macros
+import std/macros
 
 macro byaddr*(sect) =
   ## Allows a syntax for l-value references, being an exact analog to
diff --git a/lib/std/dirs.nim b/lib/std/dirs.nim
index 0b0366d44..380d6d08f 100644
--- a/lib/std/dirs.nim
+++ b/lib/std/dirs.nim
@@ -1,6 +1,6 @@
 ## This module implements directory handling.
 
-from paths import Path, ReadDirEffect, WriteDirEffect
+from std/paths import Path, ReadDirEffect, WriteDirEffect
 
 from std/private/osdirs import dirExists, createDir, existsOrCreateDir, removeDir,
                                moveDir, walkDir, setCurrentDir,
diff --git a/lib/std/editdistance.nim b/lib/std/editdistance.nim
index 9f29c5c05..40c0017ae 100644
--- a/lib/std/editdistance.nim
+++ b/lib/std/editdistance.nim
@@ -10,7 +10,7 @@
 ## This module implements an algorithm to compute the
 ## `edit distance`:idx: between two Unicode strings.
 
-import unicode
+import std/unicode
 
 proc editDistance*(a, b: string): int {.noSideEffect.} =
   ## Returns the **unicode-rune** edit distance between `a` and `b`.
@@ -18,7 +18,7 @@ proc editDistance*(a, b: string): int {.noSideEffect.} =
   ## This uses the `Levenshtein`:idx: distance algorithm with only a linear
   ## memory overhead.
   runnableExamples: static: doAssert editdistance("Kitten", "Bitten") == 1
-  if len(a) > len(b):
+  if runeLen(a) > runeLen(b):
     # make `b` the longer string
     return editDistance(b, a)
   # strip common prefix
diff --git a/lib/std/effecttraits.nim b/lib/std/effecttraits.nim
index fb057a669..3d1b4ffd3 100644
--- a/lib/std/effecttraits.nim
+++ b/lib/std/effecttraits.nim
@@ -14,7 +14,7 @@
 ## One can test for the existence of this standard module
 ## via `defined(nimHasEffectTraitsModule)`.
 
-import macros
+import std/macros
 
 proc getRaisesListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
 proc getTagsListImpl(n: NimNode): NimNode = discard "see compiler/vmops.nim"
diff --git a/lib/std/enumerate.nim b/lib/std/enumerate.nim
index 4f0161b7c..beb65ed30 100644
--- a/lib/std/enumerate.nim
+++ b/lib/std/enumerate.nim
@@ -11,7 +11,7 @@
 ## macro system.
 
 import std/private/since
-import macros
+import std/macros
 
 
 macro enumerate*(x: ForLoopStmt): untyped {.since: (1, 3).} =
diff --git a/lib/std/enumutils.nim b/lib/std/enumutils.nim
index 0386c2589..9c338817d 100644
--- a/lib/std/enumutils.nim
+++ b/lib/std/enumutils.nim
@@ -7,8 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
-import macros
-from typetraits import OrdinalEnum, HoleyEnum
+import std/macros
+from std/typetraits import OrdinalEnum, HoleyEnum
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
@@ -22,7 +22,8 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
   # a normalized string comparison to the `argSym` input.
   # string normalization is done using passed normalizer.
   let typ = typ.getTypeInst[1]
-  let impl = typ.getImpl[2]
+  let typSym = typ.getTypeImpl.getTypeInst # skip aliases etc to get type sym
+  let impl = typSym.getImpl[2]
   expectKind impl, nnkEnumTy
   let normalizerNode = quote: `normalizer`
   expectKind normalizerNode, nnkSym
@@ -81,7 +82,7 @@ macro genEnumCaseStmt*(typ: typedesc, argSym: typed, default: typed,
     result.add nnkElse.newTree(default)
 
 macro enumFullRange(a: typed): untyped =
-  newNimNode(nnkCurly).add(a.getType[1][1..^1])
+  newNimNode(nnkBracket).add(a.getType[1][1..^1])
 
 macro enumNames(a: typed): untyped =
   # this could be exported too; in particular this could be useful for enum with holes.
@@ -173,6 +174,9 @@ template symbolRank*[T: enum](a: T): int =
   when T is Ordinal: ord(a) - T.low.ord.static
   else: symbolRankImpl(a)
 
+proc rangeBase(T: typedesc): typedesc {.magic: "TypeTrait".}
+  # skip one level of range; return the base type of a range type
+
 func symbolName*[T: enum](a: T): string =
   ## Returns the symbol name of an enum.
   ##
@@ -191,5 +195,8 @@ func symbolName*[T: enum](a: T): string =
       c1 = 4
       c2 = 20
     assert c1.symbolName == "c1"
-  const names = enumNames(T)
+  when T is range:
+    const names = enumNames(rangeBase T)
+  else:
+    const names = enumNames(T)
   names[a.symbolRank]
diff --git a/lib/std/envvars.nim b/lib/std/envvars.nim
index ab5c9f06e..a955077ea 100644
--- a/lib/std/envvars.nim
+++ b/lib/std/envvars.nim
@@ -60,7 +60,7 @@ when not defined(nimscript):
     when defined(windows):
       proc c_putenv(envstring: cstring): cint {.importc: "_putenv", header: "<stdlib.h>".}
       from std/private/win_setenv import setEnvImpl
-      import winlean
+      import std/winlean
       when defined(nimPreviewSlimSystem):
         import std/widestrs
 
diff --git a/lib/std/exitprocs.nim b/lib/std/exitprocs.nim
index e42397c4c..f26368f42 100644
--- a/lib/std/exitprocs.nim
+++ b/lib/std/exitprocs.nim
@@ -9,7 +9,7 @@
 
 ## This module allows adding hooks to program exit.
 
-import locks
+import std/locks
 when defined(js) and not defined(nodejs):
   import std/assertions
 
@@ -29,13 +29,13 @@ initLock(gFunsLock)
 when defined(js):
   proc addAtExit(quitProc: proc() {.noconv.}) =
     when defined(nodejs):
-      asm """
+      {.emit: """
         process.on('exit', `quitProc`);
-      """
+      """.}
     elif defined(js):
-      asm """
+      {.emit: """
         window.onbeforeunload = `quitProc`;
-      """
+      """.}
 else:
   proc addAtExit(quitProc: proc() {.noconv.}) {.
     importc: "atexit", header: "<stdlib.h>".}
@@ -72,16 +72,16 @@ proc addExitProc*(cl: proc() {.noconv.}) =
 when not defined(nimscript) and (not defined(js) or defined(nodejs)):
   proc getProgramResult*(): int =
     when defined(js) and defined(nodejs):
-      asm """
+      {.emit: """
 `result` = process.exitCode;
-"""
+""".}
     else:
       result = programResult
 
   proc setProgramResult*(a: int) =
     when defined(js) and defined(nodejs):
-      asm """
+      {.emit: """
 process.exitCode = `a`;
-"""
+""".}
     else:
       programResult = a
diff --git a/lib/std/files.nim b/lib/std/files.nim
index b61b7dafd..c4e0491c9 100644
--- a/lib/std/files.nim
+++ b/lib/std/files.nim
@@ -3,7 +3,7 @@
 ## **See also:**
 ## * `paths module <paths.html>`_ for path manipulation
 
-from paths import Path, ReadDirEffect, WriteDirEffect
+from std/paths import Path, ReadDirEffect, WriteDirEffect
 
 from std/private/osfiles import fileExists, removeFile,
                                 moveFile
diff --git a/lib/std/formatfloat.nim b/lib/std/formatfloat.nim
index 48973aa55..9258245f6 100644
--- a/lib/std/formatfloat.nim
+++ b/lib/std/formatfloat.nim
@@ -35,8 +35,8 @@ proc writeFloatToBufferRoundtrip*(buf: var array[65, char]; value: float32): int
   result = float32ToChars(buf, value, forceTrailingDotZero=true).int
   buf[result] = '\0'
 
-proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
-                                    importc: "sprintf", varargs, noSideEffect.}
+proc c_snprintf(buf: cstring, n: csize_t, frmt: cstring): cint {.header: "<stdio.h>",
+                                    importc: "snprintf", varargs, noSideEffect.}
 
 proc writeToBuffer(buf: var array[65, char]; value: cstring) =
   var i = 0
@@ -49,7 +49,7 @@ proc writeFloatToBufferSprintf*(buf: var array[65, char]; value: BiggestFloat):
   ##
   ## returns the amount of bytes written to `buf` not counting the
   ## terminating '\0' character.
-  var n = c_sprintf(cast[cstring](addr buf), "%.16g", value).int
+  var n = c_snprintf(cast[cstring](addr buf), 65, "%.16g", value).int
   var hasDot = false
   for i in 0..n-1:
     if buf[i] == ',':
@@ -100,22 +100,23 @@ proc addFloatSprintf*(result: var string; x: float) =
     let n = writeFloatToBufferSprintf(buffer, x)
     result.addCstringN(cast[cstring](buffer[0].addr), n)
 
-proc nimFloatToString(a: float): cstring =
-  ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2
-  # print `-0.0` properly
-  asm """
-    function nimOnlyDigitsOrMinus(n) {
-      return n.toString().match(/^-?\d+$/);
-    }
-    if (Number.isSafeInteger(`a`))
-      `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0"
-    else {
-      `result` = `a`+""
-      if(nimOnlyDigitsOrMinus(`result`)){
-        `result` = `a`+".0"
+when defined(js):
+  proc nimFloatToString(a: float): cstring =
+    ## ensures the result doesn't print like an integer, i.e. return 2.0, not 2
+    # print `-0.0` properly
+    {.emit: """
+      function nimOnlyDigitsOrMinus(n) {
+        return n.toString().match(/^-?\d+$/);
       }
-    }
-  """
+      if (Number.isSafeInteger(`a`))
+        `result` = `a` === 0 && 1 / `a` < 0 ? "-0.0" : `a`+".0";
+      else {
+        `result` = `a`+"";
+        if(nimOnlyDigitsOrMinus(`result`)){
+          `result` = `a`+".0";
+        }
+      }
+    """.}
 
 proc addFloat*(result: var string; x: float | float32) {.inline.} =
   ## Converts float to its string representation and appends it to `result`.
diff --git a/lib/std/genasts.nim b/lib/std/genasts.nim
index 04257533d..d0f07c527 100644
--- a/lib/std/genasts.nim
+++ b/lib/std/genasts.nim
@@ -1,6 +1,6 @@
 ## This module implements AST generation using captured variables for macros.
 
-import macros
+import std/macros
 
 type GenAstOpt* = enum
   kDirtyTemplate,
diff --git a/lib/std/jsonutils.nim b/lib/std/jsonutils.nim
index b1025d24b..2d28748ce 100644
--- a/lib/std/jsonutils.nim
+++ b/lib/std/jsonutils.nim
@@ -16,7 +16,7 @@ runnableExamples:
   assert 0.0.toJson.kind == JFloat
   assert Inf.toJson.kind == JString
 
-import json, strutils, tables, sets, strtabs, options, strformat
+import std/[json, strutils, tables, sets, strtabs, options, strformat]
 
 #[
 Future directions:
@@ -30,9 +30,9 @@ add a way to customize serialization, for e.g.:
   objects.
 ]#
 
-import macros
-from enumutils import symbolName
-from typetraits import OrdinalEnum, tupleLen
+import std/macros
+from std/enumutils import symbolName
+from std/typetraits import OrdinalEnum, tupleLen
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
diff --git a/lib/std/monotimes.nim b/lib/std/monotimes.nim
index 5c67a5d4c..bf6dc776b 100644
--- a/lib/std/monotimes.nim
+++ b/lib/std/monotimes.nim
@@ -36,7 +36,7 @@ See also
 * `times module <times.html>`_
 ]##
 
-import times
+import std/times
 
 type
   MonoTime* = object ## Represents a monotonic timestamp.
@@ -74,7 +74,7 @@ when defined(js):
   {.pop.}
 
 elif defined(posix) and not defined(osx):
-  import posix
+  import std/posix
 
 when defined(zephyr):
   proc k_uptime_ticks(): int64 {.importc: "k_uptime_ticks", header: "<kernel.h>".}
diff --git a/lib/std/oserrors.nim b/lib/std/oserrors.nim
index a641a7f47..7b11c5e8e 100644
--- a/lib/std/oserrors.nim
+++ b/lib/std/oserrors.nim
@@ -15,7 +15,7 @@ type
 
 when not defined(nimscript):
   when defined(windows):
-    import winlean
+    import std/winlean
     when defined(nimPreviewSlimSystem):
       import std/widestrs
   else:
diff --git a/lib/std/outparams.nim b/lib/std/outparams.nim
index 8a0e5ae67..a471fbaa7 100644
--- a/lib/std/outparams.nim
+++ b/lib/std/outparams.nim
@@ -9,7 +9,7 @@
 
 ## `outParamsAt` macro for easy writing code that works with both 2.0 and 1.x.
 
-import macros
+import std/macros
 
 macro outParamsAt*(positions: static openArray[int]; n: untyped): untyped =
   ## Use this macro to annotate `out` parameters in a portable way.
diff --git a/lib/std/packedsets.nim b/lib/std/packedsets.nim
index c6d007c26..3320558f2 100644
--- a/lib/std/packedsets.nim
+++ b/lib/std/packedsets.nim
@@ -17,7 +17,7 @@
 ## * `sets module <sets.html>`_ for more general hash sets
 
 import std/private/since
-import hashes
+import std/hashes
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
diff --git a/lib/std/paths.nim b/lib/std/paths.nim
index f675e7445..664dedd31 100644
--- a/lib/std/paths.nim
+++ b/lib/std/paths.nim
@@ -9,7 +9,7 @@ export osseps
 import std/envvars
 import std/private/osappdirs
 
-import pathnorm
+import std/[pathnorm, hashes, sugar, strutils]
 
 from std/private/ospaths2 import  joinPath, splitPath,
                                   ReadDirEffect, WriteDirEffect,
@@ -25,6 +25,16 @@ export ReadDirEffect, WriteDirEffect
 type
   Path* = distinct string
 
+func hash*(x: Path): Hash =
+  let x = x.string.dup(normalizePath)
+  if FileSystemCaseSensitive:
+    result = x.hash
+  else:
+    result = x.toLowerAscii.hash
+
+template `$`*(x: Path): string =
+  string(x)
+
 func `==`*(x, y: Path): bool {.inline.} =
   ## Compares two paths.
   ##
diff --git a/lib/std/private/gitutils.nim b/lib/std/private/gitutils.nim
index db323bee1..6dc9c8f3b 100644
--- a/lib/std/private/gitutils.nim
+++ b/lib/std/private/gitutils.nim
@@ -4,7 +4,7 @@ internal API for now, API subject to change
 
 # xxx move other git utilities here; candidate for stdlib.
 
-import std/[os, osproc, strutils, tempfiles]
+import std/[os, paths, osproc, strutils, tempfiles]
 
 when defined(nimPreviewSlimSystem):
   import std/[assertions, syncio]
@@ -32,15 +32,8 @@ template retryCall*(maxRetry = 3, backoffDuration = 1.0, call: untyped): bool =
   result
 
 proc isGitRepo*(dir: string): bool =
-  ## This command is used to get the relative path to the root of the repository.
-  ## Using this, we can verify whether a folder is a git repository by checking
-  ## whether the command success and if the output is empty.
-  let (output, status) = execCmdEx("git rev-parse --show-cdup", workingDir = dir)
-  # On Windows there will be a trailing newline on success, remove it.
-  # The value of a successful call typically won't have a whitespace (it's
-  # usually a series of ../), so we know that it's safe to unconditionally
-  # remove trailing whitespaces from the result.
-  result = status == 0 and output.strip() == ""
+  ## Avoid calling git since it depends on /bin/sh existing and fails in Nix.
+  return fileExists(dir/".git/HEAD")
 
 proc diffFiles*(path1, path2: string): tuple[output: string, same: bool] =
   ## Returns a human readable diff of files `path1`, `path2`, the exact form of
diff --git a/lib/std/private/globs.nim b/lib/std/private/globs.nim
index 64065aac8..a6d088558 100644
--- a/lib/std/private/globs.nim
+++ b/lib/std/private/globs.nim
@@ -4,9 +4,9 @@ this can eventually be moved to std/os and `walkDirRec` can be implemented in te
 to avoid duplication
 ]##
 
-import os
+import std/os
 when defined(windows):
-  from strutils import replace
+  from std/strutils import replace
 
 when defined(nimPreviewSlimSystem):
   import std/[assertions, objectdollar]
@@ -65,6 +65,6 @@ proc nativeToUnixPath*(path: string): string =
     result = replace(result, '\\', '/')
 
 when isMainModule:
-  import sugar
+  import std/sugar
   for a in walkDirRecFilter(".", follow = a=>a.path.lastPathPart notin ["nimcache", ".git", "csources_v1", "csources", "bin"]):
     echo a
diff --git a/lib/std/private/jsutils.nim b/lib/std/private/jsutils.nim
index fd1f395f3..5f79eab27 100644
--- a/lib/std/private/jsutils.nim
+++ b/lib/std/private/jsutils.nim
@@ -37,13 +37,13 @@ when defined(js):
       let a = array[2, float64].default
       assert jsConstructorName(a) == "Float64Array"
       assert jsConstructorName(a.toJs) == "Float64Array"
-    asm """`result` = `a`.constructor.name"""
+    {.emit: """`result` = `a`.constructor.name;""".}
 
   proc hasJsBigInt*(): bool =
-    asm """`result` = typeof BigInt != 'undefined'"""
+    {.emit: """`result` = typeof BigInt != 'undefined';""".}
 
   proc hasBigUint64Array*(): bool =
-    asm """`result` = typeof BigUint64Array != 'undefined'"""
+    {.emit: """`result` = typeof BigUint64Array != 'undefined';""".}
 
   proc getProtoName*[T](a: T): cstring {.importjs: "Object.prototype.toString.call(#)".} =
     runnableExamples:
diff --git a/lib/std/private/oscommon.nim b/lib/std/private/oscommon.nim
index c24db3f67..c49d52ef2 100644
--- a/lib/std/private/oscommon.nim
+++ b/lib/std/private/oscommon.nim
@@ -22,9 +22,9 @@ type
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean, times
+  import std/[winlean, times]
 elif defined(posix):
-  import posix
+  import std/posix
   proc c_rename(oldname, newname: cstring): cint {.
     importc: "rename", header: "<stdio.h>".}
 else:
diff --git a/lib/std/private/osdirs.nim b/lib/std/private/osdirs.nim
index a4318367d..a44cad7d9 100644
--- a/lib/std/private/osdirs.nim
+++ b/lib/std/private/osdirs.nim
@@ -16,9 +16,9 @@ when defined(nimPreviewSlimSystem):
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean, times
+  import std/[winlean, times]
 elif defined(posix):
-  import posix, times
+  import std/[posix, times]
 
 else:
   {.error: "OS module not ported to your operating system!".}
@@ -446,13 +446,17 @@ proc createDir*(dir: string) {.rtl, extern: "nos$1",
     else:
       discard existsOrCreateDir(p)
 
-proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
+proc copyDir*(source, dest: string, skipSpecial = false) {.rtl, extern: "nos$1",
   tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect], benign, noWeirdTarget.} =
   ## Copies a directory from `source` to `dest`.
   ##
   ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
   ## are skipped.
   ##
+  ## If `skipSpecial` is true, then (besides all directories) only *regular*
+  ## files (**without** special "file" objects like FIFOs, device files,
+  ## etc) will be copied on Unix.
+  ##
   ## If this fails, `OSError` is raised.
   ##
   ## On the Windows platform this proc will copy the attributes from
@@ -472,16 +476,17 @@ proc copyDir*(source, dest: string) {.rtl, extern: "nos$1",
   ## * `createDir proc`_
   ## * `moveDir proc`_
   createDir(dest)
-  for kind, path in walkDir(source):
+  for kind, path in walkDir(source, skipSpecial = skipSpecial):
     var noSource = splitPath(path).tail
     if kind == pcDir:
-      copyDir(path, dest / noSource)
+      copyDir(path, dest / noSource, skipSpecial = skipSpecial)
     else:
       copyFile(path, dest / noSource, {cfSymlinkAsIs})
 
 
 proc copyDirWithPermissions*(source, dest: string,
-                             ignorePermissionErrors = true)
+                             ignorePermissionErrors = true,
+                             skipSpecial = false)
   {.rtl, extern: "nos$1", tags: [ReadDirEffect, WriteIOEffect, ReadIOEffect],
    benign, noWeirdTarget.} =
   ## Copies a directory from `source` to `dest` preserving file permissions.
@@ -489,6 +494,10 @@ proc copyDirWithPermissions*(source, dest: string,
   ## On non-Windows OSes, symlinks are copied as symlinks. On Windows, symlinks
   ## are skipped.
   ##
+  ## If `skipSpecial` is true, then (besides all directories) only *regular*
+  ## files (**without** special "file" objects like FIFOs, device files,
+  ## etc) will be copied on Unix.
+  ##
   ## If this fails, `OSError` is raised. This is a wrapper proc around
   ## `copyDir`_ and `copyFileWithPermissions`_ procs
   ## on non-Windows platforms.
@@ -518,10 +527,10 @@ proc copyDirWithPermissions*(source, dest: string,
     except:
       if not ignorePermissionErrors:
         raise
-  for kind, path in walkDir(source):
+  for kind, path in walkDir(source, skipSpecial = skipSpecial):
     var noSource = splitPath(path).tail
     if kind == pcDir:
-      copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors)
+      copyDirWithPermissions(path, dest / noSource, ignorePermissionErrors, skipSpecial = skipSpecial)
     else:
       copyFileWithPermissions(path, dest / noSource, ignorePermissionErrors, {cfSymlinkAsIs})
 
diff --git a/lib/std/private/osfiles.nim b/lib/std/private/osfiles.nim
index f2e7bf11d..37d8eabca 100644
--- a/lib/std/private/osfiles.nim
+++ b/lib/std/private/osfiles.nim
@@ -15,9 +15,9 @@ when defined(nimPreviewSlimSystem):
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean
+  import std/winlean
 elif defined(posix):
-  import posix, times
+  import std/[posix, times]
 
   proc toTime(ts: Timespec): times.Time {.inline.} =
     result = initTime(ts.tv_sec.int64, ts.tv_nsec.int)
@@ -173,7 +173,7 @@ type
 
 const copyFlagSymlink = {cfSymlinkAsIs, cfSymlinkFollow, cfSymlinkIgnore}
 
-proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
+proc copyFile*(source, dest: string, options = {cfSymlinkFollow}; bufferSize = 16_384) {.rtl,
   extern: "nos$1", tags: [ReadDirEffect, ReadIOEffect, WriteIOEffect],
   noWeirdTarget.} =
   ## Copies a file from `source` to `dest`, where `dest.parentDir` must exist.
@@ -202,6 +202,8 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
   ## On OSX, `copyfile` C api will be used (available since OSX 10.5) unless
   ## `-d:nimLegacyCopyFile` is used.
   ##
+  ## `copyFile` allows to specify `bufferSize` to improve I/O performance.
+  ##
   ## See also:
   ## * `CopyFlag enum`_
   ## * `copyDir proc`_
@@ -210,8 +212,7 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
   ## * `removeFile proc`_
   ## * `moveFile proc`_
 
-  doAssert card(copyFlagSymlink * options) == 1, "There should be exactly " &
-                                                 "one cfSymlink* in options"
+  doAssert card(copyFlagSymlink * options) == 1, "There should be exactly one cfSymlink* in options"
   let isSymlink = source.symlinkExists
   if isSymlink and (cfSymlinkIgnore in options or defined(windows)):
     return
@@ -238,15 +239,21 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
         if status2 != 0: raiseOSError(osLastError(), $(source, dest))
       else:
         # generic version of copyFile which works for any platform:
-        const bufSize = 8000 # better for memory manager
         var d, s: File
-        if not open(s, source):raiseOSError(osLastError(), source)
+        if not open(s, source): raiseOSError(osLastError(), source)
         if not open(d, dest, fmWrite):
           close(s)
           raiseOSError(osLastError(), dest)
-        var buf = alloc(bufSize)
+
+        # Hints for kernel-level aggressive sequential low-fragmentation read-aheads:
+        # https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_fadvise.html
+        when defined(linux) or defined(osx):
+          discard posix_fadvise(getFileHandle(d), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
+          discard posix_fadvise(getFileHandle(s), 0.cint, 0.cint, POSIX_FADV_SEQUENTIAL)
+
+        var buf = alloc(bufferSize)
         while true:
-          var bytesread = readBuffer(s, buf, bufSize)
+          var bytesread = readBuffer(s, buf, bufferSize)
           if bytesread > 0:
             var byteswritten = writeBuffer(d, buf, bytesread)
             if bytesread != byteswritten:
@@ -254,13 +261,13 @@ proc copyFile*(source, dest: string, options = {cfSymlinkFollow}) {.rtl,
               close(s)
               close(d)
               raiseOSError(osLastError(), dest)
-          if bytesread != bufSize: break
+          if bytesread != bufferSize: break
         dealloc(buf)
         close(s)
         flushFile(d)
         close(d)
 
-proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow})
+proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow}; bufferSize = 16_384)
   {.noWeirdTarget, since: (1,3,7).} =
   ## Copies a file `source` into directory `dir`, which must exist.
   ##
@@ -268,12 +275,14 @@ proc copyFileToDir*(source, dir: string, options = {cfSymlinkFollow})
   ## if `source` is a symlink, copies the file symlink points to. `options` is
   ## ignored on Windows: symlinks are skipped.
   ##
+  ## `copyFileToDir` allows to specify `bufferSize` to improve I/O performance.
+  ##
   ## See also:
   ## * `CopyFlag enum`_
   ## * `copyFile proc`_
   if dir.len == 0: # treating "" as "." is error prone
     raise newException(ValueError, "dest is empty")
-  copyFile(source, dir / source.lastPathPart, options)
+  copyFile(source, dir / source.lastPathPart, options, bufferSize)
 
 
 proc copyFileWithPermissions*(source, dest: string,
@@ -399,7 +408,7 @@ proc moveFile*(source, dest: string) {.rtl, extern: "nos$1",
       raiseAssert "unreachable"
     else:
       # Fallback to copy & del
-      copyFile(source, dest, {cfSymlinkAsIs})
+      copyFileWithPermissions(source, dest, options={cfSymlinkAsIs})
       try:
         removeFile(source)
       except:
diff --git a/lib/std/private/ospaths2.nim b/lib/std/private/ospaths2.nim
index 421def62b..bc69ff725 100644
--- a/lib/std/private/ospaths2.nim
+++ b/lib/std/private/ospaths2.nim
@@ -1,7 +1,7 @@
 include system/inclrtl
 import std/private/since
 
-import strutils, pathnorm
+import std/[strutils, pathnorm]
 import std/oserrors
 
 import oscommon
@@ -17,9 +17,9 @@ const weirdTarget = defined(nimscript) or defined(js)
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean
+  import std/winlean
 elif defined(posix):
-  import posix, system/ansi_c
+  import std/posix, system/ansi_c
 else:
   {.error: "OS module not ported to your operating system!".}
 
@@ -254,10 +254,10 @@ proc isAbsolute*(path: string): bool {.rtl, noSideEffect, extern: "nos$1", raise
     result = path[0] != ':'
   elif defined(RISCOS):
     result = path[0] == '$'
-  elif defined(posix) or defined(js):
-    # `or defined(js)` wouldn't be needed pending https://github.com/nim-lang/Nim/issues/13469
-    # This works around the problem for posix, but Windows is still broken with nim js -d:nodejs
+  elif defined(posix):
     result = path[0] == '/'
+  elif defined(nodejs):
+    {.emit: [result," = require(\"path\").isAbsolute(",path.cstring,");"].}
   else:
     raiseAssert "unreachable" # if ever hits here, adapt as needed
 
@@ -763,9 +763,9 @@ proc cmpPaths*(pathA, pathB: string): int {.
   ## On a case-sensitive filesystem this is done
   ## case-sensitively otherwise case-insensitively. Returns:
   ##
-  ## | 0 if pathA == pathB
-  ## | < 0 if pathA < pathB
-  ## | > 0 if pathA > pathB
+  ## | `0` if pathA == pathB
+  ## | `< 0` if pathA < pathB
+  ## | `> 0` if pathA > pathB
   runnableExamples:
     when defined(macosx):
       assert cmpPaths("foo", "Foo") == 0
@@ -862,13 +862,13 @@ when not defined(nimscript):
       raiseAssert "use -d:nodejs to have `getCurrentDir` defined"
     elif defined(windows):
       var bufsize = MAX_PATH.int32
-      var res = newWideCString("", bufsize)
+      var res = newWideCString(bufsize)
       while true:
         var L = getCurrentDirectoryW(bufsize, res)
         if L == 0'i32:
           raiseOSError(osLastError())
         elif L > bufsize:
-          res = newWideCString("", L)
+          res = newWideCString(L)
           bufsize = L
         else:
           result = res$L
diff --git a/lib/std/private/ossymlinks.nim b/lib/std/private/ossymlinks.nim
index 18737b8b5..c1760c42e 100644
--- a/lib/std/private/ossymlinks.nim
+++ b/lib/std/private/ossymlinks.nim
@@ -10,9 +10,9 @@ when defined(nimPreviewSlimSystem):
 when weirdTarget:
   discard
 elif defined(windows):
-  import winlean, times
+  import std/[winlean, times]
 elif defined(posix):
-  import posix
+  import std/posix
 else:
   {.error: "OS module not ported to your operating system!".}
 
@@ -66,11 +66,13 @@ proc expandSymlink*(symlinkPath: string): string {.noWeirdTarget.} =
   when defined(windows) or defined(nintendoswitch):
     result = symlinkPath
   else:
-    result = newString(maxSymlinkLen)
-    var len = readlink(symlinkPath, result.cstring, maxSymlinkLen)
-    if len < 0:
-      raiseOSError(osLastError(), symlinkPath)
-    if len > maxSymlinkLen:
-      result = newString(len+1)
-      len = readlink(symlinkPath, result.cstring, len)
-    setLen(result, len)
+    var bufLen = 1024
+    while true:
+      result = newString(bufLen)
+      let len = readlink(symlinkPath.cstring, result.cstring, bufLen)
+      if len < 0:
+        raiseOSError(osLastError(), symlinkPath)
+      if len < bufLen:
+        result.setLen(len)
+        break
+      bufLen = bufLen shl 1
diff --git a/lib/std/private/syslocks.nim b/lib/std/private/syslocks.nim
index ca8897dc2..e19ec2c04 100644
--- a/lib/std/private/syslocks.nim
+++ b/lib/std/private/syslocks.nim
@@ -16,7 +16,7 @@ when defined(windows):
     Handle = int
 
     SysLock* {.importc: "CRITICAL_SECTION",
-              header: "<windows.h>", final, pure.} = object # CRITICAL_SECTION in WinApi
+              header: "<windows.h>", final, pure, byref.} = object # CRITICAL_SECTION in WinApi
       DebugInfo: pointer
       LockCount: int32
       RecursionCount: int32
@@ -24,7 +24,7 @@ when defined(windows):
       LockSemaphore: int
       SpinCount: int
 
-    SysCond* {.importc: "RTL_CONDITION_VARIABLE", header: "<windows.h>".} = object
+    SysCond* {.importc: "RTL_CONDITION_VARIABLE", header: "<windows.h>", byref.} = object
       thePtr {.importc: "Ptr".} : Handle
 
   proc initSysLock*(L: var SysLock) {.importc: "InitializeCriticalSection",
@@ -46,7 +46,7 @@ when defined(windows):
                                     header: "<windows.h>".}
     ## Releases the lock `L`.
 
-  proc deinitSys*(L: var SysLock) {.importc: "DeleteCriticalSection",
+  proc deinitSys*(L: SysLock) {.importc: "DeleteCriticalSection",
                                    header: "<windows.h>".}
 
   proc initializeConditionVariable(
@@ -68,7 +68,7 @@ when defined(windows):
 
   proc initSysCond*(cond: var SysCond) {.inline.} =
     initializeConditionVariable(cond)
-  proc deinitSysCond*(cond: var SysCond) {.inline.} =
+  proc deinitSysCond*(cond: SysCond) {.inline.} =
     discard
   proc waitSysCond*(cond: var SysCond, lock: var SysLock) =
     discard sleepConditionVariableCS(cond, lock, -1'i32)
@@ -83,13 +83,13 @@ elif defined(genode):
               header: Header.} = object
 
   proc initSysLock*(L: var SysLock) = discard
-  proc deinitSys*(L: var SysLock) = discard
+  proc deinitSys*(L: SysLock) = discard
   proc acquireSys*(L: var SysLock) {.noSideEffect, importcpp.}
   proc tryAcquireSys*(L: var SysLock): bool {.noSideEffect, importcpp.}
   proc releaseSys*(L: var SysLock) {.noSideEffect, importcpp.}
 
   proc initSysCond*(L: var SysCond) = discard
-  proc deinitSysCond*(L: var SysCond) = discard
+  proc deinitSysCond*(L: SysCond) = discard
   proc waitSysCond*(cond: var SysCond, lock: var SysLock) {.
     noSideEffect, importcpp.}
   proc signalSysCond*(cond: var SysCond) {.
@@ -101,7 +101,7 @@ else:
   type
     SysLockObj {.importc: "pthread_mutex_t", pure, final,
                header: """#include <sys/types.h>
-                          #include <pthread.h>""".} = object
+                          #include <pthread.h>""", byref.} = object
       when defined(linux) and defined(amd64):
         abi: array[40 div sizeof(clong), clong]
 
@@ -113,7 +113,7 @@ else:
 
     SysCondObj {.importc: "pthread_cond_t", pure, final,
                header: """#include <sys/types.h>
-                          #include <pthread.h>""".} = object
+                          #include <pthread.h>""", byref.} = object
       when defined(linux) and defined(amd64):
         abi: array[48 div sizeof(clonglong), clonglong]
 
@@ -127,7 +127,7 @@ else:
 
   proc initSysLockAux(L: var SysLockObj, attr: ptr SysLockAttr) {.
     importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
-  proc deinitSysAux(L: var SysLockObj) {.noSideEffect,
+  proc deinitSysAux(L: SysLockObj) {.noSideEffect,
     importc: "pthread_mutex_destroy", header: "<pthread.h>".}
 
   proc acquireSysAux(L: var SysLockObj) {.noSideEffect,
@@ -156,7 +156,7 @@ else:
       L = cast[SysLock](c_malloc(csize_t(sizeof(SysLockObj))))
       initSysLockAux(L[], attr)
 
-    proc deinitSys*(L: var SysLock) =
+    proc deinitSys*(L: SysLock) =
       deinitSysAux(L[])
       c_free(L)
 
@@ -173,7 +173,7 @@ else:
 
     template initSysLock*(L: var SysLock, attr: ptr SysLockAttr = nil) =
       initSysLockAux(L, attr)
-    template deinitSys*(L: var SysLock) =
+    template deinitSys*(L: SysLock) =
       deinitSysAux(L)
     template acquireSys*(L: var SysLock) =
       acquireSysAux(L)
@@ -193,7 +193,7 @@ else:
   # locks
   proc initSysCondAux(cond: var SysCondObj, cond_attr: ptr SysCondAttr = nil) {.
     importc: "pthread_cond_init", header: "<pthread.h>", noSideEffect.}
-  proc deinitSysCondAux(cond: var SysCondObj) {.noSideEffect,
+  proc deinitSysCondAux(cond: SysCondObj) {.noSideEffect,
     importc: "pthread_cond_destroy", header: "<pthread.h>".}
 
   proc waitSysCondAux(cond: var SysCondObj, lock: var SysLockObj): cint {.
@@ -208,7 +208,7 @@ else:
       cond = cast[SysCond](c_malloc(csize_t(sizeof(SysCondObj))))
       initSysCondAux(cond[], cond_attr)
 
-    proc deinitSysCond*(cond: var SysCond) =
+    proc deinitSysCond*(cond: SysCond) =
       deinitSysCondAux(cond[])
       c_free(cond)
 
@@ -221,7 +221,7 @@ else:
   else:
     template initSysCond*(cond: var SysCond, cond_attr: ptr SysCondAttr = nil) =
       initSysCondAux(cond, cond_attr)
-    template deinitSysCond*(cond: var SysCond) =
+    template deinitSysCond*(cond: SysCond) =
       deinitSysCondAux(cond)
 
     template waitSysCond*(cond: var SysCond, lock: var SysLock) =
diff --git a/lib/std/private/underscored_calls.nim b/lib/std/private/underscored_calls.nim
index 8b0392641..f853572b5 100644
--- a/lib/std/private/underscored_calls.nim
+++ b/lib/std/private/underscored_calls.nim
@@ -10,7 +10,7 @@
 
 ## This is an internal helper module. Do not use.
 
-import macros
+import std/macros
 
 proc underscoredCalls*(result, calls, arg0: NimNode)
 
diff --git a/lib/std/setutils.nim b/lib/std/setutils.nim
index 4664d6dcc..8e7bc6a92 100644
--- a/lib/std/setutils.nim
+++ b/lib/std/setutils.nim
@@ -14,7 +14,7 @@
 ## * `std/packedsets <packedsets.html>`_
 ## * `std/sets <sets.html>`_
 
-import typetraits, macros
+import std/[typetraits, macros]
 
 #[
   type SetElement* = char|byte|bool|int16|uint16|enum|uint8|int8
diff --git a/lib/std/sha1.nim b/lib/std/sha1.nim
index a1a8c4782..213af4229 100644
--- a/lib/std/sha1.nim
+++ b/lib/std/sha1.nim
@@ -29,8 +29,8 @@ runnableExamples("-r:off"):
 
 {.deprecated: "use command `nimble install checksums` and import `checksums/sha1` instead".}
 
-import strutils
-from endians import bigEndian32, bigEndian64
+import std/strutils
+from std/endians import bigEndian32, bigEndian64
 
 when defined(nimPreviewSlimSystem):
   import std/syncio
diff --git a/lib/std/socketstreams.nim b/lib/std/socketstreams.nim
index 41d46e58a..45e906795 100644
--- a/lib/std/socketstreams.nim
+++ b/lib/std/socketstreams.nim
@@ -64,7 +64,7 @@
 ##   sendStream.write "I" # Throws an error as we can't write into an already sent buffer
 ##   ```
 
-import net, streams
+import std/[net, streams]
 
 type
   ReadSocketStream* = ref ReadSocketStreamObj
diff --git a/lib/std/symlinks.nim b/lib/std/symlinks.nim
index 60487740c..dbe908612 100644
--- a/lib/std/symlinks.nim
+++ b/lib/std/symlinks.nim
@@ -2,7 +2,7 @@
 
 ## .. importdoc:: os.nim
 
-from paths import Path, ReadDirEffect
+from std/paths import Path, ReadDirEffect
 
 from std/private/ossymlinks import symlinkExists, createSymlink, expandSymlink
 
diff --git a/lib/std/syncio.nim b/lib/std/syncio.nim
index 879301f8a..c34a025af 100644
--- a/lib/std/syncio.nim
+++ b/lib/std/syncio.nim
@@ -151,14 +151,11 @@ proc c_fprintf(f: File, frmt: cstring): cint {.
 proc c_fputc(c: char, f: File): cint {.
   importc: "fputc", header: "<stdio.h>".}
 
-template sysFatal(exc, msg) =
-  raise newException(exc, msg)
-
 proc raiseEIO(msg: string) {.noinline, noreturn.} =
-  sysFatal(IOError, msg)
+  raise newException(IOError, msg)
 
 proc raiseEOF() {.noinline, noreturn.} =
-  sysFatal(EOFError, "EOF reached")
+  raise newException(EOFError, "EOF reached")
 
 proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
 
@@ -246,7 +243,7 @@ when defined(windows):
     # machine. We also enable `setConsoleOutputCP(65001)` now by default.
     # But we cannot call printf directly as the string might contain \0.
     # So we have to loop over all the sections separated by potential \0s.
-    var i = c_fprintf(f, "%s", s)
+    var i = int c_fprintf(f, "%s", s)
     while i < s.len:
       if s[i] == '\0':
         let w = c_fputc('\0', f)
@@ -323,7 +320,7 @@ elif defined(windows):
 const
   BufSize = 4000
 
-proc close*(f: File) {.tags: [], gcsafe.} =
+proc close*(f: File) {.tags: [], gcsafe, sideEffect.} =
   ## Closes the file.
   if not f.isNil:
     discard c_fclose(f)
@@ -422,7 +419,7 @@ proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
     if f.isatty:
       const numberOfCharsToRead = 2048
       var numberOfCharsRead = 0'i32
-      var buffer = newWideCString("", numberOfCharsToRead)
+      var buffer = newWideCString(numberOfCharsToRead)
       if readConsole(getOsFileHandle(f), addr(buffer[0]),
         numberOfCharsToRead, addr(numberOfCharsRead), nil) == 0:
         var error = getLastError()
@@ -651,6 +648,9 @@ const
         ""
     else:
       ""
+  RawFormatOpen: array[FileMode, cstring] = [
+    # used for open by FileHandle, which calls `fdopen`
+    cstring("rb"), "wb", "w+b", "r+b", "ab"]
   FormatOpen: array[FileMode, cstring] = [
     cstring("rb" & NoInheritFlag), "wb" & NoInheritFlag, "w+b" & NoInheritFlag,
     "r+b" & NoInheritFlag, "ab" & NoInheritFlag
@@ -752,7 +752,7 @@ proc open*(f: var File, filehandle: FileHandle,
         filehandle) else: filehandle
     if not setInheritable(oshandle, false):
       return false
-  f = c_fdopen(filehandle, FormatOpen[mode])
+  f = c_fdopen(filehandle, RawFormatOpen[mode])
   result = f != nil
 
 proc open*(filename: string,
@@ -764,9 +764,9 @@ proc open*(filename: string,
   ##
   ## The file handle associated with the resulting `File` is not inheritable.
   if not open(result, filename, mode, bufSize):
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
-proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign.} =
+proc setFilePos*(f: File, pos: int64, relativeTo: FileSeekPos = fspSet) {.benign, sideEffect.} =
   ## Sets the position of the file pointer that is used for read/write
   ## operations. The file's first byte has the index zero.
   if c_fseek(f, pos, cint(relativeTo)) != 0:
@@ -852,7 +852,7 @@ proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.} =
     finally:
       close(f)
   else:
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
 proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} =
   ## Opens a file named `filename` for writing. Then writes the
@@ -865,7 +865,7 @@ proc writeFile*(filename, content: string) {.tags: [WriteIOEffect], benign.} =
     finally:
       close(f)
   else:
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
 proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
   ## Opens a file named `filename` for writing. Then writes the
@@ -874,7 +874,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
   var f: File = nil
   if open(f, filename, fmWrite):
     try:
-      f.writeBuffer(unsafeAddr content[0], content.len)
+      discard f.writeBuffer(unsafeAddr content[0], content.len)
     finally:
       close(f)
   else:
@@ -895,7 +895,7 @@ proc readLines*(filename: string, n: Natural): seq[string] =
     finally:
       close(f)
   else:
-    sysFatal(IOError, "cannot open: " & filename)
+    raise newException(IOError, "cannot open: " & filename)
 
 template readLines*(filename: string): seq[
     string] {.deprecated: "use readLines with two arguments".} =
diff --git a/lib/std/sysatomics.nim b/lib/std/sysatomics.nim
index 36a4e5537..2f203b3eb 100644
--- a/lib/std/sysatomics.nim
+++ b/lib/std/sysatomics.nim
@@ -265,6 +265,7 @@ else:
 
 
 proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: [], tags: [].} =
+  ## Atomically increments the integer by some `x`. It returns the new value.
   when someGcc and hasThreadSupport:
     result = atomicAddFetch(memLoc.addr, x, ATOMIC_SEQ_CST)
   elif someVcc and hasThreadSupport:
@@ -275,6 +276,7 @@ proc atomicInc*(memLoc: var int, x: int = 1): int {.inline, discardable, raises:
     result = memLoc
 
 proc atomicDec*(memLoc: var int, x: int = 1): int {.inline, discardable, raises: [], tags: [].} =
+  ## Atomically decrements the integer by some `x`. It returns the new value.
   when someGcc and hasThreadSupport:
     when declared(atomicSubFetch):
       result = atomicSubFetch(memLoc.addr, x, ATOMIC_SEQ_CST)
@@ -361,7 +363,7 @@ elif someGcc or defined(tcc):
 elif defined(icl):
   proc cpuRelax* {.importc: "_mm_pause", header: "xmmintrin.h".}
 elif false:
-  from os import sleep
+  from std/os import sleep
 
   proc cpuRelax* {.inline.} = os.sleep(1)
 
diff --git a/lib/std/sysrand.nim b/lib/std/sysrand.nim
index 8526336ad..6f2c6b0c1 100644
--- a/lib/std/sysrand.nim
+++ b/lib/std/sysrand.nim
@@ -60,7 +60,7 @@ when not defined(js):
   import std/oserrors
 
 when defined(posix):
-  import posix
+  import std/posix
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
diff --git a/lib/std/tasks.nim b/lib/std/tasks.nim
index 9eb7c97c4..7e59747f5 100644
--- a/lib/std/tasks.nim
+++ b/lib/std/tasks.nim
@@ -68,7 +68,8 @@ type
 
 proc `=copy`*(x: var Task, y: Task) {.error.}
 
-when defined(nimAllowNonVarDestructor):
+const arcLike = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
+when defined(nimAllowNonVarDestructor) and arcLike:
   proc `=destroy`*(t: Task) {.inline, gcsafe.} =
     ## Frees the resources allocated for a `Task`.
     if t.args != nil:
@@ -109,6 +110,19 @@ template addAllNode(assignParam: NimNode, procParam: NimNode) =
   tempAssignList.add newLetStmt(tempNode, newDotExpr(objTemp, formalParams[i][0]))
   scratchRecList.add newIdentDefs(newIdentNode(formalParams[i][0].strVal), assignParam)
 
+proc analyseRootSym(s: NimNode): NimNode =
+  result = s
+  while true:
+    case result.kind
+    of nnkBracketExpr, nnkDerefExpr, nnkHiddenDeref,
+        nnkAddr, nnkHiddenAddr,
+        nnkObjDownConv, nnkObjUpConv:
+      result = result[0]
+    of nnkDotExpr, nnkCheckedFieldExpr, nnkHiddenStdConv, nnkHiddenSubConv:
+      result = result[1]
+    else:
+      break
+
 macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkCallStrLit}): Task =
   ## Converts the call and its arguments to `Task`.
   runnableExamples:
@@ -120,11 +134,14 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
   let retType = getTypeInst(e)
   let returnsVoid = retType.typeKind == ntyVoid
 
+  let rootSym = analyseRootSym(e[0])
+  expectKind rootSym, nnkSym
+
   when compileOption("threads"):
-    if not isGcSafe(e[0]):
+    if not isGcSafe(rootSym):
       error("'toTask' takes a GC safe call expression", e)
 
-  if hasClosure(e[0]):
+  if hasClosure(rootSym):
     error("closure call is not allowed", e)
 
   if e.len > 1:
@@ -208,7 +225,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
     let funcCall = newCall(e[0], callNode)
     functionStmtList.add tempAssignList
 
-    let funcName = genSym(nskProc, e[0].strVal)
+    let funcName = genSym(nskProc, rootSym.strVal)
     let destroyName = genSym(nskProc, "destroyScratch")
     let objTemp2 = genSym(ident = "obj")
     let tempNode = quote("@") do:
@@ -240,7 +257,7 @@ macro toTask*(e: typed{nkCall | nkInfix | nkPrefix | nkPostfix | nkCommand | nkC
       Task(callback: `funcName`, args: `scratchIdent`, destroy: `destroyName`)
   else:
     let funcCall = newCall(e[0])
-    let funcName = genSym(nskProc, e[0].strVal)
+    let funcName = genSym(nskProc, rootSym.strVal)
 
     if returnsVoid:
       result = quote do:
diff --git a/lib/std/tempfiles.nim b/lib/std/tempfiles.nim
index 1160aaaad..539305bde 100644
--- a/lib/std/tempfiles.nim
+++ b/lib/std/tempfiles.nim
@@ -17,7 +17,7 @@ See also:
 * `mkstemp` (posix), refs https://man7.org/linux/man-pages/man3/mkstemp.3.html
 ]#
 
-import os, random
+import std / [os, random]
 
 when defined(nimPreviewSlimSystem):
   import std/syncio
@@ -29,7 +29,7 @@ const
 
 
 when defined(windows):
-  import winlean
+  import std/winlean
   when defined(nimPreviewSlimSystem):
     import std/widestrs
 
@@ -46,7 +46,7 @@ when defined(windows):
   proc close_osfandle(fd: cint): cint {.
     importc: "_close", header: "<io.h>".}
 else:
-  import posix
+  import std/posix
 
   proc c_fdopen(
     filehandle: cint,
diff --git a/lib/std/time_t.nim b/lib/std/time_t.nim
index 7fb6e6d46..de051b135 100644
--- a/lib/std/time_t.nim
+++ b/lib/std/time_t.nim
@@ -14,10 +14,10 @@ when defined(nimdoc):
       ## Wrapper for `time_t`. On posix, this is an alias to `posix.Time`.
 elif defined(windows):
   when defined(i386) and defined(gcc):
-    type Time* {.importc: "time_t", header: "<time.h>".} = distinct int32
+    type Time* {.importc: "time_t", header: "<time.h>".} = distinct clong
   else:
     # newest version of Visual C++ defines time_t to be of 64 bits
     type Time* {.importc: "time_t", header: "<time.h>".} = distinct int64
 elif defined(posix):
-  import posix
+  import std/posix
   export posix.Time
\ No newline at end of file
diff --git a/lib/std/typedthreads.nim b/lib/std/typedthreads.nim
index 501a0d0fa..7b0b81968 100644
--- a/lib/std/typedthreads.nim
+++ b/lib/std/typedthreads.nim
@@ -7,33 +7,73 @@
 #    distribution, for details about the copyright.
 #
 
-## Thread support for Nim.
-##
-## Examples
-## ========
-##
-##   ```Nim
-##   import std/locks
-##
-##   var
-##     thr: array[0..4, Thread[tuple[a,b: int]]]
-##     L: Lock
-##
-##   proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
-##     for i in interval.a..interval.b:
-##       acquire(L) # lock stdout
-##       echo i
-##       release(L)
-##
-##   initLock(L)
-##
-##   for i in 0..high(thr):
-##     createThread(thr[i], threadFunc, (i*10, i*10+5))
-##   joinThreads(thr)
-##
-##   deinitLock(L)
-##   ```
-
+##[
+Thread support for Nim. Threads allow multiple functions to execute concurrently.
+ 
+In Nim, threads are a low-level construct and using a library like `malebolgia`, `taskpools` or `weave` is recommended.
+ 
+When creating a thread, you can pass arguments to it. As Nim's garbage collector does not use atomic references, sharing
+`ref` and other variables managed by the garbage collector between threads is not supported.
+Use global variables to do so, or pointers.
+ 
+Memory allocated using [`sharedAlloc`](./system.html#allocShared.t%2CNatural) can be used and shared between threads.
+
+To communicate between threads, consider using [channels](./system.html#Channel)
+
+Examples
+========
+
+```Nim
+import std/locks
+
+var
+  thr: array[0..4, Thread[tuple[a,b: int]]]
+  L: Lock
+
+proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
+  for i in interval.a..interval.b:
+    acquire(L) # lock stdout
+    echo i
+    release(L)
+
+initLock(L)
+
+for i in 0..high(thr):
+  createThread(thr[i], threadFunc, (i*10, i*10+5))
+joinThreads(thr)
+
+deinitLock(L)
+```
+ 
+When using a memory management strategy that supports shared heaps like `arc` or `boehm`,
+you can pass pointer to threads and share memory between them, but the memory must outlive the thread.
+The default memory management strategy, `orc`, supports this.
+The example below is **not valid** for memory management strategies that use local heaps like `refc`!
+
+```Nim
+import locks
+ 
+var l: Lock
+ 
+proc threadFunc(obj: ptr seq[int]) {.thread.} =
+  withLock l:
+    for i in 0..<100:
+      obj[].add(obj[].len * obj[].len)
+ 
+proc threadHandler() =
+  var thr: array[0..4, Thread[ptr seq[int]]]
+  var s = newSeq[int]()
+    
+  for i in 0..high(thr):
+    createThread(thr[i], threadFunc, s.addr)
+  joinThreads(thr)
+  echo s
+ 
+initLock(l)
+threadHandler()
+deinitLock(l)
+```
+]##
 
 
 import std/private/[threadtypes]
diff --git a/lib/std/varints.nim b/lib/std/varints.nim
index 0d18b9069..32fe2fffb 100644
--- a/lib/std/varints.nim
+++ b/lib/std/varints.nim
@@ -82,29 +82,29 @@ proc writeVu64*(z: var openArray[byte], x: uint64): int =
       z[3] = cast[uint8](y)
       return 4
     z[0] = 251
-    varintWrite32(toOpenArray(z, 1, z.high-1), y)
+    varintWrite32(toOpenArray(z, 1, 4), y)
     return 5
   if w <= 255:
     z[0] = 252
     z[1] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 2, z.high-2), y)
+    varintWrite32(toOpenArray(z, 2, 5), y)
     return 6
   if w <= 65535:
     z[0] = 253
     z[1] = cast[uint8](w shr 8)
     z[2] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 3, z.high-3), y)
+    varintWrite32(toOpenArray(z, 3, 6), y)
     return 7
   if w <= 16777215:
     z[0] = 254
     z[1] = cast[uint8](w shr 16)
     z[2] = cast[uint8](w shr 8)
     z[3] = cast[uint8](w)
-    varintWrite32(toOpenArray(z, 4, z.high-4), y)
+    varintWrite32(toOpenArray(z, 4, 7), y)
     return 8
   z[0] = 255
-  varintWrite32(toOpenArray(z, 1, z.high-1), w)
-  varintWrite32(toOpenArray(z, 5, z.high-5), y)
+  varintWrite32(toOpenArray(z, 1, 4), w)
+  varintWrite32(toOpenArray(z, 5, 8), y)
   return 9
 
 proc sar(a, b: int64): int64 =
diff --git a/lib/std/widestrs.nim b/lib/std/widestrs.nim
index 0bf50be45..2ddf80d14 100644
--- a/lib/std/widestrs.nim
+++ b/lib/std/widestrs.nim
@@ -25,7 +25,8 @@ when not (defined(cpu16) or defined(cpu8)):
         bytes: int
         data: WideCString
 
-    when defined(nimAllowNonVarDestructor):
+    const arcLike = defined(gcArc) or defined(gcAtomicArc) or defined(gcOrc)
+    when defined(nimAllowNonVarDestructor) and arcLike:
       proc `=destroy`(a: WideCStringObj) =
         if a.data != nil:
           when compileOption("threads"):
@@ -154,6 +155,7 @@ when not (defined(cpu16) or defined(cpu8)):
     createWide(result, size * 2 + 2)
 
   proc newWideCString*(source: cstring, L: int): WideCStringObj =
+    ## Warning:: `source` needs to be preallocated with the length `L`
     createWide(result, L * 2 + 2)
     var d = 0
     for ch in runes(source, L):
diff --git a/lib/std/with.nim b/lib/std/with.nim
index 8043a0b8a..c2eaa4bef 100644
--- a/lib/std/with.nim
+++ b/lib/std/with.nim
@@ -14,7 +14,7 @@
 ##
 ## **Since:** version 1.2.
 
-import macros, private / underscored_calls
+import std/[macros, private / underscored_calls]
 
 macro with*(arg: typed; calls: varargs[untyped]): untyped =
   ## This macro provides `chaining`:idx: of function calls.
diff --git a/lib/std/wordwrap.nim b/lib/std/wordwrap.nim
index 7dcfc7f59..9333f880b 100644
--- a/lib/std/wordwrap.nim
+++ b/lib/std/wordwrap.nim
@@ -9,7 +9,7 @@
 
 ## This module contains an algorithm to wordwrap a Unicode string.
 
-import strutils, unicode
+import std/[strutils, unicode]
 
 proc olen(s: string; start, lastExclusive: int): int =
   var i = start
diff --git a/lib/std/wrapnils.nim b/lib/std/wrapnils.nim
index 235638134..0b75c270e 100644
--- a/lib/std/wrapnils.nim
+++ b/lib/std/wrapnils.nim
@@ -13,7 +13,7 @@ consider handling indexing operations, eg:
 doAssert ?.default(seq[int])[3] == default(int)
 ]#
 
-import macros
+import std/macros
 
 runnableExamples:
   type Foo = ref object
@@ -122,7 +122,7 @@ macro `?.`*(a: typed): auto =
     `lhs`
 
 # the code below is not needed for `?.`
-from options import Option, isSome, get, option, unsafeGet, UnpackDefect
+from std/options import Option, isSome, get, option, unsafeGet, UnpackDefect
 
 macro `??.`*(a: typed): Option =
   ## Same as `?.` but returns an `Option`.