From b09aa98f7080d7db6d926a751f90d75513f6dbbf Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Mon, 5 Aug 2024 22:05:38 +0200 Subject: [PATCH] feat: support loading extreamly large files - Allocate initial file and leaf data outside of Buffer.arena - Disable gutter diffs for very large files - Disable syntax highlighting for very large files --- src/buffer/Buffer.zig | 13 ++++++++++--- src/main.zig | 3 +++ src/tui/editor.zig | 23 +++++++++++++++-------- src/tui/editor_gutter.zig | 4 ++++ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/buffer/Buffer.zig b/src/buffer/Buffer.zig index 8f548ef..0540284 100644 --- a/src/buffer/Buffer.zig +++ b/src/buffer/Buffer.zig @@ -28,6 +28,8 @@ arena: std.heap.ArenaAllocator, a: Allocator, external_a: Allocator, root: Root, +leaves_buf: ?[]Node = null, +file_buf: ?[]const u8 = null, file_path: []const u8 = "", last_save: ?Root = null, file_exists: bool = true, @@ -1023,6 +1025,8 @@ pub fn create(a: Allocator) !*Self { } pub fn deinit(self: *Self) void { + if (self.file_buf) |buf| self.external_a.free(buf); + if (self.leaves_buf) |buf| self.external_a.free(buf); self.arena.deinit(); self.external_a.destroy(self); } @@ -1034,8 +1038,10 @@ fn new_file(self: *const Self, file_exists: *bool) !Root { pub fn load(self: *const Self, reader: anytype, size: usize) !Root { const eol = '\n'; - var buf = try self.a.alloc(u8, size); - const read_size = try reader.read(buf); + var buf = try self.external_a.alloc(u8, size); + const self_ = @constCast(self); + self_.file_buf = buf; + const read_size = try reader.readAll(buf); if (read_size != size) return error.BufferUnderrun; const final_read = try reader.read(buf); @@ -1047,7 +1053,8 @@ pub fn load(self: *const Self, reader: anytype, size: usize) !Root { if (buf[i] == eol) leaf_count += 1; } - var leaves = try self.a.alloc(Node, leaf_count); + var leaves = try self.external_a.alloc(Node, leaf_count); + self_.leaves_buf = leaves; var cur_leaf: usize = 0; var b: usize = 0; for (0..buf.len) |i| { diff --git a/src/main.zig b/src/main.zig index 6180c11..52506e0 100644 --- a/src/main.zig +++ b/src/main.zig @@ -13,6 +13,9 @@ const c = @cImport({ const build_options = @import("build_options"); const log = @import("log"); +pub var max_diff_lines: usize = 50000; +pub var max_syntax_lines: usize = 50000; + pub const application_name = "flow"; pub const application_logo = "󱞏 "; diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 0eeee25..426cb3a 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -10,6 +10,7 @@ const text_manip = @import("text_manip"); const syntax = @import("syntax"); const project_manager = @import("project_manager"); const CaseData = @import("CaseData"); +const root_mod = @import("root"); const Plane = @import("renderer").Plane; const Cell = @import("renderer").Cell; @@ -403,17 +404,21 @@ pub const Editor = struct { if (self.buffer) |_| try self.close(); self.buffer = new_buf; - var content = std.ArrayList(u8).init(self.a); - defer content.deinit(); - try new_buf.root.store(content.writer()); self.syntax = syntax: { + if (new_buf.root.lines() > root_mod.max_syntax_lines) + break :syntax null; const lang_override = tp.env.get().str("language"); - if (lang_override.len > 0) - break :syntax syntax.create_file_type(self.a, content.items, lang_override) catch null; - break :syntax syntax.create_guess_file_type(self.a, content.items, self.file_path) catch null; + var content = std.ArrayList(u8).init(self.a); + defer content.deinit(); + try new_buf.root.store(content.writer()); + const syn = if (lang_override.len > 0) + syntax.create_file_type(self.a, content.items, lang_override) catch null + else + syntax.create_guess_file_type(self.a, content.items, self.file_path) catch null; + if (syn) |syn_| + project_manager.did_open(file_path, syn_.file_type, self.lsp_version, try content.toOwnedSlice()) catch {}; + break :syntax syn; }; - if (self.syntax) |syn| - project_manager.did_open(file_path, syn.file_type, self.lsp_version, try content.toOwnedSlice()) catch {}; const ftn = if (self.syntax) |syn| syn.file_type.name else "text"; const fti = if (self.syntax) |syn| syn.file_type.icon else "🖹"; @@ -2907,6 +2912,8 @@ pub const Editor = struct { defer frame.deinit(); const root = try self.buf_root(); const token = @intFromPtr(root); + if (root.lines() > root_mod.max_syntax_lines) + return; if (self.syntax_token == token) return; if (self.syntax) |syn| { diff --git a/src/tui/editor_gutter.zig b/src/tui/editor_gutter.zig index b0f2948..2ee54da 100644 --- a/src/tui/editor_gutter.zig +++ b/src/tui/editor_gutter.zig @@ -300,6 +300,10 @@ fn mouse_click_button5(_: *Self) error{Exit}!bool { } fn diff_update(self: *Self) !void { + if (self.lines > root.max_diff_lines) { + self.diff_symbols_clear(); + return; + } const editor = self.editor; const new = if (editor.get_current_root()) |new| new else return; const old = if (editor.buffer) |buffer| if (buffer.last_save) |old| old else return else return;