Merge branch 'master' into zig-0.15.0
This commit is contained in:
commit
6e6d6daed9
14 changed files with 195 additions and 61 deletions
|
@ -413,11 +413,11 @@ pub fn walk_tree_entry(self: *Self, file_path: []const u8, mtime: i128) OutOfMem
|
||||||
(try self.pending.addOne(self.allocator)).* = .{ .path = try self.allocator.dupe(u8, file_path), .mtime = mtime };
|
(try self.pending.addOne(self.allocator)).* = .{ .path = try self.allocator.dupe(u8, file_path), .mtime = mtime };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn walk_tree_done(self: *Self) OutOfMemoryError!void {
|
pub fn walk_tree_done(self: *Self, parent: tp.pid_ref) OutOfMemoryError!void {
|
||||||
self.state.walk_tree = .done;
|
self.state.walk_tree = .done;
|
||||||
if (self.walker) |pid| pid.deinit();
|
if (self.walker) |pid| pid.deinit();
|
||||||
self.walker = null;
|
self.walker = null;
|
||||||
return self.loaded();
|
return self.loaded(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_pending_files(self: *Self) OutOfMemoryError!void {
|
fn merge_pending_files(self: *Self) OutOfMemoryError!void {
|
||||||
|
@ -433,7 +433,7 @@ fn merge_pending_files(self: *Self) OutOfMemoryError!void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loaded(self: *Self) OutOfMemoryError!void {
|
fn loaded(self: *Self, parent: tp.pid_ref) OutOfMemoryError!void {
|
||||||
inline for (@typeInfo(@TypeOf(self.state)).@"struct".fields) |f|
|
inline for (@typeInfo(@TypeOf(self.state)).@"struct".fields) |f|
|
||||||
if (@field(self.state, f.name) == .running) return;
|
if (@field(self.state, f.name) == .running) return;
|
||||||
|
|
||||||
|
@ -449,6 +449,8 @@ fn loaded(self: *Self) OutOfMemoryError!void {
|
||||||
self.files.items.len,
|
self.files.items.len,
|
||||||
std.time.milliTimestamp() - self.open_time,
|
std.time.milliTimestamp() - self.open_time,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
parent.send(.{ "PRJ", "open_done", self.name, self.longest_file_path, self.files.items.len }) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_mru(self: *Self, file_path: []const u8, row: usize, col: usize) OutOfMemoryError!void {
|
pub fn update_mru(self: *Self, file_path: []const u8, row: usize, col: usize) OutOfMemoryError!void {
|
||||||
|
@ -1913,13 +1915,13 @@ fn start_walker(self: *Self) void {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn process_git(self: *Self, m: tp.message) (OutOfMemoryError || error{Exit})!void {
|
pub fn process_git(self: *Self, parent: tp.pid_ref, m: tp.message) (OutOfMemoryError || error{Exit})!void {
|
||||||
var value: []const u8 = undefined;
|
var value: []const u8 = undefined;
|
||||||
var path: []const u8 = undefined;
|
var path: []const u8 = undefined;
|
||||||
if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.null_ })) {
|
if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.null_ })) {
|
||||||
self.state.workspace_path = .done;
|
self.state.workspace_path = .done;
|
||||||
self.start_walker();
|
self.start_walker();
|
||||||
try self.loaded();
|
try self.loaded(parent);
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.extract(&value) })) {
|
} else if (try m.match(.{ tp.any, tp.any, "workspace_path", tp.extract(&value) })) {
|
||||||
if (self.workspace) |p| self.allocator.free(p);
|
if (self.workspace) |p| self.allocator.free(p);
|
||||||
self.workspace = try self.allocator.dupe(u8, value);
|
self.workspace = try self.allocator.dupe(u8, value);
|
||||||
|
@ -1930,19 +1932,19 @@ pub fn process_git(self: *Self, m: tp.message) (OutOfMemoryError || error{Exit})
|
||||||
};
|
};
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "current_branch", tp.null_ })) {
|
} else if (try m.match(.{ tp.any, tp.any, "current_branch", tp.null_ })) {
|
||||||
self.state.current_branch = .done;
|
self.state.current_branch = .done;
|
||||||
try self.loaded();
|
try self.loaded(parent);
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "current_branch", tp.extract(&value) })) {
|
} else if (try m.match(.{ tp.any, tp.any, "current_branch", tp.extract(&value) })) {
|
||||||
if (self.branch) |p| self.allocator.free(p);
|
if (self.branch) |p| self.allocator.free(p);
|
||||||
self.branch = try self.allocator.dupe(u8, value);
|
self.branch = try self.allocator.dupe(u8, value);
|
||||||
self.state.current_branch = .done;
|
self.state.current_branch = .done;
|
||||||
try self.loaded();
|
try self.loaded(parent);
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.extract(&path) })) {
|
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.extract(&path) })) {
|
||||||
self.longest_file_path = @max(self.longest_file_path, path.len);
|
self.longest_file_path = @max(self.longest_file_path, path.len);
|
||||||
const stat = std.fs.cwd().statFile(path) catch return;
|
const stat = std.fs.cwd().statFile(path) catch return;
|
||||||
(try self.pending.addOne(self.allocator)).* = .{ .path = try self.allocator.dupe(u8, path), .mtime = stat.mtime };
|
(try self.pending.addOne(self.allocator)).* = .{ .path = try self.allocator.dupe(u8, path), .mtime = stat.mtime };
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.null_ })) {
|
} else if (try m.match(.{ tp.any, tp.any, "workspace_files", tp.null_ })) {
|
||||||
self.state.workspace_files = .done;
|
self.state.workspace_files = .done;
|
||||||
try self.loaded();
|
try self.loaded(parent);
|
||||||
} else {
|
} else {
|
||||||
self.logger_git.err("git", tp.unexpected(m));
|
self.logger_git.err("git", tp.unexpected(m));
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,7 @@ external_allocator: Allocator,
|
||||||
root: Root,
|
root: Root,
|
||||||
leaves_buf: ?[]Node = null,
|
leaves_buf: ?[]Node = null,
|
||||||
file_buf: ?[]const u8 = null,
|
file_buf: ?[]const u8 = null,
|
||||||
file_path: []const u8 = "",
|
file_path_buf: std.ArrayListUnmanaged(u8) = .empty,
|
||||||
last_save: ?Root = null,
|
last_save: ?Root = null,
|
||||||
file_exists: bool = true,
|
file_exists: bool = true,
|
||||||
file_eol_mode: EolMode = .lf,
|
file_eol_mode: EolMode = .lf,
|
||||||
|
@ -1084,6 +1084,7 @@ pub fn deinit(self: *Self) void {
|
||||||
if (self.meta) |buf| self.external_allocator.free(buf);
|
if (self.meta) |buf| self.external_allocator.free(buf);
|
||||||
if (self.file_buf) |buf| self.external_allocator.free(buf);
|
if (self.file_buf) |buf| self.external_allocator.free(buf);
|
||||||
if (self.leaves_buf) |buf| self.external_allocator.free(buf);
|
if (self.leaves_buf) |buf| self.external_allocator.free(buf);
|
||||||
|
self.file_path_buf.deinit(self.external_allocator);
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
self.external_allocator.destroy(self);
|
self.external_allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
@ -1098,6 +1099,17 @@ pub fn get_meta(self: *Self) ?[]const u8 {
|
||||||
return self.meta;
|
return self.meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_file_path(self: *Self, file_path: []const u8) void {
|
||||||
|
self.file_path_buf.clearRetainingCapacity();
|
||||||
|
self.file_path_buf.appendSlice(self.external_allocator, file_path) catch |e| switch (e) {
|
||||||
|
error.OutOfMemory => @panic("OOM in Buffer.set_file_path"),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn get_file_path(self: *const Self) []const u8 {
|
||||||
|
return self.file_path_buf.items;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_last_used_time(self: *Self) void {
|
pub fn update_last_used_time(self: *Self) void {
|
||||||
self.utime = std.time.milliTimestamp();
|
self.utime = std.time.milliTimestamp();
|
||||||
}
|
}
|
||||||
|
@ -1177,13 +1189,20 @@ pub fn load_from_string(self: *const Self, s: []const u8, eol_mode: *EolMode, ut
|
||||||
|
|
||||||
pub fn load_from_string_and_update(self: *Self, file_path: []const u8, s: []const u8) LoadFromStringError!void {
|
pub fn load_from_string_and_update(self: *Self, file_path: []const u8, s: []const u8) LoadFromStringError!void {
|
||||||
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
|
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
|
||||||
self.file_path = try self.allocator.dupe(u8, file_path);
|
self.set_file_path(file_path);
|
||||||
self.last_save = self.root;
|
self.last_save = self.root;
|
||||||
self.last_save_eol_mode = self.file_eol_mode;
|
self.last_save_eol_mode = self.file_eol_mode;
|
||||||
self.file_exists = false;
|
self.file_exists = false;
|
||||||
self.mtime = std.time.milliTimestamp();
|
self.mtime = std.time.milliTimestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn reset_from_string_and_update(self: *Self, s: []const u8) LoadFromStringError!void {
|
||||||
|
self.root = try self.load_from_string(s, &self.file_eol_mode, &self.file_utf8_sanitized);
|
||||||
|
self.last_save = self.root;
|
||||||
|
self.last_save_eol_mode = self.file_eol_mode;
|
||||||
|
self.mtime = std.time.milliTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
pub const LoadFromFileError = error{
|
pub const LoadFromFileError = error{
|
||||||
OutOfMemory,
|
OutOfMemory,
|
||||||
Unexpected,
|
Unexpected,
|
||||||
|
@ -1251,7 +1270,7 @@ pub fn load_from_file_and_update(self: *Self, file_path: []const u8) LoadFromFil
|
||||||
var eol_mode: EolMode = .lf;
|
var eol_mode: EolMode = .lf;
|
||||||
var utf8_sanitized: bool = false;
|
var utf8_sanitized: bool = false;
|
||||||
self.root = try self.load_from_file(file_path, &file_exists, &eol_mode, &utf8_sanitized);
|
self.root = try self.load_from_file(file_path, &file_exists, &eol_mode, &utf8_sanitized);
|
||||||
self.file_path = try self.allocator.dupe(u8, file_path);
|
self.set_file_path(file_path);
|
||||||
self.last_save = self.root;
|
self.last_save = self.root;
|
||||||
self.file_exists = file_exists;
|
self.file_exists = file_exists;
|
||||||
self.file_eol_mode = eol_mode;
|
self.file_eol_mode = eol_mode;
|
||||||
|
@ -1270,7 +1289,7 @@ pub fn reset_to_last_saved(self: *Self) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn refresh_from_file(self: *Self) LoadFromFileError!void {
|
pub fn refresh_from_file(self: *Self) LoadFromFileError!void {
|
||||||
try self.load_from_file_and_update(self.file_path);
|
try self.load_from_file_and_update(self.get_file_path());
|
||||||
self.update_last_used_time();
|
self.update_last_used_time();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1362,7 +1381,7 @@ pub fn store_to_file_and_clean(self: *Self, file_path: []const u8) StoreToFileEr
|
||||||
self.file_utf8_sanitized = false;
|
self.file_utf8_sanitized = false;
|
||||||
if (self.ephemeral) {
|
if (self.ephemeral) {
|
||||||
self.ephemeral = false;
|
self.ephemeral = false;
|
||||||
self.file_path = try self.allocator.dupe(u8, file_path);
|
self.set_file_path(file_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1370,6 +1389,10 @@ pub fn mark_clean(self: *Self) void {
|
||||||
self.last_save = self.root;
|
self.last_save = self.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mark_dirty(self: *Self) void {
|
||||||
|
self.last_save = null;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn is_hidden(self: *const Self) bool {
|
pub fn is_hidden(self: *const Self) bool {
|
||||||
return self.hidden;
|
return self.hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,15 +64,15 @@ 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.get_file_path(), "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
|
||||||
if (meta) |buf| tp.trace(tp.channel.debug, tp.message{ .buf = buf });
|
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 {
|
||||||
buffer.hidden = true;
|
buffer.hidden = true;
|
||||||
tp.trace(tp.channel.debug, .{ "buffer", "close", buffer.file_path, "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
|
tp.trace(tp.channel.debug, .{ "buffer", "close", buffer.get_file_path(), "hidden", buffer.hidden, "ephemeral", buffer.ephemeral });
|
||||||
if (buffer.is_ephemeral()) {
|
if (buffer.is_ephemeral()) {
|
||||||
_ = self.buffers.remove(buffer.file_path);
|
_ = self.buffers.remove(buffer.get_file_path());
|
||||||
buffer.deinit();
|
buffer.deinit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,7 +116,7 @@ pub fn save_all(self: *const Self) Buffer.StoreToFileError!void {
|
||||||
if (buffer.is_ephemeral())
|
if (buffer.is_ephemeral())
|
||||||
buffer.mark_clean()
|
buffer.mark_clean()
|
||||||
else
|
else
|
||||||
try buffer.store_to_file_and_clean(buffer.file_path);
|
try buffer.store_to_file_and_clean(buffer.get_file_path());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -341,10 +341,10 @@ const Process = struct {
|
||||||
project.walk_tree_entry(path, mtime) catch |e| self.logger.err("walk_tree_entry", e);
|
project.walk_tree_entry(path, mtime) catch |e| self.logger.err("walk_tree_entry", e);
|
||||||
} else if (try cbor.match(m.buf, .{ "walk_tree_done", tp.extract(&project_directory) })) {
|
} else if (try cbor.match(m.buf, .{ "walk_tree_done", tp.extract(&project_directory) })) {
|
||||||
if (self.projects.get(project_directory)) |project|
|
if (self.projects.get(project_directory)) |project|
|
||||||
project.walk_tree_done() catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
project.walk_tree_done(self.parent.ref()) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "git", tp.extract(&context), tp.more })) {
|
} else if (try cbor.match(m.buf, .{ "git", tp.extract(&context), tp.more })) {
|
||||||
const project: *Project = @ptrFromInt(context);
|
const project: *Project = @ptrFromInt(context);
|
||||||
project.process_git(m) catch {};
|
project.process_git(self.parent.ref(), m) catch {};
|
||||||
} else if (try cbor.match(m.buf, .{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
} else if (try cbor.match(m.buf, .{ "update_mru", tp.extract(&project_directory), tp.extract(&path), tp.extract(&row), tp.extract(&col) })) {
|
||||||
self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
self.update_mru(project_directory, path, row, col) catch |e| return from.forward_error(e, @errorReturnTrace()) catch error.ClientFailed;
|
||||||
} else if (try cbor.match(m.buf, .{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
|
} else if (try cbor.match(m.buf, .{ "child", tp.extract(&project_directory), tp.extract(&language_server), "notify", tp.extract(&method), tp.extract_cbor(¶ms_cb) })) {
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub const Handlers = struct {
|
||||||
err: ?*const OutputHandler = null,
|
err: ?*const OutputHandler = null,
|
||||||
exit: *const ExitHandler = log_exit_handler,
|
exit: *const ExitHandler = log_exit_handler,
|
||||||
log_execute: bool = true,
|
log_execute: bool = true,
|
||||||
|
line_buffered: bool = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn execute(allocator: std.mem.Allocator, argv: tp.message, handlers: Handlers) Error!void {
|
pub fn execute(allocator: std.mem.Allocator, argv: tp.message, handlers: Handlers) Error!void {
|
||||||
|
@ -145,6 +146,8 @@ const Process = struct {
|
||||||
logger: log.Logger,
|
logger: log.Logger,
|
||||||
stdin_behavior: std.process.Child.StdIo,
|
stdin_behavior: std.process.Child.StdIo,
|
||||||
handlers: Handlers,
|
handlers: Handlers,
|
||||||
|
stdout_line_buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||||
|
stderr_line_buffer: std.ArrayListUnmanaged(u8) = .empty,
|
||||||
|
|
||||||
const Receiver = tp.Receiver(*Process);
|
const Receiver = tp.Receiver(*Process);
|
||||||
|
|
||||||
|
@ -181,6 +184,8 @@ const Process = struct {
|
||||||
self.logger.deinit();
|
self.logger.deinit();
|
||||||
self.allocator.free(self.arg0);
|
self.allocator.free(self.arg0);
|
||||||
self.allocator.free(self.argv.buf);
|
self.allocator.free(self.argv.buf);
|
||||||
|
self.stdout_line_buffer.deinit(self.allocator);
|
||||||
|
self.stderr_line_buffer.deinit(self.allocator);
|
||||||
self.allocator.destroy(self);
|
self.allocator.destroy(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,9 +220,9 @@ const Process = struct {
|
||||||
} else if (try m.match(.{"close"})) {
|
} else if (try m.match(.{"close"})) {
|
||||||
self.close();
|
self.close();
|
||||||
} else if (try m.match(.{ module_name, "stdout", tp.extract(&bytes) })) {
|
} else if (try m.match(.{ module_name, "stdout", tp.extract(&bytes) })) {
|
||||||
self.handlers.out(self.handlers.context, self.parent.ref(), self.arg0, bytes);
|
self.handle_stdout(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
} else if (try m.match(.{ module_name, "stderr", tp.extract(&bytes) })) {
|
} else if (try m.match(.{ module_name, "stderr", tp.extract(&bytes) })) {
|
||||||
(self.handlers.err orelse self.handlers.out)(self.handlers.context, self.parent.ref(), self.arg0, bytes);
|
self.handle_stderr(bytes) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
} else if (try m.match(.{ module_name, "term", tp.more })) {
|
} else if (try m.match(.{ module_name, "term", tp.more })) {
|
||||||
defer self.sp = null;
|
defer self.sp = null;
|
||||||
self.handle_terminated(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
self.handle_terminated(m) catch |e| return tp.exit_error(e, @errorReturnTrace());
|
||||||
|
@ -231,9 +236,57 @@ const Process = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_stdout(self: *Process, bytes: []const u8) error{OutOfMemory}!void {
|
||||||
|
return if (!self.handlers.line_buffered)
|
||||||
|
self.handlers.out(self.handlers.context, self.parent.ref(), self.arg0, bytes)
|
||||||
|
else
|
||||||
|
self.handle_buffered_output(self.handlers.out, &self.stdout_line_buffer, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_stderr(self: *Process, bytes: []const u8) error{OutOfMemory}!void {
|
||||||
|
const handler = self.handlers.err orelse self.handlers.out;
|
||||||
|
return if (!self.handlers.line_buffered)
|
||||||
|
handler(self.handlers.context, self.parent.ref(), self.arg0, bytes)
|
||||||
|
else
|
||||||
|
self.handle_buffered_output(handler, &self.stderr_line_buffer, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_buffered_output(self: *Process, handler: *const OutputHandler, buffer: *std.ArrayListUnmanaged(u8), bytes: []const u8) error{OutOfMemory}!void {
|
||||||
|
var it = std.mem.splitScalar(u8, bytes, '\n');
|
||||||
|
var have_nl = false;
|
||||||
|
var prev = it.first();
|
||||||
|
while (it.next()) |next| {
|
||||||
|
have_nl = true;
|
||||||
|
try buffer.appendSlice(self.allocator, prev);
|
||||||
|
try buffer.append(self.allocator, '\n');
|
||||||
|
prev = next;
|
||||||
|
}
|
||||||
|
if (have_nl) {
|
||||||
|
handler(self.handlers.context, self.parent.ref(), self.arg0, buffer.items);
|
||||||
|
buffer.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
try buffer.appendSlice(self.allocator, prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_stdout(self: *Process) void {
|
||||||
|
self.flush_buffer(self.handlers.out, &self.stdout_line_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_stderr(self: *Process) void {
|
||||||
|
self.flush_buffer(self.handlers.err orelse self.handlers.out, &self.stderr_line_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush_buffer(self: *Process, handler: *const OutputHandler, buffer: *std.ArrayListUnmanaged(u8)) void {
|
||||||
|
if (!self.handlers.line_buffered) return;
|
||||||
|
if (buffer.items.len > 0) handler(self.handlers.context, self.parent.ref(), self.arg0, buffer.items);
|
||||||
|
buffer.clearRetainingCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_terminated(self: *Process, m: tp.message) !void {
|
fn handle_terminated(self: *Process, m: tp.message) !void {
|
||||||
var err_msg: []const u8 = undefined;
|
var err_msg: []const u8 = undefined;
|
||||||
var exit_code: i64 = undefined;
|
var exit_code: i64 = undefined;
|
||||||
|
self.flush_stdout();
|
||||||
|
self.flush_stderr();
|
||||||
if (try m.match(.{ tp.any, tp.any, "exited", 0 })) {
|
if (try m.match(.{ tp.any, tp.any, "exited", 0 })) {
|
||||||
self.handlers.exit(self.handlers.context, self.parent.ref(), self.arg0, "exited", 0);
|
self.handlers.exit(self.handlers.context, self.parent.ref(), self.arg0, "exited", 0);
|
||||||
} else if (try m.match(.{ tp.any, tp.any, "error.FileNotFound", 1 })) {
|
} else if (try m.match(.{ tp.any, tp.any, "error.FileNotFound", 1 })) {
|
||||||
|
|
|
@ -722,15 +722,6 @@ pub const Editor = struct {
|
||||||
self.update_event() catch {};
|
self.update_event() catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save_as(self: *Self, file_path: []const u8) !void {
|
|
||||||
if (self.buffer) |b_mut| try b_mut.store_to_file_and_clean(file_path);
|
|
||||||
if (self.file_path) |old_file_path| self.allocator.free(old_file_path);
|
|
||||||
self.file_path = try self.allocator.dupe(u8, file_path);
|
|
||||||
try self.send_editor_save(self.file_path.?);
|
|
||||||
self.last.dirty = false;
|
|
||||||
self.update_event() catch {};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_cursor(self: *Self) !void {
|
pub fn push_cursor(self: *Self) !void {
|
||||||
const primary = self.cursels.getLastOrNull() orelse CurSel{} orelse CurSel{};
|
const primary = self.cursels.getLastOrNull() orelse CurSel{} orelse CurSel{};
|
||||||
(try self.cursels.addOne(self.allocator)).* = primary;
|
(try self.cursels.addOne(self.allocator)).* = primary;
|
||||||
|
@ -4950,14 +4941,6 @@ pub const Editor = struct {
|
||||||
}
|
}
|
||||||
pub const save_file_without_formatting_meta: Meta = .{ .description = "Save file without formatting" };
|
pub const save_file_without_formatting_meta: Meta = .{ .description = "Save file without formatting" };
|
||||||
|
|
||||||
pub fn save_file_as(self: *Self, ctx: Context) Result {
|
|
||||||
var file_path: []const u8 = undefined;
|
|
||||||
if (ctx.args.match(.{tp.extract(&file_path)}) catch false) {
|
|
||||||
try self.save_as(file_path);
|
|
||||||
} else return error.InvalidSafeFileAsArgument;
|
|
||||||
}
|
|
||||||
pub const save_file_as_meta: Meta = .{ .arguments = &.{.string} };
|
|
||||||
|
|
||||||
pub fn close_file(self: *Self, _: Context) Result {
|
pub fn close_file(self: *Self, _: Context) Result {
|
||||||
const buffer_ = self.buffer;
|
const buffer_ = self.buffer;
|
||||||
if (buffer_) |buffer| if (buffer.is_dirty())
|
if (buffer_) |buffer| if (buffer.is_dirty())
|
||||||
|
|
|
@ -564,6 +564,48 @@ const cmds = struct {
|
||||||
}
|
}
|
||||||
pub const create_new_file_meta: Meta = .{ .description = "New file" };
|
pub const create_new_file_meta: Meta = .{ .description = "New file" };
|
||||||
|
|
||||||
|
pub fn save_file_as(self: *Self, ctx: Ctx) Result {
|
||||||
|
var file_path: []const u8 = undefined;
|
||||||
|
if (!(ctx.args.match(.{tp.extract(&file_path)}) catch false))
|
||||||
|
return error.InvalidSafeFileAsArgument;
|
||||||
|
|
||||||
|
if (self.get_active_editor()) |editor| {
|
||||||
|
const buffer = editor.buffer orelse return;
|
||||||
|
var content = std.ArrayListUnmanaged(u8).empty;
|
||||||
|
defer content.deinit(self.allocator);
|
||||||
|
try buffer.root.store(content.writer(self.allocator), buffer.file_eol_mode);
|
||||||
|
|
||||||
|
var existing = false;
|
||||||
|
if (self.buffer_manager.get_buffer_for_file(file_path)) |new_buffer| {
|
||||||
|
if (new_buffer.is_dirty())
|
||||||
|
return tp.exit("save as would overwrite unsaved changes");
|
||||||
|
if (buffer == new_buffer)
|
||||||
|
return tp.exit("same file");
|
||||||
|
existing = true;
|
||||||
|
}
|
||||||
|
try self.create_editor();
|
||||||
|
try command.executeName("open_scratch_buffer", command.fmt(.{
|
||||||
|
file_path,
|
||||||
|
"",
|
||||||
|
buffer.file_type_name,
|
||||||
|
}));
|
||||||
|
if (self.get_active_editor()) |new_editor| {
|
||||||
|
const new_buffer = new_editor.buffer orelse return;
|
||||||
|
if (existing) new_editor.update_buf(new_buffer.root) catch {}; // store an undo point
|
||||||
|
try new_buffer.reset_from_string_and_update(content.items);
|
||||||
|
new_buffer.mark_not_ephemeral();
|
||||||
|
new_buffer.mark_dirty();
|
||||||
|
new_editor.clamp();
|
||||||
|
new_editor.update_buf(new_buffer.root) catch {};
|
||||||
|
tui.need_render();
|
||||||
|
}
|
||||||
|
try command.executeName("save_file", .{});
|
||||||
|
if (buffer.is_ephemeral() and !buffer.is_dirty())
|
||||||
|
_ = self.buffer_manager.close_buffer(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub const save_file_as_meta: Meta = .{ .arguments = &.{.string} };
|
||||||
|
|
||||||
pub fn delete_buffer(self: *Self, ctx: Ctx) Result {
|
pub fn delete_buffer(self: *Self, ctx: Ctx) Result {
|
||||||
var file_path: []const u8 = undefined;
|
var file_path: []const u8 = undefined;
|
||||||
if (!(ctx.args.match(.{tp.extract(&file_path)}) catch false))
|
if (!(ctx.args.match(.{tp.extract(&file_path)}) catch false))
|
||||||
|
@ -1274,11 +1316,11 @@ fn get_next_mru_buffer(self: *Self) ?[]const u8 {
|
||||||
defer self.allocator.free(buffers);
|
defer self.allocator.free(buffers);
|
||||||
const active_file_path = self.get_active_file_path();
|
const active_file_path = self.get_active_file_path();
|
||||||
for (buffers) |buffer| {
|
for (buffers) |buffer| {
|
||||||
if (active_file_path) |fp| if (std.mem.eql(u8, fp, buffer.file_path))
|
if (active_file_path) |fp| if (std.mem.eql(u8, fp, buffer.get_file_path()))
|
||||||
continue;
|
continue;
|
||||||
if (buffer.hidden)
|
if (buffer.hidden)
|
||||||
continue;
|
continue;
|
||||||
return buffer.file_path;
|
return buffer.get_file_path();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ const keybind = @import("keybind");
|
||||||
const project_manager = @import("project_manager");
|
const project_manager = @import("project_manager");
|
||||||
const command = @import("command");
|
const command = @import("command");
|
||||||
const EventHandler = @import("EventHandler");
|
const EventHandler = @import("EventHandler");
|
||||||
|
const Buffer = @import("Buffer");
|
||||||
|
|
||||||
const tui = @import("../../tui.zig");
|
const tui = @import("../../tui.zig");
|
||||||
const MessageFilter = @import("../../MessageFilter.zig");
|
const MessageFilter = @import("../../MessageFilter.zig");
|
||||||
|
@ -23,6 +24,7 @@ pub fn Create(options: type) type {
|
||||||
match: std.ArrayList(u8),
|
match: std.ArrayList(u8),
|
||||||
entries: std.ArrayList(Entry),
|
entries: std.ArrayList(Entry),
|
||||||
complete_trigger_count: usize = 0,
|
complete_trigger_count: usize = 0,
|
||||||
|
total_matches: usize = 0,
|
||||||
matched_entry: usize = 0,
|
matched_entry: usize = 0,
|
||||||
commands: Commands = undefined,
|
commands: Commands = undefined,
|
||||||
|
|
||||||
|
@ -171,14 +173,23 @@ pub fn Create(options: type) type {
|
||||||
fn do_complete(self: *Self) !void {
|
fn do_complete(self: *Self) !void {
|
||||||
self.complete_trigger_count = @min(self.complete_trigger_count, self.entries.items.len);
|
self.complete_trigger_count = @min(self.complete_trigger_count, self.entries.items.len);
|
||||||
self.file_path.clearRetainingCapacity();
|
self.file_path.clearRetainingCapacity();
|
||||||
|
const match_number = self.complete_trigger_count;
|
||||||
if (self.match.items.len > 0) {
|
if (self.match.items.len > 0) {
|
||||||
try self.match_path();
|
try self.match_path();
|
||||||
|
if (self.total_matches == 1)
|
||||||
|
self.complete_trigger_count = 0;
|
||||||
} else if (self.entries.items.len > 0) {
|
} else if (self.entries.items.len > 0) {
|
||||||
try self.construct_path(self.query.items, self.entries.items[self.complete_trigger_count - 1], self.complete_trigger_count - 1);
|
try self.construct_path(self.query.items, self.entries.items[self.complete_trigger_count - 1], self.complete_trigger_count - 1);
|
||||||
} else {
|
} else {
|
||||||
try self.construct_path(self.query.items, .{ .name = "", .type = .file }, 0);
|
try self.construct_path(self.query.items, .{ .name = "", .type = .file }, 0);
|
||||||
}
|
}
|
||||||
message("{d}/{d}", .{ self.matched_entry + 1, self.entries.items.len });
|
if (self.match.items.len > 0)
|
||||||
|
if (self.total_matches > 1)
|
||||||
|
message("{d}/{d} ({d}/{d} matches)", .{ self.matched_entry + 1, self.entries.items.len, match_number, self.total_matches })
|
||||||
|
else
|
||||||
|
message("{d}/{d} ({d} match)", .{ self.matched_entry + 1, self.entries.items.len, self.total_matches })
|
||||||
|
else
|
||||||
|
message("{d}/{d}", .{ self.matched_entry + 1, self.entries.items.len });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn construct_path(self: *Self, path_: []const u8, entry: Entry, entry_no: usize) error{OutOfMemory}!void {
|
fn construct_path(self: *Self, path_: []const u8, entry: Entry, entry_no: usize) error{OutOfMemory}!void {
|
||||||
|
@ -193,22 +204,23 @@ pub fn Create(options: type) type {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn match_path(self: *Self) !void {
|
fn match_path(self: *Self) !void {
|
||||||
|
var found_match: ?usize = null;
|
||||||
var matched: usize = 0;
|
var matched: usize = 0;
|
||||||
var last: ?Entry = null;
|
var last: ?Entry = null;
|
||||||
var last_no: usize = 0;
|
var last_no: usize = 0;
|
||||||
for (self.entries.items, 0..) |entry, i| {
|
for (self.entries.items, 0..) |entry, i| {
|
||||||
if (entry.name.len >= self.match.items.len and
|
if (try prefix_compare_icase(self.allocator, self.match.items, entry.name)) {
|
||||||
std.mem.eql(u8, self.match.items, entry.name[0..self.match.items.len]))
|
|
||||||
{
|
|
||||||
matched += 1;
|
matched += 1;
|
||||||
if (matched == self.complete_trigger_count) {
|
if (matched == self.complete_trigger_count) {
|
||||||
try self.construct_path(self.query.items, entry, i);
|
try self.construct_path(self.query.items, entry, i);
|
||||||
return;
|
found_match = i;
|
||||||
}
|
}
|
||||||
last = entry;
|
last = entry;
|
||||||
last_no = i;
|
last_no = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.total_matches = matched;
|
||||||
|
if (found_match) |_| return;
|
||||||
if (last) |entry| {
|
if (last) |entry| {
|
||||||
try self.construct_path(self.query.items, entry, last_no);
|
try self.construct_path(self.query.items, entry, last_no);
|
||||||
self.complete_trigger_count = matched;
|
self.complete_trigger_count = matched;
|
||||||
|
@ -218,6 +230,15 @@ pub fn Create(options: type) type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prefix_compare_icase(allocator: std.mem.Allocator, prefix: []const u8, str: []const u8) error{OutOfMemory}!bool {
|
||||||
|
const icase_prefix = Buffer.unicode.get_letter_casing().toLowerStr(allocator, prefix) catch try allocator.dupe(u8, prefix);
|
||||||
|
defer allocator.free(icase_prefix);
|
||||||
|
const icase_str = Buffer.unicode.get_letter_casing().toLowerStr(allocator, str) catch try allocator.dupe(u8, str);
|
||||||
|
defer allocator.free(icase_str);
|
||||||
|
if (icase_str.len < icase_prefix.len) return false;
|
||||||
|
return std.mem.eql(u8, icase_prefix, icase_str[0..icase_prefix.len]);
|
||||||
|
}
|
||||||
|
|
||||||
fn delete_to_previous_path_segment(self: *Self) void {
|
fn delete_to_previous_path_segment(self: *Self) void {
|
||||||
self.complete_trigger_count = 0;
|
self.complete_trigger_count = 0;
|
||||||
if (self.file_path.items.len == 0) return;
|
if (self.file_path.items.len == 0) return;
|
||||||
|
|
|
@ -37,12 +37,9 @@ pub fn select(self: *Type) void {
|
||||||
var buf = std.ArrayList(u8).init(self.allocator);
|
var buf = std.ArrayList(u8).init(self.allocator);
|
||||||
defer buf.deinit();
|
defer buf.deinit();
|
||||||
const file_path = project_manager.expand_home(&buf, self.file_path.items);
|
const file_path = project_manager.expand_home(&buf, self.file_path.items);
|
||||||
if (root.is_directory(file_path)) {
|
|
||||||
tp.self_pid().send(.{ "cmd", "exit_overlay_mode" }) catch return;
|
|
||||||
tp.self_pid().send(.{ "cmd", "change_project", .{file_path} }) catch {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (file_path.len > 0)
|
|
||||||
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch {};
|
|
||||||
command.executeName("exit_mini_mode", .{}) catch {};
|
command.executeName("exit_mini_mode", .{}) catch {};
|
||||||
|
if (root.is_directory(file_path))
|
||||||
|
tp.self_pid().send(.{ "cmd", "change_project", .{file_path} }) catch {}
|
||||||
|
else if (file_path.len > 0)
|
||||||
|
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = file_path } }) catch {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub fn load_entries(palette: *Type) !usize {
|
||||||
else
|
else
|
||||||
"";
|
"";
|
||||||
(try palette.entries.addOne()).* = .{
|
(try palette.entries.addOne()).* = .{
|
||||||
.label = buffer.file_path,
|
.label = buffer.get_file_path(),
|
||||||
.icon = buffer.file_type_icon orelse "",
|
.icon = buffer.file_type_icon orelse "",
|
||||||
.color = buffer.file_type_color,
|
.color = buffer.file_type_color,
|
||||||
.indicator = indicator,
|
.indicator = indicator,
|
||||||
|
|
|
@ -36,6 +36,8 @@ longest: usize = 0,
|
||||||
commands: Commands = undefined,
|
commands: Commands = undefined,
|
||||||
buffer_manager: ?*BufferManager,
|
buffer_manager: ?*BufferManager,
|
||||||
|
|
||||||
|
const inputbox_label = "Search files by name";
|
||||||
|
|
||||||
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
||||||
const mv = tui.mainview() orelse return error.NotFound;
|
const mv = tui.mainview() orelse return error.NotFound;
|
||||||
const self = try allocator.create(Self);
|
const self = try allocator.create(Self);
|
||||||
|
@ -51,7 +53,7 @@ pub fn create(allocator: std.mem.Allocator) !tui.Mode {
|
||||||
.logger = log.logger(@typeName(Self)),
|
.logger = log.logger(@typeName(Self)),
|
||||||
.inputbox = (try self.menu.add_header(try InputBox.create(*Self, self.allocator, self.menu.menu.parent, .{
|
.inputbox = (try self.menu.add_header(try InputBox.create(*Self, self.allocator, self.menu.menu.parent, .{
|
||||||
.ctx = self,
|
.ctx = self,
|
||||||
.label = "Search files by name",
|
.label = inputbox_label,
|
||||||
}))).dynamic_cast(InputBox.State(*Self)) orelse unreachable,
|
}))).dynamic_cast(InputBox.State(*Self)) orelse unreachable,
|
||||||
.buffer_manager = tui.get_buffer_manager(),
|
.buffer_manager = tui.get_buffer_manager(),
|
||||||
};
|
};
|
||||||
|
@ -82,7 +84,7 @@ pub fn deinit(self: *Self) void {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn menu_width(self: *Self) usize {
|
inline fn menu_width(self: *Self) usize {
|
||||||
return @min(self.longest, max_menu_width()) + 2;
|
return @max(@min(self.longest, max_menu_width()) + 2, inputbox_label.len + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fn menu_pos_x(self: *Self) usize {
|
inline fn menu_pos_x(self: *Self) usize {
|
||||||
|
@ -198,6 +200,10 @@ fn process_project_manager(self: *Self, m: tp.message) MessageFilter.Error!void
|
||||||
self.need_reset = true;
|
self.need_reset = true;
|
||||||
if (!std.mem.eql(u8, self.inputbox.text.items, query))
|
if (!std.mem.eql(u8, self.inputbox.text.items, query))
|
||||||
try self.start_query();
|
try self.start_query();
|
||||||
|
} else if (try cbor.match(m.buf, .{ "PRJ", "open_done", tp.string, tp.extract(&self.longest), tp.any })) {
|
||||||
|
self.query_pending = false;
|
||||||
|
self.need_reset = true;
|
||||||
|
try self.start_query();
|
||||||
} else {
|
} else {
|
||||||
self.logger.err("receive", tp.unexpected(m));
|
self.logger.err("receive", tp.unexpected(m));
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,7 +153,7 @@ pub fn Create(options: type) type {
|
||||||
|
|
||||||
fn do_resize(self: *Self) void {
|
fn do_resize(self: *Self) void {
|
||||||
const screen = tui.screen();
|
const screen = tui.screen();
|
||||||
const w = @min(self.longest, max_menu_width) + 2 + 1 + self.longest_hint;
|
const w = @max(@min(self.longest, max_menu_width) + 2 + 1 + self.longest_hint, options.label.len + 2);
|
||||||
const x = if (screen.w > w) (screen.w - w) / 2 else 0;
|
const x = if (screen.w > w) (screen.w - w) / 2 else 0;
|
||||||
self.view_rows = get_view_rows(screen);
|
self.view_rows = get_view_rows(screen);
|
||||||
const h = @min(self.items + self.menu.header_count, self.view_rows + self.menu.header_count);
|
const h = @min(self.items + self.menu.header_count, self.view_rows + self.menu.header_count);
|
||||||
|
|
|
@ -265,7 +265,7 @@ const TabBar = struct {
|
||||||
fn navigate_to_tab(tab: *const TabBarTab) void {
|
fn navigate_to_tab(tab: *const TabBarTab) void {
|
||||||
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");
|
||||||
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.file_path } }) catch {};
|
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.get_file_path() } }) catch {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -298,13 +298,13 @@ const Tab = struct {
|
||||||
fn on_click(self: *@This(), _: *Button.State(@This())) void {
|
fn on_click(self: *@This(), _: *Button.State(@This())) void {
|
||||||
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");
|
||||||
if (buffer_manager.buffer_from_ref(self.buffer_ref)) |buffer|
|
if (buffer_manager.buffer_from_ref(self.buffer_ref)) |buffer|
|
||||||
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.file_path } }) catch {};
|
tp.self_pid().send(.{ "cmd", "navigate", .{ .file = buffer.get_file_path() } }) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_click2(self: *@This(), _: *Button.State(@This())) void {
|
fn on_click2(self: *@This(), _: *Button.State(@This())) void {
|
||||||
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");
|
||||||
if (buffer_manager.buffer_from_ref(self.buffer_ref)) |buffer|
|
if (buffer_manager.buffer_from_ref(self.buffer_ref)) |buffer|
|
||||||
tp.self_pid().send(.{ "cmd", "close_buffer", .{buffer.file_path} }) catch {};
|
tp.self_pid().send(.{ "cmd", "close_buffer", .{buffer.get_file_path()} }) catch {};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render(self: *@This(), btn: *Button.State(@This()), theme: *const Widget.Theme) bool {
|
fn render(self: *@This(), btn: *Button.State(@This()), theme: *const Widget.Theme) bool {
|
||||||
|
@ -450,7 +450,7 @@ const Tab = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn name_from_buffer(buffer: *Buffer) []const u8 {
|
fn name_from_buffer(buffer: *Buffer) []const u8 {
|
||||||
const file_path = buffer.file_path;
|
const file_path = buffer.get_file_path();
|
||||||
if (file_path.len > 0 and file_path[0] == '*')
|
if (file_path.len > 0 and file_path[0] == '*')
|
||||||
return file_path;
|
return file_path;
|
||||||
const basename_begin = std.mem.lastIndexOfScalar(u8, file_path, std.fs.path.sep);
|
const basename_begin = std.mem.lastIndexOfScalar(u8, file_path, std.fs.path.sep);
|
||||||
|
|
|
@ -196,7 +196,14 @@ fn init_input_namespace(self: *Self) InitError!void {
|
||||||
|
|
||||||
fn init_delayed(self: *Self) command.Result {
|
fn init_delayed(self: *Self) command.Result {
|
||||||
self.delayed_init_done = true;
|
self.delayed_init_done = true;
|
||||||
if (self.input_mode_) |_| {} else {
|
if (self.input_mode_) |_| {
|
||||||
|
if (self.delayed_init_input_mode) |delayed_init_input_mode| {
|
||||||
|
if (self.input_mode_outer_ == null) {
|
||||||
|
self.input_mode_outer_ = delayed_init_input_mode;
|
||||||
|
self.delayed_init_input_mode = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
if (self.delayed_init_input_mode) |delayed_init_input_mode| {
|
if (self.delayed_init_input_mode) |delayed_init_input_mode| {
|
||||||
try enter_input_mode(self, delayed_init_input_mode);
|
try enter_input_mode(self, delayed_init_input_mode);
|
||||||
self.delayed_init_input_mode = null;
|
self.delayed_init_input_mode = null;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue