forked from Spencer/math_shell
135 lines
3.9 KiB
Zig
135 lines
3.9 KiB
Zig
pub fn main() !void {
|
|
clear();
|
|
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}).init;
|
|
defer _ = gpa.deinit();
|
|
|
|
const allocator = gpa.allocator();
|
|
|
|
var ln = Linenoise.init(allocator);
|
|
defer ln.deinit();
|
|
|
|
var prng = Random.DefaultPrng.init(blk: {
|
|
var seed: u64 = undefined;
|
|
try std.posix.getrandom(std.mem.asBytes(&seed));
|
|
break :blk seed;
|
|
});
|
|
const rand = prng.random();
|
|
|
|
const p = try getPrompt(allocator);
|
|
defer allocator.free(p);
|
|
|
|
while (try ln.linenoise(p)) |input| {
|
|
defer allocator.free(input);
|
|
if (input.len > 0) {
|
|
try ln.history.add(input);
|
|
const command = try tokenizeCommand(input, allocator);
|
|
defer allocator.free(command);
|
|
if (mathTest(rand, 100)) {
|
|
_ = runCommand(command, allocator) catch |err| switch (err) {
|
|
error.FileNotFound => print("mash: {s}: command not found\n", .{command[0]}),
|
|
error.AccessDenied => print("mash: {s}: Permission denied\n", .{command[0]}),
|
|
else => print("Unkown error: {}\n", .{err}),
|
|
};
|
|
} else {
|
|
print(
|
|
\\\n
|
|
\\How can you expect to execute commands without knowing any math???\n
|
|
\\\n
|
|
, .{});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const Operators = enum {
|
|
add,
|
|
subtract,
|
|
multiply,
|
|
divide,
|
|
|
|
const Self = @This();
|
|
|
|
fn toString(s: Self) []const u8 {
|
|
return switch (s) {
|
|
.add => "+",
|
|
.subtract => "-",
|
|
.multiply => "*",
|
|
.divide => "/",
|
|
};
|
|
}
|
|
|
|
fn apply(s: Self, a: i32, b: i32) i32 {
|
|
return switch (s) {
|
|
.add => a + b,
|
|
.subtract => a - b,
|
|
.multiply => a * b,
|
|
.divide => @divTrunc(a, b),
|
|
};
|
|
}
|
|
};
|
|
|
|
/// return true if the user passed, false if the user did not.
|
|
fn mathTest(rand: Random, limit: i32) bool {
|
|
|
|
// const operators = comptime .{
|
|
// .{ "+", add },
|
|
// .{ "-", subtract },
|
|
// .{ "*", multiply },
|
|
// .{ "/", divide },
|
|
// };
|
|
// const ops = StaticStringMap(BinaryOperator).initComptime(operators);
|
|
// _ = ops;
|
|
const op = rand.enumValue(Operators);
|
|
const num1 = rand.intRangeAtMost(i32, 1, limit);
|
|
const num2 = rand.intRangeAtMost(i32, 1, limit);
|
|
const answer = op.apply(num1, num2);
|
|
print("{d} {s} {d} = {d}\n", .{ num1, op.toString(), num2, answer });
|
|
return true;
|
|
}
|
|
|
|
fn runCommand(command: [][]const u8, allocator: Allocator) !u8 {
|
|
var child = process.Child.init(command, allocator);
|
|
const result = try child.spawnAndWait();
|
|
return result.Exited;
|
|
}
|
|
|
|
fn getPrompt(allocator: Allocator) ![]const u8 {
|
|
const script = @embedFile("./get_prompt.bash");
|
|
const result = try process.Child.run(.{
|
|
.allocator = allocator,
|
|
.argv = &[_][]const u8{ "bash", "-i", "-c", script },
|
|
});
|
|
allocator.free(result.stderr);
|
|
return result.stdout;
|
|
}
|
|
|
|
fn tokenizeCommand(command: []const u8, allocator: Allocator) ![][]const u8 {
|
|
var argv_array_list = ArrayList([]const u8).init(allocator);
|
|
defer argv_array_list.deinit();
|
|
|
|
var tokens = tokenizeAny(u8, command, " ");
|
|
while (tokens.next()) |token| {
|
|
try argv_array_list.append(token);
|
|
}
|
|
return argv_array_list.toOwnedSlice();
|
|
}
|
|
|
|
fn clear() void {
|
|
print("\u{001b}[H\u{001b}[J", .{});
|
|
}
|
|
|
|
fn print(comptime fmt: []const u8, args: anytype) void {
|
|
stdout.print(fmt, args) catch unreachable;
|
|
}
|
|
|
|
const std = @import("std");
|
|
const stdout = std.io.getStdOut().writer();
|
|
const tokenizeAny = std.mem.tokenizeAny;
|
|
const process = std.process;
|
|
const Allocator = std.mem.Allocator;
|
|
const ArrayList = std.ArrayList;
|
|
const StaticStringMap = std.static_string_map.StaticStringMap;
|
|
const Random = std.Random;
|
|
const Linenoise = @import("linenoise").Linenoise;
|