From 679927f8bd292d283e9dbf28bc9f345a356af548 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 25 Nov 2025 15:48:07 +0100 Subject: [PATCH 1/2] fix: add support for non-authorative file URIs from LSPs This should fix current zls. --- src/Project.zig | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Project.zig b/src/Project.zig index 80de0ef..967ec9e 100644 --- a/src/Project.zig +++ b/src/Project.zig @@ -959,9 +959,13 @@ fn send_goto_request(self: *Self, from: tp.pid_ref, file_path: []const u8, row: fn navigate_to_location_link(from: tp.pid_ref, location_link: []const u8) (ClientError || InvalidMessageError || cbor.Error)!void { const location: LocationLink = try read_locationlink(location_link); if (location.targetUri == null or location.targetRange == null) return error.InvalidMessageField; - if (!std.mem.eql(u8, location.targetUri.?[0..7], "file://")) return error.InvalidTargetURI; var file_path_buf: [std.fs.max_path_bytes]u8 = undefined; - var file_path = std.Uri.percentDecodeBackwards(&file_path_buf, location.targetUri.?[7..]); + var file_path = std.Uri.percentDecodeBackwards(&file_path_buf, if (std.mem.eql(u8, location.targetUri.?[0..7], "file://")) + location.targetUri.?[7..] + else if (std.mem.eql(u8, location.targetUri.?[0..5], "file:")) + location.targetUri.?[5..] + else + return error.InvalidTargetURI); if (builtin.os.tag == .windows) { if (file_path[0] == '/') file_path = file_path[1..]; for (file_path, 0..) |c, i| if (c == '/') { From 86ec27893ddeb188d5eb428592363a905c7cc962 Mon Sep 17 00:00:00 2001 From: CJ van den Berg Date: Tue, 25 Nov 2025 15:53:12 +0100 Subject: [PATCH 2/2] feat: implement case insensitive search (part 1) --- src/buffer/Buffer.zig | 20 +++++++++++++++----- src/tui/editor.zig | 2 +- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/buffer/Buffer.zig b/src/buffer/Buffer.zig index 344bba4..80470d9 100644 --- a/src/buffer/Buffer.zig +++ b/src/buffer/Buffer.zig @@ -943,8 +943,9 @@ const Node = union(enum) { } } + pub const FindMode = enum { exact, case_folded }; pub const FindAllCallback = fn (data: *anyopaque, begin_row: usize, begin_col: usize, end_row: usize, end_col: usize) error{Stop}!void; - pub fn find_all_ranges(self: *const Node, pattern: []const u8, data: *anyopaque, callback: *const FindAllCallback, allocator: Allocator) error{ OutOfMemory, Stop }!void { + pub fn find_all_ranges(self: *const Node, pattern: []const u8, data: *anyopaque, callback: *const FindAllCallback, mode: FindMode, allocator: Allocator) error{ OutOfMemory, Stop }!void { const Ctx = struct { pattern: []const u8, data: *anyopaque, @@ -954,6 +955,7 @@ const Node = union(enum) { buf: []u8, rest: []u8 = "", writer: std.Io.Writer, + mode: FindMode, const Ctx = @This(); fn drain(w: *std.Io.Writer, data_: []const []const u8, splat: usize) std.Io.Writer.Error!usize { @@ -975,10 +977,17 @@ const Node = union(enum) { fn write(ctx: *Ctx, bytes: []const u8) std.Io.Writer.Error!usize { var input = bytes; while (true) { - const input_consume_size = @min(ctx.buf.len - ctx.rest.len, input.len); - @memcpy(ctx.buf[ctx.rest.len .. ctx.rest.len + input_consume_size], input[0..input_consume_size]); - ctx.rest = ctx.buf[0 .. ctx.rest.len + input_consume_size]; - input = input[input_consume_size..]; + switch (ctx.mode) { + .exact => { + const input_consume_size = @min(ctx.buf.len - ctx.rest.len, input.len); + @memcpy(ctx.buf[ctx.rest.len .. ctx.rest.len + input_consume_size], input[0..input_consume_size]); + ctx.rest = ctx.buf[0 .. ctx.rest.len + input_consume_size]; + input = input[input_consume_size..]; + }, + .case_folded => { + @panic("unimplemented"); + }, + } if (ctx.rest.len < ctx.pattern.len) return bytes.len - input.len; @@ -1031,6 +1040,7 @@ const Node = union(enum) { }, .buffer = &.{}, }, + .mode = mode, }; defer allocator.free(ctx.buf); return self.store(&ctx.writer, .lf) catch |e| switch (e) { diff --git a/src/tui/editor.zig b/src/tui/editor.zig index ad34ee9..1777b9a 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -5296,7 +5296,7 @@ pub const Editor = struct { defer self.add_match_done(); var ctx: Ctx = .{ .self = self }; self.init_matches_update(); - try root.find_all_ranges(query, &ctx, Ctx.cb, self.allocator); + try root.find_all_ranges(query, &ctx, Ctx.cb, .exact, self.allocator); } fn find_in_buffer_async(self: *Self, query: []const u8) !void {