summaryrefslogtreecommitdiff
path: root/src/memory.zig
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-06 18:11:36 -0300
committerGabriel Schneider <[email protected]>2026-09-07 13:59:12 -0300
commit60367d8fe23f6af98ec28e3cf6c2094dfe332df0 (patch)
tree310fc734173cf771881f4691c71909135fadde97 /src/memory.zig
parentfa82cac885cb4738fe36d1e49b4749b5a3e31a4a (diff)
downloadpardes-60367d8fe23f6af98ec28e3cf6c2094dfe332df0.tar.gz
pardes-60367d8fe23f6af98ec28e3cf6c2094dfe332df0.zip
Refactor panes and filesystem; replace FUSE with 9P
Consolidate pane, layout, memory and host code. Serve 9P by default over Unix sockets, with runtime mounts and optional TCP/QUIC transports. Remove FUSE and obsolete proof-of-concept examples. Fix highlighting and terminal-history performance, expand differential and stress-test infrastructure, sort navigation results while preserving the next occurrence, add syntax-colored Braille minimaps, remove SPC-k, and document 9P interaction as a repository skill.
Diffstat (limited to 'src/memory.zig')
-rw-r--r--src/memory.zig148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/memory.zig b/src/memory.zig
new file mode 100644
index 00000000..60ec1bb6
--- /dev/null
+++ b/src/memory.zig
@@ -0,0 +1,148 @@
+const std = @import("std");
+const builtin = @import("builtin");
+const config = @import("pardes_config");
+
+const board = config.platform == .esp32p4;
+const reduced_target = builtin.os.tag == .freestanding;
+const KiB = 1024;
+const MiB = 1024 * KiB;
+
+pub const limits = struct {
+ pub const max_file_bytes = 256 * MiB;
+ pub const max_stream_bytes = 4 * MiB;
+ // P4: 384 KiB heap; static buffers and stack share a separate 240 KiB region.
+ pub const board_heap_bytes = 384 * KiB;
+ pub const effect_cap = if (board) 128 else 4096;
+ pub const pending_write_cap: usize = if (board) 0 else 4 * MiB;
+ pub const wrap_rows = if (board) 128 else 256;
+ pub const undo_max = if (board) 16 else 256;
+ pub const message_log = if (board) 16 else 128;
+ pub const max_tag_tail: usize = if (board) 512 else 4096;
+ pub const host_path_cap: usize = if (board) 0 else 4095;
+ pub const embedded_sources = !board;
+ pub const hexdump_row_bytes: u32 = if (board) 8 else 16;
+
+ pub const arena = struct {
+ pub const pardes = if (board) 4 * KiB else if (reduced_target) 8 * MiB else 32 * MiB;
+ pub const frame = if (board) 4 * KiB else if (reduced_target) 4 * MiB else 16 * MiB;
+ pub const tree_sitter = if (board) 0 else if (reduced_target) 4 * MiB else 16 * MiB;
+ pub const image = if (board) 0 else if (reduced_target) 64 * KiB else 32 * MiB;
+ pub const pdf = if (board) 0 else if (reduced_target or !config.mupdf) 64 * KiB else 64 * MiB;
+ };
+};
+
+const Allocator = std.mem.Allocator;
+const debug_enabled = builtin.mode == .Debug;
+
+pub const Allocators = struct {
+ pardes: Allocator,
+ frame: Allocator,
+ lsp: Allocator,
+ tree_sitter: Allocator,
+ image: Allocator,
+ pdf: Allocator,
+};
+
+var pardes_fallback: std.heap.StackFallbackAllocator(limits.arena.pardes) = undefined;
+var frame_fallback: std.heap.StackFallbackAllocator(limits.arena.frame) = undefined;
+var tree_sitter_fallback: std.heap.StackFallbackAllocator(limits.arena.tree_sitter) = undefined;
+var image_fallback: std.heap.StackFallbackAllocator(limits.arena.image) = undefined;
+var pdf_fallback: std.heap.StackFallbackAllocator(limits.arena.pdf) = undefined;
+
+const Debug = std.heap.DebugAllocator(.{});
+var pardes_debug: Debug = .init;
+var frame_debug: Debug = .init;
+var lsp_debug: Debug = .init;
+var tree_sitter_debug: Debug = .init;
+var image_debug: Debug = .init;
+var pdf_debug: Debug = .init;
+
+// One session at a time; free its allocations before deinit. Concurrent LSP workers use the caller's allocator.
+pub fn init(fallback: Allocator) Allocators {
+ pardes_fallback.fallback_allocator = fallback;
+ pardes_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ frame_fallback.fallback_allocator = fallback;
+ frame_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ tree_sitter_fallback.fallback_allocator = fallback;
+ tree_sitter_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ image_fallback.fallback_allocator = fallback;
+ image_fallback.get_called = if (std.debug.runtime_safety) false else {};
+ pdf_fallback.fallback_allocator = fallback;
+ pdf_fallback.get_called = if (std.debug.runtime_safety) false else {};
+
+ const raw: Allocators = .{
+ .pardes = pardes_fallback.get(),
+ .frame = frame_fallback.get(),
+ .lsp = fallback,
+ .tree_sitter = tree_sitter_fallback.get(),
+ .image = image_fallback.get(),
+ .pdf = pdf_fallback.get(),
+ };
+ if (!debug_enabled) return raw;
+
+ pardes_debug = .{ .backing_allocator = raw.pardes };
+ frame_debug = .{ .backing_allocator = raw.frame };
+ lsp_debug = .{ .backing_allocator = raw.lsp };
+ tree_sitter_debug = .{ .backing_allocator = raw.tree_sitter };
+ image_debug = .{ .backing_allocator = raw.image };
+ pdf_debug = .{ .backing_allocator = raw.pdf };
+ return .{
+ .pardes = pardes_debug.allocator(),
+ .frame = frame_debug.allocator(),
+ .lsp = lsp_debug.allocator(),
+ .tree_sitter = tree_sitter_debug.allocator(),
+ .image = image_debug.allocator(),
+ .pdf = pdf_debug.allocator(),
+ };
+}
+
+pub fn deinit() void {
+ if (!debug_enabled) return;
+ var leaked = pardes_debug.deinit() == .leak;
+ leaked = (frame_debug.deinit() == .leak) or leaked;
+ leaked = (lsp_debug.deinit() == .leak) or leaked;
+ leaked = (tree_sitter_debug.deinit() == .leak) or leaked;
+ leaked = (image_debug.deinit() == .leak) or leaked;
+ leaked = (pdf_debug.deinit() == .leak) or leaked;
+ if (leaked) @panic("allocator leaks detected");
+}
+
+test "fixed allocators are separate, spill, and restart" {
+ var allocs = init(std.testing.allocator);
+ const core = try allocs.pardes.alloc(u8, 32);
+ const frame = try allocs.frame.alloc(u8, 32);
+ try std.testing.expect(pardes_fallback.fixed_buffer_allocator.ownsPtr(core.ptr));
+ try std.testing.expect(frame_fallback.fixed_buffer_allocator.ownsPtr(frame.ptr));
+ try std.testing.expect(core.ptr != frame.ptr);
+
+ const spill = try allocs.pardes.alloc(u8, limits.arena.pardes + 1);
+ try std.testing.expect(!pardes_fallback.fixed_buffer_allocator.ownsPtr(spill.ptr));
+ allocs.pardes.free(spill);
+ allocs.frame.free(frame);
+ allocs.pardes.free(core);
+ deinit();
+
+ allocs = init(std.testing.allocator);
+ defer deinit();
+ const restarted = try allocs.pardes.alloc(u8, 32);
+ defer allocs.pardes.free(restarted);
+ try std.testing.expect(pardes_fallback.fixed_buffer_allocator.ownsPtr(restarted.ptr));
+}
+
+test "memory limits preserve desktop capacities" {
+ if (board or reduced_target) return error.SkipZigTest;
+ try std.testing.expectEqual(4096, limits.effect_cap);
+ try std.testing.expectEqual(@as(usize, 4 * MiB), limits.pending_write_cap);
+ try std.testing.expectEqual(256, limits.wrap_rows);
+ try std.testing.expectEqual(256, limits.undo_max);
+ try std.testing.expectEqual(128, limits.message_log);
+ try std.testing.expectEqual(@as(usize, 4096), limits.max_tag_tail);
+ try std.testing.expectEqual(@as(usize, 4095), limits.host_path_cap);
+ try std.testing.expect(limits.embedded_sources);
+ try std.testing.expectEqual(@as(u32, 16), limits.hexdump_row_bytes);
+ try std.testing.expectEqual(32 * MiB, limits.arena.pardes);
+ try std.testing.expectEqual(16 * MiB, limits.arena.frame);
+ try std.testing.expectEqual(16 * MiB, limits.arena.tree_sitter);
+ try std.testing.expectEqual(32 * MiB, limits.arena.image);
+ try std.testing.expectEqual(if (config.mupdf) 64 * MiB else 64 * KiB, limits.arena.pdf);
+}