feat: query project files via git (part 1)
This commit is contained in:
		
							parent
							
								
									4cb84e25b3
								
							
						
					
					
						commit
						f76085325a
					
				
					 5 changed files with 75 additions and 21 deletions
				
			
		| 
						 | 
					@ -461,6 +461,7 @@ pub fn build_exe(
 | 
				
			||||||
            .{ .name = "syntax", .module = syntax_mod },
 | 
					            .{ .name = "syntax", .module = syntax_mod },
 | 
				
			||||||
            .{ .name = "dizzy", .module = dizzy_dep.module("dizzy") },
 | 
					            .{ .name = "dizzy", .module = dizzy_dep.module("dizzy") },
 | 
				
			||||||
            .{ .name = "fuzzig", .module = fuzzig_dep.module("fuzzig") },
 | 
					            .{ .name = "fuzzig", .module = fuzzig_dep.module("fuzzig") },
 | 
				
			||||||
 | 
					            .{ .name = "git", .module = git_mod },
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,7 @@ const dizzy = @import("dizzy");
 | 
				
			||||||
const Buffer = @import("Buffer");
 | 
					const Buffer = @import("Buffer");
 | 
				
			||||||
const fuzzig = @import("fuzzig");
 | 
					const fuzzig = @import("fuzzig");
 | 
				
			||||||
const tracy = @import("tracy");
 | 
					const tracy = @import("tracy");
 | 
				
			||||||
 | 
					const git = @import("git");
 | 
				
			||||||
const builtin = @import("builtin");
 | 
					const builtin = @import("builtin");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const LSP = @import("LSP.zig");
 | 
					const LSP = @import("LSP.zig");
 | 
				
			||||||
| 
						 | 
					@ -24,6 +25,9 @@ persistent: bool = false,
 | 
				
			||||||
logger_lsp: log.Logger,
 | 
					logger_lsp: log.Logger,
 | 
				
			||||||
logger_git: log.Logger,
 | 
					logger_git: log.Logger,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					workspace: ?[]const u8 = null,
 | 
				
			||||||
 | 
					branch: ?[]const u8 = null,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Self = @This();
 | 
					const Self = @This();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const OutOfMemoryError = error{OutOfMemory};
 | 
					const OutOfMemoryError = error{OutOfMemory};
 | 
				
			||||||
| 
						 | 
					@ -67,6 +71,8 @@ pub fn init(allocator: std.mem.Allocator, name: []const u8) OutOfMemoryError!Sel
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn deinit(self: *Self) void {
 | 
					pub fn deinit(self: *Self) void {
 | 
				
			||||||
 | 
					    if (self.workspace) |p| self.allocator.free(p);
 | 
				
			||||||
 | 
					    if (self.branch) |p| self.allocator.free(p);
 | 
				
			||||||
    var i_ = self.file_language_server.iterator();
 | 
					    var i_ = self.file_language_server.iterator();
 | 
				
			||||||
    while (i_.next()) |p| {
 | 
					    while (i_.next()) |p| {
 | 
				
			||||||
        self.allocator.free(p.key_ptr.*);
 | 
					        self.allocator.free(p.key_ptr.*);
 | 
				
			||||||
| 
						 | 
					@ -1850,3 +1856,26 @@ pub fn get_line(allocator: std.mem.Allocator, buf: []const u8) ![]const u8 {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return allocator.dupe(u8, buf);
 | 
					    return allocator.dupe(u8, buf);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn query_git(self: *Self) void {
 | 
				
			||||||
 | 
					    git.workspace_path(@intFromPtr(self)) catch {};
 | 
				
			||||||
 | 
					    git.current_branch(@intFromPtr(self)) catch {};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn process_git(self: *Self, m: tp.message) !void {
 | 
				
			||||||
 | 
					    var value: []const u8 = undefined;
 | 
				
			||||||
 | 
					    if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.null_ })) {
 | 
				
			||||||
 | 
					        // no git workspace
 | 
				
			||||||
 | 
					    } else if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.extract(&value) })) {
 | 
				
			||||||
 | 
					        if (self.workspace) |p| self.allocator.free(p);
 | 
				
			||||||
 | 
					        self.workspace = try self.allocator.dupe(u8, value);
 | 
				
			||||||
 | 
					        git.workspace_files(@intFromPtr(self)) catch {};
 | 
				
			||||||
 | 
					    } else if (try m.match(.{ tp.any, tp.any, "current_branch", tp.extract(&value) })) {
 | 
				
			||||||
 | 
					        if (self.branch) |p| self.allocator.free(p);
 | 
				
			||||||
 | 
					        self.branch = try self.allocator.dupe(u8, value);
 | 
				
			||||||
 | 
					    } else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.extract(&value) })) {
 | 
				
			||||||
 | 
					        // TODO
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        self.logger_git.err("git", tp.unexpected(m));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										49
									
								
								src/git.zig
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								src/git.zig
									
										
									
									
									
								
							| 
						 | 
					@ -7,37 +7,55 @@ pub const Error = error{ OutOfMemory, GitNotFound, GitCallFailed };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const log_execute = false;
 | 
					const log_execute = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn workspace_path() Error!void {
 | 
					pub fn workspace_path(context_: usize) Error!void {
 | 
				
			||||||
    const fn_name = @src().fn_name;
 | 
					    const fn_name = @src().fn_name;
 | 
				
			||||||
    try git(.{ "rev-parse", "--show-toplevel" }, struct {
 | 
					    try git(context_, .{ "rev-parse", "--show-toplevel" }, struct {
 | 
				
			||||||
        fn result(parent: tp.pid_ref, output: []const u8) void {
 | 
					        fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
 | 
				
			||||||
            var it = std.mem.splitScalar(u8, output, '\n');
 | 
					            var it = std.mem.splitScalar(u8, output, '\n');
 | 
				
			||||||
            while (it.next()) |branch| if (branch.len > 0)
 | 
					            while (it.next()) |value| if (value.len > 0)
 | 
				
			||||||
                parent.send(.{ module_name, fn_name, branch }) catch {};
 | 
					                parent.send(.{ module_name, context, fn_name, value }) catch {};
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }.result, exit_null_on_error(fn_name));
 | 
					    }.result, exit_null_on_error(fn_name));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn current_branch() Error!void {
 | 
					pub fn current_branch(context_: usize) Error!void {
 | 
				
			||||||
    const fn_name = @src().fn_name;
 | 
					    const fn_name = @src().fn_name;
 | 
				
			||||||
    try git(.{ "rev-parse", "--abbrev-ref", "HEAD" }, struct {
 | 
					    try git(context_, .{ "rev-parse", "--abbrev-ref", "HEAD" }, struct {
 | 
				
			||||||
        fn result(parent: tp.pid_ref, output: []const u8) void {
 | 
					        fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
 | 
				
			||||||
            var it = std.mem.splitScalar(u8, output, '\n');
 | 
					            var it = std.mem.splitScalar(u8, output, '\n');
 | 
				
			||||||
            while (it.next()) |branch| if (branch.len > 0)
 | 
					            while (it.next()) |value| if (value.len > 0)
 | 
				
			||||||
                parent.send(.{ module_name, fn_name, branch }) catch {};
 | 
					                parent.send(.{ module_name, context, fn_name, value }) catch {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }.result, exit_null_on_error(fn_name));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub fn workspace_files(context_: usize) Error!void {
 | 
				
			||||||
 | 
					    const fn_name = @src().fn_name;
 | 
				
			||||||
 | 
					    try git_err(context_, .{ "ls-files", "--cached", "--others", "--exclude-standard" }, struct {
 | 
				
			||||||
 | 
					        fn result(context: usize, parent: tp.pid_ref, output: []const u8) void {
 | 
				
			||||||
 | 
					            var it = std.mem.splitScalar(u8, output, '\n');
 | 
				
			||||||
 | 
					            while (it.next()) |value| if (value.len > 0)
 | 
				
			||||||
 | 
					                parent.send(.{ module_name, context, fn_name, value }) catch {};
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }.result, struct {
 | 
				
			||||||
 | 
					        fn result(_: usize, _: tp.pid_ref, output: []const u8) void {
 | 
				
			||||||
 | 
					            var it = std.mem.splitScalar(u8, output, '\n');
 | 
				
			||||||
 | 
					            while (it.next()) |line| std.log.err("{s}: {s}", .{ module_name, line });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }.result, exit_null_on_error(fn_name));
 | 
					    }.result, exit_null_on_error(fn_name));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn git(
 | 
					fn git(
 | 
				
			||||||
 | 
					    context: usize,
 | 
				
			||||||
    cmd: anytype,
 | 
					    cmd: anytype,
 | 
				
			||||||
    out: OutputHandler,
 | 
					    out: OutputHandler,
 | 
				
			||||||
    exit: ExitHandler,
 | 
					    exit: ExitHandler,
 | 
				
			||||||
) Error!void {
 | 
					) Error!void {
 | 
				
			||||||
    return git_err(cmd, out, noop, exit);
 | 
					    return git_err(context, cmd, out, noop, exit);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn git_err(
 | 
					fn git_err(
 | 
				
			||||||
 | 
					    context: usize,
 | 
				
			||||||
    cmd: anytype,
 | 
					    cmd: anytype,
 | 
				
			||||||
    out: OutputHandler,
 | 
					    out: OutputHandler,
 | 
				
			||||||
    err: OutputHandler,
 | 
					    err: OutputHandler,
 | 
				
			||||||
| 
						 | 
					@ -54,6 +72,7 @@ fn git_err(
 | 
				
			||||||
            inline for (info.fields) |f|
 | 
					            inline for (info.fields) |f|
 | 
				
			||||||
                try cbor.writeValue(writer, @field(cmd, f.name));
 | 
					                try cbor.writeValue(writer, @field(cmd, f.name));
 | 
				
			||||||
            return shell.execute(allocator, .{ .buf = buf.items }, .{
 | 
					            return shell.execute(allocator, .{ .buf = buf.items }, .{
 | 
				
			||||||
 | 
					                .context = context,
 | 
				
			||||||
                .out = to_shell_output_handler(out),
 | 
					                .out = to_shell_output_handler(out),
 | 
				
			||||||
                .err = to_shell_output_handler(err),
 | 
					                .err = to_shell_output_handler(err),
 | 
				
			||||||
                .exit = exit,
 | 
					                .exit = exit,
 | 
				
			||||||
| 
						 | 
					@ -74,18 +93,18 @@ fn exit_null_on_error(comptime tag: []const u8) shell.ExitHandler {
 | 
				
			||||||
    }.exit;
 | 
					    }.exit;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const OutputHandler = fn (parent: tp.pid_ref, output: []const u8) void;
 | 
					const OutputHandler = fn (context: usize, parent: tp.pid_ref, output: []const u8) void;
 | 
				
			||||||
const ExitHandler = shell.ExitHandler;
 | 
					const ExitHandler = shell.ExitHandler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn to_shell_output_handler(handler: anytype) shell.OutputHandler {
 | 
					fn to_shell_output_handler(handler: anytype) shell.OutputHandler {
 | 
				
			||||||
    return struct {
 | 
					    return struct {
 | 
				
			||||||
        fn out(_: usize, parent: tp.pid_ref, _: []const u8, output: []const u8) void {
 | 
					        fn out(context: usize, parent: tp.pid_ref, _: []const u8, output: []const u8) void {
 | 
				
			||||||
            handler(parent, output);
 | 
					            handler(context, parent, output);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }.out;
 | 
					    }.out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn noop(_: tp.pid_ref, _: []const u8) void {}
 | 
					fn noop(_: usize, _: tp.pid_ref, _: []const u8) void {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var git_path: ?struct {
 | 
					var git_path: ?struct {
 | 
				
			||||||
    path: ?[:0]const u8 = null,
 | 
					    path: ?[:0]const u8 = null,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -325,6 +325,7 @@ const Process = struct {
 | 
				
			||||||
        var text_len: usize = 0;
 | 
					        var text_len: usize = 0;
 | 
				
			||||||
        var n: usize = 0;
 | 
					        var n: usize = 0;
 | 
				
			||||||
        var task: []const u8 = undefined;
 | 
					        var task: []const u8 = undefined;
 | 
				
			||||||
 | 
					        var context: usize = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        var root_dst: usize = 0;
 | 
					        var root_dst: usize = 0;
 | 
				
			||||||
        var root_src: usize = 0;
 | 
					        var root_src: usize = 0;
 | 
				
			||||||
| 
						 | 
					@ -341,6 +342,9 @@ const Process = struct {
 | 
				
			||||||
            if (self.walker) |pid| pid.deinit();
 | 
					            if (self.walker) |pid| pid.deinit();
 | 
				
			||||||
            self.walker = null;
 | 
					            self.walker = null;
 | 
				
			||||||
            self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
 | 
					            self.loaded(project_directory) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
 | 
				
			||||||
 | 
					        } else if (try cbor.match(m.buf, .{ "git", tp.extract(&context), tp.more })) {
 | 
				
			||||||
 | 
					            const project: *Project = @ptrFromInt(context);
 | 
				
			||||||
 | 
					            project.process_git(m) catch {};
 | 
				
			||||||
        } else if (try cbor.match(m.buf, .{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
 | 
					        } else if (try cbor.match(m.buf, .{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
 | 
				
			||||||
            self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
 | 
					            self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
 | 
				
			||||||
        } else if (try cbor.match(m.buf, .{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
 | 
					        } else if (try cbor.match(m.buf, .{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
 | 
				
			||||||
| 
						 | 
					@ -423,6 +427,7 @@ const Process = struct {
 | 
				
			||||||
            self.walker = try walk_tree_async(self.allocator, project_directory);
 | 
					            self.walker = try walk_tree_async(self.allocator, project_directory);
 | 
				
			||||||
            self.restore_project(project) catch |e| self.logger.err("restore_project", e);
 | 
					            self.restore_project(project) catch |e| self.logger.err("restore_project", e);
 | 
				
			||||||
            project.sort_files_by_mtime();
 | 
					            project.sort_files_by_mtime();
 | 
				
			||||||
 | 
					            project.query_git();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            self.logger.print("switched to: {s}", .{project_directory});
 | 
					            self.logger.print("switched to: {s}", .{project_directory});
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ pub fn create(
 | 
				
			||||||
        .plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
 | 
					        .plane = try Plane.init(&(Widget.Box{}).opts(@typeName(Self)), parent),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    try tui.message_filters().add(MessageFilter.bind(self, receive_git));
 | 
					    try tui.message_filters().add(MessageFilter.bind(self, receive_git));
 | 
				
			||||||
    git.workspace_path() catch {};
 | 
					    git.workspace_path(0) catch {};
 | 
				
			||||||
    return Widget.to(self);
 | 
					    return Widget.to(self);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -51,11 +51,11 @@ fn process_git(
 | 
				
			||||||
    m: tp.message,
 | 
					    m: tp.message,
 | 
				
			||||||
) MessageFilter.Error!bool {
 | 
					) MessageFilter.Error!bool {
 | 
				
			||||||
    var branch: []const u8 = undefined;
 | 
					    var branch: []const u8 = undefined;
 | 
				
			||||||
    if (try match(m.buf, .{ any, "workspace_path", null_ })) {
 | 
					    if (try match(m.buf, .{ any, any, "workspace_path", null_ })) {
 | 
				
			||||||
        self.branch = try self.allocator.dupe(u8, "null");
 | 
					        // do nothing, we do not have a git workspace
 | 
				
			||||||
    } else if (try match(m.buf, .{ any, "workspace_path", string })) {
 | 
					    } else if (try match(m.buf, .{ any, any, "workspace_path", string })) {
 | 
				
			||||||
        git.current_branch() catch {};
 | 
					        git.current_branch(0) catch {};
 | 
				
			||||||
    } else if (try match(m.buf, .{ any, "current_branch", extract(&branch) })) {
 | 
					    } else if (try match(m.buf, .{ any, any, "current_branch", extract(&branch) })) {
 | 
				
			||||||
        if (self.branch) |p| self.allocator.free(p);
 | 
					        if (self.branch) |p| self.allocator.free(p);
 | 
				
			||||||
        self.branch = try self.allocator.dupe(u8, branch);
 | 
					        self.branch = try self.allocator.dupe(u8, branch);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue