diff --git a/src/config.zig b/src/config.zig index 26791bb..4c4c4d4 100644 --- a/src/config.zig +++ b/src/config.zig @@ -48,7 +48,7 @@ lsp_output: enum { quiet, verbose } = .quiet, include_files: []const u8 = "", -const default_actions = [_]IdleAction{.highlight_references}; +const default_actions = [_]IdleAction{}; pub const IdleAction = enum { hover, highlight_references, diff --git a/src/tui/editor.zig b/src/tui/editor.zig index 77a51ba..5a86c5c 100644 --- a/src/tui/editor.zig +++ b/src/tui/editor.zig @@ -64,6 +64,12 @@ pub const Match = struct { has_selection: bool = false, style: ?Widget.Theme.Style = null, + const Type = enum { + none, + auto_find, + find, + highlight_references, + }; const List = std.ArrayListUnmanaged(?Self); const Self = @This(); @@ -325,7 +331,9 @@ pub const Editor = struct { matches: Match.List = .empty, match_token: usize = 0, match_done_token: usize = 0, + match_type: Match.Type = .none, last_find_query: ?[]const u8 = null, + last_find_query_match_type: Match.Type = .none, find_history: ?std.ArrayListUnmanaged([]const u8) = null, find_operation: ?enum { goto_next_match, goto_prev_match } = null, highlight_references_state: enum { adding, done } = .done, @@ -1910,6 +1918,17 @@ pub const Editor = struct { fn cancel_all_matches(self: *Self) void { self.matches.clearAndFree(self.allocator); + self.match_type = .none; + } + + pub fn init_matches_update(self: *Self) void { + self.matches.clearAndFree(self.allocator); + self.match_token += 1; + } + + pub fn have_matches_not_of_type(self: *Self, match_type: Match.Type) bool { + if (self.matches.items.len == 0) return false; + return self.match_type != match_type; } pub fn clear_matches(self: *Self) void { @@ -1918,9 +1937,26 @@ pub const Editor = struct { self.match_done_token = self.match_token; } - pub fn init_matches_update(self: *Self) void { - self.cancel_all_matches(); - self.match_token += 1; + pub fn clear_matches_if_type(self: *Self, match_type: Match.Type) bool { + if (self.match_type == match_type) { + self.clear_matches(); + return true; + } + return false; + } + + pub fn sort_matches(self: *Self) void { + const less_fn = struct { + fn less_fn(_: void, lhs_: ?Match, rhs_: ?Match) bool { + const lhs = lhs_ orelse return false; + const rhs = rhs_ orelse return false; + return if (lhs.begin.row == rhs.begin.row) + lhs.begin.col < rhs.begin.col + else + lhs.begin.row < rhs.begin.row; + } + }.less_fn; + std.mem.sort(?Match, self.matches.items, {}, less_fn); } fn with_cursor_const(root: Buffer.Root, move: cursor_operator_const, cursel: *CurSel, metrics: Buffer.Metrics) error{Stop}!void { @@ -2466,6 +2502,7 @@ pub const Editor = struct { self.clamp_mouse(); try self.send_editor_jump_destination(); if (self.jump_mode) try self.goto_definition(.{}); + tui.reset_input_idle_timer(); } pub fn primary_double_click(self: *Self, y: c_int, x: c_int) !void { @@ -3517,7 +3554,8 @@ pub const Editor = struct { self.with_cursors_const_once(root, move_cursor_word_begin) catch {}; try self.with_selections_const_once(root, move_cursor_word_end); } else if (self.get_next_match(self.get_primary().cursor)) |match| { - try self.push_cursor(); + if (self.get_primary().selection) |_| + try self.push_cursor(); const primary = self.get_primary(); const root = self.buf_root() catch return; primary.selection = match.to_selection(); @@ -3534,7 +3572,8 @@ pub const Editor = struct { if (self.matches.items.len == 0) return; try self.send_editor_jump_source(); while (self.get_next_match(self.get_primary().cursor)) |match| { - try self.push_cursor(); + if (self.get_primary().selection) |_| + try self.push_cursor(); const primary = self.get_primary(); const root = self.buf_root() catch return; primary.selection = match.to_selection(); @@ -5119,8 +5158,13 @@ pub const Editor = struct { pub fn find_query(self: *Self, ctx: Context) Result { var query: []const u8 = undefined; + var match_type: Match.Type = undefined; if (ctx.args.match(.{tp.extract(&query)}) catch false) { - try self.find_in_buffer(query); + self.match_type = .find; + try self.find_in_buffer(query, .none); + self.clamp(); + } else if (ctx.args.match(.{ tp.extract(&query), tp.extract(&match_type) }) catch false) { + try self.find_in_buffer(query, match_type); self.clamp(); } else return error.InvalidFindQueryArgument; } @@ -5130,7 +5174,7 @@ pub const Editor = struct { _ = ctx; const query: []const u8 = try self.copy_word_at_cursor(self.allocator); defer self.allocator.free(query); - try self.find_in_buffer(query); + try self.find_in_buffer(query, .find); } pub const find_word_at_cursor_meta: Meta = .{ .description = "Search for the word under the cursor" }; @@ -5161,7 +5205,8 @@ pub const Editor = struct { (history.addOne(self.allocator) catch return).* = new; } - fn set_last_find_query(self: *Self, query: []const u8) void { + fn set_last_find_query(self: *Self, query: []const u8, match_type: Match.Type) void { + self.last_find_query_match_type = match_type; if (self.last_find_query) |last| { if (query.ptr != last.ptr) { self.allocator.free(last); @@ -5170,8 +5215,9 @@ pub const Editor = struct { } else self.last_find_query = self.allocator.dupe(u8, query) catch return; } - pub fn find_in_buffer(self: *Self, query: []const u8) !void { - self.set_last_find_query(query); + pub fn find_in_buffer(self: *Self, query: []const u8, match_type: Match.Type) !void { + self.set_last_find_query(query, match_type); + self.match_type = match_type; return self.find_in_buffer_sync(query); } @@ -5346,9 +5392,12 @@ pub const Editor = struct { const row = cursor.row; const col = cursor.col; const multi_cursor = self.cursels.items.len > 1; - for (self.matches.items) |*match_| if (match_.*) |*match| - if ((!multi_cursor or !match.has_selection) and (row < match.begin.row or (row == match.begin.row and col < match.begin.col))) - return match; + for (self.matches.items) |*match_| if (match_.*) |*match| { + if (match.has_selection) continue; + if (cursor.within(match.to_selection())) return match; + if (multi_cursor) continue; + if (row < match.begin.row or (row == match.begin.row and col < match.begin.col)) return match; + }; return null; } @@ -5365,8 +5414,9 @@ pub const Editor = struct { const count = self.matches.items.len; for (0..count) |i| { const match = if (self.matches.items[count - 1 - i]) |*m| m else continue; - if (!match.has_selection and (row > match.end.row or (row == match.end.row and col > match.end.col))) - return match; + if (match.has_selection) continue; + if (cursor.eql(match.end)) return match; + if (row > match.end.row or (row == match.end.row and col > match.end.col)) return match; } return null; } @@ -5387,6 +5437,7 @@ pub const Editor = struct { match_.has_selection = false; }; primary.selection = match.to_selection(); + match.has_selection = true; primary.cursor.move_to(root, match.end.row, match.end.col, self.metrics) catch return; self.clamp(); } @@ -5399,7 +5450,7 @@ pub const Editor = struct { if (self.matches.items.len == 0) { if (self.last_find_query) |last| { self.find_operation = .goto_next_match; - try self.find_in_buffer(last); + try self.find_in_buffer(last, self.last_find_query_match_type); } } try self.move_cursor_next_match(ctx); @@ -5428,7 +5479,7 @@ pub const Editor = struct { if (self.matches.items.len == 0) { if (self.last_find_query) |last| { self.find_operation = .goto_prev_match; - try self.find_in_buffer(last); + try self.find_in_buffer(last, self.last_find_query_match_type); } } try self.move_cursor_prev_match(ctx); @@ -5807,6 +5858,7 @@ pub const Editor = struct { pub const highlight_references_meta: Meta = .{ .description = "Language: Highlight references" }; pub fn add_highlight_reference(self: *Self, match_: Match) void { + self.match_type = .highlight_references; if (self.highlight_references_state == .done) { self.highlight_references_state = .adding; self.cancel_all_matches(); diff --git a/src/tui/mainview.zig b/src/tui/mainview.zig index a0f3e9b..8ac2879 100644 --- a/src/tui/mainview.zig +++ b/src/tui/mainview.zig @@ -1269,15 +1269,15 @@ pub fn handle_editor_event(self: *Self, _: tp.pid_ref, m: tp.message) tp.result if (try m.match(.{ tp.any, tp.any, "none" })) return self.clear_auto_find(editor); if (try m.match(.{ tp.any, tp.any, tp.extract(&sel.begin.row), tp.extract(&sel.begin.col), tp.extract(&sel.end.row), tp.extract(&sel.end.col) })) { + if (editor.have_matches_not_of_type(.auto_find)) return; sel.normalize(); if (sel.end.row - sel.begin.row > ed.max_match_lines) return self.clear_auto_find(editor); const text = editor.get_selection(sel, self.allocator) catch return self.clear_auto_find(editor); if (text.len == 0) return self.clear_auto_find(editor); - if (!self.is_last_match_text(text)) { - tp.self_pid().send(.{ "cmd", "find_query", .{text} }) catch return; - } + if (!self.is_last_match_text(text)) + tp.self_pid().send(.{ "cmd", "find_query", .{ text, "auto_find" } }) catch return; } return; } @@ -1326,8 +1326,8 @@ fn location_jump(from: tp.pid_ref, file_path: []const u8, cursor: location_histo } fn clear_auto_find(self: *Self, editor: *ed.Editor) void { - editor.clear_matches(); - self.store_last_match_text(null); + if (editor.clear_matches_if_type(.auto_find)) + self.store_last_match_text(null); } fn is_last_match_text(self: *Self, text: []const u8) bool { diff --git a/src/tui/mode/mini/find.zig b/src/tui/mode/mini/find.zig index e22386e..45a139b 100644 --- a/src/tui/mode/mini/find.zig +++ b/src/tui/mode/mini/find.zig @@ -91,7 +91,7 @@ fn flush_input(self: *Self) !void { const primary = self.editor.get_primary(); primary.selection = null; primary.cursor = self.start_cursor; - try self.editor.find_in_buffer(self.input_.items); + try self.editor.find_in_buffer(self.input_.items, .find); } else { self.editor.get_primary().selection = null; self.editor.init_matches_update(); diff --git a/src/tui/tui.zig b/src/tui/tui.zig index 4b7c2de..75058ce 100644 --- a/src/tui/tui.zig +++ b/src/tui/tui.zig @@ -321,6 +321,11 @@ fn update_input_idle_timer(self: *Self) void { self.input_idle_timer = tp.self_pid().delay_send_cancellable(self.allocator, "tui.input_idle_timer", delay, .{"INPUT_IDLE"}) catch return; } +pub fn reset_input_idle_timer() void { + const self = current(); + self.update_input_idle_timer(); +} + fn update_mouse_idle_timer(self: *Self) void { if (!self.enable_mouse_idle_timer) return; const delay = std.time.us_per_ms * @as(u64, mouse_idle_time_milliseconds);