Compare commits
6 commits
fa6ea11d57
...
9026404d6d
| Author | SHA1 | Date | |
|---|---|---|---|
| 9026404d6d | |||
| 15c9469365 | |||
| 99cd7b6dc5 | |||
| 0c38e8c4ea | |||
| 8d0f333ad8 | |||
| 30b1329d10 |
4 changed files with 71 additions and 31 deletions
|
|
@ -42,6 +42,7 @@ last_save_eol_mode: EolMode = .lf,
|
||||||
file_utf8_sanitized: bool = false,
|
file_utf8_sanitized: bool = false,
|
||||||
hidden: bool = false,
|
hidden: bool = false,
|
||||||
ephemeral: bool = false,
|
ephemeral: bool = false,
|
||||||
|
auto_save: bool = false,
|
||||||
meta: ?[]const u8 = null,
|
meta: ?[]const u8 = null,
|
||||||
lsp_version: usize = 1,
|
lsp_version: usize = 1,
|
||||||
|
|
||||||
|
|
@ -1479,6 +1480,18 @@ pub fn mark_not_ephemeral(self: *Self) void {
|
||||||
self.ephemeral = false;
|
self.ephemeral = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn enable_auto_save(self: *Self) void {
|
||||||
|
self.auto_save = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn disable_auto_save(self: *Self) void {
|
||||||
|
self.auto_save = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_auto_save(self: *const Self) bool {
|
||||||
|
return self.auto_save;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_dirty(self: *const Self) bool {
|
pub fn is_dirty(self: *const Self) bool {
|
||||||
return if (!self.file_exists)
|
return if (!self.file_exists)
|
||||||
self.root.length() > 0
|
self.root.length() > 0
|
||||||
|
|
@ -1570,16 +1583,18 @@ pub fn write_state(self: *const Self, writer: *std.Io.Writer) error{ Stop, OutOf
|
||||||
try self.root.store(&content.writer, self.file_eol_mode);
|
try self.root.store(&content.writer, self.file_eol_mode);
|
||||||
const dirty = self.is_dirty();
|
const dirty = self.is_dirty();
|
||||||
|
|
||||||
try cbor.writeArrayHeader(writer, 9);
|
try cbor.writeValue(writer, .{
|
||||||
try cbor.writeValue(writer, self.get_file_path());
|
self.get_file_path(),
|
||||||
try cbor.writeValue(writer, self.file_exists);
|
self.file_exists,
|
||||||
try cbor.writeValue(writer, self.file_eol_mode);
|
self.file_eol_mode,
|
||||||
try cbor.writeValue(writer, self.hidden);
|
self.hidden,
|
||||||
try cbor.writeValue(writer, self.ephemeral);
|
self.ephemeral,
|
||||||
try cbor.writeValue(writer, dirty);
|
self.auto_save,
|
||||||
try cbor.writeValue(writer, self.meta);
|
dirty,
|
||||||
try cbor.writeValue(writer, self.file_type_name);
|
self.meta,
|
||||||
try cbor.writeValue(writer, content.written());
|
self.file_type_name,
|
||||||
|
content.written(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const ExtractStateOperation = enum { none, open_file };
|
pub const ExtractStateOperation = enum { none, open_file };
|
||||||
|
|
@ -1597,6 +1612,7 @@ pub fn extract_state(self: *Self, iter: *[]const u8) !void {
|
||||||
cbor.extract(&self.file_eol_mode),
|
cbor.extract(&self.file_eol_mode),
|
||||||
cbor.extract(&self.hidden),
|
cbor.extract(&self.hidden),
|
||||||
cbor.extract(&self.ephemeral),
|
cbor.extract(&self.ephemeral),
|
||||||
|
cbor.extract(&self.auto_save),
|
||||||
cbor.extract(&dirty),
|
cbor.extract(&dirty),
|
||||||
cbor.extract(&meta),
|
cbor.extract(&meta),
|
||||||
cbor.extract(&file_type_name),
|
cbor.extract(&file_type_name),
|
||||||
|
|
|
||||||
|
|
@ -383,7 +383,6 @@ pub const Editor = struct {
|
||||||
completion_col: usize = 0,
|
completion_col: usize = 0,
|
||||||
completion_is_complete: bool = true,
|
completion_is_complete: bool = true,
|
||||||
|
|
||||||
enable_auto_save: bool,
|
|
||||||
enable_format_on_save: bool,
|
enable_format_on_save: bool,
|
||||||
|
|
||||||
restored_state: bool = false,
|
restored_state: bool = false,
|
||||||
|
|
@ -411,11 +410,10 @@ pub const Editor = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_state(self: *const Self, writer: *std.Io.Writer) !void {
|
pub fn write_state(self: *const Self, writer: *std.Io.Writer) !void {
|
||||||
try cbor.writeArrayHeader(writer, 11);
|
try cbor.writeArrayHeader(writer, 10);
|
||||||
try cbor.writeValue(writer, self.file_path orelse "");
|
try cbor.writeValue(writer, self.file_path orelse "");
|
||||||
try cbor.writeValue(writer, self.last_find_query orelse "");
|
try cbor.writeValue(writer, self.last_find_query orelse "");
|
||||||
try cbor.writeValue(writer, self.enable_format_on_save);
|
try cbor.writeValue(writer, self.enable_format_on_save);
|
||||||
try cbor.writeValue(writer, self.enable_auto_save);
|
|
||||||
try cbor.writeValue(writer, self.indent_size);
|
try cbor.writeValue(writer, self.indent_size);
|
||||||
try cbor.writeValue(writer, self.tab_width);
|
try cbor.writeValue(writer, self.tab_width);
|
||||||
try cbor.writeValue(writer, self.indent_mode);
|
try cbor.writeValue(writer, self.indent_mode);
|
||||||
|
|
@ -450,7 +448,6 @@ pub const Editor = struct {
|
||||||
tp.extract(&file_path),
|
tp.extract(&file_path),
|
||||||
tp.extract(&last_find_query),
|
tp.extract(&last_find_query),
|
||||||
tp.extract(&self.enable_format_on_save),
|
tp.extract(&self.enable_format_on_save),
|
||||||
tp.extract(&self.enable_auto_save),
|
|
||||||
tp.extract(&self.indent_size),
|
tp.extract(&self.indent_size),
|
||||||
tp.extract(&self.tab_width),
|
tp.extract(&self.tab_width),
|
||||||
tp.extract(&self.indent_mode),
|
tp.extract(&self.indent_mode),
|
||||||
|
|
@ -514,7 +511,6 @@ pub const Editor = struct {
|
||||||
.animation_lag = get_animation_max_lag(),
|
.animation_lag = get_animation_max_lag(),
|
||||||
.animation_frame_rate = frame_rate,
|
.animation_frame_rate = frame_rate,
|
||||||
.animation_last_time = time.microTimestamp(),
|
.animation_last_time = time.microTimestamp(),
|
||||||
.enable_auto_save = tui.config().enable_auto_save,
|
|
||||||
.enable_format_on_save = tui.config().enable_format_on_save,
|
.enable_format_on_save = tui.config().enable_format_on_save,
|
||||||
.enable_terminal_cursor = tui.config().enable_terminal_cursor,
|
.enable_terminal_cursor = tui.config().enable_terminal_cursor,
|
||||||
.render_whitespace = from_whitespace_mode(tui.config().whitespace_mode),
|
.render_whitespace = from_whitespace_mode(tui.config().whitespace_mode),
|
||||||
|
|
@ -598,6 +594,7 @@ pub const Editor = struct {
|
||||||
defer frame.deinit();
|
defer frame.deinit();
|
||||||
break :blk try self.buffer_manager.open_file(file_path);
|
break :blk try self.buffer_manager.open_file(file_path);
|
||||||
};
|
};
|
||||||
|
if (tui.config().enable_auto_save) buffer.enable_auto_save();
|
||||||
return self.open_buffer(file_path, buffer, null);
|
return self.open_buffer(file_path, buffer, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -689,6 +686,7 @@ pub const Editor = struct {
|
||||||
buffer.file_type_icon = fti;
|
buffer.file_type_icon = fti;
|
||||||
buffer.file_type_color = ftc;
|
buffer.file_type_color = ftc;
|
||||||
}
|
}
|
||||||
|
const auto_save = if (self.buffer) |b| b.is_auto_save() else false;
|
||||||
|
|
||||||
if (buffer_meta) |meta| {
|
if (buffer_meta) |meta| {
|
||||||
const frame_ = tracy.initZone(@src(), .{ .name = "extract_state" });
|
const frame_ = tracy.initZone(@src(), .{ .name = "extract_state" });
|
||||||
|
|
@ -696,12 +694,13 @@ pub const Editor = struct {
|
||||||
var iter = meta;
|
var iter = meta;
|
||||||
try self.extract_state(&iter, .none);
|
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, auto_save);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_enable_auto_save(self: *Self) void {
|
fn maybe_enable_auto_save(self: *Self) void {
|
||||||
|
const buffer = self.buffer orelse return;
|
||||||
if (self.restored_state) return;
|
if (self.restored_state) return;
|
||||||
self.enable_auto_save = false;
|
buffer.disable_auto_save();
|
||||||
if (!tui.config().enable_auto_save) return;
|
if (!tui.config().enable_auto_save) return;
|
||||||
const self_file_type = self.file_type orelse return;
|
const self_file_type = self.file_type orelse return;
|
||||||
|
|
||||||
|
|
@ -712,7 +711,7 @@ pub const Editor = struct {
|
||||||
break :enable;
|
break :enable;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.enable_auto_save = true;
|
buffer.enable_auto_save();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detect_indent_mode(self: *Self, content: []const u8) void {
|
fn detect_indent_mode(self: *Self, content: []const u8) void {
|
||||||
|
|
@ -769,7 +768,7 @@ pub const Editor = struct {
|
||||||
if (self.file_path) |file_path| {
|
if (self.file_path) |file_path| {
|
||||||
if (self.buffer) |b_mut| try b_mut.store_to_file_and_clean(file_path);
|
if (self.buffer) |b_mut| try b_mut.store_to_file_and_clean(file_path);
|
||||||
} else return error.SaveNoFileName;
|
} else return error.SaveNoFileName;
|
||||||
try self.send_editor_save(self.file_path.?);
|
try self.send_editor_save(self.file_path.?, b.is_auto_save());
|
||||||
self.last.dirty = false;
|
self.last.dirty = false;
|
||||||
self.update_event() catch {};
|
self.update_event() catch {};
|
||||||
}
|
}
|
||||||
|
|
@ -1752,12 +1751,12 @@ pub const Editor = struct {
|
||||||
self.handlers.msg(.{ "E", "location", tag, c.row, c.col });
|
self.handlers.msg(.{ "E", "location", tag, c.row, c.col });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_editor_open(self: *const Self, file_path: []const u8, file_exists: bool, file_type: []const u8, file_icon: []const u8, file_color: u24) !void {
|
fn send_editor_open(self: *const Self, file_path: []const u8, file_exists: bool, file_type: []const u8, file_icon: []const u8, file_color: u24, auto_save: bool) !void {
|
||||||
_ = try self.handlers.msg(.{ "E", "open", file_path, file_exists, file_type, file_icon, file_color });
|
_ = try self.handlers.msg(.{ "E", "open", file_path, file_exists, file_type, file_icon, file_color, auto_save });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_editor_save(self: *const Self, file_path: []const u8) !void {
|
fn send_editor_save(self: *const Self, file_path: []const u8, auto_save: bool) !void {
|
||||||
_ = try self.handlers.msg(.{ "E", "save", file_path });
|
_ = try self.handlers.msg(.{ "E", "save", file_path, auto_save });
|
||||||
if (self.syntax) |_| project_manager.did_save(file_path) catch {};
|
if (self.syntax) |_| project_manager.did_save(file_path) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1765,6 +1764,10 @@ pub const Editor = struct {
|
||||||
_ = try self.handlers.msg(.{ "E", "dirty", file_dirty });
|
_ = try self.handlers.msg(.{ "E", "dirty", file_dirty });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn send_editor_auto_save(self: *const Self, auto_save: bool) !void {
|
||||||
|
_ = try self.handlers.msg(.{ "E", "auto_save", auto_save });
|
||||||
|
}
|
||||||
|
|
||||||
fn token_from(p: ?*const anyopaque) usize {
|
fn token_from(p: ?*const anyopaque) usize {
|
||||||
return if (p) |p_| @intFromPtr(p_) else 0;
|
return if (p) |p_| @intFromPtr(p_) else 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1781,7 +1784,7 @@ pub const Editor = struct {
|
||||||
_ = 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.buffer) |buffer| 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, buffer.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.buffer) |b| if (b.is_auto_save())
|
||||||
tp.self_pid().send(.{ "cmd", "save_file", .{} }) catch {};
|
tp.self_pid().send(.{ "cmd", "save_file", .{} }) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5005,7 +5008,14 @@ pub const Editor = struct {
|
||||||
pub const SaveOption = enum { default, format, no_format };
|
pub const SaveOption = enum { default, format, no_format };
|
||||||
|
|
||||||
pub fn toggle_auto_save(self: *Self, _: Context) Result {
|
pub fn toggle_auto_save(self: *Self, _: Context) Result {
|
||||||
self.enable_auto_save = !self.enable_auto_save;
|
const buffer = self.buffer orelse return;
|
||||||
|
if (!buffer.is_auto_save())
|
||||||
|
buffer.enable_auto_save()
|
||||||
|
else
|
||||||
|
buffer.disable_auto_save();
|
||||||
|
self.send_editor_auto_save(buffer.is_auto_save()) catch {};
|
||||||
|
if (buffer.is_auto_save())
|
||||||
|
tp.self_pid().send(.{ "cmd", "save_file", .{} }) catch {};
|
||||||
}
|
}
|
||||||
pub const toggle_auto_save_meta: Meta = .{ .description = "Toggle auto save" };
|
pub const toggle_auto_save_meta: Meta = .{ .description = "Toggle auto save" };
|
||||||
|
|
||||||
|
|
@ -6136,7 +6146,8 @@ pub const Editor = struct {
|
||||||
buffer.file_type_color = ftc;
|
buffer.file_type_color = ftc;
|
||||||
}
|
}
|
||||||
const file_exists = if (self.buffer) |b| b.file_exists else false;
|
const file_exists = if (self.buffer) |b| b.file_exists else false;
|
||||||
try self.send_editor_open(self.file_path orelse "", file_exists, ftn, fti, ftc);
|
const auto_save = if (self.buffer) |b| b.is_auto_save() else false;
|
||||||
|
try self.send_editor_open(self.file_path orelse "", file_exists, ftn, fti, ftc, auto_save);
|
||||||
self.logger.print("file type {s}", .{file_type});
|
self.logger.print("file type {s}", .{file_type});
|
||||||
}
|
}
|
||||||
pub const set_file_type_meta: Meta = .{ .arguments = &.{.string} };
|
pub const set_file_type_meta: Meta = .{ .arguments = &.{.string} };
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ 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,
|
indent_mode: config.IndentMode = .spaces,
|
||||||
|
auto_save: bool = false,
|
||||||
|
|
||||||
const project_icon = "";
|
const project_icon = "";
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
@ -141,7 +142,7 @@ fn render_normal(self: *Self, plane: *Plane, theme: *const Widget.Theme) void {
|
||||||
self.render_file_icon(plane, theme);
|
self.render_file_icon(plane, theme);
|
||||||
_ = plane.print(" ", .{}) catch {};
|
_ = plane.print(" ", .{}) catch {};
|
||||||
}
|
}
|
||||||
_ = plane.putstr(if (!self.file_exists) " " else if (self.file_dirty) " " else "") catch {};
|
_ = plane.putstr(if (!self.file_exists) " " else if (self.auto_save) " " else if (self.file_dirty) " " else "") catch {};
|
||||||
_ = plane.print("{s}", .{self.name}) catch {};
|
_ = plane.print("{s}", .{self.name}) catch {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +167,7 @@ fn render_detailed(self: *Self, plane: *Plane, theme: *const Widget.Theme) void
|
||||||
.tabs => "[⭾ = ␉]",
|
.tabs => "[⭾ = ␉]",
|
||||||
};
|
};
|
||||||
|
|
||||||
_ = plane.putstr(if (!self.file_exists) "" else if (self.file_dirty) "" else "") catch {};
|
_ = plane.putstr(if (!self.file_exists) "" else if (self.auto_save) "" 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)
|
||||||
|
|
@ -225,15 +226,26 @@ fn process_event(self: *Self, m: tp.message) error{Exit}!bool {
|
||||||
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, "auto_save", tp.extract(&self.auto_save) })) {
|
||||||
|
//
|
||||||
} else if (try m.match(.{ tp.any, "eol_mode", tp.extract(&self.eol_mode), tp.extract(&self.utf8_sanitized), tp.extract(&self.indent_mode) })) {
|
} else if (try m.match(.{ tp.any, "eol_mode", tp.extract(&self.eol_mode), tp.extract(&self.utf8_sanitized), tp.extract(&self.indent_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), tp.extract(&self.auto_save) })) {
|
||||||
@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];
|
||||||
self.file_exists = true;
|
self.file_exists = true;
|
||||||
self.file_dirty = false;
|
self.file_dirty = false;
|
||||||
self.name = project_manager.abbreviate_home(&self.name_buf, self.name);
|
self.name = project_manager.abbreviate_home(&self.name_buf, self.name);
|
||||||
} else if (try m.match(.{ tp.any, "open", tp.extract(&file_path), tp.extract(&self.file_exists), tp.extract(&file_type), tp.extract(&file_icon), tp.extract(&self.file_color) })) {
|
} else if (try m.match(.{
|
||||||
|
tp.any,
|
||||||
|
"open",
|
||||||
|
tp.extract(&file_path),
|
||||||
|
tp.extract(&self.file_exists),
|
||||||
|
tp.extract(&file_type),
|
||||||
|
tp.extract(&file_icon),
|
||||||
|
tp.extract(&self.file_color),
|
||||||
|
tp.extract(&self.auto_save),
|
||||||
|
})) {
|
||||||
self.eol_mode = .lf;
|
self.eol_mode = .lf;
|
||||||
@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];
|
||||||
|
|
|
||||||
|
|
@ -628,6 +628,7 @@ const Tab = struct {
|
||||||
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
|
const buffer_manager = tui.get_buffer_manager() orelse @panic("tabs no buffer manager");
|
||||||
const buffer_ = buffer_manager.buffer_from_ref(self.buffer_ref);
|
const buffer_ = buffer_manager.buffer_from_ref(self.buffer_ref);
|
||||||
const is_dirty = if (buffer_) |buffer| buffer.is_dirty() else false;
|
const is_dirty = if (buffer_) |buffer| buffer.is_dirty() else false;
|
||||||
|
const auto_save = if (buffer_) |buffer| buffer.is_auto_save() else false;
|
||||||
self.render_padding(plane, .left);
|
self.render_padding(plane, .left);
|
||||||
if (self.tab_style.file_type_icon) if (buffer_) |buffer| if (buffer.file_type_icon) |icon| {
|
if (self.tab_style.file_type_icon) if (buffer_) |buffer| if (buffer.file_type_icon) |icon| {
|
||||||
const color_: ?u24 = if (buffer.file_type_color) |color| if (!(color == 0xFFFFFF or color == 0x000000 or color == 0x000001)) color else null else null;
|
const color_: ?u24 = if (buffer.file_type_color) |color| if (!(color == 0xFFFFFF or color == 0x000000 or color == 0x000001)) color else null else null;
|
||||||
|
|
@ -653,7 +654,7 @@ const Tab = struct {
|
||||||
self.close_pos = plane.cursor_x();
|
self.close_pos = plane.cursor_x();
|
||||||
_ = plane.putstr(self.tabbar.tab_style.close_icon) catch {};
|
_ = plane.putstr(self.tabbar.tab_style.close_icon) catch {};
|
||||||
}
|
}
|
||||||
} else if (is_dirty) {
|
} else if (is_dirty and !auto_save) {
|
||||||
if (self.tab_style.dirty_indicator_fg) |color|
|
if (self.tab_style.dirty_indicator_fg) |color|
|
||||||
plane.set_style(.{ .fg = color.from_theme(theme) });
|
plane.set_style(.{ .fg = color.from_theme(theme) });
|
||||||
_ = plane.putstr(self.tabbar.tab_style.dirty_indicator) catch {};
|
_ = plane.putstr(self.tabbar.tab_style.dirty_indicator) catch {};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue