Compare commits

...

6 commits

5 changed files with 121 additions and 53 deletions

View file

@ -114,6 +114,7 @@ pub const WhitespaceMode = enum {
leading,
eol,
tabs,
external,
visible,
full,
none,

View file

@ -58,17 +58,36 @@ pub fn shutdown() void {
pid.send(.{"shutdown"}) catch {};
}
pub fn open(rel_project_directory: []const u8) (ProjectManagerError || FileSystemError || std.fs.File.OpenError || SetCwdError)!void {
pub fn open(rel_project_directory: []const u8) (ProjectManagerError || FileSystemError || std.fs.File.OpenError || SetCwdError)!?[]const u8 {
var path_buf: [std.fs.max_path_bytes]u8 = undefined;
const project_directory = std.fs.cwd().realpath(rel_project_directory, &path_buf) catch "(none)";
const current_project = tp.env.get().str("project");
if (std.mem.eql(u8, current_project, project_directory)) return;
if (std.mem.eql(u8, current_project, project_directory)) return get_project_state(project_directory);
if (!root.is_directory(project_directory)) return error.InvalidProjectDirectory;
var dir = try std.fs.openDirAbsolute(project_directory, .{});
try dir.setAsCwd();
dir.close();
tp.env.get().str_set("project", project_directory);
return send(.{ "open", project_directory });
try send(.{ "open", project_directory });
return get_project_state(project_directory);
}
const project_state_allocator = std.heap.c_allocator;
var project_state_mutex: std.Thread.Mutex = .{};
var project_state: ProjectStateMap = .empty;
const ProjectStateMap = std.StringHashMapUnmanaged(std.array_list.Managed(u8));
fn get_project_state(project_directory: []const u8) ?[]const u8 {
project_state_mutex.lock();
defer project_state_mutex.unlock();
return if (project_state.get(project_directory)) |state| state.items else null;
}
pub fn store_state(project_directory: []const u8, state: std.array_list.Managed(u8)) error{OutOfMemory}!void {
project_state_mutex.lock();
defer project_state_mutex.unlock();
if (project_state.fetchRemove(project_directory)) |old_state| old_state.value.deinit();
try project_state.put(project_state_allocator, try project_state_allocator.dupe(u8, project_directory), state);
}
pub fn close(project_directory: []const u8) (ProjectManagerError || error{CloseCurrentProject})!void {

View file

@ -1562,6 +1562,18 @@ pub const Editor = struct {
cell.cell.char.grapheme = c;
}
},
.external => {
if (leading) {
if (get_whitespace_char(cell_type, next_cell_type)) |c|
cell.cell.char.grapheme = c;
}
if (cell_type == .eol)
cell.cell.char.grapheme = char.eol;
if (cell_type == .tab or cell_type == .extension) {
if (get_whitespace_char(cell_type, next_cell_type)) |c|
cell.cell.char.grapheme = c;
}
},
.visible => {
if (get_whitespace_char(cell_type, next_cell_type)) |c|
cell.cell.char.grapheme = c;
@ -1573,7 +1585,7 @@ pub const Editor = struct {
else => "#",
};
},
else => {},
.none => {},
}
if (tab_error) {
cell.set_style_fg(theme.editor_error);

View file

@ -356,7 +356,8 @@ const cmds = struct {
pub const quit_without_saving_meta: Meta = .{ .description = "Quit without saving" };
pub fn open_project_cwd(self: *Self, _: Ctx) Result {
try project_manager.open(".");
if (try project_manager.open(".")) |state|
try self.restore_state(state);
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
}
@ -366,7 +367,8 @@ const cmds = struct {
var project_dir: []const u8 = undefined;
if (!try ctx.args.match(.{tp.extract(&project_dir)}))
return;
try project_manager.open(project_dir);
if (try project_manager.open(project_dir)) |state|
try self.restore_state(state);
const project = tp.env.get().str("project");
tui.rdr().set_terminal_working_directory(project);
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
@ -394,7 +396,20 @@ const cmds = struct {
if (!try ctx.args.match(.{tp.extract(&project_dir)}))
return;
try self.check_all_not_dirty();
try project_manager.open(project_dir);
{
var state_writer: std.Io.Writer.Allocating = .init(self.allocator);
defer state_writer.deinit();
try self.write_state(&state_writer.writer);
try state_writer.writer.flush();
const old_project = tp.env.get().str("project");
var state_al = state_writer.toArrayList();
const state = state_al.toManaged(self.allocator);
try project_manager.store_state(old_project, state);
}
const project_state = try project_manager.open(project_dir);
try self.close_all_editors();
self.delete_all_buffers();
self.clear_find_in_files_results(.diagnostics);
@ -402,11 +417,15 @@ const cmds = struct {
try self.toggle_panel_view(filelist_view, false);
self.buffer_manager.deinit();
self.buffer_manager = Buffer.Manager.init(self.allocator);
const project = tp.env.get().str("project");
tui.rdr().set_terminal_working_directory(project);
if (project_state) |state| try self.restore_state(state);
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
tp.self_pid().send(.{ "cmd", "open_recent" }) catch return;
if (project_state == null)
tp.self_pid().send(.{ "cmd", "open_recent" }) catch return;
}
pub const change_project_meta: Meta = .{ .arguments = &.{.string} };
@ -1599,42 +1618,49 @@ fn create_home_split(self: *Self) !void {
tui.resize();
}
pub fn write_restore_info(self: *Self) void {
var sfa = std.heap.stackFallback(512, self.allocator);
const a = sfa.get();
var meta: std.Io.Writer.Allocating = .init(a);
defer meta.deinit();
const writer = &meta.writer;
if (self.get_active_editor()) |editor| {
cbor.writeValue(writer, editor.file_path) catch return;
editor.update_meta();
} else {
cbor.writeValue(writer, null) catch return;
}
if (tui.clipboard_get_history()) |clipboard| {
cbor.writeArrayHeader(writer, clipboard.len) catch return;
for (clipboard) |item| {
cbor.writeArrayHeader(writer, 2) catch return;
cbor.writeValue(writer, item.group) catch return;
cbor.writeValue(writer, item.text) catch return;
}
} else {
cbor.writeValue(writer, null) catch return;
}
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
buffer_manager.write_state(writer) catch return;
if (self.widgets.get("tabs")) |tabs_widget|
if (tabs_widget.dynamic_cast(@import("status/tabs.zig").TabBar)) |tabs|
tabs.write_state(writer) catch return;
pub const WriteStateError = error{
OutOfMemory,
Stop,
WriteFailed,
};
pub fn write_restore_info(self: *Self) WriteStateError!void {
const file_name = root.get_restore_file_name() catch return;
var file = std.fs.createFileAbsolute(file_name, .{ .truncate = true }) catch return;
defer file.close();
file.writeAll(meta.written()) catch return;
var buf: [32 + 1024]u8 = undefined;
var file_writer = file.writer(&buf);
const writer = &file_writer.interface;
try self.write_state(writer);
try writer.flush();
}
pub fn write_state(self: *Self, writer: *std.Io.Writer) WriteStateError!void {
if (self.get_active_editor()) |editor| {
try cbor.writeValue(writer, editor.file_path);
editor.update_meta();
} else {
try cbor.writeValue(writer, null);
}
if (tui.clipboard_get_history()) |clipboard| {
try cbor.writeArrayHeader(writer, clipboard.len);
for (clipboard) |item| {
try cbor.writeArrayHeader(writer, 2);
try cbor.writeValue(writer, item.group);
try cbor.writeValue(writer, item.text);
}
} else {
try cbor.writeValue(writer, null);
}
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
try buffer_manager.write_state(writer);
if (self.widgets.get("tabs")) |tabs_widget|
if (tabs_widget.dynamic_cast(@import("status/tabs.zig").TabBar)) |tabs|
try tabs.write_state(writer);
}
fn read_restore_info(self: *Self) !void {
@ -1647,31 +1673,40 @@ fn read_restore_info(self: *Self) !void {
const size = try file.readAll(buf);
var iter: []const u8 = buf[0..size];
try self.extract_state(&iter);
}
fn restore_state(self: *Self, state: []const u8) !void {
var iter = state;
try self.extract_state(&iter);
}
fn extract_state(self: *Self, iter: *[]const u8) !void {
tp.trace(tp.channel.debug, .{ "mainview", "extract" });
var editor_file_path: ?[]const u8 = undefined;
if (!try cbor.matchValue(&iter, cbor.extract(&editor_file_path))) return error.Stop;
if (!try cbor.matchValue(iter, cbor.extract(&editor_file_path))) return error.MatchFilePathFailed;
tui.clipboard_clear_all();
var len = try cbor.decodeArrayHeader(&iter);
var len = try cbor.decodeArrayHeader(iter);
var prev_group: usize = 0;
const clipboard_allocator = tui.clipboard_allocator();
while (len > 0) : (len -= 1) {
const len_ = try cbor.decodeArrayHeader(&iter);
if (len_ != 2) return error.Stop;
const len_ = try cbor.decodeArrayHeader(iter);
if (len_ != 2) return error.MatchClipboardArrayFailed;
var group: usize = 0;
var text: []const u8 = undefined;
if (!try cbor.matchValue(&iter, cbor.extract(&group))) return error.Stop;
if (!try cbor.matchValue(&iter, cbor.extract(&text))) return error.Stop;
if (!try cbor.matchValue(iter, cbor.extract(&group))) return error.MatchClipboardGroupFailed;
if (!try cbor.matchValue(iter, cbor.extract(&text))) return error.MatchClipboardTextFailed;
if (prev_group != group) tui.clipboard_start_group();
prev_group = group;
tui.clipboard_add_chunk(try clipboard_allocator.dupe(u8, text));
}
try self.buffer_manager.extract_state(&iter);
try self.buffer_manager.extract_state(iter);
if (self.widgets.get("tabs")) |tabs_widget|
if (tabs_widget.dynamic_cast(@import("status/tabs.zig").TabBar)) |tabs|
tabs.extract_state(&iter) catch |e| {
tabs.extract_state(iter) catch |e| {
const logger = log.logger("mainview");
defer logger.deinit();
logger.print_err("mainview", "failed to restore tabs: {}", .{e});
@ -1683,10 +1718,10 @@ fn read_restore_info(self: *Self) !void {
send_buffer_did_open(self.allocator, buffer) catch {};
if (editor_file_path) |file_path| {
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } });
} else {
try tp.self_pid().send(.{ "cmd", "close_file" });
if (self.buffer_manager.get_buffer_for_file(file_path)) |_|
return tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } });
}
try tp.self_pid().send(.{ "cmd", "close_file" });
}
fn send_buffer_did_open(allocator: std.mem.Allocator, buffer: *Buffer) !void {

View file

@ -397,7 +397,7 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
}
if (try m.match(.{"restart"})) {
if (mainview()) |mv| mv.write_restore_info();
if (mainview()) |mv| try mv.write_restore_info();
project_manager.shutdown();
self.final_exit = "restart";
return;
@ -1002,7 +1002,8 @@ const cmds = struct {
.indent => .leading,
.leading => .eol,
.eol => .tabs,
.tabs => .visible,
.tabs => .external,
.external => .visible,
.visible => .full,
.full => .none,
};