Example #1
0
    /**
     * @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();
    }
Example #2
0
        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);
                }
            }
        });
Example #3
0
    /**
     * 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();
    }
Example #4
0
            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);
                }
            };
Example #5
0
    /**
     * 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);
        });
    }
Example #6
0
    /**
     * 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();
    }
Example #7
0
 .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);
         }
     }
 })
Example #8
0
 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);
                 });
         }
     });
 }
Example #9
0
 /**
  * @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();
 }
Example #10
0
 $("#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());
 });
Example #11
0
    /**
     * 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();
    }
Example #12
0
 /**
  * @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);
 }
Example #13
0
 checkExists: function (filename) {
     var result = new $.Deferred(),
         file = FileSystem.getFileForPath(filename);
     file.exists(function (err, doesExist) {
         result.resolve(doesExist);
     });
     return result.promise();
 },
Example #14
0
 _.forEach(state, function (entry) {
     filesToAdd.push(FileSystem.getFileForPath(entry.file));
     if (entry.active) {
         activeFile = entry.file;
     }
     if (entry.viewState) {
         viewStates[entry.file] = entry.viewState;
     }
 });
Example #15
0
 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;
     }
 });
Example #16
0
        Object.keys(_idsToUpdate).forEach(function (id) {
            var installResult = _idsToUpdate[id],
                keepFile = installResult.keepFile,
                filename = installResult.localPath;

            if (filename && !keepFile) {
                FileSystem.getFileForPath(filename).unlink();
            }
        });
Example #17
0
    /**
     * 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();
         }
     });
 });
Example #19
0
            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);
            });
Example #20
0
            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);
            });
Example #21
0
 /**
  * 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]);
 }
Example #22
0
            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);
            });
Example #23
0
 /**
  * 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();
 }
Example #24
0
                    .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);
                    })
Example #25
0
 /**
  * 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();
 }
Example #26
0
 /**
  * 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();
 }
Example #27
0
    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();
    }
Example #28
0
    /**
     * @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 });
                    });
            }
        });

    }
Example #29
0
 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);
     }
 };
Example #30
0
 /**
  * @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();
 }