feat: add support for ~ expansion to open_file command and file_browser

This commit is contained in:
CJ van den Berg 2025-06-19 16:08:34 +02:00
parent 9a580ac0e7
commit a33f6c8c2b
Signed by: neurocyte
GPG key ID: 8EB1E1BB660E3FB9
4 changed files with 43 additions and 25 deletions

View file

@ -968,22 +968,3 @@ pub fn shorten_path(buf: []u8, path: []const u8, removed_prefix: *usize, max_len
@memcpy(buf[ellipsis.len .. max_len + ellipsis.len], path[prefix..]);
return buf[0 .. max_len + ellipsis.len];
}
pub fn abbreviate_home(buf: []u8, path: []const u8) []const u8 {
const a = std.heap.c_allocator;
if (builtin.os.tag == .windows) return path;
if (!std.fs.path.isAbsolute(path)) return path;
const homedir = std.posix.getenv("HOME") orelse return path;
const homerelpath = std.fs.path.relative(a, homedir, path) catch return path;
defer a.free(homerelpath);
if (homerelpath.len == 0) {
return "~";
} else if (homerelpath.len > 3 and std.mem.eql(u8, homerelpath[0..3], "../")) {
return path;
} else {
buf[0] = '~';
buf[1] = '/';
@memcpy(buf[2 .. homerelpath.len + 2], homerelpath);
return buf[0 .. homerelpath.len + 2];
}
}

View file

@ -480,7 +480,9 @@ const Process = struct {
fn request_path_files(self: *Process, from: tp.pid_ref, project_directory: []const u8, max: usize, path: []const u8) (ProjectError || SpawnError || std.fs.Dir.OpenError)!void {
const project = self.projects.get(project_directory) orelse return error.NoProject;
try request_path_files_async(self.allocator, from, project, max, path);
var buf = std.ArrayList(u8).init(self.allocator);
defer buf.deinit();
try request_path_files_async(self.allocator, from, project, max, expand_home(&buf, path));
}
fn request_tasks(self: *Process, from: tp.pid_ref, project_directory: []const u8) (ProjectError || Project.ClientError)!void {
@ -811,3 +813,34 @@ pub fn normalize_file_path(file_path: []const u8) []const u8 {
return file_path[project.len + 1 ..];
return file_path;
}
pub fn abbreviate_home(buf: []u8, path: []const u8) []const u8 {
const a = std.heap.c_allocator;
if (builtin.os.tag == .windows) return path;
if (!std.fs.path.isAbsolute(path)) return path;
const homedir = std.posix.getenv("HOME") orelse return path;
const homerelpath = std.fs.path.relative(a, homedir, path) catch return path;
defer a.free(homerelpath);
if (homerelpath.len == 0) {
return "~";
} else if (homerelpath.len > 3 and std.mem.eql(u8, homerelpath[0..3], "../")) {
return path;
} else {
buf[0] = '~';
buf[1] = '/';
@memcpy(buf[2 .. homerelpath.len + 2], homerelpath);
return buf[0 .. homerelpath.len + 2];
}
}
pub fn expand_home(buf: *std.ArrayList(u8), file_path: []const u8) []const u8 {
if (builtin.os.tag == .windows) return file_path;
if (file_path.len > 0 and file_path[0] == '~') {
if (file_path.len > 1 and file_path[1] != std.fs.path.sep) return file_path;
const homedir = std.posix.getenv("HOME") orelse return file_path;
buf.appendSlice(homedir) catch return file_path;
buf.append(std.fs.path.sep) catch return file_path;
buf.appendSlice(file_path[2..]) catch return file_path;
return buf.items;
} else return file_path;
}

View file

@ -380,7 +380,10 @@ const cmds = struct {
try open_project_cwd(self, .{});
}
const f = project_manager.normalize_file_path(file orelse return);
const f_ = project_manager.normalize_file_path(file orelse return);
var buf = std.ArrayList(u8).init(self.allocator);
defer buf.deinit();
const f = project_manager.expand_home(&buf, f_);
const same_file = if (self.get_active_file_path()) |fp| std.mem.eql(u8, fp, f) else false;
const have_editor_metadata = if (self.buffer_manager.get_buffer_for_file(f)) |_| true else false;

View file

@ -4,6 +4,7 @@ const tp = @import("thespian");
const tracy = @import("tracy");
const Buffer = @import("Buffer");
const root = @import("root");
const project_manager = @import("project_manager");
const Plane = @import("renderer").Plane;
const style = @import("renderer").style;
@ -177,7 +178,7 @@ fn render_terminal_title(self: *Self) void {
var new_title_buf: [512]u8 = undefined;
const project_path = tp.env.get().str("project");
const project_name = root.abbreviate_home(&project_name_buf, project_path);
const project_name = project_manager.abbreviate_home(&project_name_buf, project_path);
const file_name = if (std.mem.lastIndexOfScalar(u8, self.name, '/')) |pos| self.name[pos + 1 ..] else self.name;
const edit_state = if (!self.file_exists) "" else if (self.file_dirty) "" else "";
@ -210,7 +211,7 @@ pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message
self.name = self.name_buf[0..file_path.len];
self.file_exists = true;
self.file_dirty = false;
self.name = root.abbreviate_home(&self.name_buf, self.name);
self.name = project_manager.abbreviate_home(&self.name_buf, self.name);
} else if (try m.match(.{ "E", "open", tp.extract(&file_path), tp.extract(&self.file_exists), tp.extract(&file_type), tp.extract(&file_icon), tp.extract(&self.file_color) })) {
self.eol_mode = .lf;
@memcpy(self.name_buf[0..file_path.len], file_path);
@ -221,7 +222,7 @@ pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message
self.file_icon_buf[file_icon.len] = 0;
self.file_icon = self.file_icon_buf[0..file_icon.len :0];
self.file_dirty = false;
self.name = root.abbreviate_home(&self.name_buf, self.name);
self.name = project_manager.abbreviate_home(&self.name_buf, self.name);
self.file = true;
} else if (try m.match(.{ "E", "close" })) {
self.name = "";
@ -256,5 +257,5 @@ fn show_project(self: *Self) void {
const project_name = tp.env.get().str("project");
@memcpy(self.name_buf[0..project_name.len], project_name);
self.name = self.name_buf[0..project_name.len];
self.name = root.abbreviate_home(&self.name_buf, self.name);
self.name = project_manager.abbreviate_home(&self.name_buf, self.name);
}