Skip to content
This repository was archived by the owner on Jan 27, 2023. It is now read-only.

Commit 3bd23c3

Browse files
initial commit
0 parents  commit 3bd23c3

13 files changed

Lines changed: 330 additions & 0 deletions

Default.sublime-commands

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[
2+
{
3+
"caption": "Search In Project",
4+
"command": "search_in_project"
5+
}
6+
]

Main.sublime-menu

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/* Borrowed from SublimeLinter https://github.com/SublimeLinter/SublimeLinter/blob/master/Main.sublime-menu */
2+
[
3+
{
4+
"caption": "Preferences",
5+
"mnemonic": "n",
6+
"id": "preferences",
7+
"children":
8+
[
9+
{
10+
"caption": "Package Settings",
11+
"mnemonic": "P",
12+
"id": "package-settings",
13+
"children":
14+
[
15+
{
16+
"caption": "Search In Project",
17+
"children":
18+
[
19+
{
20+
"command": "open_file",
21+
"args": {"file": "${packages}/SearchInProject/README.md"},
22+
"caption": "README"
23+
},
24+
{ "caption": "-" },
25+
{
26+
"command": "open_file",
27+
"args": {"file": "${packages}/SearchInProject/SearchInProject.sublime-settings"},
28+
"caption": "Settings – Default"
29+
},
30+
{
31+
"command": "open_file",
32+
"args": {"file": "${packages}/User/SearchInProject.sublime-settings"},
33+
"caption": "Settings – User"
34+
},
35+
{ "caption": "-" },
36+
{
37+
"command": "open_file",
38+
"args": {
39+
"file": "${packages}/SearchInProject/Default (OSX).sublime-keymap",
40+
"platform": "OSX"
41+
},
42+
"caption": "Key Bindings – Default"
43+
},
44+
{
45+
"command": "open_file",
46+
"args": {
47+
"file": "${packages}/SearchInProject/Default (Linux).sublime-keymap",
48+
"platform": "Linux"
49+
},
50+
"caption": "Key Bindings – Default"
51+
},
52+
{
53+
"command": "open_file",
54+
"args": {
55+
"file": "${packages}/SearchInProject/Default (Windows).sublime-keymap",
56+
"platform": "Windows"
57+
},
58+
"caption": "Key Bindings – Default"
59+
},
60+
{
61+
"command": "open_file",
62+
"args": {
63+
"file": "${packages}/User/Default (OSX).sublime-keymap",
64+
"platform": "OSX"
65+
},
66+
"caption": "Key Bindings – User"
67+
},
68+
{
69+
"command": "open_file",
70+
"args": {
71+
"file": "${packages}/User/Default (Linux).sublime-keymap",
72+
"platform": "Linux"
73+
},
74+
"caption": "Key Bindings – User"
75+
},
76+
{
77+
"command": "open_file",
78+
"args": {
79+
"file": "${packages}/User/Default (Windows).sublime-keymap",
80+
"platform": "Windows"
81+
},
82+
"caption": "Key Bindings – User"
83+
},
84+
{ "caption": "-" }
85+
]
86+
}
87+
]
88+
}
89+
]
90+
}
91+
]

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Search In Project
2+
3+
A plugin for [Sublime Text 2](http://www.sublimetext.com/).
4+
5+
## Synopsis
6+
7+
This plugin makes it possible to use various external search tools (`grep`, `ack`, `ag`, `git grep`, or `findstr`) to find strings inside your current Sublime Text project.
8+
9+
It opens a quick selection panel to browse results, and highlights matches inside files.
10+
11+
It's easy to add another search tool, if you so desire.
12+
13+
## Installation
14+
15+
Copy the folder into the Packages folder.
16+
17+
## Usage
18+
19+
Call the "Search in Project" command.
20+
21+
## Configuration
22+
23+
Configuration is stored in a separate, user-specific `SearchInProject.sublime-settings` file. See the default file for configuration options; links to both could be
24+
found in the main menu in `Preferences -> Package Settings -> Search In Project`.
25+
26+
On any OS I recommend you to install [ack](http://betterthangrep.com/), and use it instead of the default `grep`/`findstr`, because it's much faster.
27+
28+
* * *
29+
30+
Made by [Leonid Shevtsov](http://leonid.shevtsov.me)
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
/* Use findstr on Windows, because it's built-in */
3+
"search_in_project_engine": "find_str"
4+
}

SearchInProject.sublime-settings

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
SearchInProject default settings
3+
Do not change this file; change your user settings file instead
4+
*/
5+
{
6+
/* What engine to use; one of grep, ack, the_silver_searcher, or git_grep (or find_str, on Windows) */
7+
/* The default is grep because it's widely available on *nix machines, but ack and The Silver Searcher are both faster, */
8+
/* and git grep is also faster, but only works inside a Git repository */
9+
"search_in_project_engine": "grep",
10+
11+
/* Grep configuration */
12+
"search_in_project_Grep_path_to_executable": "grep",
13+
"search_in_project_Grep_mandatory_options": "-nr",
14+
15+
/* Ack configuration */
16+
"search_in_project_Ack_path_to_executable": "ack",
17+
"search_in_project_Ack_mandatory_options": "",
18+
"search_in_project_Ack_common_options": "--type-add coffeescript=.coffee --type-add haml=.haml --type-add sass=.sass --type-add scss=.scss",
19+
20+
/* TheSilverSearcher configuration */
21+
"search_in_project_TheSilverSearcher_path_to_executable": "ag",
22+
"search_in_project_TheSilverSearcher_mandatory_options": "",
23+
24+
/* GitGrep configuration */
25+
"search_in_project_GitGrep_path_to_executable": "git grep",
26+
"search_in_project_GitGrep_mandatory_options": "--line",
27+
28+
/* FindStr configuration */
29+
"search_in_project_FindStr_path_to_executable": "findstr",
30+
"search_in_project_FindStr_mandatory_options": "/n /s"
31+
}

search_in_project.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import sublime
2+
import sublime_plugin
3+
import os.path
4+
import searchengines
5+
6+
basedir = os.getcwdu()
7+
8+
9+
class SearchInProjectCommand(sublime_plugin.WindowCommand):
10+
def run(self):
11+
self.settings = sublime.load_settings('SearchInProject.sublime-settings')
12+
self.engine_name = self.settings.get("search_in_project_engine")
13+
pushd = os.getcwdu()
14+
os.chdir(basedir)
15+
__import__("searchengines.%s" % self.engine_name)
16+
self.engine = searchengines.__dict__[self.engine_name].engine_class(self.settings)
17+
os.chdir(pushd)
18+
view = self.window.active_view()
19+
selection_text = view.substr(view.sel()[0])
20+
self.window.show_input_panel(
21+
"Search in project:",
22+
selection_text,
23+
self.perform_search, None, None)
24+
pass
25+
26+
def perform_search(self, text):
27+
self.search_string = text
28+
folders = self.search_folders()
29+
30+
self.common_path = self.find_common_path(folders)
31+
self.results = self.engine.run(self.search_string, folders)
32+
if self.results:
33+
self.results = [[result[0].replace(self.common_path, ''), result[1]] for result in self.results]
34+
self.window.show_quick_panel(self.results, self.goto_result)
35+
else:
36+
self.results = []
37+
self.window.show_quick_panel(["No results"], None)
38+
39+
def goto_result(self, file_no):
40+
if file_no != -1:
41+
file_name = self.common_path + self.results[file_no][0]
42+
view = self.window.open_file(file_name, sublime.ENCODED_POSITION)
43+
regions = view.find_all(self.search_string)
44+
view.add_regions("ack", regions, "entity.name.filename.find-in-files", "circle", sublime.DRAW_OUTLINED)
45+
46+
def search_folders(self):
47+
return self.window.folders() or [os.path.dirname(self.window.active_view().file_name())]
48+
49+
def find_common_path(self, paths):
50+
paths = [path.split("/") for path in paths]
51+
common_path = []
52+
while 0 not in [len(path) for path in paths]:
53+
next_segment = list(set([path.pop(0) for path in paths]))
54+
if len(next_segment) == 1:
55+
common_path += next_segment
56+
else:
57+
break
58+
return "/".join(common_path) + "/"

searchengines/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#__all__ = ["base", "grep", "ack", "the_silver_searcher", "git_grep"]

searchengines/ack.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import base
2+
3+
4+
class Ack (base.Base):
5+
pass
6+
7+
engine_class = Ack

searchengines/base.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import subprocess
2+
3+
4+
class Base:
5+
"""
6+
This is the base search engine class.
7+
Override it to define new search engines.
8+
"""
9+
10+
SETTINGS = [
11+
"path_to_executable",
12+
"mandatory_options",
13+
"common_options"
14+
]
15+
16+
def __init__(self, settings):
17+
"""
18+
Receives the sublime.Settings object
19+
"""
20+
self.settings = settings
21+
for setting_name in self.__class__.SETTINGS:
22+
setattr(self, setting_name, self.settings.get(self._full_settings_name(setting_name), ''))
23+
pass
24+
25+
def run(self, query, folders):
26+
"""
27+
Run the search engine. Return a list of tuples, where first element is
28+
the absolute file path, and optionally row information, separated
29+
by a semicolon, and the second element is the result string
30+
"""
31+
command_line = self._command_line(query, folders)
32+
print("Running: %s" % command_line)
33+
pipe = subprocess.Popen(command_line, shell=True, stdout=subprocess.PIPE)
34+
output, error = pipe.communicate()
35+
if pipe.returncode != 0:
36+
raise Exception('Search engine returned error level: %s' % pipe.returncode, output, error)
37+
return self._parse_output(self._sanitize_output(output).strip())
38+
39+
def _command_line(self, query, folders):
40+
"""
41+
Prepare a command line for the search engine.
42+
"""
43+
return " ".join([
44+
self.path_to_executable,
45+
self.mandatory_options,
46+
self.common_options,
47+
query
48+
] + folders)
49+
50+
def _sanitize_output(self, output):
51+
return unicode(output, errors='replace')
52+
53+
def _parse_output(self, output):
54+
lines = output.split("\n")
55+
line_parts = [line.split(":", 2) for line in lines]
56+
line_parts = self._filter_lines_without_matches(line_parts)
57+
return [(":".join(line[0:-1]), line[-1].strip()) for line in line_parts]
58+
59+
def _full_settings_name(self, name):
60+
return "search_in_project_%s_%s" % (self.__class__.__name__, name)
61+
62+
def _filter_lines_without_matches(self, line_parts):
63+
return filter(lambda line: len(line) > 2, line_parts)

searchengines/find_str.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import base
2+
3+
4+
class FindStr (base.Base):
5+
"""Uses Windows built-in findstr command."""
6+
7+
def _command_line(self, query, folders):
8+
return " ".join([
9+
self.path_to_executable,
10+
self.mandatory_options,
11+
self.common_options,
12+
'"/d:%s"' % ":".join(folders),
13+
query,
14+
"*.*"
15+
])
16+
17+
18+
engine_class = FindStr

0 commit comments

Comments
 (0)