Path Algebra¶
Lexical path manipulation: join, split, extension, normalize. POSIX separators only.
Import¶
use <io/path>
Overview¶
io/path is a Sushi-source standard-library module: it ships as bundled .sushi source and is merged as a compilation unit when you import it. Every function works on the string alone — no OS call, no file system read. The rules mirror Python's posixpath, and a differential test holds them there.
Limitations: the separator is / only. normalize is lexical — it resolves .. without looking at symlinks, so the result can name a different file than the input on a tree that uses them. There is no canonicalize().
Functions¶
join(string base, string child) -> Result@(string)¶
Join two path segments with a single separator. An absolute child replaces the base.
use <io/path>
fn main() i32:
println(join("src", "main.sushi").realise("?")) # src/main.sushi
println(join("src/", "main.sushi").realise("?")) # src/main.sushi
println(join("src", "/etc/hosts").realise("?")) # /etc/hosts
return Result.Ok(0)
basename(string path) -> Result@(string)¶
The part after the last separator. A path with a trailing separator has an empty basename.
use <io/path>
fn main() i32:
println(basename("/a/b.txt").realise("?")) # b.txt
println(basename("a/").realise("?")) # (empty)
return Result.Ok(0)
dirname(string path) -> Result@(string)¶
The part before the last separator, trailing separators stripped. A path with no separator has an empty dirname.
use <io/path>
fn main() i32:
println(dirname("/a/b.txt").realise("?")) # /a
println(dirname("/").realise("?")) # /
return Result.Ok(0)
extension(string path) -> Result@(string)¶
The extension of the last component, without the leading dot. The leading dot of a hidden file does not count.
use <io/path>
fn main() i32:
println(extension("archive.tar.gz").realise("?")) # gz
println(extension(".bashrc").realise("?")) # (empty)
return Result.Ok(0)
normalize(string path) -> Result@(string)¶
Normalize a path lexically: doubled separators collapse, . components vanish, and a .. removes the component before it when one exists. An empty result becomes ..
use <io/path>
fn main() i32:
println(normalize("/a/./b/../c").realise("?")) # /a/c
println(normalize("a//b").realise("?")) # a/b
return Result.Ok(0)