feat(buffers): save/restore full editor state on buffer switch
This commit is contained in:
parent
b45b5910ee
commit
e6e0301a78
3 changed files with 51 additions and 17 deletions
|
@ -65,6 +65,7 @@ pub fn delete_buffer(self: *Self, file_path: []const u8) bool {
|
||||||
pub fn retire(_: *Self, buffer: *Buffer, meta: ?[]const u8) void {
|
pub fn retire(_: *Self, buffer: *Buffer, meta: ?[]const u8) void {
|
||||||
if (meta) |buf| buffer.set_meta(buf) catch {};
|
if (meta) |buf| buffer.set_meta(buf) catch {};
|
||||||
tp.trace(tp.channel.debug, .{ "buffer", "retire", buffer.file_path, "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
|
tp.trace(tp.channel.debug, .{ "buffer", "retire", buffer.file_path, "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
|
||||||
|
if (meta) |buf| tp.trace(tp.channel.debug, tp.message{ .buf = buf });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_buffer(self: *Self, buffer: *Buffer) void {
|
pub fn close_buffer(self: *Self, buffer: *Buffer) void {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
const cbor = @import("cbor");
|
||||||
|
|
||||||
const Buffer = @import("Buffer.zig");
|
const Buffer = @import("Buffer.zig");
|
||||||
const Cursor = @import("Cursor.zig");
|
const Cursor = @import("Cursor.zig");
|
||||||
|
|
||||||
|
@ -44,13 +46,19 @@ pub fn normalize(self: *Self) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(self: *const Self, writer: Buffer.MetaWriter) !void {
|
pub fn write(self: *const Self, writer: Buffer.MetaWriter) !void {
|
||||||
|
try cbor.writeArrayHeader(writer, 2);
|
||||||
try self.begin.write(writer);
|
try self.begin.write(writer);
|
||||||
try self.end.write(writer);
|
try self.end.write(writer);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract(self: *Self, iter: *[]const u8) !bool {
|
pub fn extract(self: *Self, iter: *[]const u8) !bool {
|
||||||
if (!try self.begin.extract(iter)) return false;
|
var iter2 = iter.*;
|
||||||
return self.end.extract(iter);
|
const len = cbor.decodeArrayHeader(&iter2) catch return false;
|
||||||
|
if (len != 2) return false;
|
||||||
|
if (!try self.begin.extract(&iter2)) return false;
|
||||||
|
if (!try self.end.extract(&iter2)) return false;
|
||||||
|
iter.* = iter2;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nudge_insert(self: *Self, nudge: Self) void {
|
pub fn nudge_insert(self: *Self, nudge: Self) void {
|
||||||
|
|
|
@ -181,6 +181,7 @@ pub const CurSel = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write(self: *const Self, writer: Buffer.MetaWriter) !void {
|
fn write(self: *const Self, writer: Buffer.MetaWriter) !void {
|
||||||
|
try cbor.writeArrayHeader(writer, 2);
|
||||||
try self.cursor.write(writer);
|
try self.cursor.write(writer);
|
||||||
if (self.selection) |sel| {
|
if (self.selection) |sel| {
|
||||||
try sel.write(writer);
|
try sel.write(writer);
|
||||||
|
@ -190,15 +191,21 @@ pub const CurSel = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract(self: *Self, iter: *[]const u8) !bool {
|
fn extract(self: *Self, iter: *[]const u8) !bool {
|
||||||
if (!try self.cursor.extract(iter)) return false;
|
|
||||||
var iter2 = iter.*;
|
var iter2 = iter.*;
|
||||||
if (try cbor.matchValue(&iter2, cbor.null_)) {
|
const len = cbor.decodeArrayHeader(&iter2) catch return false;
|
||||||
iter.* = iter2;
|
if (len != 2) return false;
|
||||||
|
if (!try self.cursor.extract(&iter2)) return false;
|
||||||
|
var iter3 = iter2;
|
||||||
|
if (try cbor.matchValue(&iter3, cbor.null_)) {
|
||||||
|
iter2 = iter3;
|
||||||
} else {
|
} else {
|
||||||
|
iter3 = iter2;
|
||||||
var sel: Selection = .{};
|
var sel: Selection = .{};
|
||||||
if (!try sel.extract(iter)) return false;
|
if (!try sel.extract(&iter3)) return false;
|
||||||
self.selection = sel;
|
self.selection = sel;
|
||||||
|
iter2 = iter3;
|
||||||
}
|
}
|
||||||
|
iter.* = iter2;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,13 +371,23 @@ pub const Editor = struct {
|
||||||
try cbor.writeArrayHeader(writer, 0);
|
try cbor.writeArrayHeader(writer, 0);
|
||||||
}
|
}
|
||||||
try self.view.write(writer);
|
try self.view.write(writer);
|
||||||
try self.get_primary().cursor.write(writer);
|
|
||||||
|
var count_cursels: usize = 0;
|
||||||
|
for (self.cursels.items) |*cursel_| if (cursel_.*) |_| {
|
||||||
|
count_cursels += 1;
|
||||||
|
};
|
||||||
|
try cbor.writeArrayHeader(writer, count_cursels);
|
||||||
|
for (self.cursels.items) |*cursel_| if (cursel_.*) |*cursel| {
|
||||||
|
try cursel.write(writer);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_state(self: *Self, buf: []const u8, comptime op: enum { none, open_file }) !void {
|
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 });
|
||||||
var file_path: []const u8 = undefined;
|
var file_path: []const u8 = undefined;
|
||||||
var view_cbor: []const u8 = undefined;
|
var view_cbor: []const u8 = undefined;
|
||||||
var primary_cbor: []const u8 = undefined;
|
var cursels_cbor: []const u8 = undefined;
|
||||||
var clipboard: []const u8 = undefined;
|
var clipboard: []const u8 = undefined;
|
||||||
var query: []const u8 = undefined;
|
var query: []const u8 = undefined;
|
||||||
var find_history: []const u8 = undefined;
|
var find_history: []const u8 = undefined;
|
||||||
|
@ -380,7 +397,7 @@ pub const Editor = struct {
|
||||||
tp.extract(&query),
|
tp.extract(&query),
|
||||||
tp.extract_cbor(&find_history),
|
tp.extract_cbor(&find_history),
|
||||||
tp.extract_cbor(&view_cbor),
|
tp.extract_cbor(&view_cbor),
|
||||||
tp.extract_cbor(&primary_cbor),
|
tp.extract_cbor(&cursels_cbor),
|
||||||
}))
|
}))
|
||||||
return error.RestoreStateMatch;
|
return error.RestoreStateMatch;
|
||||||
if (op == .open_file)
|
if (op == .open_file)
|
||||||
|
@ -390,13 +407,22 @@ pub const Editor = struct {
|
||||||
if (!try self.view.extract(&view_cbor))
|
if (!try self.view.extract(&view_cbor))
|
||||||
return error.RestoreView;
|
return error.RestoreView;
|
||||||
self.scroll_dest = self.view.row;
|
self.scroll_dest = self.view.row;
|
||||||
if (!try self.get_primary().cursor.extract(&primary_cbor))
|
|
||||||
return error.RestoreCursor;
|
if (cursels_cbor.len > 0)
|
||||||
var len = cbor.decodeArrayHeader(&find_history) catch return error.RestoryFindHistory;
|
self.clear_all_cursors();
|
||||||
|
var iter = cursels_cbor;
|
||||||
|
var len = cbor.decodeArrayHeader(&iter) catch return error.RestoreCurSels;
|
||||||
|
while (len > 0) : (len -= 1) {
|
||||||
|
var cursel: CurSel = .{};
|
||||||
|
if (!(cursel.extract(&iter) catch false)) break;
|
||||||
|
(try self.cursels.addOne()).* = cursel;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = cbor.decodeArrayHeader(&find_history) catch return error.RestoreFindHistory;
|
||||||
while (len > 0) : (len -= 1) {
|
while (len > 0) : (len -= 1) {
|
||||||
var value: []const u8 = undefined;
|
var value: []const u8 = undefined;
|
||||||
if (!(cbor.matchValue(&find_history, cbor.extract(&value)) catch return error.RestoryFindHistory))
|
if (!(cbor.matchValue(&find_history, cbor.extract(&value)) catch return error.RestoreFindHistory))
|
||||||
return error.RestoryFindHistory;
|
return error.RestoreFindHistory;
|
||||||
self.push_find_history(value);
|
self.push_find_history(value);
|
||||||
}
|
}
|
||||||
self.clamp();
|
self.clamp();
|
||||||
|
@ -433,7 +459,7 @@ pub const Editor = struct {
|
||||||
fn deinit(self: *Self) void {
|
fn deinit(self: *Self) void {
|
||||||
var meta = std.ArrayList(u8).init(self.allocator);
|
var meta = std.ArrayList(u8).init(self.allocator);
|
||||||
defer meta.deinit();
|
defer meta.deinit();
|
||||||
self.write_state(meta.writer()) catch {};
|
if (self.buffer) |_| self.write_state(meta.writer()) catch {};
|
||||||
for (self.diagnostics.items) |*d| d.deinit(self.diagnostics.allocator);
|
for (self.diagnostics.items) |*d| d.deinit(self.diagnostics.allocator);
|
||||||
self.diagnostics.deinit();
|
self.diagnostics.deinit();
|
||||||
if (self.syntax) |syn| syn.destroy();
|
if (self.syntax) |syn| syn.destroy();
|
||||||
|
@ -568,6 +594,7 @@ pub const Editor = struct {
|
||||||
defer meta.deinit();
|
defer meta.deinit();
|
||||||
self.write_state(meta.writer()) catch {};
|
self.write_state(meta.writer()) catch {};
|
||||||
if (self.buffer) |b_mut| self.buffer_manager.retire(b_mut, meta.items);
|
if (self.buffer) |b_mut| self.buffer_manager.retire(b_mut, meta.items);
|
||||||
|
self.cancel_all_selections();
|
||||||
self.buffer = null;
|
self.buffer = null;
|
||||||
self.plane.erase();
|
self.plane.erase();
|
||||||
self.plane.home();
|
self.plane.home();
|
||||||
|
@ -3809,7 +3836,6 @@ pub const Editor = struct {
|
||||||
const buffer_ = self.buffer;
|
const buffer_ = self.buffer;
|
||||||
if (buffer_) |buffer| if (buffer.is_dirty())
|
if (buffer_) |buffer| if (buffer.is_dirty())
|
||||||
return tp.exit("unsaved changes");
|
return tp.exit("unsaved changes");
|
||||||
self.cancel_all_selections();
|
|
||||||
try self.close();
|
try self.close();
|
||||||
if (buffer_) |buffer|
|
if (buffer_) |buffer|
|
||||||
self.buffer_manager.close_buffer(buffer);
|
self.buffer_manager.close_buffer(buffer);
|
||||||
|
@ -3817,7 +3843,6 @@ pub const Editor = struct {
|
||||||
pub const close_file_meta = .{ .description = "Close file" };
|
pub const close_file_meta = .{ .description = "Close file" };
|
||||||
|
|
||||||
pub fn close_file_without_saving(self: *Self, _: Context) Result {
|
pub fn close_file_without_saving(self: *Self, _: Context) Result {
|
||||||
self.cancel_all_selections();
|
|
||||||
const buffer_ = self.buffer;
|
const buffer_ = self.buffer;
|
||||||
if (buffer_) |buffer|
|
if (buffer_) |buffer|
|
||||||
buffer.reset_to_last_saved();
|
buffer.reset_to_last_saved();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue