From 35f5d5777ec06b652d7d62487ae19c9304de8b9e Mon Sep 17 00:00:00 2001 From: drvxor Date: Sun, 23 Aug 2026 11:43:28 +0300 Subject: [PATCH] Refactor builtin commands dispatcher --- src/builtin/builtin.zig | 51 ++++++++++++++++----------------------- src/builtin/cmds/cd.zig | 20 +++++++-------- src/builtin/cmds/echo.zig | 15 ++++++------ src/builtin/cmds/exit.zig | 6 +++-- src/builtin/cmds/pwd.zig | 15 ++++++------ src/builtin/cmds/run.zig | 24 +++++++++--------- src/builtin/types.zig | 14 +++++++++++ src/main.zig | 5 ++-- src/shell/execute.zig | 3 ++- 9 files changed, 78 insertions(+), 75 deletions(-) create mode 100644 src/builtin/types.zig diff --git a/src/builtin/builtin.zig b/src/builtin/builtin.zig index 818409c..60bbb20 100644 --- a/src/builtin/builtin.zig +++ b/src/builtin/builtin.zig @@ -8,16 +8,22 @@ const exit = @import("cmds/exit.zig"); const pwd = @import("cmds/pwd.zig"); const run = @import("cmds/run.zig"); -pub const Shell = struct { - running: bool = true, - interrupted: bool = false, - environ: *const std.process.Environ.Map, -}; +const types = @import("types.zig"); + +const CommandFn = *const fn (types.BuiltinCommandContext) anyerror!void; + +const commands = std.StaticStringMap(CommandFn).initComptime(.{ + .{ "cd", cd.execute }, + .{ "pwd", pwd.execute }, + .{ "run", run.execute }, + .{ "echo", echo.execute }, + .{ "exit", exit.execute }, +}); pub fn execute( io: std.Io, allocator: std.mem.Allocator, - shell: *Shell, + shell: *types.Shell, command: parser.Command, ) !bool { if (command.argv.len == 0) @@ -25,30 +31,15 @@ pub fn execute( const name = command.argv[0]; - if (std.mem.eql(u8, name, "cd")) { - try cd.execute(io, shell.environ, command.argv); - return true; - } + const execute_fn = commands.get(name) orelse + return false; - if (std.mem.eql(u8, name, "pwd")) { - try pwd.execute(io, allocator); - return true; - } + try execute_fn(.{ + .io = io, + .allocator = allocator, + .shell = shell, + .argv = command.argv, + }); - if (std.mem.eql(u8, name, "run")) { - try run.execute(io, allocator, command.argv); - return true; - } - - if (std.mem.eql(u8, name, "echo")) { - try echo.execute(io, command.argv); - return true; - } - - if (std.mem.eql(u8, name, "exit")) { - exit.execute(&shell.running); - return true; - } - - return false; + return true; } diff --git a/src/builtin/cmds/cd.zig b/src/builtin/cmds/cd.zig index ce7c903..4e204b3 100644 --- a/src/builtin/cmds/cd.zig +++ b/src/builtin/cmds/cd.zig @@ -1,20 +1,18 @@ const std = @import("std"); -pub fn execute( - io: std.Io, - environ: *const std.process.Environ.Map, - argv: []const []const u8, -) !void { - const path = if (argv.len >= 2) - argv[1] +const types = @import("../types.zig"); + +pub fn execute(ctx: types.BuiltinCommandContext) !void { + const path = if (ctx.argv.len >= 2) + ctx.argv[1] else - environ.get("USERPROFILE") orelse environ.get("HOME") orelse { + ctx.shell.environ.get("USERPROFILE") orelse ctx.shell.environ.get("HOME") orelse { std.debug.print("xsh: cd: cannot find home directory\n", .{}); return; }; - var dir = try std.Io.Dir.cwd().openDir(io, path, .{}); - defer dir.close(io); + var dir = try std.Io.Dir.cwd().openDir(ctx.io, path, .{}); + defer dir.close(ctx.io); - try std.process.setCurrentDir(io, dir); + try std.process.setCurrentDir(ctx.io, dir); } diff --git a/src/builtin/cmds/echo.zig b/src/builtin/cmds/echo.zig index 9e85055..79e6c38 100644 --- a/src/builtin/cmds/echo.zig +++ b/src/builtin/cmds/echo.zig @@ -1,16 +1,15 @@ const std = @import("std"); -pub fn execute( - io: std.Io, - argv: []const []const u8, -) !void { - for (argv[1..], 0..) |argument, index| { +const types = @import("../types.zig"); + +pub fn execute(ctx: types.BuiltinCommandContext) !void { + for (ctx.argv[1..], 0..) |argument, index| { if (index != 0) { - try std.Io.File.stdout().writeStreamingAll(io, " "); + try std.Io.File.stdout().writeStreamingAll(ctx.io, " "); } - try std.Io.File.stdout().writeStreamingAll(io, argument); + try std.Io.File.stdout().writeStreamingAll(ctx.io, argument); } - try std.Io.File.stdout().writeStreamingAll(io, "\n"); + try std.Io.File.stdout().writeStreamingAll(ctx.io, "\n"); } diff --git a/src/builtin/cmds/exit.zig b/src/builtin/cmds/exit.zig index 5498b99..d4d9cfc 100644 --- a/src/builtin/cmds/exit.zig +++ b/src/builtin/cmds/exit.zig @@ -1,3 +1,5 @@ -pub fn execute(running: *bool) void { - running.* = false; +const types = @import("../types.zig"); + +pub fn execute(ctx: types.BuiltinCommandContext) !void { + ctx.shell.running = false; } diff --git a/src/builtin/cmds/pwd.zig b/src/builtin/cmds/pwd.zig index f22c689..a4374b1 100644 --- a/src/builtin/cmds/pwd.zig +++ b/src/builtin/cmds/pwd.zig @@ -1,12 +1,11 @@ const std = @import("std"); -pub fn execute( - io: std.Io, - allocator: std.mem.Allocator, -) !void { - const path = try std.process.currentPathAlloc(io, allocator); - defer allocator.free(path); +const types = @import("../types.zig"); - try std.Io.File.stdout().writeStreamingAll(io, path); - try std.Io.File.stdout().writeStreamingAll(io, "\n"); +pub fn execute(ctx: types.BuiltinCommandContext) !void { + const path = try std.process.currentPathAlloc(ctx.io, ctx.allocator); + defer ctx.allocator.free(path); + + try std.Io.File.stdout().writeStreamingAll(ctx.io, path); + try std.Io.File.stdout().writeStreamingAll(ctx.io, "\n"); } diff --git a/src/builtin/cmds/run.zig b/src/builtin/cmds/run.zig index 6e49059..3d50384 100644 --- a/src/builtin/cmds/run.zig +++ b/src/builtin/cmds/run.zig @@ -2,31 +2,29 @@ const std = @import("std"); const script = @import("../../script/script.zig"); -pub fn execute( - io: std.Io, - allocator: std.mem.Allocator, - argv: []const []const u8, -) !void { - if (argv.len < 2) { +const types = @import("../types.zig"); + +pub fn execute(ctx: types.BuiltinCommandContext) !void { + if (ctx.argv.len < 2) { std.debug.print("xsh: run: missing script path\n", .{}); return; } - var file = try std.Io.Dir.cwd().openFile(io, argv[1], .{}); - defer file.close(io); + var file = try std.Io.Dir.cwd().openFile(ctx.io, ctx.argv[1], .{}); + defer file.close(ctx.io); - var file_reader = file.reader(io, &.{}); + var file_reader = file.reader(ctx.io, &.{}); const source = try file_reader.interface.allocRemaining( - allocator, + ctx.allocator, .limited(16 * 1024 * 1024), ); - const name_z = try allocator.dupeZ(u8, argv[1]); + const name_z = try ctx.allocator.dupeZ(u8, ctx.argv[1]); try script.run( - allocator, - io, + ctx.allocator, + ctx.io, name_z, source, ); diff --git a/src/builtin/types.zig b/src/builtin/types.zig new file mode 100644 index 0000000..0509cec --- /dev/null +++ b/src/builtin/types.zig @@ -0,0 +1,14 @@ +const std = @import("std"); + +pub const Shell = struct { + running: bool = true, + interrupted: bool = false, + environ: *const std.process.Environ.Map, +}; + +pub const BuiltinCommandContext = struct { + io: std.Io, + allocator: std.mem.Allocator, + shell: *Shell, + argv: []const []const u8, +}; diff --git a/src/main.zig b/src/main.zig index 3081f86..0de0485 100644 --- a/src/main.zig +++ b/src/main.zig @@ -5,6 +5,7 @@ const parser = @import("shell/parser.zig"); const execute = @import("shell/execute.zig"); const builtin = @import("builtin/builtin.zig"); +const builtin_types = @import("builtin/types.zig"); const script = @import("script/script.zig"); @@ -14,7 +15,7 @@ pub fn main(init: std.process.Init) !void { const allocator = init.gpa; const io = init.io; - var shell = builtin.Shell{ + var shell = builtin_types.Shell{ .environ = init.environ_map, }; @@ -55,7 +56,7 @@ pub fn main(init: std.process.Init) !void { } } -fn runPipeline(allocator: std.mem.Allocator, io: std.Io, shell: *builtin.Shell, source: []const u8) !void { +fn runPipeline(allocator: std.mem.Allocator, io: std.Io, shell: *builtin_types.Shell, source: []const u8) !void { const tokens = try lexer.lex(allocator, source); const command = try parser.parse(allocator, tokens.items); diff --git a/src/shell/execute.zig b/src/shell/execute.zig index e2b2368..55b10bc 100644 --- a/src/shell/execute.zig +++ b/src/shell/execute.zig @@ -1,13 +1,14 @@ const std = @import("std"); const builtin = @import("../builtin/builtin.zig"); +const builtin_types = @import("../builtin/types.zig"); const parser = @import("parser.zig"); pub fn run( io: std.Io, allocator: std.mem.Allocator, - shell: *builtin.Shell, + shell: *builtin_types.Shell, command: parser.Command, ) !void { if (try builtin.execute(io, allocator, shell, command))