Refactor builtin commands dispatcher

This commit is contained in:
2026-08-23 11:43:28 +03:00
parent 0548f8de26
commit 35f5d5777e
9 changed files with 78 additions and 75 deletions
+22 -31
View File
@@ -8,16 +8,22 @@ const exit = @import("cmds/exit.zig");
const pwd = @import("cmds/pwd.zig"); const pwd = @import("cmds/pwd.zig");
const run = @import("cmds/run.zig"); const run = @import("cmds/run.zig");
pub const Shell = struct { const types = @import("types.zig");
running: bool = true,
interrupted: bool = false, const CommandFn = *const fn (types.BuiltinCommandContext) anyerror!void;
environ: *const std.process.Environ.Map,
}; const commands = std.StaticStringMap(CommandFn).initComptime(.{
.{ "cd", cd.execute },
.{ "pwd", pwd.execute },
.{ "run", run.execute },
.{ "echo", echo.execute },
.{ "exit", exit.execute },
});
pub fn execute( pub fn execute(
io: std.Io, io: std.Io,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
shell: *Shell, shell: *types.Shell,
command: parser.Command, command: parser.Command,
) !bool { ) !bool {
if (command.argv.len == 0) if (command.argv.len == 0)
@@ -25,30 +31,15 @@ pub fn execute(
const name = command.argv[0]; const name = command.argv[0];
if (std.mem.eql(u8, name, "cd")) { const execute_fn = commands.get(name) orelse
try cd.execute(io, shell.environ, command.argv);
return true;
}
if (std.mem.eql(u8, name, "pwd")) {
try pwd.execute(io, allocator);
return true;
}
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 false;
try execute_fn(.{
.io = io,
.allocator = allocator,
.shell = shell,
.argv = command.argv,
});
return true;
} }
+9 -11
View File
@@ -1,20 +1,18 @@
const std = @import("std"); const std = @import("std");
pub fn execute( const types = @import("../types.zig");
io: std.Io,
environ: *const std.process.Environ.Map, pub fn execute(ctx: types.BuiltinCommandContext) !void {
argv: []const []const u8, const path = if (ctx.argv.len >= 2)
) !void { ctx.argv[1]
const path = if (argv.len >= 2)
argv[1]
else 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", .{}); std.debug.print("xsh: cd: cannot find home directory\n", .{});
return; return;
}; };
var dir = try std.Io.Dir.cwd().openDir(io, path, .{}); var dir = try std.Io.Dir.cwd().openDir(ctx.io, path, .{});
defer dir.close(io); defer dir.close(ctx.io);
try std.process.setCurrentDir(io, dir); try std.process.setCurrentDir(ctx.io, dir);
} }
+7 -8
View File
@@ -1,16 +1,15 @@
const std = @import("std"); const std = @import("std");
pub fn execute( const types = @import("../types.zig");
io: std.Io,
argv: []const []const u8, pub fn execute(ctx: types.BuiltinCommandContext) !void {
) !void { for (ctx.argv[1..], 0..) |argument, index| {
for (argv[1..], 0..) |argument, index| {
if (index != 0) { 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");
} }
+4 -2
View File
@@ -1,3 +1,5 @@
pub fn execute(running: *bool) void { const types = @import("../types.zig");
running.* = false;
pub fn execute(ctx: types.BuiltinCommandContext) !void {
ctx.shell.running = false;
} }
+7 -8
View File
@@ -1,12 +1,11 @@
const std = @import("std"); const std = @import("std");
pub fn execute( const types = @import("../types.zig");
io: std.Io,
allocator: std.mem.Allocator,
) !void {
const path = try std.process.currentPathAlloc(io, allocator);
defer allocator.free(path);
try std.Io.File.stdout().writeStreamingAll(io, path); pub fn execute(ctx: types.BuiltinCommandContext) !void {
try std.Io.File.stdout().writeStreamingAll(io, "\n"); 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");
} }
+11 -13
View File
@@ -2,31 +2,29 @@ const std = @import("std");
const script = @import("../../script/script.zig"); const script = @import("../../script/script.zig");
pub fn execute( const types = @import("../types.zig");
io: std.Io,
allocator: std.mem.Allocator, pub fn execute(ctx: types.BuiltinCommandContext) !void {
argv: []const []const u8, if (ctx.argv.len < 2) {
) !void {
if (argv.len < 2) {
std.debug.print("xsh: run: missing script path\n", .{}); std.debug.print("xsh: run: missing script path\n", .{});
return; return;
} }
var file = try std.Io.Dir.cwd().openFile(io, argv[1], .{}); var file = try std.Io.Dir.cwd().openFile(ctx.io, ctx.argv[1], .{});
defer file.close(io); 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( const source = try file_reader.interface.allocRemaining(
allocator, ctx.allocator,
.limited(16 * 1024 * 1024), .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( try script.run(
allocator, ctx.allocator,
io, ctx.io,
name_z, name_z,
source, source,
); );
+14
View File
@@ -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,
};
+3 -2
View File
@@ -5,6 +5,7 @@ const parser = @import("shell/parser.zig");
const execute = @import("shell/execute.zig"); const execute = @import("shell/execute.zig");
const builtin = @import("builtin/builtin.zig"); const builtin = @import("builtin/builtin.zig");
const builtin_types = @import("builtin/types.zig");
const script = @import("script/script.zig"); const script = @import("script/script.zig");
@@ -14,7 +15,7 @@ pub fn main(init: std.process.Init) !void {
const allocator = init.gpa; const allocator = init.gpa;
const io = init.io; const io = init.io;
var shell = builtin.Shell{ var shell = builtin_types.Shell{
.environ = init.environ_map, .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 tokens = try lexer.lex(allocator, source);
const command = try parser.parse(allocator, tokens.items); const command = try parser.parse(allocator, tokens.items);
+2 -1
View File
@@ -1,13 +1,14 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("../builtin/builtin.zig"); const builtin = @import("../builtin/builtin.zig");
const builtin_types = @import("../builtin/types.zig");
const parser = @import("parser.zig"); const parser = @import("parser.zig");
pub fn run( pub fn run(
io: std.Io, io: std.Io,
allocator: std.mem.Allocator, allocator: std.mem.Allocator,
shell: *builtin.Shell, shell: *builtin_types.Shell,
command: parser.Command, command: parser.Command,
) !void { ) !void {
if (try builtin.execute(io, allocator, shell, command)) if (try builtin.execute(io, allocator, shell, command))