const std = @import("std"); const lang = @import("lang.zig"); const images = @import("image.zig"); const Image = images.Image; pub const RunError = error{ UnknownCommand, NoBMP, }; pub const Runner = struct { allocator: *std.mem.Allocator, image: ?*Image = null, pub fn init(allocator: *std.mem.Allocator) Runner { return Runner{ .allocator = allocator }; } pub fn deinit(self: *Runner) void { if (self.image) |image| { image.close(); } } fn resolveArg(self: *Runner, load_path: []const u8) ![]const u8 { if (load_path[0] == ':') { // parse the index from 1 to end const index = try std.fmt.parseInt(usize, load_path[1..], 10); var args_it = std.process.args(); _ = args_it.skip(); var i: usize = 0; while (i <= index) : (i += 1) { _ = args_it.skip(); } const arg = try (args_it.next(self.allocator) orelse @panic("expected argument")); return arg; } else { return load_path; } } fn resolveArgPath(self: *Runner, path_or_argidx: []const u8) ![]const u8 { const path = try self.resolveArg(path_or_argidx); const resolved_path = try std.fs.path.resolve( self.allocator, [_][]const u8{path}, ); return resolved_path; } fn loadCmd(self: *Runner, path_or_argidx: []const u8) !void { var load_path = try self.resolveArgPath(path_or_argidx); std.debug.warn("load path: {}\n", load_path); // we could use ImageMagick to convert from X to BMP // but i can't find an easy way to do things in memory. // the upside is that this allows some pre-processing by the user // before loading the file into scritcher. for example, you can start // krita/gimp and make it export a bmp and while in the program you can // apply filters, etc. if (!std.mem.endsWith(u8, load_path, ".bmp")) { std.debug.warn("Only BMP files are allowed to be loaded.\n"); return RunError.NoBMP; } self.image = try Image.open(self.allocator, load_path); } fn runCommand(self: *Runner, cmd: *lang.Command) !void { return switch (cmd.command) { .Noop => {}, .Load => blk: { var path = cmd.args.at(0); try self.loadCmd(path); break :blk; }, .Quicksave => {}, //.Quicksave => try self.quicksaveCmd(), else => blk: { std.debug.warn("Unknown command: {}\n", cmd.command); break :blk RunError.UnknownCommand; }, }; } /// Run a list of commands. pub fn runCommands( self: *Runner, cmds: lang.CommandList, debug_flag: bool, ) !void { var it = cmds.iterator(); while (it.next()) |cmd| { if (debug_flag) cmd.print(); try self.runCommand(cmd); } } };