Skip to content

yurizhang/zave

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

57 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Zave

v2.0.1 Β· A fast, powerful Windows 11-style file manager for macOS β€” a real Finder replacement, packed into a single dependency-free Zig 0.16 binary.

πŸ‡¨πŸ‡³ δΈ­ζ–‡ζ–‡ζ‘£θ―·ηœ‹ README.zh.md

πŸŽ‰ Zave is the 2.0 evolution of window-finder (frozen at v1.8) β€” same project, new name and home.

Let's be honest: macOS Finder is clunky. You can't see the full path, copying a path is a chore, and it's slower than it has any right to be. Zave fixes all of that β€” a snappy, Windows 11-style file manager that shows and copies the full path instantly, with tabs, multi-select, live preview, ZIP, drag-and-drop, "open in Terminal" and a lot more. It does more than Finder, gets out of your way faster, and ships as one tiny self-contained binary.

And the whole backend is pure Zig β€” no third-party dependencies, only the standard library β€” so it doubles as a hands-on tour of Zig 0.16's new I/O API.


✨ Features

Feature Description
πŸ“ Full path bar The top address bar always shows the absolute path of the current directory (like Windows)
πŸ“‹ One-click path copy "Copy Path" copies the current directory; each row also has a hover "Copy Path" button
🧭 Breadcrumbs Click any level under the path bar to jump there
⬆ Up Go to the parent directory
πŸ“‚ Navigate Double-click a folder to enter; double-click a file to copy its full path
βœ‚οΈ Cut / Copy / Paste Move or copy files and folders (recursive directory copy)
βž• New folder Create a directory in the current location
✏️ Rename Rename a file or folder (in-place move)
πŸ—‘οΈ Delete Delete a file or an entire directory tree (with a confirmation dialog)
πŸ—œοΈ Zip / Unzip Compress any item to a ZIP, or extract a ZIP in place (via zip/unzip)
β˜‘οΈ Multi-select Ctrl/Cmd-click, Shift-click range, Ctrl/Cmd+A; batch cut/copy/paste, delete and drag
πŸ‘οΈβ€πŸ—¨οΈ Preview Inline preview of text/code & images in the details panel; everything else gets an "Open with default app" button (macOS open)
πŸ‘οΈ Hidden files Toggle to show/hide dot-files
πŸ” Search Live filter of the current directory by filename
⌨️ Keyboard shortcuts ↑/↓ to move selection (Home/End for first/last), Enter to open, Cmd/Ctrl + X / C / V cut/copy/paste, F2 rename, Delete remove
πŸŒ— Theme & 🌐 language Dark / light theme and English / δΈ­ζ–‡ toggles, both persisted
πŸ”€ Auto sort Directories first, then files, sorted by name
πŸ“ File size Auto-formatted as B / KB / MB / GB

πŸš€ Quick Start

Just use it (no build) β€” recommended

  1. Download zave.zip from the latest release and double-click to unzip.
  2. Double-click Zave. macOS says "Not Opened" β€” click Done (the app isn't code-signed).
  3. Open System Settings β†’ Privacy & Security, scroll down to "Zave was blocked…", click Open Anyway, then open the app again and confirm.

⚠️ The old "right-click β†’ Open" trick no longer works on macOS 15+ (Sequoia/Tahoe) β€” you must use System Settings β†’ Privacy & Security β†’ Open Anyway. Only needed once. Developers can instead run xattr -dr com.apple.quarantine Zave.app. Runs from anywhere; universal (Apple Silicon + Intel).

Build from source

Requirements: Zig 0.16.0

# Build and run (opens a native window)
zig build run

# Or in two steps
zig build
./zig-out/bin/zave

Then open: http://127.0.0.1:9781

The server listens on 127.0.0.1:9781 (local-only, safe).

Set a custom port with the PORT env var (PORT=9000 zig build run). If the chosen port is busy, the server automatically tries the next ones. The port can also be changed from Settings βš™ β†’ System settings in the UI, which saves it and restarts the app on the new port.

Desktop app

zig build run opens a native window (a WKWebView hosting the UI) β€” no browser needed. Under the hood the HTTP server runs as a child process and the window points at it.

  • Build a distributable universal (arm64 + Intel) .app, .zip or .dmg:
    ./packaging/package.sh                # -> dist/Zave.app
    ./packaging/package.sh --zip          # -> dist/zave.zip
    ./packaging/package.sh --zip --dmg    # both
  • Installing a downloaded build: the app is not code-signed (no paid Apple Developer account). On macOS 15+ (Sequoia/Tahoe): double-click β†’ Done, then System Settings β†’ Privacy & Security β†’ Open Anyway. (Developers: xattr -dr com.apple.quarantine Zave.app.)
  • Prefer the browser instead of a window? Run headless: HEADLESS=1 zig build run, then open the printed URL.
  • macOS will ask permission the first time it touches Desktop/Documents/Downloads (normal privacy prompts). Click Allow, or grant Full Disk Access to Zave once in System Settings β†’ Privacy & Security.

How to use

  • Single-click a row to select it; double-click a folder to enter it.
  • Use the toolbar buttons (or keyboard shortcuts) to cut / copy / paste / delete.
  • Paste drops the clipboard item into the current directory.

🧱 Project Structure

Zave/
β”œβ”€β”€ build.zig          # Build script (defines the exe and the `run` step)
└── src/
    β”œβ”€β”€ main.zig       # HTTP server + filesystem logic
    └── index.html     # Frontend (HTML/CSS/JS, embedded into the binary at compile time)

index.html is embedded into the executable at compile time via @embedFile("index.html"), so the final artifact is a single binary β€” no extra static files to ship.


πŸ—οΈ Architecture

Browser                          Zig backend (127.0.0.1:9781)
  β”‚                                    β”‚
  β”‚  GET /                             β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ά  returns the embedded index.html
  β”‚                                    β”‚
  β”‚  GET /api/list?path=/Users/...     β”‚
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ά  Io.Dir.openDirAbsolute + iterate
  β”‚  ◀─────────────────────────────────  returns JSON listing
  β”‚                                    β”‚
  β”‚  POST /api/move | /api/copy | /api/delete
  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ά  rename / copy / deleteTree
  β”‚  ◀─────────────────────────────────  { "ok": true } or { "error": "..." }

The frontend is a single-page app: all navigation and operations call the API via fetch and refresh asynchronously, without reloading the page.


πŸ”Œ API Reference

GET /api/list?path=<abs>

Lists the contents of a directory. path is URL-encoded; empty defaults to /.

Success 200 application/json

{
  "path": "/Users/yurizhang/Documents",
  "entries": [
    { "name": "project", "kind": "directory", "size": 0 },
    { "name": "notes.txt", "kind": "file", "size": 1024 }
  ]
}
  • kind: "directory" or "file" (symlinks etc. are reported as file)
  • size: bytes; always 0 for directories

POST /api/move?from=<abs>&to=<abs>

Moves (cut + paste) a file or directory from from to to. Backed by renameAbsolute.

POST /api/copy?from=<abs>&to=<abs>

Copies a file or directory (directories are copied recursively).

POST /api/delete?path=<abs>

Deletes a file, or an entire directory tree.

POST /api/mkdir?path=<abs>

Creates a new directory at path. (Rename reuses /api/move β€” it's just an in-place move.)

GET /api/file?path=<abs>

Returns the raw file bytes (capped at 16 MB) with a Content-Type guessed from the extension β€” used by the details panel to preview text and images.

POST /api/open?path=<abs>

Opens the file or folder with the default application via macOS open.

Error response (for any of the above)

{ "error": "FileNotFound" }

Safety guards: refuses to copy a directory into its own subtree (infinite recursion), refuses to delete /, rejects identical source/destination and non-absolute paths.


🧩 Zig 0.16 features used

Zig 0.16 reworked the I/O model β€” almost every I/O operation now takes an explicit Io value. This project happens to cover most of that new surface:

Stdlib module Used for
std.Io.Threaded Creating the I/O instance (.init(gpa, .{}) β†’ .io())
std.Io.net Pure-Zig networking: IpAddress.parse β†’ listen β†’ accept
std.http.Server HTTP handling: receiveHead / respond
std.Io.Dir Filesystem: openDirAbsolute, iterate, renameAbsolute, copyFileAbsolute, createDirAbsolute, deleteTree
std.Io.Writer.Allocating Building JSON strings dynamically
@embedFile Embedding the frontend at compile time

Key differences from older versions

// 0.16: build an Io instance first, then pass it everywhere.
var threaded: std.Io.Threaded = .init(gpa, .{});
const io = threaded.io();

// Networking
var addr = try std.Io.net.IpAddress.parse("127.0.0.1", 9781);
var server = try addr.listen(io, .{ .reuse_address = true });
const stream = try server.accept(io);

// Directory iteration: iterate() returns an iterator, next(io) takes io
var dir = try std.Io.Dir.openDirAbsolute(io, path, .{ .iterate = true });
var it = dir.iterate();
while (try it.next(io)) |entry| { ... }

Each request uses an ArenaAllocator that is freed as a whole when the request finishes, avoiding piecemeal manual frees.

A gotcha worth noting: http.Server.respond() asserts (under keep-alive) that a POST request declares a body length. Since the mutation endpoints are POSTs that may carry no Content-Length, their responses set .keep_alive = false to bypass the body-discard path.


πŸ—ΊοΈ Roadmap

  • Cut / copy / paste files and folders
  • Delete (file / tree)
  • Create new folder / rename
  • Toggle for hidden files
  • Filename search / filter
  • English / δΈ­ζ–‡ + dark / light toggles
  • Copy current path
  • File preview (text / code / images) + open with default app
  • PDF inline preview (<iframe> embed)
  • Right-click context menu
  • Compress / extract ZIP
  • Multi-select (Ctrl/Shift click) with batch operations
  • Multiple tabs (independent directories)
  • Drag-and-drop to move
  • Finer file-type icons

⚠️ Notes

  • Listens on 127.0.0.1 only β€” not exposed to the network β€” suited for local use.
  • Files are accessed with the permissions of the server process.

πŸ“Έ Screenshots

List view (light) List view (dark)
List view β€” light List view β€” dark

Grid view

Grid view


πŸ“„ License

MIT Β© 2026 Yong Zhang <zhangyong0604@126.com>

About

πŸš€ Zave β€” a fast, powerful Windows 11-style file manager for macOS. A real Finder replacement. Tabs, multi-window, preview, ZIP, drag-and-drop, full-path. One dependency-free Zig binary.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors