1 Commits

Author SHA1 Message Date
2043e20b88 feat: Added table viewer. 2026-06-08 17:39:45 -04:00
5 changed files with 90 additions and 97 deletions

2
.envrc
View File

@@ -1,4 +1,4 @@
use flake
ROOT="."
ROOT="/home/spencer/Desktop/envr"
export PATH=".:${ROOT}/deps/zig:${ROOT}/deps/zls:$PATH"

View File

@@ -177,7 +177,7 @@ pub fn list(self: *@This(), gpa: std.mem.Allocator) ![]EnvFile {
return stmt.all(EnvFile, gpa, .{}, .{});
}
pub const EnvFile = struct {
const EnvFile = struct {
// TODO: Should use file_name in the struct and derive from the path.
path: []const u8,

View File

@@ -44,7 +44,7 @@ fn run(
var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer);
const stdout_writer = &stdout_file_writer.interface;
return envr.deps(
return deps(
io,
stdout_writer,
environ_map.get("PATH").?,
@@ -75,6 +75,63 @@ fn version(writer: *Io.Writer) !void {
try writer.flush();
}
// Display dependency statuses
fn deps(
io: Io,
writer: *Io.Writer,
path: []const u8,
) !void {
const feats: Features = try .scan(io, path);
// FIXME: Draw as a table
try writer.print("features: {}", .{feats});
try writer.flush();
}
const Features = packed struct {
git: bool = false,
fd: bool = false,
const all_features: Features = .{
.git = true,
.fd = true,
};
/// Scans your PATH variable for programs.
pub fn scan(io: Io, path: []const u8) !@This() {
var feats: Features = .{};
var dirs = std.mem.splitScalar(u8, path, std.fs.path.delimiter);
loop: while (dirs.next()) |dir| {
const dirt = Io.Dir.openDir(Io.Dir.cwd(), io, dir, .{ .follow_symlinks = true, .iterate = true }) catch continue;
defer dirt.close(io);
var dir_paths = dirt.iterate();
while (try dir_paths.next(io)) |file| {
// FIXME: Check if executable
if (std.mem.eql(u8, std.fs.path.basename(file.name), "git")) {
feats.git = true;
if (feats == Features.all_features) {
break :loop;
}
}
if (std.mem.eql(u8, std.fs.path.basename(file.name), "fd")) {
feats.fd = true;
if (feats == Features.all_features) {
break :loop;
}
}
}
}
return feats;
}
};
fn fallback_to_go(
io: Io,
arena: std.mem.Allocator,

View File

@@ -63,63 +63,6 @@ pub const root: Command = .new(.{
},
});
// Display dependency statuses
pub fn deps(
io: Io,
writer: *Io.Writer,
path: []const u8,
) !void {
const feats: Features = try .scan(io, path);
// FIXME: Draw as a table
try writer.print("features: {}", .{feats});
try writer.flush();
}
const Features = packed struct {
git: bool = false,
fd: bool = false,
const all_features: Features = .{
.git = true,
.fd = true,
};
/// Scans your PATH variable for programs.
pub fn scan(io: Io, path: []const u8) !@This() {
var feats: Features = .{};
var dirs = std.mem.splitScalar(u8, path, std.fs.path.delimiter);
loop: while (dirs.next()) |dir| {
const dirt = Io.Dir.openDir(Io.Dir.cwd(), io, dir, .{ .follow_symlinks = true, .iterate = true }) catch continue;
defer dirt.close(io);
var dir_paths = dirt.iterate();
while (try dir_paths.next(io)) |file| {
// FIXME: Check if executable
if (std.mem.eql(u8, std.fs.path.basename(file.name), "git")) {
feats.git = true;
if (feats == Features.all_features) {
break :loop;
}
}
if (std.mem.eql(u8, std.fs.path.basename(file.name), "fd")) {
feats.fd = true;
if (feats == Features.all_features) {
break :loop;
}
}
}
}
return feats;
}
};
pub fn list(
io: Io,
arena: std.mem.Allocator,
@@ -129,13 +72,10 @@ pub fn list(
) !void {
// TODO: Don't hardcode
const cfgPath = try std.fs.path.join(arena, &.{ home, ".envr", "config.json" });
defer arena.free(cfgPath);
var cfg = (try Config.load(io, arena, cfgPath));
defer cfg.deinit();
const cfg: Config = (try Config.load(io, arena, cfgPath)).value;
var db: Db = try .open(io, arena, .{
.config = cfg.value,
.config = cfg,
.home = home,
.tmp = tmp,
});
@@ -143,14 +83,15 @@ pub fn list(
const files = try db.list(arena);
defer arena.free(files);
const table: tabula.Table(Db.EnvFile, .initOne(.path)) = .{ .items = files };
const table = tabula.Table(@TypeOf(files[0]));
try out.print("{f}", .{table});
try out.flush();
try db.close(io, arena); // TODO: Defer this
for (files) |*file| {
file.deinit(arena);
// TODO: Is this bad?
for (files) |file| {
@constCast(&file).deinit(arena);
}
}
@@ -258,15 +199,12 @@ test "list returns a table" {
tmp,
);
const got = try out.toOwnedSlice();
defer gpa.free(got);
try std.testing.expectEqualStrings(
\\┌────────────────────────┐
\\│ path
\\│ path
\\├────────────────────────┤
\\│ ~/project/.env.example │
\\└────────────────────────┘
\\
, got);
, try out.toOwnedSlice());
}

View File

@@ -27,37 +27,38 @@ pub fn Table(
// Print body
for (self.items) |item| {
try writer.writeAll(sep);
_ = try writer.write(sep);
comptime var itr = fields.iterator();
comptime var i: usize = 0;
inline while (comptime itr.next()) |c| : (i += 1) {
try writer.writeByte(' ');
_ = try writer.write(" ");
try write_aligned(writer, @field(item, @tagName(c)), max_column_widths[i], .left);
try writer.print(" {s}", .{sep});
}
try writer.writeAll("\n");
_ = try writer.write("\n");
}
// Print post-body
{
try writer.writeAll(bl);
_ = try writer.write(bl);
var itr = fields.iterator();
var i: usize = 0;
while (itr.next()) |_| : (i += 1) {
if (i > 0) {
try writer.writeAll(bm);
_ = try writer.write(bm);
}
const padding = max_column_widths[i] + 2;
for (0..padding) |_| {
try writer.writeAll(hor);
_ = try writer.write(hor);
}
}
try writer.writeAll(br ++ "\n");
_ = try writer.write(br);
_ = try writer.write("\n");
}
}
};
@@ -95,29 +96,29 @@ fn header(
// Print Pre-Header
{
try writer.writeAll(tl);
_ = try writer.write(tl);
inline for (0..comptime fields.count()) |i| {
if (i > 0) {
try writer.writeAll(tm);
_ = try writer.write(tm);
}
const padding = max_column_widths[i] + 2;
for (0..padding) |_| {
try writer.writeAll(hor);
_ = try writer.write(hor);
}
}
try writer.writeAll(tr ++ "\n");
_ = try writer.write(tr ++ "\n");
}
// Main Header
{
try writer.writeAll(sep);
_ = try writer.write(sep);
comptime var itr = fields.iterator();
comptime var i: usize = 0;
inline while (comptime itr.next()) |field| : (i += 1) {
try writer.writeByte(' ');
_ = try writer.write(" ");
try write_aligned(
writer,
@tagName(field),
@@ -127,24 +128,24 @@ fn header(
try writer.print(" {s}", .{sep});
}
try writer.writeByte('\n');
try writer.print("\n", .{});
}
// Print post-header
{
try writer.writeAll(ml);
_ = try writer.write(ml);
inline for (0..comptime fields.count()) |i| {
if (i > 0) {
try writer.writeAll(mm);
_ = try writer.write(mm);
}
const padding = max_column_widths[i] + 2;
for (0..padding) |_| {
try writer.writeAll(hor);
_ = try writer.write(hor);
}
}
try writer.writeAll(mr ++ "\n");
_ = try writer.write(mr ++ "\n");
}
}
@@ -154,9 +155,6 @@ fn write_aligned(
max_width: usize,
alignment: Alignment,
) !void {
std.debug.assert(data.len > 0);
std.debug.assert(max_width >= data.len);
const padding: [2]usize = switch (alignment) {
.left => .{ 0, max_width - data.len },
.right => .{ max_width - data.len, 0 },
@@ -168,13 +166,13 @@ fn write_aligned(
};
for (0..padding[0]) |_| {
try writer.writeByte(' ');
_ = try writer.write(" ");
}
try writer.writeAll(data);
_ = try writer.write(data);
for (0..padding[1]) |_| {
try writer.writeByte(' ');
_ = try writer.write(" ");
}
}