Proposal: Filesystem & IO library (Fs / Path / Mime) — saves, config, mods, assets #10

Closed
opened 2026-08-29 20:21:55 +02:00 by orkun · 0 comments
Owner

Summary

A cohesive Filesystem & IO library: OS paths, reading/writing files,
directory listing, existence checks, and basic MIME/type sniffing — the
foundation for saves, config, mods, and asset loading.

Some low-level pieces already exist as bare builtins (file_*, read_char).
This issue is about wrapping them into one safe, ergonomic, namespaced API a
non-expert can use without thinking about file descriptors or byte buffers.

Why it matters for game devs

  • Save/load beyond the built-in snapshot (JSON configs, human-editable settings).
  • Mods / user content: read a folder of .ludic or data files a player dropped in.
  • Assets: load levels, dialogue, tilemaps from disk.
  • Screenshots / exports: write a file the player can find.

Proposed API (illustrative)

# doc-check: skip — illustrative API sketch
if (Fs.exists("saves/slot1.json")) {
  let text = try Fs.read_text("saves/slot1.json") else return World.fresh()
}
Fs.write_text("settings.ini", serialize(settings))

for name in Fs.list("mods/") { load_mod(Path.join("mods", name)) }

let dir  = Path.dir("mods/foo/data.json")     # "mods/foo"
let ext  = Path.ext("data.json")              # ".json"
let safe = Path.join(save_dir(), "slot1.json")
let kind = Mime.of("hero.png")                # "image/png"

Namespaces: Fs.* (read/write/exists/list/mkdir/remove/copy),
Path.* (join/dir/base/ext/normalize — cross-platform separators),
Mime.* (extension + magic-byte sniff).

Considerations

  • Every fallible call returns an error value (ties into the error-handling
    issue) — non-experts get a recoverable failure, never a crash.
  • Sandboxing: default to a per-game data directory (Fs.save_dir(),
    Fs.assets_dir()); make escaping it explicit. Important for safety and for a
    future web/wasm target where the FS is virtual.
  • Text vs binary helpers; UTF-8 by default (ties into Unicode issue).
  • Native/C-free via the existing syscall/IR path; wasm target uses a virtual FS.
  • Determinism: directory-listing order must be sorted/stable.

Scope / acceptance

  • Fs, Path, Mime namespaces with the ops above.
  • Sandboxed default directories + documented escape hatch.
  • Errors as values; no partial-write corruption (write-temp-then-rename).
  • Docs pages + a "load all mods in a folder" example.
  • Tests.

Related: error handling, Unicode, OS interface, #2 (stdlib).

## Summary A cohesive **Filesystem & IO** library: OS paths, reading/writing files, directory listing, existence checks, and basic MIME/type sniffing — the foundation for saves, config, mods, and asset loading. Some low-level pieces already exist as bare builtins (`file_*`, `read_char`). This issue is about wrapping them into one **safe, ergonomic, namespaced** API a non-expert can use without thinking about file descriptors or byte buffers. ## Why it matters for game devs - **Save/load** beyond the built-in snapshot (JSON configs, human-editable settings). - **Mods / user content**: read a folder of `.ludic` or data files a player dropped in. - **Assets**: load levels, dialogue, tilemaps from disk. - **Screenshots / exports**: write a file the player can find. ## Proposed API (illustrative) ```ludic # doc-check: skip — illustrative API sketch if (Fs.exists("saves/slot1.json")) { let text = try Fs.read_text("saves/slot1.json") else return World.fresh() } Fs.write_text("settings.ini", serialize(settings)) for name in Fs.list("mods/") { load_mod(Path.join("mods", name)) } let dir = Path.dir("mods/foo/data.json") # "mods/foo" let ext = Path.ext("data.json") # ".json" let safe = Path.join(save_dir(), "slot1.json") let kind = Mime.of("hero.png") # "image/png" ``` Namespaces: `Fs.*` (read/write/exists/list/mkdir/remove/copy), `Path.*` (join/dir/base/ext/normalize — cross-platform separators), `Mime.*` (extension + magic-byte sniff). ## Considerations - **Every fallible call returns an error value** (ties into the error-handling issue) — non-experts get a recoverable failure, never a crash. - **Sandboxing**: default to a per-game data directory (`Fs.save_dir()`, `Fs.assets_dir()`); make escaping it explicit. Important for safety and for a future web/wasm target where the FS is virtual. - Text vs binary helpers; UTF-8 by default (ties into Unicode issue). - Native/C-free via the existing syscall/IR path; wasm target uses a virtual FS. - Determinism: directory-listing order must be sorted/stable. ## Scope / acceptance - [ ] `Fs`, `Path`, `Mime` namespaces with the ops above. - [ ] Sandboxed default directories + documented escape hatch. - [ ] Errors as values; no partial-write corruption (write-temp-then-rename). - [ ] Docs pages + a "load all mods in a folder" example. - [ ] Tests. Related: error handling, Unicode, OS interface, #2 (stdlib).
orkun added the
proposal
priority:high
area:stdlib
labels 2026-08-29 20:21:55 +02:00
orkun closed this issue 2026-08-30 21:43:52 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: workshopsoft/ludic#10
No description provided.