blob: 39187c7602be53c8d0aa6b27295913f9c50ee193 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
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
14 * distribution.
15 *
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.
27 */
28/**
29 * @implements {Search.SearchScope}
30 */
31Sources.SourcesSearchScope = class {
32 constructor() {
33 // FIXME: Add title once it is used by search controller.
34 this._searchId = 0;
35 /** @type {!Array<!Workspace.UISourceCode>} */
36 this._searchResultCandidates = [];
37 /** @type {?function(!Search.SearchResult)} */
38 this._searchResultCallback = null;
39 /** @type {?function(boolean)} */
40 this._searchFinishedCallback = null;
41 /** @type {?Workspace.ProjectSearchConfig} */
42 this._searchConfig = null;
43 }
44
45 /**
46 * @param {!Workspace.UISourceCode} uiSourceCode1
47 * @param {!Workspace.UISourceCode} uiSourceCode2
48 * @return {number}
49 */
50 static _filesComparator(uiSourceCode1, uiSourceCode2) {
Tim van der Lippe1d6e57a2019-09-30 11:55:3451 if (uiSourceCode1.isDirty() && !uiSourceCode2.isDirty()) {
Blink Reformat4c46d092018-04-07 15:32:3752 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:3453 }
54 if (!uiSourceCode1.isDirty() && uiSourceCode2.isDirty()) {
Blink Reformat4c46d092018-04-07 15:32:3755 return 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:3456 }
Joel Einbinderef3555d2018-12-04 02:14:4457 const isFileSystem1 = uiSourceCode1.project().type() === Workspace.projectTypes.FileSystem &&
58 !Persistence.persistence.binding(uiSourceCode1);
59 const isFileSystem2 = uiSourceCode2.project().type() === Workspace.projectTypes.FileSystem &&
60 !Persistence.persistence.binding(uiSourceCode2);
Tim van der Lippe1d6e57a2019-09-30 11:55:3461 if (isFileSystem1 !== isFileSystem2) {
Joel Einbinderef3555d2018-12-04 02:14:4462 return isFileSystem1 ? 1 : -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:3463 }
Blink Reformat4c46d092018-04-07 15:32:3764 const url1 = uiSourceCode1.url();
65 const url2 = uiSourceCode2.url();
Tim van der Lippe1d6e57a2019-09-30 11:55:3466 if (url1 && !url2) {
Blink Reformat4c46d092018-04-07 15:32:3767 return -1;
Tim van der Lippe1d6e57a2019-09-30 11:55:3468 }
69 if (!url1 && url2) {
Blink Reformat4c46d092018-04-07 15:32:3770 return 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:3471 }
Blink Reformat4c46d092018-04-07 15:32:3772 return String.naturalOrderComparator(uiSourceCode1.fullDisplayName(), uiSourceCode2.fullDisplayName());
73 }
74
75 /**
76 * @override
77 * @param {!Common.Progress} progress
78 */
79 performIndexing(progress) {
80 this.stopSearch();
81
82 const projects = this._projects();
83 const compositeProgress = new Common.CompositeProgress(progress);
84 for (let i = 0; i < projects.length; ++i) {
85 const project = projects[i];
86 const projectProgress = compositeProgress.createSubProgress(project.uiSourceCodes().length);
87 project.indexContent(projectProgress);
88 }
89 }
90
91 /**
92 * @return {!Array.<!Workspace.Project>}
93 */
94 _projects() {
95 const searchInAnonymousAndContentScripts = Common.moduleSetting('searchInAnonymousAndContentScripts').get();
96
97 return Workspace.workspace.projects().filter(project => {
Tim van der Lippe1d6e57a2019-09-30 11:55:3498 if (project.type() === Workspace.projectTypes.Service) {
Blink Reformat4c46d092018-04-07 15:32:3799 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34100 }
101 if (!searchInAnonymousAndContentScripts && project.isServiceProject()) {
Blink Reformat4c46d092018-04-07 15:32:37102 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34103 }
104 if (!searchInAnonymousAndContentScripts && project.type() === Workspace.projectTypes.ContentScripts) {
Blink Reformat4c46d092018-04-07 15:32:37105 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34106 }
Blink Reformat4c46d092018-04-07 15:32:37107 return true;
108 });
109 }
110
111 /**
112 * @override
113 * @param {!Workspace.ProjectSearchConfig} searchConfig
114 * @param {!Common.Progress} progress
115 * @param {function(!Search.SearchResult)} searchResultCallback
116 * @param {function(boolean)} searchFinishedCallback
117 */
118 performSearch(searchConfig, progress, searchResultCallback, searchFinishedCallback) {
119 this.stopSearch();
120 this._searchResultCandidates = [];
121 this._searchResultCallback = searchResultCallback;
122 this._searchFinishedCallback = searchFinishedCallback;
123 this._searchConfig = searchConfig;
124
125 const promises = [];
126 const compositeProgress = new Common.CompositeProgress(progress);
127 const searchContentProgress = compositeProgress.createSubProgress();
128 const findMatchingFilesProgress = new Common.CompositeProgress(compositeProgress.createSubProgress());
129 for (const project of this._projects()) {
130 const weight = project.uiSourceCodes().length;
131 const findMatchingFilesInProjectProgress = findMatchingFilesProgress.createSubProgress(weight);
132 const filesMathingFileQuery = this._projectFilesMatchingFileQuery(project, searchConfig);
133 const promise =
134 project
135 .findFilesMatchingSearchRequest(searchConfig, filesMathingFileQuery, findMatchingFilesInProjectProgress)
136 .then(this._processMatchingFilesForProject.bind(
137 this, this._searchId, project, searchConfig, filesMathingFileQuery));
138 promises.push(promise);
139 }
140
141 Promise.all(promises).then(this._processMatchingFiles.bind(
142 this, this._searchId, searchContentProgress, this._searchFinishedCallback.bind(this, true)));
143 }
144
145 /**
146 * @param {!Workspace.Project} project
147 * @param {!Workspace.ProjectSearchConfig} searchConfig
148 * @param {boolean=} dirtyOnly
149 * @return {!Array.<string>}
150 */
151 _projectFilesMatchingFileQuery(project, searchConfig, dirtyOnly) {
152 const result = [];
153 const uiSourceCodes = project.uiSourceCodes();
154 for (let i = 0; i < uiSourceCodes.length; ++i) {
155 const uiSourceCode = uiSourceCodes[i];
Tim van der Lippe1d6e57a2019-09-30 11:55:34156 if (!uiSourceCode.contentType().isTextType()) {
Blink Reformat4c46d092018-04-07 15:32:37157 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34158 }
Blink Reformat4c46d092018-04-07 15:32:37159 const binding = Persistence.persistence.binding(uiSourceCode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34160 if (binding && binding.network === uiSourceCode) {
Blink Reformat4c46d092018-04-07 15:32:37161 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34162 }
163 if (dirtyOnly && !uiSourceCode.isDirty()) {
Blink Reformat4c46d092018-04-07 15:32:37164 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34165 }
166 if (searchConfig.filePathMatchesFileQuery(uiSourceCode.fullDisplayName())) {
Blink Reformat4c46d092018-04-07 15:32:37167 result.push(uiSourceCode.url());
Tim van der Lippe1d6e57a2019-09-30 11:55:34168 }
Blink Reformat4c46d092018-04-07 15:32:37169 }
170 result.sort(String.naturalOrderComparator);
171 return result;
172 }
173
174 /**
175 * @param {number} searchId
176 * @param {!Workspace.Project} project
177 * @param {!Workspace.ProjectSearchConfig} searchConfig
178 * @param {!Array<string>} filesMathingFileQuery
179 * @param {!Array<string>} files
180 */
181 _processMatchingFilesForProject(searchId, project, searchConfig, filesMathingFileQuery, files) {
182 if (searchId !== this._searchId) {
183 this._searchFinishedCallback(false);
184 return;
185 }
186
187 files.sort(String.naturalOrderComparator);
188 files = files.intersectOrdered(filesMathingFileQuery, String.naturalOrderComparator);
189 const dirtyFiles = this._projectFilesMatchingFileQuery(project, searchConfig, true);
190 files = files.mergeOrdered(dirtyFiles, String.naturalOrderComparator);
191
192 const uiSourceCodes = [];
193 for (const file of files) {
194 const uiSourceCode = project.uiSourceCodeForURL(file);
Tim van der Lippe1d6e57a2019-09-30 11:55:34195 if (!uiSourceCode) {
Blink Reformat4c46d092018-04-07 15:32:37196 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34197 }
Blink Reformat4c46d092018-04-07 15:32:37198 const script = Bindings.DefaultScriptMapping.scriptForUISourceCode(uiSourceCode);
Tim van der Lippe1d6e57a2019-09-30 11:55:34199 if (script && !script.isAnonymousScript()) {
Blink Reformat4c46d092018-04-07 15:32:37200 continue;
Tim van der Lippe1d6e57a2019-09-30 11:55:34201 }
Blink Reformat4c46d092018-04-07 15:32:37202 uiSourceCodes.push(uiSourceCode);
203 }
204 uiSourceCodes.sort(Sources.SourcesSearchScope._filesComparator);
205 this._searchResultCandidates =
206 this._searchResultCandidates.mergeOrdered(uiSourceCodes, Sources.SourcesSearchScope._filesComparator);
207 }
208
209 /**
210 * @param {number} searchId
211 * @param {!Common.Progress} progress
212 * @param {function()} callback
213 */
214 _processMatchingFiles(searchId, progress, callback) {
215 if (searchId !== this._searchId) {
216 this._searchFinishedCallback(false);
217 return;
218 }
219
220 const files = this._searchResultCandidates;
221 if (!files.length) {
222 progress.done();
223 callback();
224 return;
225 }
226
227 progress.setTotalWork(files.length);
228
229 let fileIndex = 0;
230 const maxFileContentRequests = 20;
231 let callbacksLeft = 0;
232
Tim van der Lippe1d6e57a2019-09-30 11:55:34233 for (let i = 0; i < maxFileContentRequests && i < files.length; ++i) {
Blink Reformat4c46d092018-04-07 15:32:37234 scheduleSearchInNextFileOrFinish.call(this);
Tim van der Lippe1d6e57a2019-09-30 11:55:34235 }
Blink Reformat4c46d092018-04-07 15:32:37236
237 /**
238 * @param {!Workspace.UISourceCode} uiSourceCode
239 * @this {Sources.SourcesSearchScope}
240 */
241 function searchInNextFile(uiSourceCode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34242 if (uiSourceCode.isDirty()) {
Blink Reformat4c46d092018-04-07 15:32:37243 contentLoaded.call(this, uiSourceCode, uiSourceCode.workingCopy());
Tim van der Lippe1d6e57a2019-09-30 11:55:34244 } else {
Rob Paveza2eb8c142019-10-13 18:02:38245 uiSourceCode.requestContent().then(deferredContent => {
246 contentLoaded.call(this, uiSourceCode, deferredContent.content || '');
247 });
Tim van der Lippe1d6e57a2019-09-30 11:55:34248 }
Blink Reformat4c46d092018-04-07 15:32:37249 }
250
251 /**
252 * @this {Sources.SourcesSearchScope}
253 */
254 function scheduleSearchInNextFileOrFinish() {
255 if (fileIndex >= files.length) {
256 if (!callbacksLeft) {
257 progress.done();
258 callback();
259 return;
260 }
261 return;
262 }
263
264 ++callbacksLeft;
265 const uiSourceCode = files[fileIndex++];
266 setTimeout(searchInNextFile.bind(this, uiSourceCode), 0);
267 }
268
269 /**
270 * @param {!Workspace.UISourceCode} uiSourceCode
Rob Paveza2eb8c142019-10-13 18:02:38271 * @param {string} content
Blink Reformat4c46d092018-04-07 15:32:37272 * @this {Sources.SourcesSearchScope}
273 */
274 function contentLoaded(uiSourceCode, content) {
275 /**
276 * @param {!Common.ContentProvider.SearchMatch} a
277 * @param {!Common.ContentProvider.SearchMatch} b
278 */
279 function matchesComparator(a, b) {
280 return a.lineNumber - b.lineNumber;
281 }
282
283 progress.worked(1);
284 let matches = [];
285 const queries = this._searchConfig.queries();
286 if (content !== null) {
287 for (let i = 0; i < queries.length; ++i) {
288 const nextMatches = Common.ContentProvider.performSearchInContent(
289 content, queries[i], !this._searchConfig.ignoreCase(), this._searchConfig.isRegex());
290 matches = matches.mergeOrdered(nextMatches, matchesComparator);
291 }
292 }
293 if (matches) {
294 const searchResult = new Sources.FileBasedSearchResult(uiSourceCode, matches);
295 this._searchResultCallback(searchResult);
296 }
297
298 --callbacksLeft;
299 scheduleSearchInNextFileOrFinish.call(this);
300 }
301 }
302
303 /**
304 * @override
305 */
306 stopSearch() {
307 ++this._searchId;
308 }
309};
310
311
312/**
313 * @implements {Search.SearchResult}
314 */
315Sources.FileBasedSearchResult = class {
316 /**
317 * @param {!Workspace.UISourceCode} uiSourceCode
318 * @param {!Array.<!Common.ContentProvider.SearchMatch>} searchMatches
319 */
320 constructor(uiSourceCode, searchMatches) {
321 this._uiSourceCode = uiSourceCode;
322 this._searchMatches = searchMatches;
323 }
324
325 /**
326 * @override
327 * @return {string}
328 */
329 label() {
330 return this._uiSourceCode.displayName();
331 }
332
333 /**
334 * @override
335 * @return {string}
336 */
337 description() {
338 return this._uiSourceCode.fullDisplayName();
339 }
340
341 /**
342 * @override
343 * @return {number}
344 */
345 matchesCount() {
346 return this._searchMatches.length;
347 }
348
349 /**
350 * @override
351 * @param {number} index
352 * @return {string}
353 */
354 matchLineContent(index) {
355 return this._searchMatches[index].lineContent;
356 }
357
358 /**
359 * @override
360 * @param {number} index
361 * @return {!Object}
362 */
363 matchRevealable(index) {
364 const match = this._searchMatches[index];
Tim van der Lippeffa78622019-09-16 12:07:12365 return this._uiSourceCode.uiLocation(match.lineNumber, undefined);
Blink Reformat4c46d092018-04-07 15:32:37366 }
367
368 /**
369 * @override
370 * @param {number} index
371 * @return {?}
372 */
373 matchLabel(index) {
374 return this._searchMatches[index].lineNumber + 1;
375 }
376};