2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
16 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
20 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * @implements {WebInspector.SearchScope}
33 WebInspector
.SourcesSearchScope = function()
35 // FIXME: Add title once it is used by search controller.
40 * @param {!WebInspector.UISourceCode} uiSourceCode1
41 * @param {!WebInspector.UISourceCode} uiSourceCode2
44 WebInspector
.SourcesSearchScope
._filesComparator = function(uiSourceCode1
, uiSourceCode2
)
46 if (uiSourceCode1
.isDirty() && !uiSourceCode2
.isDirty())
48 if (!uiSourceCode1
.isDirty() && uiSourceCode2
.isDirty())
50 var networkURL1
= WebInspector
.networkMapping
.networkURL(uiSourceCode1
);
51 var networkURL2
= WebInspector
.networkMapping
.networkURL(uiSourceCode2
);
52 if (networkURL1
&& !networkURL2
)
54 if (!networkURL1
&& networkURL2
)
56 return String
.naturalOrderComparator(uiSourceCode1
.fullDisplayName(), uiSourceCode2
.fullDisplayName());
60 WebInspector
.SourcesSearchScope
.prototype = {
63 * @param {!WebInspector.Progress} progress
65 performIndexing: function(progress
)
69 var projects
= this._projects();
70 var compositeProgress
= new WebInspector
.CompositeProgress(progress
);
71 for (var i
= 0; i
< projects
.length
; ++i
) {
72 var project
= projects
[i
];
73 var projectProgress
= compositeProgress
.createSubProgress(project
.uiSourceCodes().length
);
74 project
.indexContent(projectProgress
);
79 * @return {!Array.<!WebInspector.Project>}
84 * @param {!WebInspector.Project} project
87 function filterOutServiceProjects(project
)
89 return !project
.isServiceProject() || project
.type() === WebInspector
.projectTypes
.Formatter
;
93 * @param {!WebInspector.Project} project
96 function filterOutContentScriptsIfNeeded(project
)
98 return WebInspector
.moduleSetting("searchInContentScripts").get() || project
.type() !== WebInspector
.projectTypes
.ContentScripts
;
101 return WebInspector
.workspace
.projects().filter(filterOutServiceProjects
).filter(filterOutContentScriptsIfNeeded
);
106 * @param {!WebInspector.ProjectSearchConfig} searchConfig
107 * @param {!WebInspector.Progress} progress
108 * @param {function(!WebInspector.FileBasedSearchResult)} searchResultCallback
109 * @param {function(boolean)} searchFinishedCallback
111 performSearch: function(searchConfig
, progress
, searchResultCallback
, searchFinishedCallback
)
114 this._searchResultCandidates
= [];
115 this._searchResultCallback
= searchResultCallback
;
116 this._searchFinishedCallback
= searchFinishedCallback
;
117 this._searchConfig
= searchConfig
;
119 var projects
= this._projects();
120 var barrier
= new CallbackBarrier();
121 var compositeProgress
= new WebInspector
.CompositeProgress(progress
);
122 var searchContentProgress
= compositeProgress
.createSubProgress();
123 var findMatchingFilesProgress
= new WebInspector
.CompositeProgress(compositeProgress
.createSubProgress());
124 for (var i
= 0; i
< projects
.length
; ++i
) {
125 var project
= projects
[i
];
126 var weight
= project
.uiSourceCodes().length
;
127 var findMatchingFilesInProjectProgress
= findMatchingFilesProgress
.createSubProgress(weight
);
128 var barrierCallback
= barrier
.createCallback();
129 var filesMathingFileQuery
= this._projectFilesMatchingFileQuery(project
, searchConfig
);
130 var callback
= this._processMatchingFilesForProject
.bind(this, this._searchId
, project
, filesMathingFileQuery
, barrierCallback
);
131 project
.findFilesMatchingSearchRequest(searchConfig
, filesMathingFileQuery
, findMatchingFilesInProjectProgress
, callback
);
133 barrier
.callWhenDone(this._processMatchingFiles
.bind(this, this._searchId
, searchContentProgress
, this._searchFinishedCallback
.bind(this, true)));
137 * @param {!WebInspector.Project} project
138 * @param {!WebInspector.ProjectSearchConfig} searchConfig
139 * @param {boolean=} dirtyOnly
140 * @return {!Array.<string>}
142 _projectFilesMatchingFileQuery: function(project
, searchConfig
, dirtyOnly
)
145 var uiSourceCodes
= project
.uiSourceCodes();
146 for (var i
= 0; i
< uiSourceCodes
.length
; ++i
) {
147 var uiSourceCode
= uiSourceCodes
[i
];
148 if (dirtyOnly
&& !uiSourceCode
.isDirty())
150 if (this._searchConfig
.filePathMatchesFileQuery(uiSourceCode
.fullDisplayName()))
151 result
.push(uiSourceCode
.path());
153 result
.sort(String
.naturalOrderComparator
);
158 * @param {number} searchId
159 * @param {!WebInspector.Project} project
160 * @param {!Array.<string>} filesMathingFileQuery
161 * @param {function()} callback
162 * @param {!Array.<string>} files
164 _processMatchingFilesForProject: function(searchId
, project
, filesMathingFileQuery
, callback
, files
)
166 if (searchId
!== this._searchId
) {
167 this._searchFinishedCallback(false);
171 files
.sort(String
.naturalOrderComparator
);
172 files
= files
.intersectOrdered(filesMathingFileQuery
, String
.naturalOrderComparator
);
173 var dirtyFiles
= this._projectFilesMatchingFileQuery(project
, this._searchConfig
, true);
174 files
= files
.mergeOrdered(dirtyFiles
, String
.naturalOrderComparator
);
176 var uiSourceCodes
= [];
177 for (var i
= 0; i
< files
.length
; ++i
) {
178 var uiSourceCode
= project
.uiSourceCode(files
[i
]);
180 uiSourceCodes
.push(uiSourceCode
);
182 uiSourceCodes
.sort(WebInspector
.SourcesSearchScope
._filesComparator
);
183 this._searchResultCandidates
= this._searchResultCandidates
.mergeOrdered(uiSourceCodes
, WebInspector
.SourcesSearchScope
._filesComparator
);
188 * @param {number} searchId
189 * @param {!WebInspector.Progress} progress
190 * @param {function()} callback
192 _processMatchingFiles: function(searchId
, progress
, callback
)
194 if (searchId
!== this._searchId
) {
195 this._searchFinishedCallback(false);
199 var files
= this._searchResultCandidates
;
206 progress
.setTotalWork(files
.length
);
209 var maxFileContentRequests
= 20;
210 var callbacksLeft
= 0;
212 for (var i
= 0; i
< maxFileContentRequests
&& i
< files
.length
; ++i
)
213 scheduleSearchInNextFileOrFinish
.call(this);
216 * @param {!WebInspector.UISourceCode} uiSourceCode
217 * @this {WebInspector.SourcesSearchScope}
219 function searchInNextFile(uiSourceCode
)
221 if (uiSourceCode
.isDirty())
222 contentLoaded
.call(this, uiSourceCode
, uiSourceCode
.workingCopy());
224 uiSourceCode
.checkContentUpdated(contentUpdated
.bind(this, uiSourceCode
));
228 * @param {!WebInspector.UISourceCode} uiSourceCode
229 * @this {WebInspector.SourcesSearchScope}
231 function contentUpdated(uiSourceCode
)
233 uiSourceCode
.requestContent(contentLoaded
.bind(this, uiSourceCode
));
237 * @this {WebInspector.SourcesSearchScope}
239 function scheduleSearchInNextFileOrFinish()
241 if (fileIndex
>= files
.length
) {
242 if (!callbacksLeft
) {
251 var uiSourceCode
= files
[fileIndex
++];
252 setTimeout(searchInNextFile
.bind(this, uiSourceCode
), 0);
256 * @param {!WebInspector.UISourceCode} uiSourceCode
257 * @param {?string} content
258 * @this {WebInspector.SourcesSearchScope}
260 function contentLoaded(uiSourceCode
, content
)
263 * @param {!WebInspector.ContentProvider.SearchMatch} a
264 * @param {!WebInspector.ContentProvider.SearchMatch} b
266 function matchesComparator(a
, b
)
268 return a
.lineNumber
- b
.lineNumber
;
273 var queries
= this._searchConfig
.queries();
274 if (content
!== null) {
275 for (var i
= 0; i
< queries
.length
; ++i
) {
276 var nextMatches
= WebInspector
.ContentProvider
.performSearchInContent(content
, queries
[i
], !this._searchConfig
.ignoreCase(), this._searchConfig
.isRegex());
277 matches
= matches
.mergeOrdered(nextMatches
, matchesComparator
);
281 var searchResult
= new WebInspector
.FileBasedSearchResult(uiSourceCode
, matches
);
282 this._searchResultCallback(searchResult
);
286 scheduleSearchInNextFileOrFinish
.call(this);
293 stopSearch: function()
300 * @param {!WebInspector.ProjectSearchConfig} searchConfig
301 * @return {!WebInspector.FileBasedSearchResultsPane}
303 createSearchResultsPane: function(searchConfig
)
305 return new WebInspector
.FileBasedSearchResultsPane(searchConfig
);