Search code examples
sublimetext3sublimetextsublime-text-plugin

Sublime - Keyboard shortcut to go to first selection of 'Find in Files'


When I search in Sublime Text using 'Find in Files' for a keyword, I always have to use my mouse to click the selection I want to go to in that file. Is there any way I can use my keyboard to make the selection jump instead? Or if there's any plugins that do this?

enter image description here


Solution

  • By default you can navigate between all of the results of a find operation by using the menu items in Find > Find Results or their associated key bindings (visible in the menu). Doing that, the results go in order forward or backward, which may or may not be desirable if there are many results.

    There aren't any navigation keys for jumping around inside the find in files output apart from the usual file navigation, but you can add such with a plugin:

    import sublime
    import sublime_plugin
    
    class JumpToFindMatchCommand(sublime_plugin.TextCommand):
        """
        In a find in files result, skip the cursor to the next or previous find
        match, based on the location of the first cursor in the view.
        """
        def run(self, edit, forward=True):
            # Find the location of all matches and specify the one to navigate to
            # if there aren't any in the location of travel.
            matches = self.view.find_by_selector("constant.numeric.line-number.match")
            fallback = matches[0] if forward else matches[-1]
    
            # Get the position of the first caret.
            cur = self.view.sel()[0].begin()
    
            # Navigate the found locations and focus the first one that comes
            # before or after the cursor location, if any.
            pick = lambda p: (cur < p.begin()) if forward else (cur > p.begin())
            for pos in matches if forward else reversed(matches):
                if pick(pos):
                    return self.focus(pos)
    
            # not found; Focus the fallback location.
            self.focus(fallback)
    
        def focus(self, location):
                # Focus the found location in the window
                self.view.show(location, True)
    
                # Set the cursor to that location.
                self.view.sel().clear()
                self.view.sel().add(location.begin())
    

    This implements a new command jump_to_find_match that takes an optional argument of forward to determine if the jump should be forward or backward, and will focus the view on the next or previous find result based on the cursor location of the first cursor in the file, wrapping as needed.

    In combination with this plugin, key bindings such as the following can be set up to use the command. Here we're using the Tab and Shift+Tab keys; the context in each ensures that the binding is only active while in find results.

    {
        "keys": ["tab"],
        "command": "jump_to_find_match",
        "args": {
            "forward": true
        },
        "context": [
            { "key": "selector", "operator": "equal", "operand": "text.find-in-files", "match_all": true },
        ],
    },
    
    {
        "keys": ["shift+tab"],
        "command": "jump_to_find_match",
        "args": {
            "forward": false
        },
        "context": [
            { "key": "selector", "operator": "equal", "operand": "text.find-in-files", "match_all": true },
        ],
    },
    

    That will allow you to navigate between the matches in the find panel, but you would still have to use the mouse in order to actually jump to the match location in the related file.

    To do that by keyboard, you can use this plugin, which implements a command that simulates a double click at the location of the cursor. A key binding such as the following triggers the command in response to the Enter key, as long as the cursor is on a find match:

    {
        "keys": ["enter"],
        "command": "double_click_at_caret",
        "context": [
            { "key": "selector", "operator": "equal", "operand": "text.find-in-files", "match_all": true },
        ],
    },