aboutsummaryrefslogtreecommitdiff
path: root/docs/paths.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/paths.md')
-rw-r--r--docs/paths.md579
1 files changed, 579 insertions, 0 deletions
diff --git a/docs/paths.md b/docs/paths.md
new file mode 100644
index 00000000..f4cdb1f4
--- /dev/null
+++ b/docs/paths.md
@@ -0,0 +1,579 @@
+# Paths and Files
+
+Tomo supports a built-in syntax for file and directory paths, with some logic
+to help prevent or mitigate the risks of errors caused by string manipulations
+of file paths. Tomo does not have a built-in datatype to represent files
+specifically, but instead relies on Paths as the API to do filesystem
+operations.
+
+## Syntax
+
+Paths are [domain-specific languages](langs.md) that have their own dedicated
+syntax. A path literal begins with either `(/`, `(./`, `(../`, or `(~/` and continues
+until a matching closing parenethesis:
+
+```tomo
+>> (/tmp)
+= (/tmp)
+>> (~/path with/(parens) is/ok/)
+= (~/path with/(parens) is/ok/)
+```
+
+### Interpolation
+
+Paths can contain interpolations using `$`, just like strings. However, there are
+certain values that _cannot_ be interpolated:
+
+- The literal string `.`
+- The literal string `..`
+- Any text that contains a forward slash (`/`)
+
+The intended use for path interpolation is to take user input which may or may
+not be trustworthy and interpret that value as a single path component name,
+i.e. the name of a directory or file. If a user were to supply a value like
+`..` or `foo/baz`, it would risk navigating into a directory other than
+intended. Paths can be created from text with slashes using
+`Path.from_unsafe_text(text)` if you need to use arbitrary text as a file path.
+
+## Path Methods
+
+### `append`
+
+**Description:**
+Appends the given text to the file at the specified path, creating the file if it doesn't already exist. Failure to write will result in a runtime error.
+
+**Usage:**
+```markdown
+append(path: Path, text: Text, permissions: Int32 = 0o644_i32) -> Void
+```
+
+**Parameters:**
+
+- `path`: The path of the file to append to.
+- `text`: The text to append to the file.
+- `permissions` (optional): The permissions to set on the file if it is being created (default is `0o644`).
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+(./log.txt):append("extra line$(\n)")
+```
+
+---
+
+### `base_name`
+
+**Description:**
+Returns the base name of the file or directory at the specified path.
+
+**Usage:**
+```markdown
+base_name(path: Path) -> Text
+```
+
+**Parameters:**
+
+- `path`: The path of the file or directory.
+
+**Returns:**
+The base name of the file or directory.
+
+**Example:**
+```markdown
+>> (./path/to/file.txt):base_name()
+= "file.txt"
+```
+
+---
+
+### `children`
+
+**Description:**
+Returns a list of children (files and directories) within the directory at the specified path. Optionally includes hidden files.
+
+**Usage:**
+```markdown
+children(path: Path, include_hidden=no) -> [Path]
+```
+
+**Parameters:**
+
+- `path`: The path of the directory.
+- `include_hidden` (optional): Whether to include hidden files, which start with a `.` (default is `no`).
+
+**Returns:**
+A list of paths for the children.
+
+**Example:**
+```markdown
+>> (./directory):children(include_hidden=yes)
+= [".git", "foo.txt"]
+```
+
+---
+
+### `create_directory`
+
+**Description:**
+Creates a new directory at the specified path with the given permissions.
+
+**Usage:**
+```markdown
+create_directory(path: Path, permissions=0o644_i32) -> Void
+```
+
+**Parameters:**
+
+- `path`: The path of the directory to create.
+- `permissions` (optional): The permissions to set on the new directory (default is `0o644`).
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+(./new_directory):create_directory()
+```
+
+---
+
+### `exists`
+
+**Description:**
+Checks if a file or directory exists at the specified path.
+
+**Usage:**
+```markdown
+exists(path: Path) -> Bool
+```
+
+**Parameters:**
+
+- `path`: The path to check.
+
+**Returns:**
+`True` if the file or directory exists, `False` otherwise.
+
+**Example:**
+```markdown
+>> (/):exists()
+= yes
+```
+
+---
+
+### `extension`
+
+**Description:**
+Returns the file extension of the file at the specified path. Optionally returns the full extension.
+
+**Usage:**
+```markdown
+extension(path: Path, full=yes) -> Text
+```
+
+**Parameters:**
+
+- `path`: The path of the file.
+- `full` (optional): Whether to return everything after the first `.` in the
+ base name, or only the last part of the extension (default is `yes`).
+
+**Returns:**
+The file extension (not including the leading `.`) or an empty text if there is
+no file extension.
+
+**Example:**
+```markdown
+>> (./file.tar.gz):extension()
+= "tar.gz"
+>> (./file.tar.gz):extension(full=no)
+= "gz"
+>> (/foo):extension()
+= ""
+>> (./.git):extension()
+= ""
+```
+
+---
+
+### `files`
+
+**Description:**
+Returns a list of files within the directory at the specified path. Optionally includes hidden files.
+
+**Usage:**
+```markdown
+files(path: Path, include_hidden=no) -> [Path]
+```
+
+**Parameters:**
+
+- `path`: The path of the directory.
+- `include_hidden` (optional): Whether to include hidden files (default is `no`).
+
+**Returns:**
+A list of file paths.
+
+**Example:**
+```markdown
+>> (./directory):files(include_hidden=yes)
+= [(./directory/file1.txt), (./directory/file2.txt)]
+```
+
+---
+
+### `is_directory`
+
+**Description:**
+Checks if the path represents a directory. Optionally follows symbolic links.
+
+**Usage:**
+```markdown
+is_directory(path: Path, follow_symlinks=yes) -> Bool
+```
+
+**Parameters:**
+
+- `path`: The path to check.
+- `follow_symlinks` (optional): Whether to follow symbolic links (default is `yes`).
+
+**Returns:**
+`True` if the path is a directory, `False` otherwise.
+
+**Example:**
+```markdown
+>> (./directory/):is_directory()
+= yes
+
+>> (./file.txt):is_directory()
+= no
+```
+
+---
+
+### `is_file`
+
+**Description:**
+Checks if the path represents a file. Optionally follows symbolic links.
+
+**Usage:**
+```markdown
+is_file(path: Path, follow_symlinks=yes) -> Bool
+```
+
+**Parameters:**
+
+- `path`: The path to check.
+- `follow_symlinks` (optional): Whether to follow symbolic links (default is `yes`).
+
+**Returns:**
+`True` if the path is a file, `False` otherwise.
+
+**Example:**
+```markdown
+>> (./file.txt):is_file()
+= yes
+
+>> (./directory/):is_file()
+= no
+```
+
+---
+
+### `is_socket`
+
+**Description:**
+Checks if the path represents a socket. Optionally follows symbolic links.
+
+**Usage:**
+```markdown
+is_socket(path: Path, follow_symlinks=yes) -> Bool
+```
+
+**Parameters:**
+
+- `path`: The path to check.
+- `follow_symlinks` (optional): Whether to follow symbolic links (default is `yes`).
+
+**Returns:**
+`True` if the path is a socket, `False` otherwise.
+
+**Example:**
+```markdown
+>> (./socket):is_socket()
+= yes
+```
+
+---
+
+### `is_symlink`
+
+**Description:**
+Checks if the path represents a symbolic link.
+
+**Usage:**
+```markdown
+is_symlink(path: Path) -> Bool
+```
+
+**Parameters:**
+
+- `path`: The path to check.
+
+**Returns:**
+`True` if the path is a symbolic link, `False` otherwise.
+
+**Example:**
+```markdown
+>> (./link):is_symlink()
+= yes
+```
+
+---
+
+### `parent`
+
+**Description:**
+Returns the parent directory of the file or directory at the specified path.
+
+**Usage:**
+```markdown
+parent(path: Path) -> Path
+```
+
+**Parameters:**
+
+- `path`: The path of the file or directory.
+
+**Returns:**
+The path of the parent directory.
+
+**Example:**
+```markdown
+>> (./path/to/file.txt):parent()
+= (./path/to/)
+```
+
+---
+
+### `read`
+
+**Description:**
+Reads the contents of the file at the specified path.
+
+**Usage:**
+```markdown
+read(path: Path) -> Text
+```
+
+**Parameters:**
+
+- `path`: The path of the file to read.
+
+**Returns:**
+The contents of the file. If the file does not exist, an error will be raised.
+
+**Example:**
+```markdown
+content := (./file.txt):read()
+```
+
+---
+
+### `relative`
+
+**Description:**
+Returns the path relative to a given base path. By default, the base path is the current directory.
+
+**Usage:**
+```markdown
+relative(path: Path, relative_to=(./)) -> Path
+```
+
+**Parameters:**
+
+- `path`: The path to convert.
+- `relative_to` (optional): The base path for the relative path (default is `./`).
+
+**Returns:**
+The relative path.
+
+**Example:**
+```markdown
+>> (./path/to/file.txt):relative(relative_to=(./path))
+= (./to/file.txt)
+```
+
+---
+
+### `remove`
+
+**Description:**
+Removes the file or directory at the specified path. A runtime error is raised if something goes wrong.
+
+**Usage:**
+```markdown
+remove(path: Path, ignore_missing=no) -> Void
+```
+
+**Parameters:**
+
+- `path`: The path to remove.
+- `ignore_missing` (optional): Whether to ignore errors if the file or directory does not exist (default is `no`).
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+(./file.txt):remove()
+```
+
+---
+
+### `resolved`
+
+**Description:**
+Resolves the absolute path of the given path relative to a base path. By default, the base path is the current directory.
+
+**Usage:**
+```markdown
+resolved(path: Path, relative_to=(./)) -> Path
+```
+
+**Parameters:**
+
+- `path`: The path to resolve.
+- `relative_to` (optional): The base path for resolution (default is `./`).
+
+**Returns:**
+The resolved absolute path.
+
+**Example:**
+```markdown
+>> (~/foo):resolved()
+= (/home/user/foo)
+
+>> (./path/to/file.txt):resolved(relative_to=(/foo))
+= (/foo/path/to/file.txt)
+```
+
+---
+
+### `subdirectories`
+
+**Description:**
+Returns a list of subdirectories within the directory at the specified path. Optionally includes hidden subdirectories.
+
+**Usage:**
+```markdown
+subdirectories(path: Path, include_hidden=no) -> [Path]
+```
+
+**Parameters:**
+
+- `path`: The path of the directory.
+- `include_hidden` (optional): Whether to include hidden subdirectories (default is `no`).
+
+**Returns:**
+A list of subdirectory paths.
+
+**Example:**
+```markdown
+>> (./directory):subdirectories()
+= [(./directory/subdir1), (./directory/subdir2)]
+
+>> (./directory):subdirectories(include_hidden=yes)
+= [(./directory/.git), (./directory/subdir1), (./directory/subdir2)]
+```
+
+---
+
+### `unique_directory`
+
+**Description:**
+Generates a unique directory path based on the given path. Useful for creating temporary directories.
+
+**Usage:**
+```markdown
+unique_directory(path: Path) -> Path
+```
+
+**Parameters:**
+
+- `path`: The base path for generating the unique directory. The last six letters of this path must be `XXXXXX`.
+
+**Returns:**
+A unique directory path after creating the directory.
+
+**Example:**
+
+```
+>> created := (/tmp/my-dir.XXXXXX):unique_directory()
+= (/tmp/my-dir-AwoxbM/)
+>> created:is_directory()
+= yes
+created:remove()
+```
+
+---
+
+### `write`
+
+**Description:**
+Writes the given text to the file at the specified path, creating the file if
+it doesn't already exist. Sets the file permissions as specified. If the file
+writing cannot be successfully completed, a runtime error is raised.
+
+**Usage:**
+```markdown
+write(path: Path, text: Text, permissions=0o644_i32) -> Void
+```
+
+**Parameters:**
+
+- `path`: The path of the file to write to.
+- `text`: The text to write to the file.
+- `permissions` (optional): The permissions to set on the file if it is created (default is `0o644`).
+
+**Returns:**
+Nothing.
+
+**Example:**
+```markdown
+(./file.txt):write("Hello, world!")
+```
+
+---
+
+### `write_unique`
+
+**Description:**
+Writes the given text to a unique file path based on the specified path. The
+file is created if it doesn't exist. This is useful for creating temporary
+files.
+
+**Usage:**
+```markdown
+write_unique(path: Path, text: Text) -> Path
+```
+
+**Parameters:**
+
+- `path`: The base path for generating the unique file. This path must include
+ the string `XXXXXX` in the file base name.
+- `text`: The text to write to the file.
+
+**Returns:**
+The path of the newly created unique file.
+
+**Example:**
+```markdown
+>> created := (./file-XXXXXX.txt):write_unique("Hello, world!")
+= (./file-27QHtq.txt)
+>> created:read()
+= "Hello, world!"
+created:remove()
+```