Compare commits
6 commits
690498fdcc
...
e134cfc949
| Author | SHA1 | Date | |
|---|---|---|---|
| e134cfc949 | |||
| 2ca1a742a1 | |||
| 741096cb43 | |||
| c8840f0756 | |||
| 20129ea773 | |||
| bbeba10fe5 |
5 changed files with 121 additions and 53 deletions
|
|
@ -114,6 +114,7 @@ pub const WhitespaceMode = enum {
|
||||||
leading,
|
leading,
|
||||||
eol,
|
eol,
|
||||||
tabs,
|
tabs,
|
||||||
|
external,
|
||||||
visible,
|
visible,
|
||||||
full,
|
full,
|
||||||
none,
|
none,
|
||||||
|
|
|
||||||
|
|
@ -58,17 +58,36 @@ pub fn shutdown() void {
|
||||||
pid.send(.{"shutdown"}) catch {};
|
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;
|
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 project_directory = std.fs.cwd().realpath(rel_project_directory, &path_buf) catch "(none)";
|
||||||
const current_project = tp.env.get().str("project");
|
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;
|
if (!root.is_directory(project_directory)) return error.InvalidProjectDirectory;
|
||||||
var dir = try std.fs.openDirAbsolute(project_directory, .{});
|
var dir = try std.fs.openDirAbsolute(project_directory, .{});
|
||||||
try dir.setAsCwd();
|
try dir.setAsCwd();
|
||||||
dir.close();
|
dir.close();
|
||||||
tp.env.get().str_set("project", project_directory);
|
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 {
|
pub fn close(project_directory: []const u8) (ProjectManagerError || error{CloseCurrentProject})!void {
|
||||||
|
|
|
||||||
|
|
@ -1562,6 +1562,18 @@ pub const Editor = struct {
|
||||||
cell.cell.char.grapheme = c;
|
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 => {
|
.visible => {
|
||||||
if (get_whitespace_char(cell_type, next_cell_type)) |c|
|
if (get_whitespace_char(cell_type, next_cell_type)) |c|
|
||||||
cell.cell.char.grapheme = c;
|
cell.cell.char.grapheme = c;
|
||||||
|
|
@ -1573,7 +1585,7 @@ pub const Editor = struct {
|
||||||
else => "#",
|
else => "#",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
else => {},
|
.none => {},
|
||||||
}
|
}
|
||||||
if (tab_error) {
|
if (tab_error) {
|
||||||
cell.set_style_fg(theme.editor_error);
|
cell.set_style_fg(theme.editor_error);
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,8 @@ const cmds = struct {
|
||||||
pub const quit_without_saving_meta: Meta = .{ .description = "Quit without saving" };
|
pub const quit_without_saving_meta: Meta = .{ .description = "Quit without saving" };
|
||||||
|
|
||||||
pub fn open_project_cwd(self: *Self, _: Ctx) Result {
|
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.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||||
if (self.bottom_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;
|
var project_dir: []const u8 = undefined;
|
||||||
if (!try ctx.args.match(.{tp.extract(&project_dir)}))
|
if (!try ctx.args.match(.{tp.extract(&project_dir)}))
|
||||||
return;
|
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");
|
const project = tp.env.get().str("project");
|
||||||
tui.rdr().set_terminal_working_directory(project);
|
tui.rdr().set_terminal_working_directory(project);
|
||||||
if (self.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
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)}))
|
if (!try ctx.args.match(.{tp.extract(&project_dir)}))
|
||||||
return;
|
return;
|
||||||
try self.check_all_not_dirty();
|
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();
|
try self.close_all_editors();
|
||||||
self.delete_all_buffers();
|
self.delete_all_buffers();
|
||||||
self.clear_find_in_files_results(.diagnostics);
|
self.clear_find_in_files_results(.diagnostics);
|
||||||
|
|
@ -402,10 +417,14 @@ const cmds = struct {
|
||||||
try self.toggle_panel_view(filelist_view, false);
|
try self.toggle_panel_view(filelist_view, false);
|
||||||
self.buffer_manager.deinit();
|
self.buffer_manager.deinit();
|
||||||
self.buffer_manager = Buffer.Manager.init(self.allocator);
|
self.buffer_manager = Buffer.Manager.init(self.allocator);
|
||||||
|
|
||||||
const project = tp.env.get().str("project");
|
const project = tp.env.get().str("project");
|
||||||
tui.rdr().set_terminal_working_directory(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.top_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||||
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
if (self.bottom_bar) |bar| _ = try bar.msg(.{ "PRJ", "open" });
|
||||||
|
if (project_state == null)
|
||||||
tp.self_pid().send(.{ "cmd", "open_recent" }) catch return;
|
tp.self_pid().send(.{ "cmd", "open_recent" }) catch return;
|
||||||
}
|
}
|
||||||
pub const change_project_meta: Meta = .{ .arguments = &.{.string} };
|
pub const change_project_meta: Meta = .{ .arguments = &.{.string} };
|
||||||
|
|
@ -1599,42 +1618,49 @@ fn create_home_split(self: *Self) !void {
|
||||||
tui.resize();
|
tui.resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_restore_info(self: *Self) void {
|
pub const WriteStateError = error{
|
||||||
var sfa = std.heap.stackFallback(512, self.allocator);
|
OutOfMemory,
|
||||||
const a = sfa.get();
|
Stop,
|
||||||
var meta: std.Io.Writer.Allocating = .init(a);
|
WriteFailed,
|
||||||
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 fn write_restore_info(self: *Self) WriteStateError!void {
|
||||||
const file_name = root.get_restore_file_name() catch return;
|
const file_name = root.get_restore_file_name() catch return;
|
||||||
var file = std.fs.createFileAbsolute(file_name, .{ .truncate = true }) catch return;
|
var file = std.fs.createFileAbsolute(file_name, .{ .truncate = true }) catch return;
|
||||||
defer file.close();
|
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 {
|
fn read_restore_info(self: *Self) !void {
|
||||||
|
|
@ -1647,31 +1673,40 @@ fn read_restore_info(self: *Self) !void {
|
||||||
const size = try file.readAll(buf);
|
const size = try file.readAll(buf);
|
||||||
var iter: []const u8 = buf[0..size];
|
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" });
|
tp.trace(tp.channel.debug, .{ "mainview", "extract" });
|
||||||
var editor_file_path: ?[]const u8 = undefined;
|
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();
|
tui.clipboard_clear_all();
|
||||||
var len = try cbor.decodeArrayHeader(&iter);
|
var len = try cbor.decodeArrayHeader(iter);
|
||||||
var prev_group: usize = 0;
|
var prev_group: usize = 0;
|
||||||
const clipboard_allocator = tui.clipboard_allocator();
|
const clipboard_allocator = tui.clipboard_allocator();
|
||||||
while (len > 0) : (len -= 1) {
|
while (len > 0) : (len -= 1) {
|
||||||
const len_ = try cbor.decodeArrayHeader(&iter);
|
const len_ = try cbor.decodeArrayHeader(iter);
|
||||||
if (len_ != 2) return error.Stop;
|
if (len_ != 2) return error.MatchClipboardArrayFailed;
|
||||||
var group: usize = 0;
|
var group: usize = 0;
|
||||||
var text: []const u8 = undefined;
|
var text: []const u8 = undefined;
|
||||||
if (!try cbor.matchValue(&iter, cbor.extract(&group))) return error.Stop;
|
if (!try cbor.matchValue(iter, cbor.extract(&group))) return error.MatchClipboardGroupFailed;
|
||||||
if (!try cbor.matchValue(&iter, cbor.extract(&text))) return error.Stop;
|
if (!try cbor.matchValue(iter, cbor.extract(&text))) return error.MatchClipboardTextFailed;
|
||||||
if (prev_group != group) tui.clipboard_start_group();
|
if (prev_group != group) tui.clipboard_start_group();
|
||||||
prev_group = group;
|
prev_group = group;
|
||||||
tui.clipboard_add_chunk(try clipboard_allocator.dupe(u8, text));
|
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 (self.widgets.get("tabs")) |tabs_widget|
|
||||||
if (tabs_widget.dynamic_cast(@import("status/tabs.zig").TabBar)) |tabs|
|
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");
|
const logger = log.logger("mainview");
|
||||||
defer logger.deinit();
|
defer logger.deinit();
|
||||||
logger.print_err("mainview", "failed to restore tabs: {}", .{e});
|
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 {};
|
send_buffer_did_open(self.allocator, buffer) catch {};
|
||||||
|
|
||||||
if (editor_file_path) |file_path| {
|
if (editor_file_path) |file_path| {
|
||||||
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } });
|
if (self.buffer_manager.get_buffer_for_file(file_path)) |_|
|
||||||
} else {
|
return tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } });
|
||||||
try tp.self_pid().send(.{ "cmd", "close_file" });
|
|
||||||
}
|
}
|
||||||
|
try tp.self_pid().send(.{ "cmd", "close_file" });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_buffer_did_open(allocator: std.mem.Allocator, buffer: *Buffer) !void {
|
fn send_buffer_did_open(allocator: std.mem.Allocator, buffer: *Buffer) !void {
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,7 @@ fn receive_safe(self: *Self, from: tp.pid_ref, m: tp.message) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (try m.match(.{"restart"})) {
|
if (try m.match(.{"restart"})) {
|
||||||
if (mainview()) |mv| mv.write_restore_info();
|
if (mainview()) |mv| try mv.write_restore_info();
|
||||||
project_manager.shutdown();
|
project_manager.shutdown();
|
||||||
self.final_exit = "restart";
|
self.final_exit = "restart";
|
||||||
return;
|
return;
|
||||||
|
|
@ -1002,7 +1002,8 @@ const cmds = struct {
|
||||||
.indent => .leading,
|
.indent => .leading,
|
||||||
.leading => .eol,
|
.leading => .eol,
|
||||||
.eol => .tabs,
|
.eol => .tabs,
|
||||||
.tabs => .visible,
|
.tabs => .external,
|
||||||
|
.external => .visible,
|
||||||
.visible => .full,
|
.visible => .full,
|
||||||
.full => .none,
|
.full => .none,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue