/** * @private * Loads optional requirejs-config.json file for an extension * @param {Object} baseConfig * @return {$.Promise} */ function _mergeConfig(baseConfig) { var deferred = new $.Deferred(), extensionConfigFile = FileSystem.getFileForPath(baseConfig.baseUrl + "/requirejs-config.json"); // Optional JSON config for require.js FileUtils.readAsText(extensionConfigFile).done(function (text) { try { var extensionConfig = JSON.parse(text); // baseConfig.paths properties will override any extension config paths _.extend(extensionConfig.paths, baseConfig.paths); // Overwrite baseUrl, context, locale (paths is already merged above) _.extend(extensionConfig, _.omit(baseConfig, "paths")); deferred.resolve(extensionConfig); } catch (err) { // Failed to parse requirejs-config.json deferred.reject("failed to parse requirejs-config.json"); } }).fail(function () { // If requirejs-config.json isn't specified, resolve with the baseConfig only deferred.resolve(baseConfig); }); return deferred.promise(); }
FileSystem.resolve(path, function (err) { if (!err) { // Item already exists, fail with error d.reject(FileSystemError.ALREADY_EXISTS); } else { if (isFolder) { var directory = FileSystem.getDirectoryForPath(path); directory.create(function (err) { if (err) { d.reject(err); } else { d.resolve(directory); } }); } else { // Create an empty file var file = FileSystem.getFileForPath(path); FileUtils.writeText(file, "").then(function () { d.resolve(file); }, d.reject); } } });
/** * Determines if the document function cache is up to date. * @param {FileInfo} fileInfo * @return {$.Promise} A promise resolved with true with true when a function cache is available for the document. Resolves * with false when there is no cache or the cache is stale. */ function _shouldGetFromCache(fileInfo) { var result = new $.Deferred(), isChanged = _changedDocumentTracker.isPathChanged(fileInfo.fullPath); if (isChanged && fileInfo.JSUtils) { // See if it's dirty and in the working set first var doc = DocumentManager.getOpenDocumentForPath(fileInfo.fullPath); if (doc && doc.isDirty) { result.resolve(false); } else { // If a cache exists, check the timestamp on disk var file = FileSystem.getFileForPath(fileInfo.fullPath); file.stat(function (err, stat) { if (!err) { result.resolve(fileInfo.JSUtils.timestamp.getTime() === stat.mtime.getTime()); } else { result.reject(err); } }); } } else { // Use the cache if the file did not change and the cache exists result.resolve(!isChanged && fileInfo.JSUtils); } return result.promise(); }
reader.onload = function(e) { delete reader.onload; var filename = Path.join(StartupState.project("root"), item.name); var file = FileSystem.getFileForPath(filename); var ext = Path.extname(filename).toLowerCase(); // Create a Filer Buffer, and determine the proper encoding. We // use the extension, and also the OS provided mime type for clues. var buffer = new Filer.Buffer(e.target.result); var utf8FromExt = Content.isUTF8Encoded(ext); var utf8FromOS = Content.isTextType(item.type); var encoding = utf8FromExt || utf8FromOS ? 'utf8' : null; if(encoding === 'utf8') { buffer = buffer.toString(); } // Special-case .zip files, so we can offer to extract the contents if(ext === ".zip") { handleZipFile(deferred, file, filename, buffer, encoding); } else if(ext === ".tar") { handleTarFile(deferred, file, filename, buffer, encoding); } else { handleRegularFile(deferred, file, filename, buffer, encoding); } };
/** * 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); }); }
/** * Loads a theme from a file. * * @param {string} fileName is the full path to the file to be opened * @param {Object} options is an optional parameter to specify metadata * for the theme. * @return {$.Promise} promise object resolved with the theme to be loaded from fileName */ function loadFile(fileName, options) { var deferred = new $.Deferred(), file = FileSystem.getFileForPath(fileName), currentThemeName = prefs.get("theme"); file.exists(function (err, exists) { var theme; if (exists) { theme = new Theme(file, options); loadedThemes[theme.name] = theme; ThemeSettings._setThemes(loadedThemes); // For themes that are loaded after ThemeManager has been loaded, // we should check if it's the current theme. If it is, then we just // load it. if (currentThemeName === theme.name) { refresh(true); } deferred.resolve(theme); } else if (err || !exists) { deferred.reject(err); } }); return deferred.promise(); }
.done(function (result) { var installationStatus = result.installationStatus; if (installationStatus === InstallationStatuses.ALREADY_INSTALLED || installationStatus === InstallationStatuses.NEEDS_UPDATE || installationStatus === InstallationStatuses.SAME_VERSION || installationStatus === InstallationStatuses.OLDER_VERSION) { // We don't delete the file in this case, because it will be needed // if the user is going to install the update. state = STATE_SUCCEEDED; result.localPath = downloadResult.localPath; d.resolve(result); } else { FileSystem.getFileForPath(downloadResult.localPath).unlink(); if (result.errors && result.errors.length > 0) { // Validation errors - for now, only return the first one state = STATE_FAILED; d.reject(result.errors[0]); } else if (result.disabledReason) { // Extension valid but left disabled (wrong API version, extension name collision, etc.) state = STATE_FAILED; d.reject(result.disabledReason); } else { // Success! Extension is now running in Brackets state = STATE_SUCCEEDED; d.resolve(result); } } })
function writeResults(path, text) { // check if the file already exists var file = FileSystem.getFileForPath(path); file.exists(function (err, exists) { if (err) { _writeResults.reject(err); return; } if (exists) { // file exists, do not overwrite _writeResults.reject(); } else { // file not found, write the new file with xml content FileUtils.writeText(file, text) .done(function () { _writeResults.resolve(); }) .fail(function (err) { _writeResults.reject(err); }); } }); }
/** * @private * * Reads in the user key map file and parses its content into JSON. * Returns the user key bindings if JSON has "overrides". * Otherwise, returns an empty object or an error if the file * cannot be parsed or loaded. * * @return {$.Promise} a jQuery promise that will be resolved with the JSON * object if the user key map file has "overrides" property or an empty JSON. * If the key map file cannot be read or cannot be parsed by the JSON parser, * then the promise is rejected with an error. */ function _readUserKeyMap() { var file = FileSystem.getFileForPath(_getUserKeyMapFilePath()), result = new $.Deferred(); file.exists(function (err, doesExist) { if (doesExist) { FileUtils.readAsText(file) .done(function (text) { var keyMap = {}; try { if (text) { var json = JSON.parse(text); // If no overrides, return an empty key map. result.resolve((json && json.overrides) || keyMap); } else { // The file is empty, so return an empty key map. result.resolve(keyMap); } } catch (err) { // Cannot parse the text read from the key map file. result.reject(err); } }) .fail(function (err) { // Key map file cannot be loaded. result.reject(err); }); } else { // Just resolve if no user key map file result.resolve(); } }); return result.promise(); }
$("#img-preview").on("load", function () { // add dimensions and size _naturalWidth = this.naturalWidth; var dimensionString = _naturalWidth + " × " + this.naturalHeight + " " + Strings.UNIT_PIXELS; // get image size var file = FileSystem.getFileForPath(fullPath); file.stat(function (err, stat) { if (err) { $("#img-data").html(dimensionString); } else { var sizeString = ""; if (stat.size) { sizeString = " — " + StringUtils.prettyPrintBytes(stat.size, 2); } var dimensionAndSize = dimensionString + sizeString; $("#img-data").html(dimensionAndSize) .attr("title", dimensionAndSize .replace("×", "x") .replace("—", "-")); } }); $("#image-holder").show(); // listen to resize to update the scale sticker $(PanelManager).on("editorAreaResize", _onEditorAreaResize); // listen to removal to stop listening to resize events $(EditorManager).on("removeCustomViewer", _removeListeners); $(DocumentManager).on("fileNameChange", _onFileNameChange); _updateScale($(this).width()); });
/** * Loads a SHA from Git metadata file. If the file contains a symbolic ref name, follows the ref * and loads the SHA from that file in turn. */ function _loadSHA(path, callback) { var result = new $.Deferred(); if (brackets.inBrowser) { result.reject(); } else { // HEAD contains a SHA in detached-head mode; otherwise it contains a relative path // to a file in /refs which in turn contains the SHA var file = FileSystem.getFileForPath(path); FileUtils.readAsText(file).done(function (text) { if (text.indexOf("ref: ") === 0) { // e.g. "ref: refs/heads/branchname" var basePath = path.substr(0, path.lastIndexOf("/")), refRelPath = text.substr(5).trim(), branch = text.substr(16).trim(); _loadSHA(basePath + "/" + refRelPath, callback).done(function (data) { result.resolve({ branch: branch, sha: data.sha.trim() }); }).fail(function () { result.resolve({ branch: branch }); }); } else { result.resolve({ sha: text }); } }).fail(function () { result.reject(); }); } return result.promise(); }
/** * @private * * Gets the FileSystem object (either a File or Directory) based on the path provided. * * @param {string} path Path to retrieve */ function _getFSObject(path) { if (!path) { return path; } else if (_pathIsFile(path)) { return FileSystem.getFileForPath(path); } return FileSystem.getDirectoryForPath(path); }
checkExists: function (filename) { var result = new $.Deferred(), file = FileSystem.getFileForPath(filename); file.exists(function (err, doesExist) { result.resolve(doesExist); }); return result.promise(); },
_.forEach(state, function (entry) { filesToAdd.push(FileSystem.getFileForPath(entry.file)); if (entry.active) { activeFile = entry.file; } if (entry.viewState) { viewStates[entry.file] = entry.viewState; } });
files.forEach(function (value, index) { filesToOpen.push(FileSystem.getFileForPath(value.file)); if (value.active) { activeFile = value.file; } if (value.viewState) { viewStates[value.file] = value.viewState; } });
Object.keys(_idsToUpdate).forEach(function (id) { var installResult = _idsToUpdate[id], keepFile = installResult.keepFile, filename = installResult.localPath; if (filename && !keepFile) { FileSystem.getFileForPath(filename).unlink(); } });
/** * Gets an existing open Document for the given file, or creates a new one if the Document is * not currently open ('open' means referenced by the UI somewhere). Always use this method to * get Documents; do not call the Document constructor directly. This method is safe to call * in parallel. * * If you are going to hang onto the Document for more than just the duration of a command - e.g. * if you are going to display its contents in a piece of UI - then you must addRef() the Document * and listen for changes on it. (Note: opening the Document in an Editor automatically manages * refs and listeners for that Editor UI). * * If all you need is the Document's getText() value, use the faster getDocumentText() instead. * * @param {!string} fullPath * @return {$.Promise} A promise object that will be resolved with the Document, or rejected * with a FileSystemError if the file is not yet open and can't be read from disk. */ function getDocumentForPath(fullPath) { var doc = getOpenDocumentForPath(fullPath); if (doc) { // use existing document return new $.Deferred().resolve(doc).promise(); } else { // Should never get here if the fullPath refers to an Untitled document if (fullPath.indexOf(_untitledDocumentPath) === 0) { console.error("getDocumentForPath called for non-open untitled document: " + fullPath); return new $.Deferred().reject().promise(); } var file = FileSystem.getFileForPath(fullPath), pendingPromise = getDocumentForPath._pendingDocumentPromises[file.id]; if (pendingPromise) { // wait for the result of a previous request return pendingPromise; } else { var result = new $.Deferred(), promise = result.promise(); // log this document's Promise as pending getDocumentForPath._pendingDocumentPromises[file.id] = promise; // create a new document var perfTimerName = PerfUtils.markStart("getDocumentForPath:\t" + fullPath); result.done(function () { PerfUtils.addMeasurement(perfTimerName); }).fail(function () { PerfUtils.finalizeMeasurement(perfTimerName); }); FileUtils.readAsText(file) .always(function () { // document is no longer pending delete getDocumentForPath._pendingDocumentPromises[file.id]; }) .done(function (rawText, readTimestamp) { doc = new DocumentModule.Document(file, readTimestamp, rawText); // This is a good point to clean up any old dangling Documents _gcDocuments(); result.resolve(doc); }) .fail(function (fileError) { result.reject(fileError); }); return promise; } } }
runs(function () { oldFile = FileSystem.getFileForPath(oldFilename); oldFile.write("", function (err) { if (err) { writeDeferred.reject(err); } else { writeDeferred.resolve(); } }); });
it("should extract scrollbars from a theme with other css", function () { var themeFile = FileSystem.getFileForPath(testFilePath + "/scrollbars.css"); var promise = FileUtils.readAsText(themeFile).done(function (content) { var themeScrollbars = ThemeManager._extractScrollbars(content); expect(themeScrollbars.scrollbar.length).toEqual(4); expect(superTrim(themeScrollbars.content)).toEqual("span{}"); }); waitsForDone(promise, "theme with scrollbar and other css", 5000); });
runs(function () { var themeFile = FileSystem.getFileForPath(testFilePath + "/empty.css"); var promise = FileUtils.readAsText(themeFile).done(function (content) { var themeScrollbars = ThemeManager._extractScrollbars(content); expect(themeScrollbars.scrollbar.length).toEqual(0); expect(superTrim(themeScrollbars.content)).toEqual(""); }); waitsForDone(promise, "empty theme", 5000); });
/** * Removes the mark for an extension to be updated on restart. Also deletes the * downloaded package file. * @param {string} id The id of the extension for which the update is being removed */ function removeUpdate(id) { var installationResult = _idsToUpdate[id]; if (!installationResult) { return; } if (installationResult.localPath && !installationResult.keepFile) { FileSystem.getFileForPath(installationResult.localPath).unlink(); } delete _idsToUpdate[id]; $(exports).triggerHandler("statusChange", [id]); }
runs(function () { var themeFile = FileSystem.getFileForPath(testFilePath + "/simple-scrollbars.css"); var promise = FileUtils.readAsText(themeFile).done(function (content) { var themeScrollbars = ThemeManager._extractScrollbars(content); expect(themeScrollbars.scrollbar.length).toEqual(3); expect(superTrim(themeScrollbars.scrollbar.join(""))).toEqual("::-webkit-scrollbar{width:12px;}::-webkit-scrollbar-thumb:window-inactive{background:white;}::-webkit-scrollbar-thumb{background:white;}"); expect(superTrim(themeScrollbars.content)).toEqual(""); }); waitsForDone(promise, "theme with only scrollbars", 5000); });
/** * Disables the extension at the given path. * * @param {string} path The absolute path to the extension to disable. * @return {$.Promise} A promise that's resolved when the extenion is disabled, or * rejected if there was an error. */ function disable(path) { var result = new $.Deferred(), file = FileSystem.getFileForPath(path + "/.disabled"); file.write("", function (err) { if (err) { result.reject(err); } else { result.resolve(); } }); return result.promise(); }
.done(function (result) { var installationStatus = result.installationStatus; state = STATE_SUCCEEDED; result.localPath = downloadResult.localPath; if (installationStatus === InstallationStatuses.INSTALLED) { // Delete temp file FileSystem.getFileForPath(downloadResult.localPath).unlink(); } d.resolve(result); })
/** * Enables the extension at the given path. * * @param {string} path The absolute path to the extension to enable. * @return {$.Promise} A promise that's resolved when the extenion is enable, or * rejected if there was an error. */ function enable(path) { var result = new $.Deferred(), file = FileSystem.getFileForPath(path + "/.disabled"); file.unlink(function (err) { if (err) { result.reject(err); return; } ExtensionLoader.loadExtension(FileUtils.getBaseName(path), { baseUrl: path }, "main") .done(result.resolve) .fail(result.reject); }); return result.promise(); }
/** * Loads the package.json file in the given extension folder as well as any additional * metadata. * * If there's a .disabled file in the extension directory, then the content of package.json * will be augmented with disabled property set to true. It will override whatever value of * disabled might be set. * * @param {string} folder The extension folder. * @return {$.Promise} A promise object that is resolved with the parsed contents of the package.json file, * or rejected if there is no package.json with the boolean indicating whether .disabled file exists. */ function loadMetadata(folder) { var packageJSONFile = FileSystem.getFileForPath(folder + "/package.json"), disabledFile = FileSystem.getFileForPath(folder + "/.disabled"), result = new $.Deferred(), jsonPromise = new $.Deferred(), disabledPromise = new $.Deferred(), json, disabled; FileUtils.readAsText(packageJSONFile) .then(function (text) { try { json = JSON.parse(text); jsonPromise.resolve(); } catch (e) { jsonPromise.reject(); } }) .fail(jsonPromise.reject); disabledFile.exists(function (err, exists) { if (err) { disabled = false; } else { disabled = exists; } disabledPromise.resolve(); }); Async.waitForAll([jsonPromise, disabledPromise]) .always(function () { if (!json) { result.reject(disabled); } else { json.disabled = disabled; result.resolve(json); } }); return result.promise(); }
function _checkFileExistance(filePath, index, encoding) { var deferred = new $.Deferred(), fileEntry = FileSystem.getFileForPath(filePath); fileEntry.exists(function (err, exists) { if (!err && exists) { deferred.resolve(); } else { delete encoding[filePath]; deferred.reject(); } }); return deferred.promise(); }
/** * @private */ function _handleOpenPreferences() { var fullPath = getUserPrefFile(), file = FileSystem.getFileForPath(fullPath); file.exists(function (err, doesExist) { if (doesExist) { CommandManager.execute(Commands.FILE_OPEN, { fullPath: fullPath }); } else { FileUtils.writeText(file, "", true) .done(function () { CommandManager.execute(Commands.FILE_OPEN, { fullPath: fullPath }); }); } }); }
InstallExtensionDialog.prototype._handleCancel = function () { if (this._state === STATE_INSTALLING) { this._enterState(STATE_CANCELING_INSTALL); } else if (this._state === STATE_ALREADY_INSTALLED) { // If we were prompting the user about overwriting a previous installation, // and the user cancels, we can delete the downloaded file. if (this._installResult && this._installResult.localPath && !this._installResult.keepFile) { var filename = this._installResult.localPath; FileSystem.getFileForPath(filename).unlink(); } this._enterState(STATE_CLOSED); } else if (this._state !== STATE_CANCELING_INSTALL) { this._enterState(STATE_CLOSED); } };
/** * @private * Loads the package.json file in the given extension folder. * @param {string} folder The extension folder. * @return {$.Promise} A promise object that is resolved with the parsed contents of the package.json file, * or rejected if there is no package.json or the contents are not valid JSON. */ function _loadPackageJson(folder) { var file = FileSystem.getFileForPath(folder + "/package.json"), result = new $.Deferred(); FileUtils.readAsText(file) .done(function (text) { try { var json = JSON.parse(text); result.resolve(json); } catch (e) { result.reject(); } }) .fail(function () { result.reject(); }); return result.promise(); }