diff --git a/src/Project.zig b/src/Project.zig index 1a7bd8b..90c6770 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -36,9 +36,13 @@ pub const LspOrClientError = (LspError || ClientError); const File = struct { path: []const u8, mtime: i128, + pos: FilePos = .{}, + visited: bool = false, +}; + +pub const FilePos = struct { row: usize = 0, col: usize = 0, - visited: bool = false, }; const Task = struct { @@ -94,9 +98,9 @@ pub fn write_state_v1(self: *Self, writer: anytype) !void { try cbor.writeArrayHeader(writer, 4); try cbor.writeValue(writer, file.path); try cbor.writeValue(writer, file.mtime); - try cbor.writeValue(writer, file.row); - try cbor.writeValue(writer, file.col); - tp.trace(tp.channel.debug, .{ "write_state_v1", "file", file.path, file.mtime, file.row, file.col }); + try cbor.writeValue(writer, file.pos.row); + try cbor.writeValue(writer, file.pos.col); + tp.trace(tp.channel.debug, .{ "write_state_v1", "file", file.path, file.mtime, file.pos.row, file.pos.col }); } try cbor.writeArrayHeader(writer, self.tasks.items.len); tp.trace(tp.channel.debug, .{ "write_state_v1", "tasks", self.tasks.items.len }); @@ -374,7 +378,7 @@ pub fn merge_pending_files(self: *Self) OutOfMemoryError!void { self.files = self.pending; self.pending = std.ArrayList(File).init(self.allocator); for (existing) |*file| { - self.update_mru_internal(file.path, file.mtime, file.row, file.col) catch {}; + self.update_mru_internal(file.path, file.mtime, file.pos.row, file.pos.col) catch {}; self.allocator.free(file.path); } self.allocator.free(existing); @@ -390,8 +394,8 @@ fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usi if (!std.mem.eql(u8, file.path, file_path)) continue; file.mtime = mtime; if (row != 0) { - file.row = row; - file.col = col; + file.pos.row = row; + file.pos.col = col; file.visited = true; } return; @@ -400,8 +404,7 @@ fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usi (try self.files.addOne()).* = .{ .path = try self.allocator.dupe(u8, file_path), .mtime = mtime, - .row = row, - .col = col, + .pos = .{ .row = row, .col = col }, .visited = true, }; } else { @@ -415,8 +418,7 @@ fn update_mru_internal(self: *Self, file_path: []const u8, mtime: i128, row: usi pub fn get_mru_position(self: *Self, from: tp.pid_ref, file_path: []const u8) ClientError!void { for (self.files.items) |*file| { if (!std.mem.eql(u8, file.path, file_path)) continue; - if (file.row != 0) - from.send(.{ "cmd", "goto_line_and_column", .{ file.row + 1, file.col + 1 } }) catch return error.ClientFailed; + from.send(.{ file.pos.row + 1, file.pos.col + 1 }) catch return error.ClientFailed; return; } } diff --git a/src/project_manager.zig b/src/project_manager.zig index caa62ef..362045e 100644 --- a/src/project_manager.zig +++ b/src/project_manager.zig @@ -16,6 +16,8 @@ const Self = @This(); const module_name = @typeName(Self); const request_timeout = std.time.ns_per_s * 5; +pub const FilePos = Project.FilePos; + pub const Error = ProjectError || ProjectManagerError; pub const ProjectError = error{NoProject}; @@ -226,11 +228,16 @@ pub fn update_mru(file_path: []const u8, row: usize, col: usize, ephemeral: bool return send(.{ "update_mru", project, file_path, row, col }); } -pub fn get_mru_position(file_path: []const u8) (ProjectManagerError || ProjectError)!void { +pub fn get_mru_position(allocator: std.mem.Allocator, file_path: []const u8) (ProjectManagerError || ProjectError || CallError || cbor.Error)!?Project.FilePos { + const frame = tracy.initZone(@src(), .{ .name = "get_mru_position" }); + defer frame.deinit(); const project = tp.env.get().str("project"); if (project.len == 0) return error.NoProject; - return send(.{ "get_mru_position", project, file_path }); + const rsp = try (try get()).pid.call(allocator, request_timeout, .{ "get_mru_position", project, file_path }); + defer allocator.free(rsp.buf); + var pos: Project.FilePos = undefined; + return if (try cbor.match(rsp.buf, .{ tp.extract(&pos.row), tp.extract(&pos.col) })) pos else null; } const Process = struct { diff --git a/src/syntax/src/file_types.zig b/src/syntax/src/file_types.zig index 7fa3e12..870c6b7 100644 --- a/src/syntax/src/file_types.zig +++ b/src/syntax/src/file_types.zig @@ -392,7 +392,7 @@ pub const php = .{ .extensions = .{"php"}, .comment = "//", .injections = "tree-sitter-php/queries/injections.scm", - .language_server = .{"intelephense", "--stdio"}, + .language_server = .{ "intelephense", "--stdio" }, }; pub const purescript = .{ diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 1cba0e1..7c34812 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -525,14 +525,26 @@ pub const Editor = struct { } fn open(self: *Self, file_path: []const u8) !void { - return self.open_buffer(file_path, try self.buffer_manager.open_file(file_path), null); + const buffer: *Buffer = blk: { + const frame = tracy.initZone(@src(), .{ .name = "open_file" }); + defer frame.deinit(); + break :blk try self.buffer_manager.open_file(file_path); + }; + return self.open_buffer(file_path, buffer, null); } fn open_scratch(self: *Self, file_path: []const u8, content: []const u8, file_type: ?[]const u8) !void { - return self.open_buffer(file_path, try self.buffer_manager.open_scratch(file_path, content), file_type); + const buffer: *Buffer = blk: { + const frame = tracy.initZone(@src(), .{ .name = "open_scratch" }); + defer frame.deinit(); + break :blk try self.buffer_manager.open_scratch(file_path, content); + }; + return self.open_buffer(file_path, buffer, file_type); } fn open_buffer(self: *Self, file_path: []const u8, new_buf: *Buffer, file_type_: ?[]const u8) !void { + const frame = tracy.initZone(@src(), .{ .name = "open_buffer" }); + defer frame.deinit(); errdefer self.buffer_manager.retire(new_buf, null); self.cancel_all_selections(); self.get_primary().reset(); @@ -553,12 +565,33 @@ pub const Editor = struct { const lang_override = file_type orelse tp.env.get().str("language"); var content = std.ArrayList(u8).init(self.allocator); defer content.deinit(); - try new_buf.root.store(content.writer(), new_buf.file_eol_mode); - const syn = if (lang_override.len > 0) - syntax.create_file_type(self.allocator, lang_override) catch null - else - syntax.create_guess_file_type(self.allocator, content.items, self.file_path) catch null; - if (syn) |syn_| + { + const frame_ = tracy.initZone(@src(), .{ .name = "store" }); + defer frame_.deinit(); + try new_buf.root.store(content.writer(), new_buf.file_eol_mode); + } + + const syn_file_type = blk: { + const frame_ = tracy.initZone(@src(), .{ .name = "guess" }); + defer frame_.deinit(); + break :blk if (lang_override.len > 0) + syntax.FileType.get_by_name(lang_override) + else + syntax.FileType.guess(self.file_path, content.items); + }; + + const syn = blk: { + const frame_ = tracy.initZone(@src(), .{ .name = "create" }); + defer frame_.deinit(); + break :blk if (syn_file_type) |ft| + syntax.create(ft, self.allocator) catch null + else + null; + }; + + if (syn) |syn_| { + const frame_ = tracy.initZone(@src(), .{ .name = "did_open" }); + defer frame_.deinit(); project_manager.did_open( file_path, syn_.file_type, @@ -567,6 +600,7 @@ pub const Editor = struct { new_buf.is_ephemeral(), ) catch |e| self.logger.print("project_manager.did_open failed: {any}", .{e}); + } break :syntax syn; }; self.syntax_no_render = tp.env.get().is("no-syntax"); @@ -581,8 +615,11 @@ pub const Editor = struct { buffer.file_type_color = ftc; } - if (self.buffer) |buffer| if (buffer.get_meta()) |meta| + if (self.buffer) |buffer| if (buffer.get_meta()) |meta| { + const frame_ = tracy.initZone(@src(), .{ .name = "extract_state" }); + defer frame_.deinit(); try self.extract_state(meta, .none); + }; try self.send_editor_open(file_path, new_buf.file_exists, ftn, fti, ftc); } @@ -4188,6 +4225,8 @@ pub const Editor = struct { pub const redo_meta: Meta = .{ .description = "Redo" }; pub fn open_buffer_from_file(self: *Self, ctx: Context) Result { + const frame = tracy.initZone(@src(), .{ .name = "open_buffer_from_file" }); + defer frame.deinit(); var file_path: []const u8 = undefined; if (ctx.args.match(.{tp.extract(&file_path)}) catch false) { try self.open(file_path); diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index 967bd9a..1b30744 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -359,6 +359,12 @@ const cmds = struct { const same_file = if (self.get_active_file_path()) |fp| std.mem.eql(u8, fp, f) else false; const have_editor_metadata = if (self.buffer_manager.get_buffer_for_file(f)) |_| true else false; + if (!same_file and !have_editor_metadata) + if (try project_manager.get_mru_position(self.allocator, f)) |pos| { + line = @intCast(pos.row); + column = @intCast(pos.col); + }; + if (!same_file) { if (self.get_active_editor()) |editor| { editor.send_editor_jump_source() catch {}; @@ -374,9 +380,6 @@ const cmds = struct { try command.executeName("scroll_view_center", .{}); if (column) |col| try command.executeName("goto_column", command.fmt(.{col})); - } else { - if (!same_file and !have_editor_metadata) - try project_manager.get_mru_position(f); } tui.need_render(); } @@ -572,7 +575,7 @@ const cmds = struct { pub fn gutter_mode_next(self: *Self, _: Ctx) Result { const config = tui.config_mut(); - const mode: ?@import("config").LineNumberMode = if (config.gutter_line_numbers_mode) |mode| switch(mode) { + const mode: ?@import("config").LineNumberMode = if (config.gutter_line_numbers_mode) |mode| switch (mode) { .absolute => .relative, .relative => .none, .none => null, @@ -1053,6 +1056,8 @@ fn replace_active_view(self: *Self, widget: Widget) !void { } fn create_editor(self: *Self) !void { + const frame = tracy.initZone(@src(), .{ .name = "create_editor" }); + defer frame.deinit(); try self.delete_active_view(); command.executeName("enter_mode_default", .{}) catch {}; var editor_widget = try ed.create(self.allocator, self.plane, &self.buffer_manager); diff --git a/src/tui/tui.zig b/src/tui/tui.zig index e21dc91..28ade15 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -147,14 +147,12 @@ fn init(allocator: Allocator) !*Self { self.mainview_ = try MainView.create(allocator); resize(); self.set_terminal_style(); - try self.rdr_.render(); try save_config(); try self.init_input_namespace(); if (tp.env.get().is("restore-session")) { command.executeName("restore_session", .{}) catch |e| self.logger.err("restore_session", e); self.logger.print("session restored", .{}); } - need_render(); return self; }