Skip to content

Commit 47a57d1

Browse files
committed
Add application default directory
1 parent 81d56a2 commit 47a57d1

3 files changed

Lines changed: 27 additions & 11 deletions

File tree

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ The current phase provides:
1111
- one `App`, multiple isolated windows, and automatic port selection;
1212
- embedded HTML, static directories, custom resources, external URLs, and a
1313
built-in JavaScript bridge;
14+
- application-wide default static directories for windows without content;
1415
- runtime content and resource-handler replacement through
1516
`Window.setContent()`;
1617
- targeted runtime content replacement through `Client.show()`;
@@ -113,6 +114,10 @@ Serve a directory by setting
113114
app starts and closed when it stops. Custom resources receive `webui.Request`
114115
and `webui.Response` directly.
115116

117+
Set `App.Options.default_directory` to let windows created without `.content`
118+
inherit one static directory. Explicit window content takes precedence. A
119+
window without either setting returns `error.MissingContent`.
120+
116121
`Window.setContent(&running, content)` prepares and installs new content, then
117122
navigates every connected client to it and returns the number notified. An
118123
invalid replacement leaves the current content unchanged. If client

docs/PURE_ZIG_REFACTOR.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ protocol input never panics.
276276
| `window.run()` | `Window.eval()` |
277277
| `Event.runClient()` | `Call.client.eval()` |
278278
| `setRootFolder()` | Initial `.directory` content or runtime `Window.setContent()`. |
279+
| `setDefaultRootFolder()` | `App.Options.default_directory` and an omitted window `content`. |
279280
| Global `setConfig()` | `App.Options` or `Window.Options` |
280281
| `wait()` / `clean()` | `Running.wait()` / `App.deinit()` |
281282
| `malloc/free/memcpy/encode/decode` | Zig allocators and standard library |
@@ -296,7 +297,6 @@ implementations.
296297
| Upstream API | Current gap |
297298
|---|---|
298299
| `webui_set_config(folder_monitor)` | Directory change monitoring and automatic browser reload are not implemented. |
299-
| `webui_set_default_root_folder()` | There is no application-wide default directory content setting. |
300300
| `webui_set_icon()`, `webui_set_icon_file()` | Window icon configuration is not implemented. |
301301
| `webui_open_url()` | The internal OS URL opener is not exposed as a general public API. |
302302
| `webui_get_best_browser()`, `webui_browser_exist()`, `webui_show_browser()`, `webui_set_browser_folder()` | Browser discovery, selection, and custom executable locations are not implemented. |
@@ -331,6 +331,7 @@ not implementation gaps:
331331
| `webui_show()`, `webui_start_server()`, `webui_get_url()` | Initial `Content`, runtime `Window.setContent()`, `App.start()`, `Window.open()`, and `Window.url()`. |
332332
| `webui_show_client()` | `Client.show()` replaces the window content and navigates only the selected client. |
333333
| `webui_is_shown()` | `Window.isShown()` reports whether the window has at least one connected browser client. |
334+
| `webui_set_default_root_folder()` | `App.Options.default_directory` supplies directory content to windows created without explicit content. |
334335
| `webui_wait()`, `webui_wait_async()` | `Running.wait()` used directly or through `std.Io` concurrency. |
335336
| `webui_close()`, `webui_destroy()`, `webui_exit()`, `webui_clean()` | `Window.close()`, `Running.stop()`, and `App.deinit()`. |
336337
| `webui_set_context()`, `webui_get_context()` | Binding and event-handler `user_data`. |
@@ -389,7 +390,6 @@ connection waiting, and caller-provided logging.
389390

390391
### Dynamic content and client state
391392

392-
- Add an application default directory.
393393
- Add inline and file-backed window icons.
394394

395395
This completes `webui_show()`, `webui_show_client()`, `webui_is_shown()`,
@@ -483,4 +483,4 @@ zig build -Dtarget=aarch64-macos
483483

484484
Continue capability parity:
485485

486-
1. Add an application default directory and window icons.
486+
1. Add inline and file-backed window icons.

src/app.zig

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1501,13 +1501,14 @@ pub const App = struct {
15011501
public: bool = false,
15021502
tls: ?Tls = null,
15031503
use_cookies: bool = false,
1504+
default_directory: ?[]const u8 = null,
15041505
logger: ?Logger = null,
15051506
logger_user_data: ?*anyopaque = null,
15061507
limits: Limits = .{},
15071508
};
15081509

15091510
pub const WindowOptions = struct {
1510-
content: Content,
1511+
content: ?Content = null,
15111512
/// One client by default; values above one explicitly enable
15121513
/// bounded multi-client mode.
15131514
max_clients: usize = 1,
@@ -1554,9 +1555,14 @@ pub const App = struct {
15541555
{
15551556
return error.InvalidPendingEventLimit;
15561557
}
1558+
const selected_content: Content = options.content orelse
1559+
if (self.options.default_directory) |path|
1560+
.{ .directory = path }
1561+
else
1562+
return error.MissingContent;
15571563
const state = try self.gpa.create(WindowState);
15581564
errdefer self.gpa.destroy(state);
1559-
var content = try StoredContent.init(self.gpa, options.content);
1565+
var content = try StoredContent.init(self.gpa, selected_content);
15601566
errdefer content.deinit(self.gpa);
15611567
state.* = .{
15621568
.gpa = self.gpa,
@@ -2321,6 +2327,13 @@ test "call accessors, window creation, and routes" {
23212327

23222328
var app = App.init(gpa, .{});
23232329
defer app.deinit();
2330+
try std.testing.expectError(error.MissingContent, app.createWindow(.{}));
2331+
var invalid_default_app = App.init(gpa, .{ .default_directory = "" });
2332+
defer invalid_default_app.deinit();
2333+
try std.testing.expectError(
2334+
error.InvalidDirectory,
2335+
invalid_default_app.createWindow(.{}),
2336+
);
23242337
try std.testing.expectError(error.InvalidDirectory, app.createWindow(.{
23252338
.content = .{ .directory = "" },
23262339
}));
@@ -3044,17 +3057,15 @@ test "JavaScript and Zig calls complete over HTTP and WebSocket" {
30443057
);
30453058
defer gpa.free(directory_path);
30463059

3047-
var app = App.init(gpa, .{});
3060+
var app = App.init(gpa, .{ .default_directory = directory_path });
30483061
defer app.deinit();
3062+
const default_window = try app.createWindow(.{});
30493063
const window = try app.createWindow(.{
30503064
.content = .{ .html = "test page" },
30513065
});
30523066
const second_window = try app.createWindow(.{
30533067
.content = .{ .html = "second page" },
30543068
});
3055-
const directory_window = try app.createWindow(.{
3056-
.content = .{ .directory = directory_path },
3057-
});
30583069
const custom_window = try app.createWindow(.{
30593070
.content = .{ .custom = .{
30603071
.handler = integrationResourceHandler,
@@ -3133,7 +3144,7 @@ test "JavaScript and Zig calls complete over HTTP and WebSocket" {
31333144
running.inner.address,
31343145
io,
31353146
try std.fmt.bufPrint(&target, "/{s}/", .{
3136-
directory_window.state.capability,
3147+
default_window.state.capability,
31373148
}),
31383149
"directory page",
31393150
&response,
@@ -3151,7 +3162,7 @@ test "JavaScript and Zig calls complete over HTTP and WebSocket" {
31513162
running.inner.address,
31523163
io,
31533164
try std.fmt.bufPrint(&target, "/{s}/%2e%2e/secret.txt", .{
3154-
directory_window.state.capability,
3165+
default_window.state.capability,
31553166
}),
31563167
"\r\n\r\n",
31573168
&response,

0 commit comments

Comments
 (0)