From 60367d8fe23f6af98ec28e3cf6c2094dfe332df0 Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Sun, 6 Sep 2026 18:11:36 -0300 Subject: Refactor panes and filesystem; replace FUSE with 9P Consolidate pane, layout, memory and host code. Serve 9P by default over Unix sockets, with runtime mounts and optional TCP/QUIC transports. Remove FUSE and obsolete proof-of-concept examples. Fix highlighting and terminal-history performance, expand differential and stress-test infrastructure, sort navigation results while preserving the next occurrence, add syntax-colored Braille minimaps, remove SPC-k, and document 9P interaction as a repository skill. --- src/user_config.zig | 188 ---------------------------------------------------- 1 file changed, 188 deletions(-) delete mode 100644 src/user_config.zig (limited to 'src/user_config.zig') diff --git a/src/user_config.zig b/src/user_config.zig deleted file mode 100644 index 15253ab2..00000000 --- a/src/user_config.zig +++ /dev/null @@ -1,188 +0,0 @@ -//! Native startup configuration discovery and loading. -//! -//! `pardes` is a directory inside the platform's per-user configuration -//! directory; its startup command file is `pardes/init`. Discovery is -//! deliberately launcher-owned: native -//! launchers opt in by putting the bytes in `Options.startup_config`, while -//! tests and the browser keep the default `null`. - -const std = @import("std"); -const builtin = @import("builtin"); - -const max_bytes = 1024 * 1024; - -pub const init_name = "init"; -pub const builtin_themes_subdir = "themes/builtin"; - -/// Resolve the native per-user config directory with stdlib environment and path -/// APIs. XDG_CONFIG_HOME is accepted only when absolute, as required by the -/// XDG base-directory specification; an empty/relative value falls back. -pub fn path(gpa: std.mem.Allocator, env: *const std.process.Environ.Map) !?[]u8 { - if (builtin.os.tag == .windows) { - if (nonEmpty(env.get("LOCALAPPDATA"))) |base| - return try std.fs.path.join(gpa, &.{ base, "pardes" }); - if (nonEmpty(env.get("USERPROFILE"))) |home| - return try std.fs.path.join(gpa, &.{ home, "AppData", "Local", "pardes" }); - return null; - } - - if (xdgBase(env)) |base| - return try std.fs.path.join(gpa, &.{ base, "pardes" }); - - const home = nonEmpty(env.get("HOME")) orelse return null; - if (builtin.os.tag == .macos) - return try std.fs.path.join(gpa, &.{ home, "Library", "Application Support", "pardes" }); - return try std.fs.path.join(gpa, &.{ home, ".config", "pardes" }); -} - -/// The config directory and its init file: WHERE they were looked for, and -/// what was there. Missing, -/// unreadable, oversized, or otherwise unusable config is simply no config — -/// but the path resolves either way, because "nothing is there yet" is the -/// answer the Config builtin exists to give and a null would erase it. The -/// arena passed by the launcher owns every returned slice for the process. -pub const Found = struct { - dir: ?[]const u8 = null, - path: ?[]const u8 = null, - bytes: ?[]const u8 = null, -}; - -pub fn load( - io: std.Io, - gpa: std.mem.Allocator, - env: *const std.process.Environ.Map, -) Found { - const config_dir = (path(gpa, env) catch return .{}) orelse return .{}; - const config_path = std.fs.path.join(gpa, &.{ config_dir, init_name }) catch return .{ .dir = config_dir }; - return .{ - .dir = config_dir, - .path = config_path, - .bytes = std.Io.Dir.cwd().readFileAlloc(io, config_path, gpa, .limited(max_bytes)) catch null, - }; -} - -fn nonEmpty(value: ?[]const u8) ?[]const u8 { - const v = value orelse return null; - return if (v.len == 0) null else v; -} - -fn xdgBase(env: *const std.process.Environ.Map) ?[]const u8 { - const value = nonEmpty(env.get("XDG_CONFIG_HOME")) orelse return null; - return if (std.fs.path.isAbsolute(value)) value else null; -} - -test "config path honors XDG and rejects a relative XDG directory" { - if (builtin.os.tag == .windows) return; - - var env: std.process.Environ.Map = .init(std.testing.allocator); - defer env.deinit(); - try env.put("HOME", "/home/pardes-test"); - try env.put("XDG_CONFIG_HOME", "/var/tmp/pardes-xdg"); - - const xdg = (try path(std.testing.allocator, &env)).?; - defer std.testing.allocator.free(xdg); - try std.testing.expectEqualStrings("/var/tmp/pardes-xdg/pardes", xdg); - - try env.put("XDG_CONFIG_HOME", "relative/config"); - const fallback = (try path(std.testing.allocator, &env)).?; - defer std.testing.allocator.free(fallback); - const expected = if (builtin.os.tag == .macos) - "/home/pardes-test/Library/Application Support/pardes" - else - "/home/pardes-test/.config/pardes"; - try std.testing.expectEqualStrings(expected, fallback); -} - -test "config loader reads init inside the config directory" { - if (builtin.os.tag == .windows) return; - - var tmp = std.testing.tmpDir(.{}); - defer tmp.cleanup(); - var base_buf: [std.fs.max_path_bytes]u8 = undefined; - const base_len = try tmp.dir.realPath(std.testing.io, &base_buf); - - var env: std.process.Environ.Map = .init(std.testing.allocator); - defer env.deinit(); - try env.put("XDG_CONFIG_HOME", base_buf[0..base_len]); - - const missing = load(std.testing.io, std.testing.allocator, &env); - defer std.testing.allocator.free(missing.dir.?); - defer std.testing.allocator.free(missing.path.?); - const expected_dir = try std.fs.path.join(std.testing.allocator, &.{ base_buf[0..base_len], "pardes" }); - defer std.testing.allocator.free(expected_dir); - const expected = try std.fs.path.join(std.testing.allocator, &.{ expected_dir, init_name }); - defer std.testing.allocator.free(expected); - try std.testing.expectEqualStrings(expected_dir, missing.dir.?); - try std.testing.expectEqualStrings(expected, missing.path.?); - try std.testing.expect(missing.bytes == null); - const source = "Theme dark\nUnknown command\nTheme acme\n"; - try tmp.dir.createDir(std.testing.io, "pardes", .default_dir); - try tmp.dir.writeFile(std.testing.io, .{ .sub_path = "pardes/init", .data = source }); - const found = load(std.testing.io, std.testing.allocator, &env); - defer std.testing.allocator.free(found.dir.?); - defer std.testing.allocator.free(found.path.?); - defer std.testing.allocator.free(found.bytes.?); - try std.testing.expectEqualStrings(expected_dir, found.dir.?); - try std.testing.expectEqualStrings(source, found.bytes.?); -} - -/// Write one editable `.zon` file per compiled theme. The caller supplies the -/// ring so this filesystem-only module does not import the core. Existing -/// generated copies are replaced; unrelated files in the directory are left -/// alone, which lets a user keep custom themes beside the reference set. -pub fn dumpThemes( - io: std.Io, - gpa: std.mem.Allocator, - config_dir: []const u8, - theme_values: anytype, -) ![]u8 { - const out_dir = try std.fs.path.join(gpa, &.{ config_dir, builtin_themes_subdir }); - errdefer gpa.free(out_dir); - try std.Io.Dir.cwd().createDirPath(io, out_dir); - - for (theme_values) |theme_value| { - var encoded: std.Io.Writer.Allocating = .init(gpa); - defer encoded.deinit(); - try std.zon.stringify.serialize(theme_value, .{ .whitespace = true }, &encoded.writer); - - const filename = try std.fmt.allocPrint(gpa, "{s}.zon", .{theme_value.name}); - defer gpa.free(filename); - const output_path = try std.fs.path.join(gpa, &.{ out_dir, filename }); - defer gpa.free(output_path); - try std.Io.Dir.cwd().writeFile(io, .{ - .sub_path = output_path, - .data = encoded.written(), - }); - } - return out_dir; -} - -test "theme dump creates the builtin subdirectory and ZON files" { - const io = std.testing.io; - const gpa = std.testing.allocator; - var tmp = std.testing.tmpDir(.{}); - defer tmp.cleanup(); - var base_buf: [std.fs.max_path_bytes]u8 = undefined; - const base_len = try tmp.dir.realPath(io, &base_buf); - const Sample = struct { name: []const u8, rgb: [3]u8 }; - const samples = [_]Sample{ - .{ .name = "one", .rgb = .{ 1, 2, 3 } }, - .{ .name = "two", .rgb = .{ 4, 5, 6 } }, - }; - const output = try dumpThemes(io, gpa, base_buf[0..base_len], &samples); - defer gpa.free(output); - const expected = try std.fs.path.join(gpa, &.{ base_buf[0..base_len], builtin_themes_subdir }); - defer gpa.free(expected); - try std.testing.expectEqualStrings(expected, output); - - const one_path = try std.fs.path.join(gpa, &.{ output, "one.zon" }); - defer gpa.free(one_path); - const bytes = try std.Io.Dir.cwd().readFileAlloc(io, one_path, gpa, .limited(4096)); - defer gpa.free(bytes); - const source = try gpa.dupeZ(u8, bytes); - defer gpa.free(source); - const parsed = try std.zon.parse.fromSliceAlloc(Sample, gpa, source, null, .{}); - defer std.zon.parse.free(gpa, parsed); - try std.testing.expectEqualStrings("one", parsed.name); - try std.testing.expectEqual([3]u8{ 1, 2, 3 }, parsed.rgb); -} -- cgit v1.3