From 69a1ee138bb78ad4663fe2d9e58678f7b0d07b74 Mon Sep 17 00:00:00 2001 From: t Date: Tue, 23 Jun 2026 09:38:23 -0600 Subject: ponytail simplifications to panto cli and lua extensiosn --- src/models_toml.zig | 97 +++++++---------------------------------------------- 1 file changed, 13 insertions(+), 84 deletions(-) (limited to 'src/models_toml.zig') diff --git a/src/models_toml.zig b/src/models_toml.zig index 6527292..9b1b4f0 100644 --- a/src/models_toml.zig +++ b/src/models_toml.zig @@ -2,8 +2,7 @@ //! //! Four files are read and merged, lowest precedence first: //! -//! 1. base — `$PANTO_HOME/models.toml` -//! (or `${XDG_DATA_HOME:-$HOME/.local/share}/panto/models.toml`) +//! 1. base — `${XDG_DATA_HOME:-$HOME/.local/share}/panto/models.toml` //! 2. user — `${XDG_CONFIG_HOME:-$HOME/.config}/panto/models.toml` //! 3. project — `./.panto/models.toml` //! 4. local — `./.panto/models.local.toml` @@ -79,6 +78,8 @@ const Io = std.Io; const toml = @import("toml"); const panto = @import("panto"); const tvalue = toml.value_mod; +const panto_home = @import("panto_home.zig"); +const toml_layer = @import("toml_layer.zig"); pub const Pricing = panto.Pricing; pub const Registry = panto.PricingRegistry; @@ -161,20 +162,13 @@ pub const Models = struct { } }; -/// Resolve the base-layer path to `models.toml`: `$PANTO_HOME/models.toml`, -/// falling back to `${XDG_DATA_HOME:-$HOME/.local/share}/panto/models.toml`. +/// Resolve the base-layer path to `models.toml`: +/// `${XDG_DATA_HOME:-$HOME/.local/share}/panto/models.toml`. /// Caller owns the returned slice. pub fn basePath(allocator: Allocator, environ_map: *const std.process.Environ.Map) ![]u8 { - if (environ_map.get("PANTO_HOME")) |home| { - return try std.fs.path.join(allocator, &.{ home, "models.toml" }); - } - if (environ_map.get("XDG_DATA_HOME")) |xdg| { - return try std.fs.path.join(allocator, &.{ xdg, "panto", "models.toml" }); - } - if (environ_map.get("HOME")) |home| { - return try std.fs.path.join(allocator, &.{ home, ".local", "share", "panto", "models.toml" }); - } - return error.NoHomeDirectory; + const home = try panto_home.homePath(allocator, environ_map); + defer allocator.free(home); + return try std.fs.path.join(allocator, &.{ home, "models.toml" }); } /// Resolve the user-layer path to `models.toml`. Caller owns the returned @@ -243,15 +237,17 @@ pub fn loadFromPaths(allocator: Allocator, io: Io, paths: []const []const u8) !M defer merged.deinit(); for (paths) |path| { - const bytes = readFileAlloc(allocator, io, path) catch |err| switch (err) { + const bytes = toml_layer.readFileAlloc(allocator, io, path) catch |err| switch (err) { error.FileNotFound => continue, - else => return err, + error.ReadFailed => return error.ModelsReadFailed, + error.Canceled => return error.Canceled, + error.OutOfMemory => return error.OutOfMemory, }; defer allocator.free(bytes); const doc = parseDoc(allocator, bytes) catch return error.InvalidModelsToml; defer doc.deinit(); - try mergeTable(merged.allocator(), merged.root, doc.root); + try toml_layer.mergeTable(merged.allocator(), merged.root, doc.root); } var models: Models = .{ @@ -269,20 +265,6 @@ pub fn loadFromPath(allocator: Allocator, io: Io, path: []const u8) !Models { return loadFromPaths(allocator, io, &.{path}); } -fn readFileAlloc(allocator: Allocator, io: Io, path: []const u8) ![]u8 { - const file = Io.Dir.cwd().openFile(io, path, .{ .mode = .read_only }) catch |err| switch (err) { - error.FileNotFound => return error.FileNotFound, - else => return error.ModelsReadFailed, - }; - defer file.close(io); - - const len = try file.length(io); - const bytes = try allocator.alloc(u8, @intCast(len)); - errdefer allocator.free(bytes); - _ = try file.readPositionalAll(io, bytes, 0); - return bytes; -} - fn parseDoc(allocator: Allocator, source: []const u8) !*toml.Document { const result = toml.parseWithError(allocator, source, .{}); return switch (result) { @@ -299,48 +281,6 @@ fn parseDoc(allocator: Allocator, source: []const u8) !*toml.Document { }; } -fn mergeTable(alloc: Allocator, dst: *toml.Value, src: *const toml.Value) Allocator.Error!void { - std.debug.assert(dst.* == .table); - if (src.* != .table) return; - - var it = toml.tableIterator(src); - while (it.next()) |entry| { - const existing = dst.get(entry.key); - if (existing != null and existing.?.* == .table and entry.value.* == .table) { - try mergeTable(alloc, @constCast(existing.?), entry.value); - } else { - const copy = try cloneValue(alloc, entry.value); - const key_copy = try alloc.dupe(u8, entry.key); - try tvalue.tableSet(alloc, dst, key_copy, copy); - } - } -} - -fn cloneValue(alloc: Allocator, src: *const toml.Value) Allocator.Error!*toml.Value { - const out = try alloc.create(toml.Value); - switch (src.*) { - .table => { - out.* = .{ .table = .{} }; - var it = toml.tableIterator(src); - while (it.next()) |entry| { - const child = try cloneValue(alloc, entry.value); - const key_copy = try alloc.dupe(u8, entry.key); - try tvalue.tableSet(alloc, out, key_copy, child); - } - }, - .array => |*a| { - out.* = .{ .array = .{} }; - for (a.items.items) |*item| { - const child = try cloneValue(alloc, item); - try tvalue.arrayAppend(alloc, out, child.*); - } - }, - .string => |s| out.* = .{ .string = try alloc.dupe(u8, s) }, - else => out.* = src.*, - } - return out; -} - /// Parse a TOML string into the given registries. Useful for tests. pub fn parseInto(models: *Models, source: []const u8) !void { const doc = try parseDoc(models.defs.allocator, source); @@ -623,17 +563,6 @@ test "ModelRegistry.get: returns null for unknown alias" { try testing.expect(models.defs.get("openai", "sonnet") == null); } -test "basePath: PANTO_HOME wins" { - const a = testing.allocator; - var env: std.process.Environ.Map = .init(a); - defer env.deinit(); - try env.put("PANTO_HOME", "/tmp/panto-home"); - try env.put("XDG_DATA_HOME", "/ignored"); - const got = try basePath(a, &env); - defer a.free(got); - try testing.expectEqualStrings("/tmp/panto-home/models.toml", got); -} - test "basePath: XDG_DATA_HOME falls back before HOME" { const a = testing.allocator; var env: std.process.Environ.Map = .init(a); -- cgit v1.3