# Url

The type `core.io.Url` stores a generic url. In the context of Storm, a url consists of a protocol followed by a sequence of `/`-separated parts. The `Url` is designed to be a convenient way of manipulating urls (such as paths) without resorting to string manipulation. As such, the `Url` class typically does not access the file system. It is therefore possible to create `Url`s that refer to non-existent or even invalid file names. To aid in differentiating between urls to files and urls to paths, the `Url` class has a notion of whether it refers to a file or directory. By convention, urls that refer to a directory are printed using a trailing slash `/`.

The associated protocol manages access to the underlying file system. As such, there are members of the `Url` class that uses the associated protocol to check if a constructed `Url` exists, to open it, list the contents of directories, etc. All protocols do not support all operations. For example, the `file://` protocol that is used for local files (and pretty-printed as regular paths) supports all operations, while the protocol for relative paths supports none of them.

## Creating Urls

The library contains a few convenience functions that produce `Url`s that serve as a starting point for further path traversal:

- `core.io.Url cwdUrl()`

  Get the current working directory.

- `core.io.Url executableUrl()`

  Get an url that points to the path where the current Storm binary is located.

- `core.io.Url userConfigUrl(core.Str appName)`

  Get the user's config directory for an application with the name `appName`. Created if not already present.

The system also contains the functions `parsePath` and `parsePathAsDir` that parses a string containing a path into a `Url` object. These functions have the limitation that they only support paths on the local filesystem:

- `core.io.Url parsePath(core.Str s)`

  Parse a path into a Url. The path is assumed to be on the local file system.

- `core.io.Url parsePathAsDir(core.Str s)`

  Parse a path into a Url. The path is assumed to be on the local file system, and refer to a directory.

An instance of the `Url` class is immutable. That is, none of the members of the class modify the object. Instead, they return a copy of the class with the modifications applied. It has the following operations:

- `init(core.io.Url other)`

  Copy constructor.

- `init()`

  Create a new, empty, relative `Url`. A relative url has to be made absolute before it can be accessed.

- `init(core.io.Protocol p, core.Array<core.Str> parts, core.io.UrlFlags flags)`

  Create from a protocol, an array of parts, and a set of flags.

- `init(core.Array<core.Str> parts, core.io.UrlFlags flags)`

  Create a relative `Url` with the specified parts and flags.

- `init(core.io.Protocol p, core.Array<core.Str> parts)`

  Ctor for STORM.

- `init(core.Array<core.Str> parts)`

  Relative path.

- `init(core.io.ObjIStream from)`

  Serialization.

- `core.Bool ==(core.io.Url o)`

  Compare this url to another url. The comparison depends on the current protocol. For example, on Windows, paths are compared in a case insensitive manner. The comparison does, however, never access the file system to resolve links, etc.

- `core.io.Url /(core.io.Url url)`

  Append another path to this one. `url` has to be a relative `Url`.

- `core.io.Url /(core.Str url)`

  Append a new part to this url. Returns the updated Url.

- `core.io.Url push(core.io.Url url)`

  Append another path to this one. `url` has to be a relative `Url`.

- `core.io.Url push(core.Str part)`

  Append a new part to this url. Returns the updated Url.

- `core.io.Url pushDir(core.Str part)`

  Append another part to this one, making the resulting Url into a directory.

- `core.Bool dir()`

  Check if this url refers to a directory. Note that this only depends on the contents in the `Url`. The file system will not be queried. Use `updated()` to query the file system.

- `core.io.Url makeDir()`

  Return a copy of this `Url` marked as a directory.

- `core.Str name()`

  Get the name of the file or directory. This includes the file extension.

- `core.Str title()`

  Get the title of the file or directory. This is the name without the file extension.

- `core.Str ext()`

  Get the file extension, if any.

- `core.io.Url withExt(core.Str ext)`

  Create a copy of this url with the current file extension replaced with `ext`.

- `core.Bool absolute()`

  Check if this `Url` is absolute.

- `core.Bool relative()`

  Check if this `Url` is relative.

- `core.io.Url makeAbsolute(core.io.Url base)`

  Make this `Url` into an absolute url if it is not already absolute. If the url is relative, assume it is relative to `base`.

- `core.Bool relative()`

  Check if this `Url` is relative.

- `core.io.Url relative(core.io.Url to)`

  Make this url relative to `to`.

- `core.io.Url relativeIfBelow(core.io.Url to)`

  Generate a relative path if the current path is below `to` (i.e. if they share a common prefix).

- `core.Bool isBelow(core.io.Url u)`

  Check if the current Url is below `to` (i.e. if they share a common prefix).

- `core.Nat count()`

  Get the number of parts in this url.

- `core.Bool empty()`

  Check if there are no parts in this url.

- `core.Bool any()`

  Check if there are any parts in this url.

- `core.Str [](core.Nat i)`

  Get the part with index `i`.

- `core.io.Protocol protocol()`

  Get the protocol used.

- `core.Str format()`

  Format for other C-api:s. May not return a sensible representation for all protocols.

Apart from the operations above, that operate on the contents of the `Url` itself, it contains the following operations that access the underlying filesystem through the associated `Protocol`. These operations are thus not available for all `Protocols`. In particular, they are not available for relative urls.

- `core.io.Url updated()`

  Return a copy of this `Url` that is updated to reflect the status of the element in the file system. That is: check if the `Url` refers to a file or a directory, and make `dir` return the appropriate value.

- `core.Array<core.io.Url> children()`

  Return an array of `Url`s that contain files and directories in the directory referred to by this `Url`. The returned `Url`s are such that their `dir` member returns whether they are directories or not.

- `core.io.IStream read()`

  Open this `Url` for reading.

- `core.io.OStream write()`

  Open this `Url` for writing.

- `core.Bool exists()`

  Check if this `Url` exists.

- `core.Bool createDir()`

  Create this url as a directory. Does not attempt to create parent directories.

- `core.Bool createDirTree()`

  Recursively create the directories for this url.

- `core.Bool delete()`

  Delete this path. If it refers to a directory, that directory needs to be empty.

- `core.Bool deleteTree()`

  Delete this path and any files and directories inside it.

## Protocols

The following protocols are provided by the library:

- `core.io.RelativeProtocol`

  The protocol used for relative paths. Does not support any file-IO operations.

- `core.io.FileProtocol`

  Used to represent local files. Behaves according to the semantics on the current operating systems with regards to comparing paths.

- `core.io.MemoryProtocol`

  A protocol that stores a set of files in memory. Useful when a `Url` is necessary, but the program does not wish to store files on disk. Each instance of `MemoryProtocol` provides its own namespace of virtual files. It does, however, not support directories.