feat: WIP add project manager service
The project manager service will provide fuzzy find, LRU, and similar background services for open projects.
This commit is contained in:
parent
a056a54104
commit
602a4dff01
5 changed files with 400 additions and 4 deletions
11
build.zig
11
build.zig
|
@ -137,6 +137,16 @@ pub fn build(b: *std.Build) void {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const project_manager_mod = b.createModule(.{
|
||||||
|
.root_source_file = .{ .path = "src/project_manager.zig" },
|
||||||
|
.imports = &.{
|
||||||
|
.{ .name = "log", .module = log_mod },
|
||||||
|
.{ .name = "cbor", .module = cbor_mod },
|
||||||
|
.{ .name = "thespian", .module = thespian_mod },
|
||||||
|
.{ .name = "tracy", .module = tracy_mod },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const diff_mod = b.createModule(.{
|
const diff_mod = b.createModule(.{
|
||||||
.root_source_file = .{ .path = "src/diff.zig" },
|
.root_source_file = .{ .path = "src/diff.zig" },
|
||||||
.imports = &.{
|
.imports = &.{
|
||||||
|
@ -163,6 +173,7 @@ pub fn build(b: *std.Build) void {
|
||||||
.{ .name = "config", .module = config_mod },
|
.{ .name = "config", .module = config_mod },
|
||||||
.{ .name = "log", .module = log_mod },
|
.{ .name = "log", .module = log_mod },
|
||||||
.{ .name = "location_history", .module = location_history_mod },
|
.{ .name = "location_history", .module = location_history_mod },
|
||||||
|
.{ .name = "project_manager", .module = project_manager_mod },
|
||||||
.{ .name = "syntax", .module = syntax_dep.module("syntax") },
|
.{ .name = "syntax", .module = syntax_dep.module("syntax") },
|
||||||
.{ .name = "text_manip", .module = text_manip_mod },
|
.{ .name = "text_manip", .module = text_manip_mod },
|
||||||
.{ .name = "Buffer", .module = Buffer_mod },
|
.{ .name = "Buffer", .module = Buffer_mod },
|
||||||
|
|
296
src/project_manager.zig
Normal file
296
src/project_manager.zig
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const tp = @import("thespian");
|
||||||
|
const cbor = @import("cbor");
|
||||||
|
const log = @import("log");
|
||||||
|
const tracy = @import("tracy");
|
||||||
|
|
||||||
|
pid: ?tp.pid,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
const module_name = @typeName(Self);
|
||||||
|
pub const Error = error{ OutOfMemory, Exit };
|
||||||
|
|
||||||
|
pub fn create(a: std.mem.Allocator) Error!Self {
|
||||||
|
return .{ .pid = try Process.create(a) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_pid(pid: tp.pid_ref) Error!Self {
|
||||||
|
return .{ .pid = pid.clone() };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
if (self.pid) |pid| {
|
||||||
|
self.pid = null;
|
||||||
|
pid.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shutdown(self: *Self) void {
|
||||||
|
if (self.pid) |pid| {
|
||||||
|
pid.send(.{"shutdown"}) catch {};
|
||||||
|
self.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open(self: *const Self, project_directory: []const u8) tp.result {
|
||||||
|
const pid = if (self.pid) |pid| pid else return tp.exit_error(error.Shutdown);
|
||||||
|
try pid.send(.{ "open", project_directory });
|
||||||
|
}
|
||||||
|
|
||||||
|
const Process = struct {
|
||||||
|
a: std.mem.Allocator,
|
||||||
|
parent: tp.pid,
|
||||||
|
logger: log.Logger,
|
||||||
|
receiver: Receiver,
|
||||||
|
projects: ProjectsMap,
|
||||||
|
|
||||||
|
const Receiver = tp.Receiver(*Process);
|
||||||
|
const ProjectsMap = std.StringHashMap(*Project);
|
||||||
|
|
||||||
|
pub fn create(a: std.mem.Allocator) Error!tp.pid {
|
||||||
|
const self = try a.create(Process);
|
||||||
|
self.* = .{
|
||||||
|
.a = a,
|
||||||
|
.parent = tp.self_pid().clone(),
|
||||||
|
.logger = log.logger(module_name),
|
||||||
|
.receiver = Receiver.init(Process.receive, self),
|
||||||
|
.projects = ProjectsMap.init(a),
|
||||||
|
};
|
||||||
|
return tp.spawn_link(self.a, self, Process.start, module_name) catch |e| tp.exit_error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *Process) void {
|
||||||
|
var i = self.projects.iterator();
|
||||||
|
while (i.next()) |p| {
|
||||||
|
self.a.free(p.key_ptr.*);
|
||||||
|
p.value_ptr.*.deinit();
|
||||||
|
self.a.destroy(p.value_ptr.*);
|
||||||
|
}
|
||||||
|
self.projects.deinit();
|
||||||
|
self.parent.deinit();
|
||||||
|
self.a.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(self: *Process) tp.result {
|
||||||
|
_ = tp.set_trap(true);
|
||||||
|
tp.receive(&self.receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(self: *Process, from: tp.pid_ref, m: tp.message) tp.result {
|
||||||
|
errdefer self.deinit();
|
||||||
|
var project_directory: []const u8 = undefined;
|
||||||
|
var path: []const u8 = undefined;
|
||||||
|
|
||||||
|
if (try m.match(.{ "walk_tree_entry", tp.extract(&project_directory), tp.extract(&path) })) {
|
||||||
|
if (self.projects.get(project_directory)) |project|
|
||||||
|
project.add_file(path) catch |e| self.logger.err("walk_tree_entry", e);
|
||||||
|
// self.logger.print("file: {s}", .{path});
|
||||||
|
} else if (try m.match(.{ "walk_tree_done", tp.extract(&project_directory) })) {
|
||||||
|
const project = self.projects.get(project_directory) orelse return;
|
||||||
|
self.logger.print("opened: {s} with {d} files in {d} ms", .{
|
||||||
|
project_directory,
|
||||||
|
project.files.count(),
|
||||||
|
std.time.milliTimestamp() - project.open_time,
|
||||||
|
});
|
||||||
|
} else if (try m.match(.{ "open", tp.extract(&project_directory) })) {
|
||||||
|
self.open(project_directory) catch |e| return from.send_raw(tp.exit_message(e));
|
||||||
|
} else if (try m.match(.{"shutdown"})) {
|
||||||
|
return tp.exit_normal();
|
||||||
|
} else if (try m.match(.{ "exit", "normal" })) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
self.logger.err("receive", tp.unexpected(m));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open(self: *Process, project_directory: []const u8) error{ OutOfMemory, Exit }!void {
|
||||||
|
self.logger.print("opening: {s}", .{project_directory});
|
||||||
|
if (self.projects.get(project_directory) == null) {
|
||||||
|
const project = try self.a.create(Project);
|
||||||
|
project.* = try Project.init(self.a, project_directory);
|
||||||
|
try self.projects.put(try self.a.dupe(u8, project_directory), project);
|
||||||
|
try walk_tree_async(self.a, project_directory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const Project = struct {
|
||||||
|
a: std.mem.Allocator,
|
||||||
|
name: []const u8,
|
||||||
|
files: FilesMap,
|
||||||
|
open_time: i64,
|
||||||
|
|
||||||
|
const FilesMap = std.StringHashMap(void);
|
||||||
|
|
||||||
|
fn init(a: std.mem.Allocator, name: []const u8) error{OutOfMemory}!Project {
|
||||||
|
return .{
|
||||||
|
.a = a,
|
||||||
|
.name = try a.dupe(u8, name),
|
||||||
|
.files = FilesMap.init(a),
|
||||||
|
.open_time = std.time.milliTimestamp(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *Project) void {
|
||||||
|
var i = self.files.iterator();
|
||||||
|
while (i.next()) |p| self.a.free(p.key_ptr.*);
|
||||||
|
self.files.deinit();
|
||||||
|
self.a.free(self.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_file(self: *Project, path: []const u8) error{OutOfMemory}!void {
|
||||||
|
if (self.files.get(path) != null) return;
|
||||||
|
try self.files.put(try self.a.dupe(u8, path), {});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn walk_tree_async(a_: std.mem.Allocator, root_path_: []const u8) tp.result {
|
||||||
|
return struct {
|
||||||
|
a: std.mem.Allocator,
|
||||||
|
root_path: []const u8,
|
||||||
|
parent: tp.pid,
|
||||||
|
|
||||||
|
const tree_walker = @This();
|
||||||
|
|
||||||
|
fn spawn_link(a: std.mem.Allocator, root_path: []const u8) tp.result {
|
||||||
|
const self = a.create(tree_walker) catch |e| return tp.exit_error(e);
|
||||||
|
self.* = tree_walker.init(a, root_path) catch |e| return tp.exit_error(e);
|
||||||
|
const pid = tp.spawn_link(a, self, tree_walker.start, module_name ++ ".tree_walker") catch |e| return tp.exit_error(e);
|
||||||
|
pid.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(a: std.mem.Allocator, root_path: []const u8) error{OutOfMemory}!tree_walker {
|
||||||
|
return .{
|
||||||
|
.a = a,
|
||||||
|
.root_path = try a.dupe(u8, root_path),
|
||||||
|
.parent = tp.self_pid().clone(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(self: *tree_walker) tp.result {
|
||||||
|
self.walk() catch |e| return tp.exit_error(e);
|
||||||
|
return tp.exit_normal();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *tree_walker) void {
|
||||||
|
self.a.free(self.root_path);
|
||||||
|
self.parent.deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn walk(self: *tree_walker) !void {
|
||||||
|
const frame = tracy.initZone(@src(), .{ .name = "project scan" });
|
||||||
|
defer frame.deinit();
|
||||||
|
defer {
|
||||||
|
self.parent.send(.{ "walk_tree_done", self.root_path }) catch {};
|
||||||
|
self.deinit();
|
||||||
|
}
|
||||||
|
var dir = try std.fs.cwd().openDir(self.root_path, .{ .iterate = true });
|
||||||
|
defer dir.close();
|
||||||
|
|
||||||
|
var walker = try walk_filtered(dir, self.a);
|
||||||
|
defer walker.deinit();
|
||||||
|
|
||||||
|
while (try walker.next()) |path|
|
||||||
|
try self.parent.send(.{ "walk_tree_entry", self.root_path, path });
|
||||||
|
}
|
||||||
|
}.spawn_link(a_, root_path_);
|
||||||
|
}
|
||||||
|
|
||||||
|
const filtered_dirs = [_][]const u8{ ".git", ".cache", "zig-out", "zig-cache" };
|
||||||
|
|
||||||
|
fn is_filtered_dir(dirname: []const u8) bool {
|
||||||
|
for (filtered_dirs) |filter|
|
||||||
|
if (std.mem.eql(u8, filter, dirname))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FilteredWalker = struct {
|
||||||
|
stack: std.ArrayList(StackItem),
|
||||||
|
name_buffer: std.ArrayList(u8),
|
||||||
|
|
||||||
|
const Path = []const u8;
|
||||||
|
|
||||||
|
const StackItem = struct {
|
||||||
|
iter: std.fs.Dir.Iterator,
|
||||||
|
dirname_len: usize,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn next(self: *FilteredWalker) error{OutOfMemory}!?Path {
|
||||||
|
while (self.stack.items.len != 0) {
|
||||||
|
var top = &self.stack.items[self.stack.items.len - 1];
|
||||||
|
var containing = top;
|
||||||
|
var dirname_len = top.dirname_len;
|
||||||
|
if (top.iter.next() catch {
|
||||||
|
var item = self.stack.pop();
|
||||||
|
if (self.stack.items.len != 0) {
|
||||||
|
item.iter.dir.close();
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}) |base| {
|
||||||
|
self.name_buffer.shrinkRetainingCapacity(dirname_len);
|
||||||
|
if (self.name_buffer.items.len != 0) {
|
||||||
|
try self.name_buffer.append(std.fs.path.sep);
|
||||||
|
dirname_len += 1;
|
||||||
|
}
|
||||||
|
try self.name_buffer.appendSlice(base.name);
|
||||||
|
switch (base.kind) {
|
||||||
|
.directory => {
|
||||||
|
if (is_filtered_dir(base.name))
|
||||||
|
continue;
|
||||||
|
var new_dir = top.iter.dir.openDir(base.name, .{ .iterate = true }) catch |err| switch (err) {
|
||||||
|
error.NameTooLong => unreachable, // no path sep in base.name
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
{
|
||||||
|
errdefer new_dir.close();
|
||||||
|
try self.stack.append(StackItem{
|
||||||
|
.iter = new_dir.iterateAssumeFirstIteration(),
|
||||||
|
.dirname_len = self.name_buffer.items.len,
|
||||||
|
});
|
||||||
|
top = &self.stack.items[self.stack.items.len - 1];
|
||||||
|
containing = &self.stack.items[self.stack.items.len - 2];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.file => return self.name_buffer.items,
|
||||||
|
else => continue,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var item = self.stack.pop();
|
||||||
|
if (self.stack.items.len != 0) {
|
||||||
|
item.iter.dir.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *FilteredWalker) void {
|
||||||
|
// Close any remaining directories except the initial one (which is always at index 0)
|
||||||
|
if (self.stack.items.len > 1) {
|
||||||
|
for (self.stack.items[1..]) |*item| {
|
||||||
|
item.iter.dir.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.stack.deinit();
|
||||||
|
self.name_buffer.deinit();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn walk_filtered(dir: std.fs.Dir, allocator: std.mem.Allocator) !FilteredWalker {
|
||||||
|
var name_buffer = std.ArrayList(u8).init(allocator);
|
||||||
|
errdefer name_buffer.deinit();
|
||||||
|
|
||||||
|
var stack = std.ArrayList(FilteredWalker.StackItem).init(allocator);
|
||||||
|
errdefer stack.deinit();
|
||||||
|
|
||||||
|
try stack.append(FilteredWalker.StackItem{
|
||||||
|
.iter = dir.iterate(),
|
||||||
|
.dirname_len = 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
return FilteredWalker{
|
||||||
|
.stack = stack,
|
||||||
|
.name_buffer = name_buffer,
|
||||||
|
};
|
||||||
|
}
|
78
src/service_template.zig
Normal file
78
src/service_template.zig
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
const std = @import("std");
|
||||||
|
const tp = @import("thespian");
|
||||||
|
const cbor = @import("cbor");
|
||||||
|
const log = @import("log");
|
||||||
|
|
||||||
|
pid: ?tp.pid,
|
||||||
|
|
||||||
|
const Self = @This();
|
||||||
|
const module_name = @typeName(Self);
|
||||||
|
pub const Error = error{ OutOfMemory, Exit };
|
||||||
|
|
||||||
|
pub fn create(a: std.mem.Allocator) Error!Self {
|
||||||
|
return .{ .pid = try Process.create(a) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_pid(pid: tp.pid_ref) Error!Self {
|
||||||
|
return .{ .pid = pid.clone() };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Self) void {
|
||||||
|
if (self.pid) |pid| {
|
||||||
|
self.pid = null;
|
||||||
|
pid.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn shutdown(self: *Self) void {
|
||||||
|
if (self.pid) |pid| {
|
||||||
|
pid.send(.{"shutdown"}) catch {};
|
||||||
|
self.deinit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub fn send(self: *Self, m: tp.message) tp.result {
|
||||||
|
// const pid = if (self.pid) |pid| pid else return tp.exit_error(error.Shutdown);
|
||||||
|
// try pid.send(m);
|
||||||
|
// }
|
||||||
|
|
||||||
|
const Process = struct {
|
||||||
|
a: std.mem.Allocator,
|
||||||
|
parent: tp.pid,
|
||||||
|
logger: log.Logger,
|
||||||
|
receiver: Receiver,
|
||||||
|
|
||||||
|
const Receiver = tp.Receiver(*Process);
|
||||||
|
|
||||||
|
pub fn create(a: std.mem.Allocator) Error!tp.pid {
|
||||||
|
const self = try a.create(Process);
|
||||||
|
self.* = .{
|
||||||
|
.a = a,
|
||||||
|
.parent = tp.self_pid().clone(),
|
||||||
|
.logger = log.logger(module_name),
|
||||||
|
.receiver = Receiver.init(Process.receive, self),
|
||||||
|
};
|
||||||
|
return tp.spawn_link(self.a, self, Process.start) catch |e| tp.exit_error(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deinit(self: *Process) void {
|
||||||
|
self.parent.deinit();
|
||||||
|
self.a.destroy(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start(self: *Process) tp.result {
|
||||||
|
_ = tp.set_trap(true);
|
||||||
|
tp.receive(&self.receiver);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive(self: *Process, _: tp.pid_ref, m: tp.message) tp.result {
|
||||||
|
errdefer self.deinit();
|
||||||
|
|
||||||
|
if (try m.match(.{"shutdown"})) {
|
||||||
|
return tp.exit_normal();
|
||||||
|
} else {
|
||||||
|
self.logger.err("receive", tp.unexpected(m));
|
||||||
|
return tp.unexpected(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
|
@ -4,6 +4,7 @@ const tp = @import("thespian");
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
const location_history = @import("location_history");
|
const location_history = @import("location_history");
|
||||||
|
const project_manager = @import("project_manager");
|
||||||
|
|
||||||
const tui = @import("tui.zig");
|
const tui = @import("tui.zig");
|
||||||
const command = @import("command.zig");
|
const command = @import("command.zig");
|
||||||
|
@ -31,6 +32,7 @@ last_match_text: ?[]const u8 = null,
|
||||||
logview_enabled: bool = false,
|
logview_enabled: bool = false,
|
||||||
|
|
||||||
location_history: location_history,
|
location_history: location_history,
|
||||||
|
project_manager: project_manager,
|
||||||
|
|
||||||
const NavState = struct {
|
const NavState = struct {
|
||||||
time: i64 = 0,
|
time: i64 = 0,
|
||||||
|
@ -42,6 +44,12 @@ const NavState = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn create(a: std.mem.Allocator, n: nc.Plane) !Widget {
|
pub fn create(a: std.mem.Allocator, n: nc.Plane) !Widget {
|
||||||
|
const project_manager_ = try project_manager.create(a);
|
||||||
|
tp.env.get().proc_set("project", project_manager_.pid.?.ref());
|
||||||
|
var project_name_buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
|
||||||
|
const project_name = std.fs.cwd().realpath(".", &project_name_buf) catch "(none)";
|
||||||
|
tp.env.get().str_set("project", project_name);
|
||||||
|
// try project_manager_.open(project_name);
|
||||||
const self = try a.create(Self);
|
const self = try a.create(Self);
|
||||||
self.* = .{
|
self.* = .{
|
||||||
.a = a,
|
.a = a,
|
||||||
|
@ -51,6 +59,7 @@ pub fn create(a: std.mem.Allocator, n: nc.Plane) !Widget {
|
||||||
.floating_views = WidgetStack.init(a),
|
.floating_views = WidgetStack.init(a),
|
||||||
.statusbar = undefined,
|
.statusbar = undefined,
|
||||||
.location_history = try location_history.create(),
|
.location_history = try location_history.create(),
|
||||||
|
.project_manager = project_manager_,
|
||||||
};
|
};
|
||||||
try self.commands.init(self);
|
try self.commands.init(self);
|
||||||
const w = Widget.to(self);
|
const w = Widget.to(self);
|
||||||
|
|
|
@ -33,7 +33,7 @@ const Self = @This();
|
||||||
pub fn create(a: Allocator, parent: nc.Plane) !Widget {
|
pub fn create(a: Allocator, parent: nc.Plane) !Widget {
|
||||||
const self: *Self = try a.create(Self);
|
const self: *Self = try a.create(Self);
|
||||||
self.* = try init(a, parent);
|
self.* = try init(a, parent);
|
||||||
self.show_cwd();
|
self.show_project();
|
||||||
return Widget.to(self);
|
return Widget.to(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ pub fn receive(self: *Self, _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||||
self.line = 0;
|
self.line = 0;
|
||||||
self.column = 0;
|
self.column = 0;
|
||||||
self.file_exists = true;
|
self.file_exists = true;
|
||||||
self.show_cwd();
|
self.show_project();
|
||||||
}
|
}
|
||||||
if (try m.match(.{ "B", nc.event_type.PRESS, nc.key.BUTTON1, tp.any, tp.any, tp.any, tp.any, tp.any })) {
|
if (try m.match(.{ "B", nc.event_type.PRESS, nc.key.BUTTON1, tp.any, tp.any, tp.any, tp.any, tp.any })) {
|
||||||
self.detailed = !self.detailed;
|
self.detailed = !self.detailed;
|
||||||
|
@ -192,10 +192,12 @@ fn render_file_icon(self: *Self, _: *const Widget.Theme) void {
|
||||||
self.plane.cursor_move_rel(0, 1) catch {};
|
self.plane.cursor_move_rel(0, 1) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn show_cwd(self: *Self) void {
|
fn show_project(self: *Self) void {
|
||||||
self.file_icon = "";
|
self.file_icon = "";
|
||||||
self.file_color = 0x000001;
|
self.file_color = 0x000001;
|
||||||
self.name = std.fs.cwd().realpath(".", &self.name_buf) catch "(none)";
|
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.abbrv_home();
|
self.abbrv_home();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue