feat: restore buffer manager state on restart
This commit is contained in:
parent
1babf86ce4
commit
991c47f3b3
6 changed files with 121 additions and 14 deletions
|
@ -361,6 +361,7 @@ pub fn build_exe(
|
|||
.{ .name = "cbor", .module = cbor_mod },
|
||||
.{ .name = "thespian", .module = thespian_mod },
|
||||
.{ .name = "LetterCasing", .module = zg_dep.module("LetterCasing") },
|
||||
.{ .name = "file_type_config", .module = file_type_config_mod },
|
||||
},
|
||||
});
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const cbor = @import("cbor");
|
||||
const file_type_config = @import("file_type_config");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const ArrayList = std.ArrayList;
|
||||
const cwd = std.fs.cwd;
|
||||
|
@ -1487,3 +1489,58 @@ pub fn redo(self: *Self) error{Stop}![]const u8 {
|
|||
self.mtime = std.time.milliTimestamp();
|
||||
return h.meta;
|
||||
}
|
||||
|
||||
pub fn write_state(self: *const Self, writer: MetaWriter) error{ Stop, OutOfMemory }!void {
|
||||
var content = std.ArrayListUnmanaged(u8).empty;
|
||||
defer content.deinit(self.external_allocator);
|
||||
try self.root.store(content.writer(self.external_allocator), self.file_eol_mode);
|
||||
|
||||
try cbor.writeArrayHeader(writer, 8);
|
||||
try cbor.writeValue(writer, self.get_file_path());
|
||||
try cbor.writeValue(writer, self.file_exists);
|
||||
try cbor.writeValue(writer, self.file_eol_mode);
|
||||
try cbor.writeValue(writer, self.hidden);
|
||||
try cbor.writeValue(writer, self.ephemeral);
|
||||
try cbor.writeValue(writer, self.meta orelse &.{});
|
||||
try cbor.writeValue(writer, self.file_type_name);
|
||||
try cbor.writeValue(writer, content.items);
|
||||
}
|
||||
|
||||
pub const ExtractStateOperation = enum { none, open_file };
|
||||
|
||||
pub fn extract_state(self: *Self, iter: *[]const u8) !void {
|
||||
var file_path: []const u8 = undefined;
|
||||
var file_type_name: []const u8 = undefined;
|
||||
var meta: []const u8 = &.{};
|
||||
var content: []const u8 = undefined;
|
||||
|
||||
if (!try cbor.matchValue(iter, .{
|
||||
cbor.extract(&file_path),
|
||||
cbor.extract(&self.file_exists),
|
||||
cbor.extract(&self.file_eol_mode),
|
||||
cbor.extract(&self.hidden),
|
||||
cbor.extract(&self.ephemeral),
|
||||
cbor.extract(&meta),
|
||||
cbor.extract(&file_type_name),
|
||||
cbor.extract(&content),
|
||||
}))
|
||||
return error.Stop;
|
||||
|
||||
self.set_file_path(file_path);
|
||||
|
||||
if (try file_type_config.get(try self.allocator.dupe(u8, file_type_name))) |config| {
|
||||
self.file_type_name = config.name;
|
||||
self.file_type_icon = config.icon;
|
||||
self.file_type_color = config.color;
|
||||
} else {
|
||||
self.file_type_name = file_type_config.default.name;
|
||||
self.file_type_icon = file_type_config.default.icon;
|
||||
self.file_type_color = file_type_config.default.color;
|
||||
}
|
||||
|
||||
if (meta.len > 0) {
|
||||
if (self.meta) |buf| self.external_allocator.free(buf);
|
||||
self.meta = if (self.meta) |buf| try self.external_allocator.dupe(u8, buf) else null;
|
||||
}
|
||||
try self.reset_from_string_and_update(content);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const tp = @import("thespian");
|
||||
const Buffer = @import("Buffer.zig");
|
||||
|
||||
|
@ -51,6 +52,34 @@ pub fn open_scratch(self: *Self, file_path: []const u8, content: []const u8) Buf
|
|||
return buffer;
|
||||
}
|
||||
|
||||
pub fn write_state(self: *const Self, writer: Buffer.MetaWriter) error{ Stop, OutOfMemory }!void {
|
||||
const buffers = self.list_unordered(self.allocator) catch return;
|
||||
defer self.allocator.free(buffers);
|
||||
try cbor.writeArrayHeader(writer, buffers.len);
|
||||
for (buffers) |buffer| {
|
||||
tp.trace(tp.channel.debug, .{ @typeName(Self), "write_state", buffer.get_file_path(), buffer.file_type_name });
|
||||
buffer.write_state(writer) catch |e| {
|
||||
tp.trace(tp.channel.debug, .{ @typeName(Self), "write_state", "failed", e });
|
||||
return;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extract_state(self: *Self, iter: *[]const u8) !void {
|
||||
var len = try cbor.decodeArrayHeader(iter);
|
||||
tp.trace(tp.channel.debug, .{ @typeName(Self), "extract_state", len });
|
||||
while (len > 0) : (len -= 1) {
|
||||
var buffer = try Buffer.create(self.allocator);
|
||||
errdefer |e| {
|
||||
tp.trace(tp.channel.debug, .{ "buffer", "extract", "failed", buffer.get_file_path(), e });
|
||||
buffer.deinit();
|
||||
}
|
||||
try buffer.extract_state(iter);
|
||||
try self.buffers.put(self.allocator, try self.allocator.dupe(u8, buffer.get_file_path()), buffer);
|
||||
tp.trace(tp.channel.debug, .{ "buffer", "extract", buffer.get_file_path(), buffer.file_type_name });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_buffer_for_file(self: *Self, file_path: []const u8) ?*Buffer {
|
||||
return self.buffers.get(file_path);
|
||||
}
|
||||
|
@ -89,7 +118,7 @@ pub fn list_most_recently_used(self: *Self, allocator: std.mem.Allocator) error{
|
|||
return result;
|
||||
}
|
||||
|
||||
pub fn list_unordered(self: *Self, allocator: std.mem.Allocator) error{OutOfMemory}![]*Buffer {
|
||||
pub fn list_unordered(self: *const Self, allocator: std.mem.Allocator) error{OutOfMemory}![]*Buffer {
|
||||
var buffers = try std.ArrayListUnmanaged(*Buffer).initCapacity(allocator, self.buffers.size);
|
||||
var i = self.buffers.iterator();
|
||||
while (i.next()) |kv|
|
||||
|
|
|
@ -942,7 +942,7 @@ pub fn get_restore_file_name() ![]const u8 {
|
|||
const restore_file = if (local.restore_file) |file|
|
||||
file
|
||||
else
|
||||
try std.fmt.bufPrint(&local.restore_file_buffer, "{s}/{s}", .{ try get_app_cache_dir(application_name), restore_file_name });
|
||||
try std.fmt.bufPrint(&local.restore_file_buffer, "{s}/{s}", .{ try get_app_state_dir(application_name), restore_file_name });
|
||||
local.restore_file = restore_file;
|
||||
return restore_file;
|
||||
}
|
||||
|
|
|
@ -371,6 +371,14 @@ pub const Editor = struct {
|
|||
const Meta = command.Metadata;
|
||||
const Result = command.Result;
|
||||
|
||||
pub fn update_meta(self: *const Self) void {
|
||||
var meta = std.ArrayListUnmanaged(u8).empty;
|
||||
defer meta.deinit(self.allocator);
|
||||
if (self.buffer) |_| self.write_state(meta.writer(self.allocator)) catch {};
|
||||
if (self.buffer) |_| self.write_state(meta.writer(self.allocator)) catch {};
|
||||
if (self.buffer) |p| p.set_meta(meta.items) catch {};
|
||||
}
|
||||
|
||||
pub fn write_state(self: *const Self, writer: Buffer.MetaWriter) !void {
|
||||
try cbor.writeArrayHeader(writer, 12);
|
||||
try cbor.writeValue(writer, self.file_path orelse "");
|
||||
|
@ -401,9 +409,7 @@ pub const Editor = struct {
|
|||
};
|
||||
}
|
||||
|
||||
pub fn extract_state(self: *Self, buf: []const u8, comptime op: enum { none, open_file }) !void {
|
||||
tp.trace(tp.channel.debug, .{ "extract_state", self.file_path });
|
||||
tp.trace(tp.channel.debug, tp.message{ .buf = buf });
|
||||
pub fn extract_state(self: *Self, iter: *[]const u8, comptime op: Buffer.ExtractStateOperation) !void {
|
||||
self.restored_state = true;
|
||||
var file_path: []const u8 = undefined;
|
||||
var view_cbor: []const u8 = undefined;
|
||||
|
@ -411,7 +417,7 @@ pub const Editor = struct {
|
|||
var clipboard: []const u8 = undefined;
|
||||
var last_find_query: []const u8 = undefined;
|
||||
var find_history: []const u8 = undefined;
|
||||
if (!try cbor.match(buf, .{
|
||||
if (!try cbor.matchValue(iter, .{
|
||||
tp.extract(&file_path),
|
||||
tp.extract(&clipboard),
|
||||
tp.extract(&last_find_query),
|
||||
|
@ -440,11 +446,11 @@ pub const Editor = struct {
|
|||
|
||||
if (cursels_cbor.len > 0)
|
||||
self.clear_all_cursors();
|
||||
var iter = cursels_cbor;
|
||||
var len = cbor.decodeArrayHeader(&iter) catch return error.RestoreCurSels;
|
||||
var cursels_iter = cursels_cbor;
|
||||
var len = cbor.decodeArrayHeader(&cursels_iter) catch return error.RestoreCurSels;
|
||||
while (len > 0) : (len -= 1) {
|
||||
var cursel: CurSel = .{};
|
||||
if (!(cursel.extract(&iter) catch false)) break;
|
||||
if (!(cursel.extract(&cursels_iter) catch false)) break;
|
||||
(try self.cursels.addOne(self.allocator)).* = cursel;
|
||||
}
|
||||
|
||||
|
@ -659,7 +665,8 @@ pub const Editor = struct {
|
|||
if (buffer_meta) |meta| {
|
||||
const frame_ = tracy.initZone(@src(), .{ .name = "extract_state" });
|
||||
defer frame_.deinit();
|
||||
try self.extract_state(meta, .none);
|
||||
var iter = meta;
|
||||
try self.extract_state(&iter, .none);
|
||||
}
|
||||
try self.send_editor_open(file_path, new_buf.file_exists, ftn, fti, ftc);
|
||||
}
|
||||
|
|
|
@ -1288,11 +1288,18 @@ fn create_home_split(self: *Self) !void {
|
|||
}
|
||||
|
||||
pub fn write_restore_info(self: *Self) void {
|
||||
const editor = self.get_active_editor() orelse return;
|
||||
var sfa = std.heap.stackFallback(512, self.allocator);
|
||||
const a = sfa.get();
|
||||
var meta = std.ArrayListUnmanaged(u8).empty;
|
||||
editor.write_state(meta.writer(a)) catch return;
|
||||
const writer = meta.writer(a);
|
||||
|
||||
const editor = self.get_active_editor() orelse return;
|
||||
cbor.writeValue(writer, editor.file_path) catch return;
|
||||
editor.update_meta();
|
||||
|
||||
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
|
||||
buffer_manager.write_state(writer) catch return;
|
||||
|
||||
const file_name = root.get_restore_file_name() catch return;
|
||||
var file = std.fs.createFileAbsolute(file_name, .{ .truncate = true }) catch return;
|
||||
defer file.close();
|
||||
|
@ -1300,7 +1307,6 @@ pub fn write_restore_info(self: *Self) void {
|
|||
}
|
||||
|
||||
fn read_restore_info(self: *Self) !void {
|
||||
const editor = self.get_active_editor() orelse return;
|
||||
const file_name = try root.get_restore_file_name();
|
||||
const file = try std.fs.cwd().openFile(file_name, .{ .mode = .read_only });
|
||||
defer file.close();
|
||||
|
@ -1308,7 +1314,14 @@ fn read_restore_info(self: *Self) !void {
|
|||
var buf = try self.allocator.alloc(u8, @intCast(stat.size));
|
||||
defer self.allocator.free(buf);
|
||||
const size = try file.readAll(buf);
|
||||
try editor.extract_state(buf[0..size], .open_file);
|
||||
var iter: []const u8 = buf[0..size];
|
||||
|
||||
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;
|
||||
try self.buffer_manager.extract_state(&iter);
|
||||
|
||||
try tp.self_pid().send(.{ "cmd", "navigate", .{ .file = editor_file_path } });
|
||||
}
|
||||
|
||||
fn get_next_mru_buffer(self: *Self) ?[]const u8 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue