Merge branch 'master' into zig-0.15.0
This commit is contained in:
commit
54a43264bb
11 changed files with 319 additions and 52 deletions
|
@ -361,6 +361,7 @@ pub fn build_exe(
|
||||||
.{ .name = "cbor", .module = cbor_mod },
|
.{ .name = "cbor", .module = cbor_mod },
|
||||||
.{ .name = "thespian", .module = thespian_mod },
|
.{ .name = "thespian", .module = thespian_mod },
|
||||||
.{ .name = "LetterCasing", .module = zg_dep.module("LetterCasing") },
|
.{ .name = "LetterCasing", .module = zg_dep.module("LetterCasing") },
|
||||||
|
.{ .name = "file_type_config", .module = file_type_config_mod },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@
|
||||||
.hash = "dizzy-1.0.0-q40X4YCRAAAGYO9QOZiYYSOwiiFlqZlecMuQcxPiBcXM",
|
.hash = "dizzy-1.0.0-q40X4YCRAAAGYO9QOZiYYSOwiiFlqZlecMuQcxPiBcXM",
|
||||||
},
|
},
|
||||||
.thespian = .{
|
.thespian = .{
|
||||||
.url = "git+https://github.com/neurocyte/thespian#f2980d3a747abdf0d18a01596dd8b953dd3e6243",
|
.url = "git+https://github.com/neurocyte/thespian?ref=master#0a386496cda74ef827d5770f6f071a7d2d54b91a",
|
||||||
.hash = "thespian-0.0.1-owFOjk0aBgC8w9ibeiVdhftyEIaVIHCnubsJWfkktE8v",
|
.hash = "thespian-0.0.1-owFOjlgaBgCAOkRjH9_mDN7dnL8n8K3XA2hqqchjXZIk",
|
||||||
},
|
},
|
||||||
.themes = .{
|
.themes = .{
|
||||||
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-952f9f630ea9544088fd30293666ee0650b7a690/flow-themes.tar.gz",
|
.url = "https://github.com/neurocyte/flow-themes/releases/download/master-952f9f630ea9544088fd30293666ee0650b7a690/flow-themes.tar.gz",
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
|
const cbor = @import("cbor");
|
||||||
|
const file_type_config = @import("file_type_config");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const ArrayList = std.ArrayList;
|
const ArrayList = std.ArrayList;
|
||||||
const cwd = std.fs.cwd;
|
const cwd = std.fs.cwd;
|
||||||
|
@ -42,6 +44,7 @@ file_utf8_sanitized: bool = false,
|
||||||
hidden: bool = false,
|
hidden: bool = false,
|
||||||
ephemeral: bool = false,
|
ephemeral: bool = false,
|
||||||
meta: ?[]const u8 = null,
|
meta: ?[]const u8 = null,
|
||||||
|
lsp_version: usize = 1,
|
||||||
|
|
||||||
undo_history: ?*UndoNode = null,
|
undo_history: ?*UndoNode = null,
|
||||||
redo_history: ?*UndoNode = null,
|
redo_history: ?*UndoNode = null,
|
||||||
|
@ -1100,6 +1103,7 @@ pub fn get_meta(self: *Self) ?[]const u8 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_file_path(self: *Self, file_path: []const u8) void {
|
pub fn set_file_path(self: *Self, file_path: []const u8) void {
|
||||||
|
if (file_path.ptr == self.file_path_buf.items.ptr) return;
|
||||||
self.file_path_buf.clearRetainingCapacity();
|
self.file_path_buf.clearRetainingCapacity();
|
||||||
self.file_path_buf.appendSlice(self.external_allocator, file_path) catch |e| switch (e) {
|
self.file_path_buf.appendSlice(self.external_allocator, file_path) catch |e| switch (e) {
|
||||||
error.OutOfMemory => @panic("OOM in Buffer.set_file_path"),
|
error.OutOfMemory => @panic("OOM in Buffer.set_file_path"),
|
||||||
|
@ -1489,3 +1493,63 @@ pub fn redo(self: *Self) error{Stop}![]const u8 {
|
||||||
self.mtime = std.time.milliTimestamp();
|
self.mtime = std.time.milliTimestamp();
|
||||||
return h.meta;
|
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);
|
||||||
|
const dirty = self.is_dirty();
|
||||||
|
|
||||||
|
try cbor.writeArrayHeader(writer, 9);
|
||||||
|
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, dirty);
|
||||||
|
try cbor.writeValue(writer, self.meta);
|
||||||
|
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 dirty: bool = undefined;
|
||||||
|
var meta: ?[]const u8 = null;
|
||||||
|
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(&dirty),
|
||||||
|
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) |buf| {
|
||||||
|
if (self.meta) |old_buf| self.external_allocator.free(old_buf);
|
||||||
|
self.meta = try self.external_allocator.dupe(u8, buf);
|
||||||
|
}
|
||||||
|
try self.reset_from_string_and_update(content);
|
||||||
|
if (dirty) self.mark_dirty();
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const cbor = @import("cbor");
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
const Buffer = @import("Buffer.zig");
|
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;
|
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 {
|
pub fn get_buffer_for_file(self: *Self, file_path: []const u8) ?*Buffer {
|
||||||
return self.buffers.get(file_path);
|
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;
|
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 buffers = try std.ArrayListUnmanaged(*Buffer).initCapacity(allocator, self.buffers.size);
|
||||||
var i = self.buffers.iterator();
|
var i = self.buffers.iterator();
|
||||||
while (i.next()) |kv|
|
while (i.next()) |kv|
|
||||||
|
|
|
@ -942,7 +942,7 @@ pub fn get_restore_file_name() ![]const u8 {
|
||||||
const restore_file = if (local.restore_file) |file|
|
const restore_file = if (local.restore_file) |file|
|
||||||
file
|
file
|
||||||
else
|
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;
|
local.restore_file = restore_file;
|
||||||
return restore_file;
|
return restore_file;
|
||||||
}
|
}
|
||||||
|
|
|
@ -271,7 +271,6 @@ pub const Editor = struct {
|
||||||
file_path: ?[]const u8,
|
file_path: ?[]const u8,
|
||||||
buffer: ?*Buffer,
|
buffer: ?*Buffer,
|
||||||
buffer_manager: *Buffer.Manager,
|
buffer_manager: *Buffer.Manager,
|
||||||
lsp_version: usize = 1,
|
|
||||||
pause_undo: bool = false,
|
pause_undo: bool = false,
|
||||||
pause_undo_root: ?Buffer.Root = null,
|
pause_undo_root: ?Buffer.Root = null,
|
||||||
|
|
||||||
|
@ -331,6 +330,7 @@ pub const Editor = struct {
|
||||||
dirty: bool = false,
|
dirty: bool = false,
|
||||||
eol_mode: Buffer.EolMode = .lf,
|
eol_mode: Buffer.EolMode = .lf,
|
||||||
utf8_sanitized: bool = false,
|
utf8_sanitized: bool = false,
|
||||||
|
indent_mode: IndentMode = .spaces,
|
||||||
} = .{},
|
} = .{},
|
||||||
|
|
||||||
file_type: ?file_type_config = null,
|
file_type: ?file_type_config = null,
|
||||||
|
@ -371,6 +371,14 @@ pub const Editor = struct {
|
||||||
const Meta = command.Metadata;
|
const Meta = command.Metadata;
|
||||||
const Result = command.Result;
|
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 {
|
pub fn write_state(self: *const Self, writer: Buffer.MetaWriter) !void {
|
||||||
try cbor.writeArrayHeader(writer, 12);
|
try cbor.writeArrayHeader(writer, 12);
|
||||||
try cbor.writeValue(writer, self.file_path orelse "");
|
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 {
|
pub fn extract_state(self: *Self, iter: *[]const u8, comptime op: Buffer.ExtractStateOperation) !void {
|
||||||
tp.trace(tp.channel.debug, .{ "extract_state", self.file_path });
|
|
||||||
tp.trace(tp.channel.debug, tp.message{ .buf = buf });
|
|
||||||
self.restored_state = true;
|
self.restored_state = true;
|
||||||
var file_path: []const u8 = undefined;
|
var file_path: []const u8 = undefined;
|
||||||
var view_cbor: []const u8 = undefined;
|
var view_cbor: []const u8 = undefined;
|
||||||
|
@ -411,7 +417,7 @@ pub const Editor = struct {
|
||||||
var clipboard: []const u8 = undefined;
|
var clipboard: []const u8 = undefined;
|
||||||
var last_find_query: []const u8 = undefined;
|
var last_find_query: []const u8 = undefined;
|
||||||
var find_history: []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(&file_path),
|
||||||
tp.extract(&clipboard),
|
tp.extract(&clipboard),
|
||||||
tp.extract(&last_find_query),
|
tp.extract(&last_find_query),
|
||||||
|
@ -440,11 +446,11 @@ pub const Editor = struct {
|
||||||
|
|
||||||
if (cursels_cbor.len > 0)
|
if (cursels_cbor.len > 0)
|
||||||
self.clear_all_cursors();
|
self.clear_all_cursors();
|
||||||
var iter = cursels_cbor;
|
var cursels_iter = cursels_cbor;
|
||||||
var len = cbor.decodeArrayHeader(&iter) catch return error.RestoreCurSels;
|
var len = cbor.decodeArrayHeader(&cursels_iter) catch return error.RestoreCurSels;
|
||||||
while (len > 0) : (len -= 1) {
|
while (len > 0) : (len -= 1) {
|
||||||
var cursel: CurSel = .{};
|
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;
|
(try self.cursels.addOne(self.allocator)).* = cursel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -636,7 +642,7 @@ pub const Editor = struct {
|
||||||
project_manager.did_open(
|
project_manager.did_open(
|
||||||
file_path,
|
file_path,
|
||||||
ft,
|
ft,
|
||||||
self.lsp_version,
|
new_buf.lsp_version,
|
||||||
try content.toOwnedSlice(std.heap.c_allocator),
|
try content.toOwnedSlice(std.heap.c_allocator),
|
||||||
new_buf.is_ephemeral(),
|
new_buf.is_ephemeral(),
|
||||||
) catch |e|
|
) catch |e|
|
||||||
|
@ -659,7 +665,8 @@ pub const Editor = struct {
|
||||||
if (buffer_meta) |meta| {
|
if (buffer_meta) |meta| {
|
||||||
const frame_ = tracy.initZone(@src(), .{ .name = "extract_state" });
|
const frame_ = tracy.initZone(@src(), .{ .name = "extract_state" });
|
||||||
defer frame_.deinit();
|
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);
|
try self.send_editor_open(file_path, new_buf.file_exists, ftn, fti, ftc);
|
||||||
}
|
}
|
||||||
|
@ -1637,11 +1644,12 @@ pub const Editor = struct {
|
||||||
|
|
||||||
if (token_from(self.last.root) != token_from(root)) {
|
if (token_from(self.last.root) != token_from(root)) {
|
||||||
try self.send_editor_update(self.last.root, root, eol_mode);
|
try self.send_editor_update(self.last.root, root, eol_mode);
|
||||||
self.lsp_version += 1;
|
if (self.buffer) |buf|
|
||||||
|
buf.lsp_version += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (self.last.eol_mode != eol_mode or self.last.utf8_sanitized != utf8_sanitized)
|
if (self.last.eol_mode != eol_mode or self.last.utf8_sanitized != utf8_sanitized or self.last.indent_mode != self.indent_mode)
|
||||||
try self.send_editor_eol_mode(eol_mode, utf8_sanitized);
|
try self.send_editor_eol_mode(eol_mode, utf8_sanitized, self.indent_mode);
|
||||||
|
|
||||||
if (self.last.dirty != dirty)
|
if (self.last.dirty != dirty)
|
||||||
try self.send_editor_dirty(dirty);
|
try self.send_editor_dirty(dirty);
|
||||||
|
@ -1762,14 +1770,14 @@ pub const Editor = struct {
|
||||||
|
|
||||||
fn send_editor_update(self: *const Self, old_root: ?Buffer.Root, new_root: ?Buffer.Root, eol_mode: Buffer.EolMode) !void {
|
fn send_editor_update(self: *const Self, old_root: ?Buffer.Root, new_root: ?Buffer.Root, eol_mode: Buffer.EolMode) !void {
|
||||||
_ = try self.handlers.msg(.{ "E", "update", token_from(new_root), token_from(old_root), @intFromEnum(eol_mode) });
|
_ = try self.handlers.msg(.{ "E", "update", token_from(new_root), token_from(old_root), @intFromEnum(eol_mode) });
|
||||||
if (self.syntax) |_| if (self.file_path) |file_path| if (old_root != null and new_root != null)
|
if (self.buffer) |buffer| if (self.syntax) |_| if (self.file_path) |file_path| if (old_root != null and new_root != null)
|
||||||
project_manager.did_change(file_path, self.lsp_version, try text_from_root(new_root, eol_mode), try text_from_root(old_root, eol_mode), eol_mode) catch {};
|
project_manager.did_change(file_path, buffer.lsp_version, try text_from_root(new_root, eol_mode), try text_from_root(old_root, eol_mode), eol_mode) catch {};
|
||||||
if (self.enable_auto_save)
|
if (self.enable_auto_save)
|
||||||
tp.self_pid().send(.{ "cmd", "save_file", .{} }) catch {};
|
tp.self_pid().send(.{ "cmd", "save_file", .{} }) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_editor_eol_mode(self: *const Self, eol_mode: Buffer.EolMode, utf8_sanitized: bool) !void {
|
fn send_editor_eol_mode(self: *const Self, eol_mode: Buffer.EolMode, utf8_sanitized: bool, indent_mode: IndentMode) !void {
|
||||||
_ = try self.handlers.msg(.{ "E", "eol_mode", @intFromEnum(eol_mode), utf8_sanitized });
|
_ = try self.handlers.msg(.{ "E", "eol_mode", eol_mode, utf8_sanitized, indent_mode });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clamp_abs(self: *Self, abs: bool) void {
|
fn clamp_abs(self: *Self, abs: bool) void {
|
||||||
|
@ -5979,11 +5987,11 @@ pub const Editor = struct {
|
||||||
const root = try self.buf_root();
|
const root = try self.buf_root();
|
||||||
try root.store(content.writer(std.heap.c_allocator), try self.buf_eol_mode());
|
try root.store(content.writer(std.heap.c_allocator), try self.buf_eol_mode());
|
||||||
|
|
||||||
if (self.file_path) |file_path|
|
if (self.buffer) |buffer| if (self.file_path) |file_path|
|
||||||
project_manager.did_open(
|
project_manager.did_open(
|
||||||
file_path,
|
file_path,
|
||||||
ft,
|
ft,
|
||||||
self.lsp_version,
|
buffer.lsp_version,
|
||||||
try content.toOwnedSlice(std.heap.c_allocator),
|
try content.toOwnedSlice(std.heap.c_allocator),
|
||||||
if (self.buffer) |p| p.is_ephemeral() else true,
|
if (self.buffer) |p| p.is_ephemeral() else true,
|
||||||
) catch |e|
|
) catch |e|
|
||||||
|
|
|
@ -1288,11 +1288,25 @@ fn create_home_split(self: *Self) !void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_restore_info(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);
|
var sfa = std.heap.stackFallback(512, self.allocator);
|
||||||
const a = sfa.get();
|
const a = sfa.get();
|
||||||
var meta = std.ArrayListUnmanaged(u8).empty;
|
var meta = std.ArrayListUnmanaged(u8).empty;
|
||||||
editor.write_state(meta.writer(a)) catch return;
|
const writer = meta.writer(a);
|
||||||
|
|
||||||
|
if (self.get_active_editor()) |editor| {
|
||||||
|
cbor.writeValue(writer, editor.file_path) catch return;
|
||||||
|
editor.update_meta();
|
||||||
|
} 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;
|
||||||
|
|
||||||
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();
|
||||||
|
@ -1300,7 +1314,6 @@ pub fn write_restore_info(self: *Self) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_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_name = try root.get_restore_file_name();
|
||||||
const file = try std.fs.cwd().openFile(file_name, .{ .mode = .read_only });
|
const file = try std.fs.cwd().openFile(file_name, .{ .mode = .read_only });
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
@ -1308,7 +1321,46 @@ fn read_restore_info(self: *Self) !void {
|
||||||
var buf = try self.allocator.alloc(u8, @intCast(stat.size));
|
var buf = try self.allocator.alloc(u8, @intCast(stat.size));
|
||||||
defer self.allocator.free(buf);
|
defer self.allocator.free(buf);
|
||||||
const size = try file.readAll(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);
|
||||||
|
|
||||||
|
if (self.widgets.get("tabs")) |tabs_widget|
|
||||||
|
if (tabs_widget.dynamic_cast(@import("status/tabs.zig").TabBar)) |tabs|
|
||||||
|
tabs.extract_state(&iter) catch |e| {
|
||||||
|
const logger = log.logger("mainview");
|
||||||
|
defer logger.deinit();
|
||||||
|
logger.print_err("mainview", "failed to restore tabs: {}", .{e});
|
||||||
|
};
|
||||||
|
|
||||||
|
const buffers = try self.buffer_manager.list_unordered(self.allocator);
|
||||||
|
defer self.allocator.free(buffers);
|
||||||
|
for (buffers) |buffer| if (!buffer.is_ephemeral())
|
||||||
|
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" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_buffer_did_open(allocator: std.mem.Allocator, buffer: *Buffer) !void {
|
||||||
|
const ft = try file_type_config.get(buffer.file_type_name orelse return) orelse return;
|
||||||
|
var content = std.ArrayListUnmanaged(u8).empty;
|
||||||
|
defer content.deinit(allocator);
|
||||||
|
try buffer.root.store(content.writer(allocator), buffer.file_eol_mode);
|
||||||
|
|
||||||
|
try project_manager.did_open(
|
||||||
|
buffer.get_file_path(),
|
||||||
|
ft,
|
||||||
|
buffer.lsp_version,
|
||||||
|
try content.toOwnedSlice(allocator),
|
||||||
|
buffer.is_ephemeral(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_next_mru_buffer(self: *Self) ?[]const u8 {
|
fn get_next_mru_buffer(self: *Self) ?[]const u8 {
|
||||||
|
|
|
@ -5,6 +5,7 @@ const command = @import("command");
|
||||||
const project_manager = @import("project_manager");
|
const project_manager = @import("project_manager");
|
||||||
|
|
||||||
const tui = @import("../../tui.zig");
|
const tui = @import("../../tui.zig");
|
||||||
|
const Widget = @import("../../Widget.zig");
|
||||||
pub const Type = @import("palette.zig").Create(@This());
|
pub const Type = @import("palette.zig").Create(@This());
|
||||||
const module_name = @typeName(@This());
|
const module_name = @typeName(@This());
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ pub const description = "task";
|
||||||
|
|
||||||
pub const Entry = struct {
|
pub const Entry = struct {
|
||||||
label: []const u8,
|
label: []const u8,
|
||||||
hint: []const u8,
|
command: ?[]const u8 = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn deinit(palette: *Type) void {
|
pub fn deinit(palette: *Type) void {
|
||||||
|
@ -29,9 +30,13 @@ pub fn load_entries(palette: *Type) !usize {
|
||||||
while (len > 0) : (len -= 1) {
|
while (len > 0) : (len -= 1) {
|
||||||
var task: []const u8 = undefined;
|
var task: []const u8 = undefined;
|
||||||
if (try cbor.matchValue(&iter, cbor.extract(&task))) {
|
if (try cbor.matchValue(&iter, cbor.extract(&task))) {
|
||||||
(try palette.entries.addOne()).* = .{ .label = try palette.allocator.dupe(u8, task), .hint = "" };
|
(try palette.entries.addOne()).* = .{ .label = try palette.allocator.dupe(u8, task) };
|
||||||
} else return error.InvalidTaskMessageField;
|
} else return error.InvalidTaskMessageField;
|
||||||
}
|
}
|
||||||
|
(try palette.entries.addOne()).* = .{
|
||||||
|
.label = try palette.allocator.dupe(u8, " Add new task"),
|
||||||
|
.command = "add_task",
|
||||||
|
};
|
||||||
return if (palette.entries.items.len == 0) label.len else blk: {
|
return if (palette.entries.items.len == 0) label.len else blk: {
|
||||||
var longest: usize = 0;
|
var longest: usize = 0;
|
||||||
for (palette.entries.items) |item| longest = @max(longest, item.label.len);
|
for (palette.entries.items) |item| longest = @max(longest, item.label.len);
|
||||||
|
@ -49,30 +54,73 @@ pub fn add_menu_entry(palette: *Type, entry: *Entry, matches: ?[]const usize) !v
|
||||||
var value = std.ArrayList(u8).init(palette.allocator);
|
var value = std.ArrayList(u8).init(palette.allocator);
|
||||||
defer value.deinit();
|
defer value.deinit();
|
||||||
const writer = value.writer();
|
const writer = value.writer();
|
||||||
try cbor.writeValue(writer, entry.label);
|
try cbor.writeValue(writer, entry);
|
||||||
try cbor.writeValue(writer, entry.hint);
|
|
||||||
try cbor.writeValue(writer, matches orelse &[_]usize{});
|
try cbor.writeValue(writer, matches orelse &[_]usize{});
|
||||||
try palette.menu.add_item_with_handler(value.items, select);
|
try palette.menu.add_item_with_handler(value.items, select);
|
||||||
palette.items += 1;
|
palette.items += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_render_menu(_: *Type, button: *Type.ButtonState, theme: *const Widget.Theme, selected: bool) bool {
|
||||||
|
var entry: Entry = undefined;
|
||||||
|
var iter = button.opts.label; // label contains cbor entry object and matches
|
||||||
|
if (!(cbor.matchValue(&iter, cbor.extract(&entry)) catch false))
|
||||||
|
entry.label = "#ERROR#";
|
||||||
|
|
||||||
|
const style_base = theme.editor_widget;
|
||||||
|
const style_label =
|
||||||
|
if (button.active)
|
||||||
|
theme.editor_cursor
|
||||||
|
else if (button.hover or selected)
|
||||||
|
theme.editor_selection
|
||||||
|
else if (entry.command) |_|
|
||||||
|
theme.input_placeholder
|
||||||
|
else
|
||||||
|
theme.editor_widget;
|
||||||
|
|
||||||
|
const style_hint = if (tui.find_scope_style(theme, "entity.name")) |sty| sty.style else style_label;
|
||||||
|
button.plane.set_base_style(style_base);
|
||||||
|
button.plane.erase();
|
||||||
|
button.plane.home();
|
||||||
|
button.plane.set_style(style_label);
|
||||||
|
button.plane.fill(" ");
|
||||||
|
button.plane.home();
|
||||||
|
button.plane.set_style(style_hint);
|
||||||
|
const pointer = if (selected) "⏵" else " ";
|
||||||
|
_ = button.plane.print("{s}", .{pointer}) catch {};
|
||||||
|
button.plane.set_style(style_label);
|
||||||
|
_ = button.plane.print("{s} ", .{entry.label}) catch {};
|
||||||
|
var index: usize = 0;
|
||||||
|
var len = cbor.decodeArrayHeader(&iter) catch return false;
|
||||||
|
while (len > 0) : (len -= 1) {
|
||||||
|
if (cbor.matchValue(&iter, cbor.extract(&index)) catch break) {
|
||||||
|
tui.render_match_cell(&button.plane, 0, index + 1, theme) catch break;
|
||||||
|
} else break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
fn select(menu: **Type.MenuState, button: *Type.ButtonState) void {
|
fn select(menu: **Type.MenuState, button: *Type.ButtonState) void {
|
||||||
var task: []const u8 = undefined;
|
var entry: Entry = undefined;
|
||||||
var iter = button.opts.label;
|
var iter = button.opts.label;
|
||||||
if (!(cbor.matchString(&iter, &task) catch false)) return;
|
if (!(cbor.matchValue(&iter, cbor.extract(&entry)) catch false)) return;
|
||||||
var buffer_name = std.ArrayList(u8).init(menu.*.opts.ctx.allocator);
|
var buffer_name = std.ArrayList(u8).init(menu.*.opts.ctx.allocator);
|
||||||
defer buffer_name.deinit();
|
defer buffer_name.deinit();
|
||||||
buffer_name.writer().print("*{s}*", .{task}) catch {};
|
buffer_name.writer().print("*{s}*", .{entry.label}) catch {};
|
||||||
project_manager.add_task(task) catch {};
|
if (entry.command) |cmd| {
|
||||||
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
tp.self_pid().send(.{ "cmd", "create_scratch_buffer", .{ buffer_name.items, "", "conf" } }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
tp.self_pid().send(.{ "cmd", cmd, .{entry.label} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
tp.self_pid().send(.{ "cmd", "shell_execute_stream", .{task} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
} else {
|
||||||
|
project_manager.add_task(entry.label) catch {};
|
||||||
|
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
|
tp.self_pid().send(.{ "cmd", "create_scratch_buffer", .{ buffer_name.items, "", "conf" } }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
|
tp.self_pid().send(.{ "cmd", "shell_execute_stream", .{entry.label} }) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete_item(menu: *Type.MenuState, button: *Type.ButtonState) bool {
|
pub fn delete_item(menu: *Type.MenuState, button: *Type.ButtonState) bool {
|
||||||
var task: []const u8 = undefined;
|
var entry: Entry = undefined;
|
||||||
var iter = button.opts.label;
|
var iter = button.opts.label;
|
||||||
if (!(cbor.matchString(&iter, &task) catch false)) return false;
|
if (!(cbor.matchValue(&iter, cbor.extract(&entry)) catch false)) return false;
|
||||||
command.executeName("delete_task", command.fmt(.{task})) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
command.executeName("delete_task", command.fmt(.{entry.label})) catch |e| menu.*.opts.ctx.logger.err(module_name, e);
|
||||||
return true; //refresh list
|
return true; //refresh list
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
const tracy = @import("tracy");
|
const tracy = @import("tracy");
|
||||||
|
const config = @import("config");
|
||||||
const Buffer = @import("Buffer");
|
const Buffer = @import("Buffer");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
const project_manager = @import("project_manager");
|
const project_manager = @import("project_manager");
|
||||||
|
@ -35,6 +36,7 @@ detailed: bool = false,
|
||||||
file: bool = false,
|
file: bool = false,
|
||||||
eol_mode: Buffer.EolMode = .lf,
|
eol_mode: Buffer.EolMode = .lf,
|
||||||
utf8_sanitized: bool = false,
|
utf8_sanitized: bool = false,
|
||||||
|
indent_mode: config.IndentMode = .spaces,
|
||||||
|
|
||||||
const project_icon = "";
|
const project_icon = "";
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
@ -155,15 +157,19 @@ fn render_detailed(self: *Self, plane: *Plane, theme: *const Widget.Theme) void
|
||||||
_ = plane.print("{s} ({s})", .{ self.name, project_name }) catch {};
|
_ = plane.print("{s} ({s})", .{ self.name, project_name }) catch {};
|
||||||
} else {
|
} else {
|
||||||
const eol_mode = switch (self.eol_mode) {
|
const eol_mode = switch (self.eol_mode) {
|
||||||
.lf => " [↩ = ␊]",
|
.lf => "[↩ = ␊]",
|
||||||
.crlf => " [↩ = ␍␊]",
|
.crlf => "[↩ = ␍␊]",
|
||||||
|
};
|
||||||
|
const indent_mode = switch (self.indent_mode) {
|
||||||
|
.spaces, .auto => "[⭾ = ␠]",
|
||||||
|
.tabs => "[⭾ = ␉]",
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = plane.putstr(if (!self.file_exists) "" else if (self.file_dirty) "" else "") catch {};
|
_ = plane.putstr(if (!self.file_exists) "" else if (self.file_dirty) "" else "") catch {};
|
||||||
_ = plane.print(" {s}:{d}:{d}", .{ self.name, self.line + 1, self.column + 1 }) catch {};
|
_ = plane.print(" {s}:{d}:{d}", .{ self.name, self.line + 1, self.column + 1 }) catch {};
|
||||||
_ = plane.print(" of {d} lines", .{self.lines}) catch {};
|
_ = plane.print(" of {d} lines", .{self.lines}) catch {};
|
||||||
if (self.file_type.len > 0)
|
if (self.file_type.len > 0)
|
||||||
_ = plane.print(" ({s}){s}", .{ self.file_type, eol_mode }) catch {};
|
_ = plane.print(" ({s}) {s}{s}", .{ self.file_type, eol_mode, indent_mode }) catch {};
|
||||||
|
|
||||||
if (self.utf8_sanitized) {
|
if (self.utf8_sanitized) {
|
||||||
plane.set_style(.{ .fg = theme.editor_error.fg.? });
|
plane.set_style(.{ .fg = theme.editor_error.fg.? });
|
||||||
|
@ -214,13 +220,12 @@ fn process_event(self: *Self, m: tp.message) error{Exit}!bool {
|
||||||
var file_type: []const u8 = undefined;
|
var file_type: []const u8 = undefined;
|
||||||
var file_icon: []const u8 = undefined;
|
var file_icon: []const u8 = undefined;
|
||||||
var file_dirty: bool = undefined;
|
var file_dirty: bool = undefined;
|
||||||
var eol_mode: Buffer.EolModeTag = @intFromEnum(Buffer.EolMode.lf);
|
|
||||||
if (try m.match(.{ tp.any, "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.extract(&self.column) }))
|
if (try m.match(.{ tp.any, "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.extract(&self.column) }))
|
||||||
return false;
|
return false;
|
||||||
if (try m.match(.{ tp.any, "dirty", tp.extract(&file_dirty) })) {
|
if (try m.match(.{ tp.any, "dirty", tp.extract(&file_dirty) })) {
|
||||||
self.file_dirty = file_dirty;
|
self.file_dirty = file_dirty;
|
||||||
} else if (try m.match(.{ tp.any, "eol_mode", tp.extract(&eol_mode), tp.extract(&self.utf8_sanitized) })) {
|
} else if (try m.match(.{ tp.any, "eol_mode", tp.extract(&self.eol_mode), tp.extract(&self.utf8_sanitized), tp.extract(&self.indent_mode) })) {
|
||||||
self.eol_mode = @enumFromInt(eol_mode);
|
//
|
||||||
} else if (try m.match(.{ tp.any, "save", tp.extract(&file_path) })) {
|
} else if (try m.match(.{ tp.any, "save", tp.extract(&file_path) })) {
|
||||||
@memcpy(self.name_buf[0..file_path.len], file_path);
|
@memcpy(self.name_buf[0..file_path.len], file_path);
|
||||||
self.name = self.name_buf[0..file_path.len];
|
self.name = self.name_buf[0..file_path.len];
|
||||||
|
|
|
@ -2,6 +2,7 @@ const std = @import("std");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
const Buffer = @import("Buffer");
|
const Buffer = @import("Buffer");
|
||||||
|
const config = @import("config");
|
||||||
|
|
||||||
const Plane = @import("renderer").Plane;
|
const Plane = @import("renderer").Plane;
|
||||||
const command = @import("command");
|
const command = @import("command");
|
||||||
|
@ -22,6 +23,7 @@ buf: [256]u8 = undefined,
|
||||||
rendered: [:0]const u8 = "",
|
rendered: [:0]const u8 = "",
|
||||||
eol_mode: Buffer.EolMode = .lf,
|
eol_mode: Buffer.EolMode = .lf,
|
||||||
utf8_sanitized: bool = false,
|
utf8_sanitized: bool = false,
|
||||||
|
indent_mode: config.IndentMode = .spaces,
|
||||||
padding: ?usize,
|
padding: ?usize,
|
||||||
leader: ?Leader,
|
leader: ?Leader,
|
||||||
style: ?DigitStyle,
|
style: ?DigitStyle,
|
||||||
|
@ -90,7 +92,11 @@ fn format(self: *Self) void {
|
||||||
.lf => "",
|
.lf => "",
|
||||||
.crlf => " [␍␊]",
|
.crlf => " [␍␊]",
|
||||||
};
|
};
|
||||||
std.fmt.format(writer, "{s} Ln ", .{eol_mode}) catch {};
|
const indent_mode = switch (self.indent_mode) {
|
||||||
|
.spaces, .auto => "",
|
||||||
|
.tabs => " [⭾]",
|
||||||
|
};
|
||||||
|
std.fmt.format(writer, "{s}{s} Ln ", .{ eol_mode, indent_mode }) catch {};
|
||||||
self.format_count(writer, self.line + 1, self.padding orelse 0) catch {};
|
self.format_count(writer, self.line + 1, self.padding orelse 0) catch {};
|
||||||
std.fmt.format(writer, ", Col ", .{}) catch {};
|
std.fmt.format(writer, ", Col ", .{}) catch {};
|
||||||
self.format_count(writer, self.column + 1, self.padding orelse 0) catch {};
|
self.format_count(writer, self.column + 1, self.padding orelse 0) catch {};
|
||||||
|
@ -115,11 +121,9 @@ fn format_count(self: *Self, writer: anytype, value: usize, width: usize) !void
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
pub fn receive(self: *Self, _: *Button.State(Self), _: tp.pid_ref, m: tp.message) error{Exit}!bool {
|
||||||
var eol_mode: Buffer.EolModeTag = @intFromEnum(Buffer.EolMode.lf);
|
|
||||||
if (try m.match(.{ "E", "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.extract(&self.column) })) {
|
if (try m.match(.{ "E", "pos", tp.extract(&self.lines), tp.extract(&self.line), tp.extract(&self.column) })) {
|
||||||
self.format();
|
self.format();
|
||||||
} else if (try m.match(.{ "E", "eol_mode", tp.extract(&eol_mode), tp.extract(&self.utf8_sanitized) })) {
|
} else if (try m.match(.{ "E", "eol_mode", tp.extract(&self.eol_mode), tp.extract(&self.utf8_sanitized), tp.extract(&self.indent_mode) })) {
|
||||||
self.eol_mode = @enumFromInt(eol_mode);
|
|
||||||
self.format();
|
self.format();
|
||||||
} else if (try m.match(.{ "E", "open", tp.more })) {
|
} else if (try m.match(.{ "E", "open", tp.more })) {
|
||||||
self.eol_mode = .lf;
|
self.eol_mode = .lf;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const cbor = @import("cbor");
|
||||||
const tp = @import("thespian");
|
const tp = @import("thespian");
|
||||||
const root = @import("root");
|
const root = @import("root");
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ pub fn create(allocator: std.mem.Allocator, parent: Plane, event_handler: ?Event
|
||||||
return Widget.to(self);
|
return Widget.to(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TabBar = struct {
|
pub const TabBar = struct {
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
plane: Plane,
|
plane: Plane,
|
||||||
widget_list: *WidgetList,
|
widget_list: *WidgetList,
|
||||||
|
@ -267,6 +268,45 @@ const TabBar = struct {
|
||||||
if (buffer_manager.buffer_from_ref(tab.buffer_ref)) |buffer|
|
if (buffer_manager.buffer_from_ref(tab.buffer_ref)) |buffer|
|
||||||
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.get_file_path() } }) catch {};
|
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.get_file_path() } }) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn write_state(self: *const Self, writer: Buffer.MetaWriter) error{OutOfMemory}!void {
|
||||||
|
try cbor.writeArrayHeader(writer, self.tabs.len);
|
||||||
|
for (self.tabs) |tab| try cbor.writeValue(writer, ref_to_name(tab.buffer_ref));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ref_to_name(buffer_ref: usize) ?[]const u8 {
|
||||||
|
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
|
||||||
|
return if (buffer_manager.buffer_from_ref(buffer_ref)) |buffer| buffer.get_file_path() else null;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extract_state(self: *Self, iter: *[]const u8) !void {
|
||||||
|
var iter2 = iter.*;
|
||||||
|
self.allocator.free(self.tabs);
|
||||||
|
self.tabs = &.{};
|
||||||
|
|
||||||
|
var result: std.ArrayListUnmanaged(TabBarTab) = .{};
|
||||||
|
errdefer result.deinit(self.allocator);
|
||||||
|
|
||||||
|
var count = cbor.decodeArrayHeader(&iter2) catch return error.MatchTabArrayFailed;
|
||||||
|
while (count > 0) : (count -= 1) {
|
||||||
|
var buffer_name: ?[]const u8 = undefined;
|
||||||
|
if (!(cbor.matchValue(&iter2, cbor.extract(&buffer_name)) catch false)) return error.MatchTabBufferNameFailed;
|
||||||
|
if (buffer_name) |name| if (name_to_ref(name)) |buffer_ref| {
|
||||||
|
(try result.addOne(self.allocator)).* = .{
|
||||||
|
.buffer_ref = buffer_ref,
|
||||||
|
.widget = try Tab.create(self, buffer_ref, &self.tab_style, self.event_handler),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
self.tabs = try result.toOwnedSlice(self.allocator);
|
||||||
|
iter.* = iter2;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn name_to_ref(buffer_name: []const u8) ?usize {
|
||||||
|
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
|
||||||
|
return if (buffer_manager.get_buffer_for_file(buffer_name)) |buffer| buffer_manager.buffer_to_ref(buffer) else null;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const Tab = struct {
|
const Tab = struct {
|
||||||
|
@ -457,6 +497,22 @@ const Tab = struct {
|
||||||
const basename = if (basename_begin) |begin| file_path[begin + 1 ..] else file_path;
|
const basename = if (basename_begin) |begin| file_path[begin + 1 ..] else file_path;
|
||||||
return basename;
|
return basename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_state(self: *const @This(), writer: Buffer.MetaWriter) error{OutOfMemory}!void {
|
||||||
|
try cbor.writeArrayHeader(writer, 9);
|
||||||
|
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);
|
||||||
|
try cbor.writeValue(writer, self.file_type_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_state(self: *@This(), iter: *[]const u8) !void {
|
||||||
|
_ = self;
|
||||||
|
_ = iter;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const spacer = struct {
|
const spacer = struct {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue