/** * Does a set of replacements in a single file on disk. * @param {string} fullPath The full path to the file. * @param {Object} matchInfo The match info for this file, as returned by `_addSearchMatches()`. * @param {string} replaceText The text to replace each result with. * @param {boolean=} isRegexp Whether the original query was a regexp. * @return {$.Promise} A promise that's resolved when the replacement is finished or rejected with an error if there were one or more errors. */ function _doReplaceOnDisk(fullPath, matchInfo, replaceText, isRegexp) { var file = FileSystem.getFileForPath(fullPath); return DocumentManager.getDocumentText(file, true).then(function (contents, timestamp, lineEndings) { if (timestamp.getTime() !== matchInfo.timestamp.getTime()) { // Return a promise that we'll reject immediately. (We can't just return the // error since this is the success handler.) return new $.Deferred().reject(exports.ERROR_FILE_CHANGED).promise(); } // Note that this assumes that the matches are sorted. // TODO: is there a more efficient way to do this in a large string? var result = [], lastIndex = 0; matchInfo.matches.forEach(function (match) { if (match.isChecked) { result.push(contents.slice(lastIndex, match.startOffset)); result.push(isRegexp ? parseDollars(replaceText, match.result) : replaceText); lastIndex = match.endOffset; } }); result.push(contents.slice(lastIndex)); var newContents = result.join(""); // TODO: duplicated logic from Document - should refactor this? if (lineEndings === FileUtils.LINE_ENDINGS_CRLF) { newContents = newContents.replace(/\n/g, "\r\n"); } return Async.promisify(file, "write", newContents); }); }
/** * Runs a file inspection over passed file, specifying a provider is optional. * This method doesn't update the Brackets UI, just provides inspection results. * These results will reflect any unsaved changes present in the file that is currently opened. * * @param {!File} file File that will be inspected for errors. * @param ?{{name:string, scanFile:function(string, string):?{!errors:Array, aborted:boolean}} provider * @return {$.Promise} a jQuery promise that will be resolved with ?{!errors:Array, aborted:boolean} */ function inspectFile(file, provider) { var response = new $.Deferred(); provider = provider || getProviderForPath(file.fullPath); if (!provider) { response.resolve(null); return response.promise(); } DocumentManager.getDocumentText(file) .done(function (fileText) { var result, perfTimerInspector = PerfUtils.markStart("CodeInspection '" + provider.name + "':\t" + file.fullPath); try { result = provider.scanFile(fileText, file.fullPath); } catch (err) { console.error("[CodeInspection] Provider " + provider.name + " threw an error: " + err); response.reject(err); return; } PerfUtils.addMeasurement(perfTimerInspector); response.resolve(result); }) .fail(function (err) { console.error("[CodeInspection] Could not read file for inspection: " + file.fullPath); response.reject(err); }); return response.promise(); }
function _doSearchInOneFile(addMatches, file) { var result = new $.Deferred(); if (!_subtreeFilter(file, currentScope)) { result.resolve(); } else { DocumentManager.getDocumentText(file) .done(function (text) { addMatches(file.fullPath, text, currentQueryExpr); }) .always(function () { // Always resolve. If there is an error, this file // is skipped and we move on to the next file. result.resolve(); }); } return result.promise(); }
/** * @private * Finds search results in the given file and adds them to 'searchResults.' Resolves with * true if any matches found, false if none found. Errors reading the file are treated the * same as if no results found. * * Does not perform any filtering - assumes caller has already vetted this file as a search * candidate. * * @param {!File} file * @return {$.Promise} */ function _doSearchInOneFile(file) { var result = new $.Deferred(); DocumentManager.getDocumentText(file) .done(function (text, timestamp) { // Note that we don't fire a model change here, since this is always called by some outer batch // operation that will fire it once it's done. var matches = _getSearchMatches(text, searchModel.queryExpr); searchModel.setResults(file.fullPath, {matches: matches, timestamp: timestamp}); result.resolve(!!matches.length); }) .fail(function () { // Always resolve. If there is an error, this file // is skipped and we move on to the next file. result.resolve(false); }); return result.promise(); }
Async.doInParallel(fileListResult, function (file) { var result = new $.Deferred(); if (!_inScope(file, currentScope)) { result.resolve(); } else { DocumentManager.getDocumentText(file) .done(function (text) { _addSearchMatches(file.fullPath, text, currentQueryExpr); result.resolve(); }) .fail(function (error) { // Always resolve. If there is an error, this file // is skipped and we move on to the next file. result.resolve(); }); } return result.promise(); })
/** * Runs a file inspection over passed file. Uses the given list of providers if specified, otherwise uses * the set of providers that are registered for the file's language. * This method doesn't update the Brackets UI, just provides inspection results. * These results will reflect any unsaved changes present in the file if currently open. * * The Promise yields an array of provider-result pair objects (the result is the return value of the * provider's scanFile() - see register() for details). The result object may be null if there were no * errors from that provider. * If there are no providers registered for this file, the Promise yields null instead. * * @param {!File} file File that will be inspected for errors. * @param {?Array.<{name:string, scanFile:function(string, string):?{errors:!Array, aborted:boolean}}>} providerList * @return {$.Promise} a jQuery promise that will be resolved with ?Array.<{provider:Object, result: ?{errors:!Array, aborted:boolean}}> */ function inspectFile(file, providerList) { var response = new $.Deferred(), results = []; providerList = (providerList || getProvidersForPath(file.fullPath)) || []; if (!providerList.length) { response.resolve(null); return response.promise(); } DocumentManager.getDocumentText(file) .done(function (fileText) { var perfTimerInspector = PerfUtils.markStart("CodeInspection:\t" + file.fullPath); providerList.forEach(function (provider) { var perfTimerProvider = PerfUtils.markStart("CodeInspection '" + provider.name + "':\t" + file.fullPath); try { var scanResult = provider.scanFile(fileText, file.fullPath); results.push({provider: provider, result: scanResult}); } catch (err) { console.error("[CodeInspection] Provider " + provider.name + " threw an error: " + err); response.reject(err); return; } PerfUtils.addMeasurement(perfTimerProvider); }); PerfUtils.addMeasurement(perfTimerInspector); response.resolve(results); }) .fail(function (err) { console.error("[CodeInspection] Could not read file for inspection: " + file.fullPath); response.reject(err); }); return response.promise(); }
/** * Runs a file inspection over passed file. Uses the given list of providers if specified, otherwise uses * the set of providers that are registered for the file's language. * This method doesn't update the Brackets UI, just provides inspection results. * These results will reflect any unsaved changes present in the file if currently open. * * The Promise yields an array of provider-result pair objects (the result is the return value of the * provider's scanFile() - see register() for details). The result object may be null if there were no * errors from that provider. * If there are no providers registered for this file, the Promise yields null instead. * * @param {!File} file File that will be inspected for errors. * @param {?Array.<{name:string, scanFileAsync:?function(string, string):!{$.Promise}, scanFile:?function(string, string):?{errors:!Array, aborted:boolean}}>} providerList * @return {$.Promise} a jQuery promise that will be resolved with ?Array.<{provider:Object, result: ?{errors:!Array, aborted:boolean}}> */ function inspectFile(file, providerList) { var response = new $.Deferred(), results = []; providerList = (providerList || getProvidersForPath(file.fullPath)) || []; if (!providerList.length) { response.resolve(null); return response.promise(); } DocumentManager.getDocumentText(file) .done(function (fileText) { var perfTimerInspector = PerfUtils.markStart("CodeInspection:\t" + file.fullPath), masterPromise; masterPromise = Async.doInParallel(providerList, function (provider) { var perfTimerProvider = PerfUtils.markStart("CodeInspection '" + provider.name + "':\t" + file.fullPath), runPromise = new $.Deferred(); runPromise.done(function (scanResult) { results.push({provider: provider, result: scanResult}); }); if (provider.scanFileAsync) { window.setTimeout(function () { // timeout error var errTimeout = { pos: { line: -1, col: 0}, message: StringUtils.format(Strings.LINTER_TIMED_OUT, provider.name, prefs.get(PREF_ASYNC_TIMEOUT)), type: Type.ERROR }; runPromise.resolve({errors: [errTimeout]}); }, prefs.get(PREF_ASYNC_TIMEOUT)); provider.scanFileAsync(fileText, file.fullPath) .done(function (scanResult) { PerfUtils.addMeasurement(perfTimerProvider); runPromise.resolve(scanResult); }) .fail(function (err) { var errError = { pos: {line: -1, col: 0}, message: StringUtils.format(Strings.LINTER_FAILED, provider.name, err), type: Type.ERROR }; console.error("[CodeInspection] Provider " + provider.name + " (async) failed: " + err); runPromise.resolve({errors: [errError]}); }); } else { try { var scanResult = provider.scanFile(fileText, file.fullPath); PerfUtils.addMeasurement(perfTimerProvider); runPromise.resolve(scanResult); } catch (err) { var errError = { pos: {line: -1, col: 0}, message: StringUtils.format(Strings.LINTER_FAILED, provider.name, err), type: Type.ERROR }; console.error("[CodeInspection] Provider " + provider.name + " (sync) threw an error: " + err); runPromise.resolve({errors: [errError]}); } } return runPromise.promise(); }, false); masterPromise.then(function () { // sync async may have pushed results in different order, restore the original order results.sort(function (a, b) { return providerList.indexOf(a.provider) - providerList.indexOf(b.provider); }); PerfUtils.addMeasurement(perfTimerInspector); response.resolve(results); }); }) .fail(function (err) { console.error("[CodeInspection] Could not read file for inspection: " + file.fullPath); response.reject(err); }); return response.promise(); }