function _doSearch(queryInfo, candidateFilesPromise, filter) {
        searchModel.filter = filter;

        var queryResult = searchModel.setQueryInfo(queryInfo);
        if (!queryResult) {
            return null;
        }

        var scopeName = searchModel.scope ? searchModel.scope.fullPath : ProjectManager.getProjectRoot().fullPath,
            perfTimer = PerfUtils.markStart("FindIn: " + scopeName + " - " + queryInfo.query);

        findOrReplaceInProgress = true;

        return candidateFilesPromise
            .then(function (fileListResult) {
                // Filter out files/folders that match user's current exclusion filter
                fileListResult = FileFilters.filterFileList(filter, fileListResult);

                if (searchModel.isReplace || FindUtils.isNodeSearchDisabled()) {
                    if (fileListResult.length) {
                        searchModel.allResultsAvailable = true;
                        return Async.doInParallel(fileListResult, _doSearchInOneFile);
                    } else {
                        return ZERO_FILES_TO_SEARCH;
                    }
                }

                var searchDeferred = new $.Deferred();

                if (fileListResult.length) {
                    var searchObject;
                    if (searchScopeChanged) {
                        var files = fileListResult
                            .filter(function (entry) {
                                return entry.isFile && _isReadableText(entry.fullPath);
                            })
                            .map(function (entry) {
                                return entry.fullPath;
                            });

                        /* The following line prioritizes the open Document in editor and
                         * pushes it to the top of the filelist. */
                        files = FindUtils.prioritizeOpenFile(files, FindUtils.getOpenFilePath());

                        searchObject = {
                            "files": files,
                            "queryInfo": queryInfo,
                            "queryExpr": searchModel.queryExpr
                        };
                        searchScopeChanged = false;
                    } else {
                        searchObject = {
                            "queryInfo": queryInfo,
                            "queryExpr": searchModel.queryExpr
                        };
                    }

                    if (searchModel.isReplace) {
                        searchObject.getAllResults = true;
                    }
                    _updateChangedDocs();
                    FindUtils.notifyNodeSearchStarted();
                    searchDomain.exec("doSearch", searchObject)
                        .done(function (rcvd_object) {
                            FindUtils.notifyNodeSearchFinished();
                            if (!rcvd_object || !rcvd_object.results) {
                                console.log('no node falling back to brackets search');
                                FindUtils.setNodeSearchDisabled(true);
                                searchDeferred.fail();
                                clearSearch();
                                return;
                            }
                            searchModel.results = rcvd_object.results;
                            searchModel.numMatches = rcvd_object.numMatches;
                            searchModel.numFiles = rcvd_object.numFiles;
                            searchModel.exceedsMaximum = rcvd_object.exceedsMaximum;
                            searchModel.allResultsAvailable = rcvd_object.allResultsAvailable;
                            searchDeferred.resolve();
                        })
                        .fail(function () {
                            FindUtils.notifyNodeSearchFinished();
                            console.log('node fails');
                            FindUtils.setNodeSearchDisabled(true);
                            clearSearch();
                            searchDeferred.reject();
                        });
                    return searchDeferred.promise();
                } else {
                    return ZERO_FILES_TO_SEARCH;
                }
            })
            .then(function (zeroFilesToken) {
                exports._searchDone = true; // for unit tests
                PerfUtils.addMeasurement(perfTimer);

                if (zeroFilesToken === ZERO_FILES_TO_SEARCH) {
                    return zeroFilesToken;
                } else {
                    return searchModel.results;
                }
            }, function (err) {
                console.log("find in files failed: ", err);
                PerfUtils.finalizeMeasurement(perfTimer);

                // In jQuery promises, returning the error here propagates the rejection,
                // unlike in Promises/A, where we would need to re-throw it to do so.
                return err;
            });
    }
@private
Executes the Find in Files search inside the current scope.
@param {{query: string, caseSensitive: boolean, isRegexp: boolean}} queryInfo Query info object
@param {!$.Promise} candidateFilesPromise Promise from getCandidateFiles(), which was called earlier
@param {?string} filter A "compiled" filter as returned by FileFilters.compile(), or null for no filter
@return {?$.Promise} A promise that's resolved with the search results (or ZERO_FILES_TO_SEARCH) or rejected when the find competes.
     Will be null if the query is invalid.