├── .gitignore ├── Default.sublime-keymap ├── CONTRIBUTORS.md ├── Base File (OSX).sublime-settings ├── LICENSE.txt ├── README.md └── open_search_result.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea 3 | -------------------------------------------------------------------------------- /Default.sublime-keymap: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "keys": ["ctrl+enter"], 4 | "command": "open_search_result" 5 | } 6 | ] -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | # Contributors 2 | 3 | The following people have contributed code to the OpenSearchResult plugin. 4 | 5 | Chris Barnett 6 | -------------------------------------------------------------------------------- /Base File (OSX).sublime-settings: -------------------------------------------------------------------------------- 1 | { 2 | "highlight_search_icon": "bookmark", 3 | "highlight_search_scope": "entity.name.function", 4 | "highlight_search_results": false 5 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Andrew Brookins 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Open Search Result Plugin for Sublime Text 2 2 | 3 | This plugin creates a command that allows you to open files listed in the search 4 | results of the 'Find in Files' command. 5 | 6 | - When run on a line in the search results that includes a line number, e.g., 7 | "102: print 'foo'" it opens the file at the correct line number. 8 | 9 | - When run on a line that contains a file path like '/path/to/somewhere:' 10 | in the search listing, it opens the file without a line number specified. 11 | 12 | ## Key Binding 13 | 14 | - The default key binding is "ctrl + enter". 15 | 16 | ## Customizing 17 | 18 | You can change various things about the plugin by adding user settings: 19 | 20 | - 'highlight_search_results': Set to false to disable highlighting openable 21 | paths (the open command will still work) 22 | - 'highlight_search_scope': The scope that will be used to color the outline for 23 | openable paths or the icon. See your theme file for examples of colors. 24 | - 'highlight_search_icon': If you want an icon to show up in the gutter next to 25 | openable paths, include a valid icon name as a string (e.g., 'circle', 'dot' or 26 | 'bookmark') 27 | -------------------------------------------------------------------------------- /open_search_result.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import sublime, sublime_plugin 4 | 5 | 6 | class HighlightFilePaths(sublime_plugin.EventListener): 7 | HIGHLIGHT_REGION_NAME = 'HighlightFilePaths' 8 | HIGHLIGHT_ENABLED_KEY = 'highlight_search_results' 9 | SCOPE_SETTINGS_KEY = 'highlight_search_scope' 10 | ICON_SETTINGS_KEY = 'highlight_search_icon' 11 | DEFAULT_SCOPE = 'search_result_highlight' 12 | DEFAULT_ICON = '' 13 | 14 | def show_highlight(self, view): 15 | valid_regions = [] 16 | show_highlight = view.settings().get(self.HIGHLIGHT_ENABLED_KEY, False) 17 | scope = view.settings().get(self.SCOPE_SETTINGS_KEY, self.DEFAULT_SCOPE) 18 | icon = view.settings().get(self.ICON_SETTINGS_KEY, self.DEFAULT_ICON) 19 | 20 | if view.name() != 'Find Results': 21 | return 22 | 23 | for s in view.sel(): 24 | line = view.line(s) 25 | line_str = view.substr(view.line(s)) 26 | line_num = Util.parse_line_number(line_str) 27 | 28 | if Util.is_file_path(line_str) or line_num: 29 | valid_regions.append(line) 30 | 31 | if valid_regions: 32 | if show_highlight: 33 | options = sublime.DRAW_EMPTY | sublime.DRAW_OUTLINED 34 | else: 35 | options = sublime.HIDDEN 36 | 37 | view.add_regions( 38 | self.HIGHLIGHT_REGION_NAME, valid_regions, scope, icon, options) 39 | else: 40 | view.erase_regions(self.HIGHLIGHT_REGION_NAME) 41 | 42 | def on_selection_modified(self, view): 43 | highlight_enabled = (view.settings().get(self.HIGHLIGHT_ENABLED_KEY) 44 | or view.settings().get(self.ICON_SETTINGS_KEY)) 45 | 46 | if view.settings().get('is_widget') \ 47 | or not view.settings().get('command_mode') \ 48 | or not highlight_enabled: 49 | view.erase_regions(self.HIGHLIGHT_REGION_NAME) 50 | return 51 | 52 | self.show_highlight(view) 53 | 54 | def on_deactivated(self, view): 55 | view.erase_regions(self.HIGHLIGHT_REGION_NAME) 56 | 57 | def on_activated(self, view): 58 | if view.settings().get('highlight_file_paths'): 59 | self.show_highlight(view) 60 | 61 | 62 | class OpenSearchResultCommand(sublime_plugin.TextCommand): 63 | """ 64 | Open a file listed in the Find In File search results at the line the 65 | cursor is on, or just open the file if the cursor is on the file path. 66 | """ 67 | 68 | def open_file_from_line(self, line, line_num): 69 | """ 70 | Attempt to parse a file path from the string `line` and open it in a 71 | new buffer. 72 | """ 73 | if ':' not in line: 74 | return 75 | 76 | file_path = line[0:-1] 77 | 78 | if os.path.exists(file_path): 79 | self.view.window().open_file( 80 | "%s:%s" % (file_path, line_num), sublime.ENCODED_POSITION) 81 | 82 | def previous_line(self, region): 83 | """ `region` should be a Region covering the entire hard line """ 84 | if region.begin() == 0: 85 | return None 86 | else: 87 | return self.view.full_line(region.begin() - 1) 88 | 89 | def open_file_path(self, line_str): 90 | """ 91 | Parse a file path from a string `line_str` of the format: ":" 92 | """ 93 | file_path = line_str[0:-1] 94 | 95 | if os.path.exists(file_path): 96 | self.view.window().open_file(file_path) 97 | 98 | def open_file_at_line_num(self, cur_line, line_num): 99 | """ 100 | Starting at the position `cur_line` (a `Region`), count backwards 101 | until we find a path or the beginning of the file. If we find a file 102 | path, open it in a new tab at `line_num`. 103 | """ 104 | prev = cur_line 105 | while True: 106 | prev = self.previous_line(prev) 107 | if prev is None: 108 | break 109 | 110 | line = self.view.substr(prev).strip() 111 | if Util.is_file_path(line): 112 | return self.open_file_from_line(line, line_num) 113 | 114 | def run(self, edit): 115 | for cursor in self.view.sel(): 116 | cur_line = self.view.line(cursor) 117 | line_str = self.view.substr(cur_line).strip() 118 | line_num = Util.parse_line_number(line_str) 119 | 120 | if self.view.name() != 'Find Results': 121 | return 122 | 123 | if Util.is_file_path(line_str): 124 | self.open_file_path(line_str) 125 | elif line_num: 126 | self.open_file_at_line_num(cur_line, line_num) 127 | 128 | class Util: 129 | def parse_line_number(line_str): 130 | parts = line_str.split() 131 | line_num = parts[0].strip().replace(':', '') 132 | return line_num 133 | 134 | 135 | def is_file_path(line_str): 136 | return re.match("^(/|\w:\\\).*:$", line_str) is not None 137 | 138 | --------------------------------------------------------------------------------