redcar 0.10 → 0.11.0dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +14 -0
- data/Rakefile +68 -29
- data/lib/redcar.rb +2 -2
- data/plugins/application/lib/application/dialogs/filter_list_dialog.rb +2 -1
- data/plugins/application_swt/spec/application_swt/gradient_spec.rb +3 -12
- data/plugins/core/lib/core/resource.rb +13 -5
- data/plugins/document_search/features/find.feature +366 -214
- data/plugins/document_search/features/incremental_search.feature +351 -0
- data/plugins/document_search/features/replace.feature +16 -16
- data/plugins/document_search/features/step_definitions/find_steps.rb +16 -0
- data/plugins/document_search/features/support/env.rb +11 -0
- data/plugins/document_search/lib/document_search.rb +149 -109
- data/plugins/document_search/lib/document_search/commands.rb +251 -202
- data/plugins/document_search/lib/document_search/find_speedbar.rb +138 -81
- data/plugins/document_search/lib/document_search/incremental_search_speedbar.rb +70 -0
- data/plugins/document_search/lib/document_search/query_options.rb +15 -39
- data/plugins/document_search/plugin.rb +1 -1
- data/plugins/edit_view/features/step_definitions/editing_steps.rb +6 -2
- data/plugins/edit_view_swt/lib/edit_view_swt.rb +2 -2
- data/plugins/file_parser/lib/file_parser.rb +6 -1
- data/plugins/html_view/features/step_definitions/web_view_steps.rb +12 -0
- data/plugins/html_view/features/support/env.rb +16 -0
- data/plugins/html_view/lib/html_view.rb +5 -1
- data/plugins/line_tools/lib/line_tools.rb +16 -0
- data/plugins/project/features/find_file.feature +28 -0
- data/plugins/project/features/open_and_save_files.feature +11 -0
- data/plugins/project/features/step_definitions/file_steps.rb +6 -1
- data/plugins/project/features/support/env.rb +2 -0
- data/plugins/project/lib/project.rb +49 -6
- data/plugins/project/lib/project/commands.rb +18 -6
- data/plugins/project/lib/project/find_file_dialog.rb +19 -8
- data/plugins/project/lib/project/find_recent_dialog.rb +30 -0
- data/plugins/project/lib/project/manager.rb +41 -10
- data/plugins/project/lib/project/recent.rb +64 -0
- data/plugins/project/spec/fixtures/myproject/vendor/bar.rb +0 -0
- data/plugins/project/spec/fixtures/myproject/vendor/plugins/bar.rb +0 -0
- data/plugins/{find-in-project → project_search}/TODO.md +3 -3
- data/plugins/project_search/features/support/env.rb +6 -0
- data/plugins/project_search/features/word_search.feature +34 -0
- data/plugins/project_search/lib/project_search.rb +73 -0
- data/plugins/project_search/lib/project_search/binary_data_detector.rb +46 -0
- data/plugins/project_search/lib/project_search/commands.rb +62 -0
- data/plugins/project_search/lib/project_search/hit.rb +17 -0
- data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/images/collapsed.png +0 -0
- data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/images/expanded.png +0 -0
- data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/images/spinner.gif +0 -0
- data/plugins/project_search/lib/project_search/lucene_index.rb +64 -0
- data/plugins/project_search/lib/project_search/lucene_refresh.rb +22 -0
- data/plugins/project_search/lib/project_search/project.rb +14 -0
- data/plugins/project_search/lib/project_search/query.rb +29 -0
- data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/stylesheets/style.css +14 -3
- data/plugins/project_search/lib/project_search/views/_file.html.erb +60 -0
- data/plugins/{find-in-project/lib/find_in_project → project_search/lib/project_search}/views/index.html.erb +12 -9
- data/plugins/project_search/lib/project_search/word_search.rb +105 -0
- data/plugins/project_search/lib/project_search/word_search_controller.rb +207 -0
- data/plugins/project_search/plugin.rb +8 -0
- data/plugins/project_search/spec/fixtures/project/binary_file.bin +0 -0
- data/plugins/project_search/spec/fixtures/project/foo.txt +43 -0
- data/plugins/project_search/spec/fixtures/project/qux.rb +3 -0
- data/plugins/project_search/spec/project_search/binary_data_detector_spec.rb +24 -0
- data/plugins/project_search/spec/project_search/word_search_spec.rb +157 -0
- data/plugins/project_search/spec/spec_helper.rb +27 -0
- data/plugins/redcar/redcar.rb +77 -71
- data/plugins/ruby/lib/ruby/syntax_checker.rb +1 -1
- data/plugins/snippets/features/snippets.feature +12 -0
- data/plugins/snippets/lib/snippets/tab_handler.rb +1 -1
- metadata +46 -25
- data/plugins/document_search/features/find_and_replace.feature +0 -723
- data/plugins/document_search/lib/document_search/find_and_replace_speedbar.rb +0 -142
- data/plugins/find-in-project/lib/find_in_project.rb +0 -35
- data/plugins/find-in-project/lib/find_in_project/commands.rb +0 -30
- data/plugins/find-in-project/lib/find_in_project/controllers.rb +0 -170
- data/plugins/find-in-project/lib/find_in_project/views/_divider.html.erb +0 -4
- data/plugins/find-in-project/lib/find_in_project/views/_file_heading.html.erb +0 -10
- data/plugins/find-in-project/lib/find_in_project/views/_file_line.html.erb +0 -6
- data/plugins/find-in-project/plugin.rb +0 -11
- data/plugins/project/lib/project/recent_directories.rb +0 -54
@@ -3,6 +3,7 @@
|
|
3
3
|
padding: 0;
|
4
4
|
font-weight: normal;
|
5
5
|
font-size: 14px;
|
6
|
+
font-family: sans-serif;
|
6
7
|
}
|
7
8
|
|
8
9
|
#search_form_container {
|
@@ -34,6 +35,7 @@
|
|
34
35
|
#search_form_container .input .field input {
|
35
36
|
width: 100%;
|
36
37
|
height: 20px;
|
38
|
+
font-family: monospace;
|
37
39
|
}
|
38
40
|
|
39
41
|
#search_form_container .input .expand {
|
@@ -122,7 +124,7 @@
|
|
122
124
|
}
|
123
125
|
|
124
126
|
#results .even {
|
125
|
-
background-color: #
|
127
|
+
background-color: #F4F4F4;
|
126
128
|
}
|
127
129
|
|
128
130
|
#results .odd {
|
@@ -141,6 +143,7 @@
|
|
141
143
|
|
142
144
|
#results .file_heading a {
|
143
145
|
font-weight: bold;
|
146
|
+
font-family: sans-serif;
|
144
147
|
}
|
145
148
|
|
146
149
|
#results .expand_collapse img {
|
@@ -155,6 +158,7 @@
|
|
155
158
|
cursor: hand;
|
156
159
|
font-size: 12px;
|
157
160
|
line-height: 12px;
|
161
|
+
font-family: sans-serif;
|
158
162
|
}
|
159
163
|
|
160
164
|
#results .divider .line_num {
|
@@ -168,17 +172,22 @@
|
|
168
172
|
padding: 3px 10px;
|
169
173
|
width: 100%;
|
170
174
|
cursor: hand;
|
175
|
+
}
|
176
|
+
|
177
|
+
#results .text pre {
|
171
178
|
font-size: 14px;
|
172
179
|
line-height: 17px;
|
180
|
+
font-family: monospace;
|
173
181
|
}
|
174
182
|
|
175
183
|
#results .divider .text {
|
176
184
|
cursor: default;
|
177
185
|
}
|
178
186
|
|
179
|
-
#results .text span {
|
180
|
-
background-color:
|
187
|
+
#results .text pre span {
|
188
|
+
background-color: #FFCCCC;
|
181
189
|
font-weight: bold;
|
190
|
+
font-family: monospace;
|
182
191
|
}
|
183
192
|
|
184
193
|
#results .break {
|
@@ -190,6 +199,8 @@
|
|
190
199
|
bottom: 0;
|
191
200
|
left: 0;
|
192
201
|
right: 0;
|
202
|
+
font-size: 1.5em;
|
203
|
+
font-family: sans-serif;
|
193
204
|
}
|
194
205
|
|
195
206
|
#results_summary .text {
|
@@ -0,0 +1,60 @@
|
|
1
|
+
|
2
|
+
<tr><td class='break' colspan='2'></td></tr>
|
3
|
+
<tr>
|
4
|
+
<td class="file_heading" colspan="2">
|
5
|
+
<a class="expand_collapse" data-file_num="<%= file %>">
|
6
|
+
<img src="<%= image_path %>/expanded.png" />
|
7
|
+
<%= CGI::escapeHTML(file.gsub(@word_search.project.path + "/", "")) %>
|
8
|
+
</a>
|
9
|
+
</td>
|
10
|
+
</tr>
|
11
|
+
|
12
|
+
<% line_index = 0 %>
|
13
|
+
<% last_matching_line_num = nil %>
|
14
|
+
<% last_displayed_line_num = -1 %>
|
15
|
+
<% hits.each_with_index do |hit, i| %>
|
16
|
+
<% next_hit = hits[i + 1] %>
|
17
|
+
<% next_hit_line_num = next_hit ? next_hit.line_num : 100_000_000 %>
|
18
|
+
|
19
|
+
<% if @word_search.context? and last_matching_line_num and (hit.line_num - last_matching_line_num) > (@word_search.context_size * 2) %>
|
20
|
+
<tr class="divider file_<%= file_num %>">
|
21
|
+
<td class="line_num">. . .</td>
|
22
|
+
<td class="text"> </td> <!-- extra space to ensure line-height is respected -->
|
23
|
+
</tr>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<% hit.pre_context.each_with_index do |context_line, i| %>
|
27
|
+
<% this_line_num = hit.line_num - @word_search.context_size + i %>
|
28
|
+
<% unless this_line_num <= last_displayed_line_num %>
|
29
|
+
<% line_index += 1 %>
|
30
|
+
<tr class="result file_<%= file_num %> line_<%= this_line_num %> <%= (line_index % 2 == 0 ? 'even' : 'odd') %>" data-href='<%= CGI::escapeHTML(file) %>' data-line_num='<%= this_line_num %>'>
|
31
|
+
<td class='line_num'><%= this_line_num %></td>
|
32
|
+
<% text = CGI.escapeHTML(context_line).gsub(@word_search.regex) { "<span>#{$&}</span>" } %>
|
33
|
+
<td class='text'><pre><%= text.chomp + " " %></pre></td> <!-- extra space to ensure line-height is respected -->
|
34
|
+
</tr>
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
37
|
+
|
38
|
+
<% line_index += 1 %>
|
39
|
+
<% last_displayed_line_num = hit.line_num %>
|
40
|
+
<tr class="result file_<%= file_num %> line_<%= hit.line_num %> <%= (line_index % 2 == 0 ? 'even' : 'odd') %>" data-href='<%= CGI::escapeHTML(file) %>' data-line_num='<%= hit.line_num %>'>
|
41
|
+
<td class='line_num'><%= hit.line_num %></td>
|
42
|
+
<% text = CGI.escapeHTML(hit.line).gsub(@word_search.regex) { "<span>#{$&}</span>" } %>
|
43
|
+
<td class='text'><pre><%= text.chomp + " " %></pre></td> <!-- extra space to ensure line-height is respected -->
|
44
|
+
</tr>
|
45
|
+
|
46
|
+
<% hit.post_context.each_with_index do |context_line, i| %>
|
47
|
+
<% this_line_num = hit.line_num + i + 1%>
|
48
|
+
<% unless this_line_num >= next_hit_line_num %>
|
49
|
+
<% last_displayed_line_num = this_line_num %>
|
50
|
+
<% line_index += 1 %>
|
51
|
+
<tr class="result file_<%= file_num %> line_<%= this_line_num %> <%= (line_index % 2 == 0 ? 'even' : 'odd') %>" data-href='<%= CGI::escapeHTML(file) %>' data-line_num='<%= this_line_num %>'>
|
52
|
+
<td class='line_num'><%= this_line_num %></td>
|
53
|
+
<% text = CGI.escapeHTML(context_line).gsub(@word_search.regex) { "<span>#{$&}</span>" } %>
|
54
|
+
<td class='text'><pre><%= text.chomp + " " %></pre></td> <!-- extra space to ensure line-height is respected -->
|
55
|
+
</tr>
|
56
|
+
<% end %>
|
57
|
+
<% end %>
|
58
|
+
|
59
|
+
<% last_matching_line_num = hit.line_num %>
|
60
|
+
<% end %>
|
@@ -3,10 +3,10 @@
|
|
3
3
|
<% json_path = File.expand_path(File.join(Redcar.root, %w(plugins html_view assets json2.js))) %>
|
4
4
|
<script type="text/javascript" src="file://<%= json_path %>"></script>
|
5
5
|
|
6
|
-
<% plugin_css = File.expand_path(File.join(
|
6
|
+
<% plugin_css = File.expand_path(File.join(plugin_root, %w(lib project_search stylesheets style.css))) %>
|
7
7
|
<link rel="stylesheet" href="file://<%= plugin_css %>" type="text/css" media="screen">
|
8
8
|
|
9
|
-
<% image_path = File.expand_path(File.join(
|
9
|
+
<% image_path = File.expand_path(File.join(plugin_root, %w(lib project_search images))) %>
|
10
10
|
|
11
11
|
<div id="search_form_container">
|
12
12
|
<form id="search_form">
|
@@ -14,14 +14,14 @@
|
|
14
14
|
<tr class="input">
|
15
15
|
<td class="label"><label for="query">Search Term</label></td>
|
16
16
|
<td class="field">
|
17
|
-
<input id="query" type="text" value="<%=
|
18
|
-
|
17
|
+
<input id="query" type="text" value="<%= default_query %>" />
|
18
|
+
|
19
19
|
<!-- keeps a cache of the current query so if the user changes the query field, this remains the same as the results -->
|
20
20
|
<input id="cached_query" type="hidden" />
|
21
21
|
|
22
22
|
<div id="recent_queries" style="display: none;">
|
23
23
|
<ul>
|
24
|
-
<% (
|
24
|
+
<% (settings['recent_queries'] || []).each do |query| %>
|
25
25
|
<li><%= CGI::escapeHTML(query) %></li>
|
26
26
|
<% end %>
|
27
27
|
</ul>
|
@@ -36,12 +36,15 @@
|
|
36
36
|
<td class="controls">
|
37
37
|
<input id="search" type="submit" value="Find In Project" />
|
38
38
|
<img id="spinner" src="<%= image_path %>/spinner.gif" style="display:none;" />
|
39
|
+
<% if show_literal_match_option? %>
|
39
40
|
<input type="checkbox" id="literal_match" <%="checked=checked" if @literal_match %>>
|
40
|
-
|
41
|
-
|
41
|
+
<label for="literal_match">Literal Match</label>
|
42
|
+
<% end %>
|
43
|
+
<input type="checkbox" id="match_case" <%="checked=checked" if match_case? %>>
|
42
44
|
<label for="match_case">Match case</label>
|
43
|
-
<input type="checkbox" id="with_context" <%="checked=checked" if
|
45
|
+
<input type="checkbox" id="with_context" <%="checked=checked" if context? %>>
|
44
46
|
<label for="with_context">With context</label>
|
47
|
+
<%= search_copy %>
|
45
48
|
<a href="#" title="Edit Preferences" id="edit_preferences">Edit Preferences...</a>
|
46
49
|
</td>
|
47
50
|
<td></td>
|
@@ -99,7 +102,7 @@
|
|
99
102
|
});
|
100
103
|
|
101
104
|
$('#edit_preferences').click(function(ev) {
|
102
|
-
Controller.
|
105
|
+
Controller.editPreferences();
|
103
106
|
});
|
104
107
|
|
105
108
|
// in the case the user wants to search for things like <table>, we need to unescape the entities
|
@@ -0,0 +1,105 @@
|
|
1
|
+
|
2
|
+
class ProjectSearch
|
3
|
+
class WordSearch
|
4
|
+
attr_reader :query_string, :context_size, :project
|
5
|
+
|
6
|
+
def initialize(project, query_string, match_case, context_size)
|
7
|
+
@project = project
|
8
|
+
@query_string = query_string
|
9
|
+
@match_case = !!match_case
|
10
|
+
@context_size = context_size
|
11
|
+
end
|
12
|
+
|
13
|
+
def match_case?
|
14
|
+
@match_case
|
15
|
+
end
|
16
|
+
|
17
|
+
def context?
|
18
|
+
@context_size > 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def matching_line?(line)
|
22
|
+
line =~ regex
|
23
|
+
end
|
24
|
+
|
25
|
+
def regex
|
26
|
+
@regex ||= begin
|
27
|
+
regexp_text = Regexp.escape(@query_string)
|
28
|
+
match_case? ? /#{regexp_text}/ : /#{regexp_text}/i
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def on_file_results(&block)
|
33
|
+
@on_file_results_block = block
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate_results
|
37
|
+
hits = []
|
38
|
+
doc_ids.each do |doc_id|
|
39
|
+
next unless File.exist?(doc_id)
|
40
|
+
contents = File.read(doc_id).split(/\n|\r/)
|
41
|
+
pre_context = []
|
42
|
+
hits_needing_post_context = []
|
43
|
+
remove_hits = []
|
44
|
+
file_hits = []
|
45
|
+
contents.each_with_index do |line, line_num|
|
46
|
+
hits_needing_post_context.each do |hit|
|
47
|
+
hit.post_context << line
|
48
|
+
if hit.post_context.length == context_size
|
49
|
+
remove_hits << hit
|
50
|
+
end
|
51
|
+
end
|
52
|
+
hits_needing_post_context -= remove_hits
|
53
|
+
|
54
|
+
if matching_line?(line)
|
55
|
+
hit = Hit.new(doc_id, line_num, line, regex, pre_context.dup, [])
|
56
|
+
hits << hit
|
57
|
+
file_hits << hit
|
58
|
+
if context_size > 0
|
59
|
+
hits_needing_post_context << hit
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
if pre_context.length == context_size
|
64
|
+
pre_context.shift
|
65
|
+
end
|
66
|
+
pre_context << line
|
67
|
+
end
|
68
|
+
send_file_results(file_hits)
|
69
|
+
end
|
70
|
+
hits
|
71
|
+
end
|
72
|
+
|
73
|
+
def send_file_results(hits)
|
74
|
+
if @on_file_results_block
|
75
|
+
@on_file_results_block.call(hits)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def results
|
80
|
+
@results ||= generate_results
|
81
|
+
end
|
82
|
+
|
83
|
+
def bits
|
84
|
+
query_string.
|
85
|
+
gsub(/[^\w]/, " ").
|
86
|
+
gsub("_", " ").
|
87
|
+
split(/\s/).
|
88
|
+
map {|b| b.strip}.
|
89
|
+
reject {|b| b == "" or org.apache.lucene.analysis.standard.StandardAnalyzer::STOP_WORDS_SET.to_a.include?(b)}
|
90
|
+
end
|
91
|
+
|
92
|
+
def doc_ids
|
93
|
+
@doc_ids ||= begin
|
94
|
+
index = ProjectSearch.indexes[project.path].lucene_index
|
95
|
+
doc_ids = nil
|
96
|
+
bits.each do |bit|
|
97
|
+
new_doc_ids = index.find(:contents => bit.downcase).map {|doc| doc.id }
|
98
|
+
doc_ids = doc_ids ? (doc_ids & new_doc_ids) : new_doc_ids
|
99
|
+
end
|
100
|
+
doc_ids
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
@@ -0,0 +1,207 @@
|
|
1
|
+
|
2
|
+
class ProjectSearch
|
3
|
+
class WordSearchController
|
4
|
+
include Redcar::HtmlController
|
5
|
+
|
6
|
+
TITLE = "Project Search"
|
7
|
+
|
8
|
+
def title
|
9
|
+
TITLE
|
10
|
+
end
|
11
|
+
|
12
|
+
def search_copy
|
13
|
+
"Search for complete words only"
|
14
|
+
end
|
15
|
+
|
16
|
+
def show_literal_match_option?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def num_context_lines
|
21
|
+
settings['context_lines']
|
22
|
+
end
|
23
|
+
|
24
|
+
def plugin_root
|
25
|
+
File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def settings
|
29
|
+
ProjectSearch.storage
|
30
|
+
end
|
31
|
+
|
32
|
+
def match_case?
|
33
|
+
ProjectSearch.storage['match_case']
|
34
|
+
end
|
35
|
+
|
36
|
+
def context?
|
37
|
+
ProjectSearch.storage['with_context']
|
38
|
+
end
|
39
|
+
|
40
|
+
def context_size
|
41
|
+
context? ? num_context_lines : 0
|
42
|
+
end
|
43
|
+
|
44
|
+
def default_query
|
45
|
+
doc.selected_text if doc && doc.selection?
|
46
|
+
end
|
47
|
+
|
48
|
+
def index
|
49
|
+
render('index')
|
50
|
+
end
|
51
|
+
|
52
|
+
def edit_preferences
|
53
|
+
Redcar.app.make_sure_at_least_one_window_open # open a new window if needed
|
54
|
+
Redcar::FindInProject.storage # populate the file if it isn't already
|
55
|
+
tab = Redcar.app.focussed_window.new_tab(Redcar::EditTab)
|
56
|
+
mirror = Project::FileMirror.new(File.join(Redcar.user_dir, "storage", "find_in_project.yaml"))
|
57
|
+
tab.edit_view.document.mirror = mirror
|
58
|
+
tab.edit_view.reset_undo
|
59
|
+
tab.focus
|
60
|
+
end
|
61
|
+
|
62
|
+
def open_file(file, line, query, literal_match, match_case)
|
63
|
+
Redcar::Project::Manager.open_file(File.expand_path(file, Redcar::Project::Manager.focussed_project.path))
|
64
|
+
doc.cursor_offset = doc.offset_at_line(line.to_i - 1)
|
65
|
+
regexp_text = literal_match ? Regexp.escape(query) : query
|
66
|
+
regex = match_case ? /(#{regexp_text})/ : /(#{regexp_text})/i
|
67
|
+
index = doc.get_line(line.to_i - 1).index(regex)
|
68
|
+
if index
|
69
|
+
length = doc.get_line(line.to_i - 1).match(regex)[1].length
|
70
|
+
doc.set_selection_range(doc.cursor_line_start_offset + index, doc.cursor_line_start_offset + index + length)
|
71
|
+
end
|
72
|
+
doc.scroll_to_line(line.to_i)
|
73
|
+
nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def close
|
77
|
+
Thread.kill(@thread) if @thread
|
78
|
+
@thread = nil
|
79
|
+
super
|
80
|
+
end
|
81
|
+
|
82
|
+
def render(view, bg=nil)
|
83
|
+
erb(view).result(bg || binding)
|
84
|
+
end
|
85
|
+
|
86
|
+
def render_file(bg)
|
87
|
+
@erb ||= erb("_file")
|
88
|
+
@erb.result(bg)
|
89
|
+
end
|
90
|
+
|
91
|
+
def erb(view)
|
92
|
+
ERB.new(File.read(File.join(File.dirname(__FILE__), "views", "#{view.to_s}.html.erb")))
|
93
|
+
end
|
94
|
+
|
95
|
+
def doc
|
96
|
+
Redcar.app.focussed_window.focussed_notebook_tab.edit_view.document rescue false
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_or_move_to_top(item, array)
|
100
|
+
return array if item.strip.empty?
|
101
|
+
array.delete_at(array.index(item)) if array.include?(item)
|
102
|
+
array.unshift(item)
|
103
|
+
end
|
104
|
+
|
105
|
+
def search(query, literal_match, match_case, with_context)
|
106
|
+
ProjectSearch.storage['recent_queries'] = add_or_move_to_top(query, ProjectSearch.storage['recent_queries'])
|
107
|
+
ProjectSearch.storage['match_case'] = (match_case == 'true')
|
108
|
+
ProjectSearch.storage['with_context'] = (with_context == 'true')
|
109
|
+
|
110
|
+
project = Redcar::Project::Manager.focussed_project
|
111
|
+
|
112
|
+
@word_search = WordSearch.new(project, query, match_case?, context_size)
|
113
|
+
|
114
|
+
# kill any existing running search to prevent memory bloat
|
115
|
+
Thread.kill(@thread) if @thread
|
116
|
+
@thread = nil
|
117
|
+
@thread = Thread.new do
|
118
|
+
begin
|
119
|
+
initialize_search_output
|
120
|
+
file_num = 0
|
121
|
+
line_num = 0
|
122
|
+
have_prepared_table = false
|
123
|
+
have_results = false
|
124
|
+
|
125
|
+
@word_search.on_file_results do |hits|
|
126
|
+
next unless hits.any?
|
127
|
+
have_results = true
|
128
|
+
file_num += 1
|
129
|
+
line_num += hits.length
|
130
|
+
set_file_count(file_num)
|
131
|
+
set_line_count(line_num)
|
132
|
+
file = hits.first.file
|
133
|
+
|
134
|
+
unless have_prepared_table
|
135
|
+
prepare_results_table
|
136
|
+
have_prepared_table = true
|
137
|
+
end
|
138
|
+
|
139
|
+
file_html = render_file(binding)
|
140
|
+
escaped_file_html = escape_javascript(file_html)
|
141
|
+
execute("$('#results table tr:last').after(\"#{escaped_file_html}\");")
|
142
|
+
end
|
143
|
+
|
144
|
+
@word_search.generate_results
|
145
|
+
|
146
|
+
if have_results
|
147
|
+
remove_initial_blank_tr
|
148
|
+
else
|
149
|
+
render_no_results
|
150
|
+
end
|
151
|
+
|
152
|
+
hide_spinner
|
153
|
+
Thread.kill(@thread) if @thread
|
154
|
+
@thread = nil
|
155
|
+
rescue => e
|
156
|
+
puts e.message
|
157
|
+
puts e.backtrace
|
158
|
+
end
|
159
|
+
end
|
160
|
+
nil
|
161
|
+
end
|
162
|
+
|
163
|
+
def initialize_search_output
|
164
|
+
execute("$('#cached_query').val(\"#{escape_javascript(@word_search.query_string)}\");")
|
165
|
+
execute("$('#results').html(\"<div id='no_results'>Searching...</div>\");")
|
166
|
+
execute("$('#spinner').show();")
|
167
|
+
execute("$('#results_summary').hide();")
|
168
|
+
execute("$('#file_results_count').html(0);")
|
169
|
+
execute("$('#line_results_count').html(0);")
|
170
|
+
end
|
171
|
+
|
172
|
+
def prepare_results_table
|
173
|
+
execute("if ($('#results table').size() == 0) { $('#results').html(\"<table><tr></tr></table>\"); }")
|
174
|
+
execute("if ($('#results_summary').first().is(':hidden')) { $('#results_summary').show(); }")
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_file_count(value)
|
178
|
+
execute("$('#file_results_count').html(\"#{value}\");")
|
179
|
+
end
|
180
|
+
|
181
|
+
def set_line_count(value)
|
182
|
+
execute("$('#line_results_count').html(\"#{value}\");")
|
183
|
+
end
|
184
|
+
|
185
|
+
def remove_initial_blank_tr
|
186
|
+
execute("$('#results table tr:first').remove();")
|
187
|
+
end
|
188
|
+
|
189
|
+
def render_no_results
|
190
|
+
result = "<div id='no_results'>No results were found using the search terms you provided.</div>"
|
191
|
+
execute("$('#results').html(\"#{escape_javascript(result)}\");")
|
192
|
+
end
|
193
|
+
|
194
|
+
def hide_spinner
|
195
|
+
execute("$('#spinner').hide();")
|
196
|
+
end
|
197
|
+
|
198
|
+
def escape_javascript(text)
|
199
|
+
escape_map = { '\\' => '\\\\', '</' => '<\/', "\r\n" => '\n', "\n" => '\n', "\r" => '\n', '"' => '\\"', "'" => "\\'" }
|
200
|
+
text.to_s.gsub(/(\\|<\/|\r\n|[\n\r"'])/) { escape_map[$1] }
|
201
|
+
end
|
202
|
+
|
203
|
+
def image_path
|
204
|
+
File.expand_path(File.join(plugin_root, %w(lib project_search images)))
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|