diff --git a/Default.sublime-keymap b/Default.sublime-keymap index 2df2259..a481081 100644 --- a/Default.sublime-keymap +++ b/Default.sublime-keymap @@ -23,14 +23,14 @@ }, { "keys": ["j"], - "command": "find_next", + "command": "find_in_files_jump_match", "context": [ {"key": "selector", "operator": "equal", "operand": "text.find-in-files" } ] }, { "keys": ["k"], - "command": "find_prev", + "command": "find_in_files_jump_match", "args": { "forward": false }, "context": [ {"key": "selector", "operator": "equal", "operand": "text.find-in-files" } diff --git a/find_results.py b/find_results.py index 852e244..4f4fda9 100644 --- a/find_results.py +++ b/find_results.py @@ -37,22 +37,61 @@ def get_file(self): return None -class FindInFilesJumpFileCommand(sublime_plugin.TextCommand): - def run(self, edit, forward=True): - v = self.view - files = v.find_by_selector("entity.name.filename.find-in-files") - caret = v.sel()[0] +class FindInFilesJumpCommand(sublime_plugin.TextCommand): + def run(self, edit, forward=True, cycle=True): + caret = self.view.sel()[0] + matches = self.filter_matches(caret, self.find_matches()) if forward: - file_match = next((f for f in files if caret.begin() < f.begin()), None) + match = self.find_next_match(caret, matches, cycle) else: - files.reverse() - file_match = next((f for f in files if caret.begin() > f.begin()), None) - if file_match: - region = sublime.Region(file_match.begin(), file_match.begin()) - v.sel().clear() - v.sel().add(region) - top_offset = v.text_to_layout(region.begin())[1] - v.line_height() - v.set_viewport_position((0, top_offset), True) + match = self.find_prev_match(caret, matches, cycle) + if match: + self.goto_match(match) + + def find_next_match(self, caret, matches, cycle): + default = matches[0] if cycle and len(matches) else None + return next((m for m in matches if caret.begin() < m.begin()), default) + + def filter_matches(self, caret, matches): + footers = self.view.find_by_selector('footer.find-in-files') + lower_bound = next((f.end() for f in reversed(footers) if f.end() < caret.begin()), 0) + upper_bound = next((f.end() for f in footers if f.end() > caret.begin()), self.view.size()) + return [m for m in matches if m.begin() > lower_bound and m.begin() < upper_bound] + + def find_prev_match(self, caret, matches, cycle): + default = matches[-1] if cycle and len(matches) else None + return next((m for m in reversed(matches) if caret.begin() > m.begin()), default) + + def goto_match(self, match): + self.view.sel().clear() + self.view.sel().add(match) + + +class FindInFilesJumpFileCommand(FindInFilesJumpCommand): + def find_matches(self): + return self.view.find_by_selector('entity.name.filename.find-in-files') + + def goto_match(self, match): + v = self.view + region = sublime.Region(match.begin(), match.begin()) + super(FindInFilesJumpFileCommand, self).goto_match(region) + top_offset = v.text_to_layout(region.begin())[1] - v.line_height() + v.set_viewport_position((0, top_offset), True) + + +class FindInFilesJumpMatchCommand(FindInFilesJumpCommand): + def find_matches(self): + return self.view.get_regions('match') + + def goto_match(self, match): + v = self.view + super(FindInFilesJumpMatchCommand, self).goto_match(match) + vx, vy = v.viewport_position() + vw, vh = v.viewport_extent() + x, y = v.text_to_layout(match.begin()) + h = v.line_height() + if y < vy or y + h > vy + vh: + v.show_at_center(match) class FindInFilesSetReadOnly(sublime_plugin.EventListener):