Set of utilities for working with files and text content.
Line endings
var LINE_ENDINGS_CRLF = "CRLF",
LINE_ENDINGS_LF = "LF";
var MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024;
var MAX_FILE_SIZE_MB = 16;
var _cmpNames = (function () {
if (brackets.platform === "win") {
// Use this function on Windows
return function (filename1, filename2, lang) {
var f1 = getFilenameWithoutExtension(filename1),
f2 = getFilenameWithoutExtension(filename2);
return f1.localeCompare(f2, lang, {numeric: true});
};
}
// Use this function other OSes
return function (filename1, filename2, lang) {
return filename1.localeCompare(filename2, lang, {numeric: true});
};
}());
Compares 2 filenames in lowercases. In Windows it compares the names without the extension first and then the extensions to fix issue #4409
function compareFilenames(filename1, filename2, extFirst) {
var lang = brackets.getLocale();
filename1 = filename1.toLocaleLowerCase();
filename2 = filename2.toLocaleLowerCase();
function cmpExt() {
var ext1 = getFileExtension(filename1),
ext2 = getFileExtension(filename2);
return ext1.localeCompare(ext2, lang, {numeric: true});
}
function cmpNames() {
return _cmpNames(filename1, filename2, lang);
}
return extFirst ? (cmpExt() || cmpNames()) : (cmpNames() || cmpExt());
}
Compares two paths segment-by-segment, used for sorting. When two files share a path prefix,
the less deeply nested one is sorted earlier in the list. Sorts files within the same parent
folder based on compareFilenames()
.
function comparePaths(path1, path2) {
var entryName1, entryName2,
pathParts1 = path1.split("/"),
pathParts2 = path2.split("/"),
length = Math.min(pathParts1.length, pathParts2.length),
folders1 = pathParts1.length - 1,
folders2 = pathParts2.length - 1,
index = 0;
while (index < length) {
entryName1 = pathParts1[index];
entryName2 = pathParts2[index];
if (entryName1 !== entryName2) {
if (index < folders1 && index < folders2) {
return entryName1.toLocaleLowerCase().localeCompare(entryName2.toLocaleLowerCase());
} else if (index >= folders1 && index >= folders2) {
return compareFilenames(entryName1, entryName2);
}
return (index >= folders1 && index < folders2) ? -1 : 1;
}
index++;
}
return 0;
}
Convert a URI path to a native path. On both platforms, this unescapes the URI On windows, URI paths start with a "/", but have a drive letter ("C:"). In this case, remove the initial "/".
function convertToNativePath(path) {
path = unescape(path);
if (path.indexOf(":") !== -1 && path[0] === "/") {
return path.substr(1);
}
return path;
}
Convert a Windows-native path to use Unix style slashes. On Windows, this converts "C:\foo\bar\baz.txt" to "C:/foo/bar/baz.txt". On Mac, this does nothing, since Mac paths are already in Unix syntax. (Note that this does not add an initial forward-slash. Internally, our APIs generally use the "C:/foo/bar/baz.txt" style for "native" paths.)
function convertWindowsPathToUnixPath(path) {
if (brackets.platform === "win") {
path = path.replace(/\\/g, "/");
}
return path;
}
function encodeFilePath(path) {
var pathArray = path.split("/");
pathArray = pathArray.map(function (subPath) {
return encodeURIComponent(subPath);
});
return pathArray.join("/");
}
// Asynchronously load DocumentCommandHandlers
// This avoids a temporary circular dependency created
// by relocating showFileOpenError() until deprecation is over
require(["document/DocumentCommandHandlers"], function (dchModule) {
DocumentCommandHandlers = dchModule;
});
// Asynchronously load LiveDevelopmentUtils
// This avoids a temporary circular dependency created
// by relocating isStaticHtmlFileExt() until deprecation is over
require(["LiveDevelopment/LiveDevelopmentUtils"], function (lduModule) {
LiveDevelopmentUtils = lduModule;
});
// Define public API
exports.LINE_ENDINGS_CRLF = LINE_ENDINGS_CRLF;
exports.LINE_ENDINGS_LF = LINE_ENDINGS_LF;
exports.getPlatformLineEndings = getPlatformLineEndings;
exports.sniffLineEndings = sniffLineEndings;
exports.translateLineEndings = translateLineEndings;
exports.showFileOpenError = showFileOpenError;
exports.getFileErrorString = getFileErrorString;
exports.makeDialogFileList = makeDialogFileList;
exports.readAsText = readAsText;
exports.writeText = writeText;
exports.convertToNativePath = convertToNativePath;
exports.convertWindowsPathToUnixPath = convertWindowsPathToUnixPath;
exports.getNativeBracketsDirectoryPath = getNativeBracketsDirectoryPath;
exports.getNativeModuleDirectoryPath = getNativeModuleDirectoryPath;
exports.stripTrailingSlash = stripTrailingSlash;
exports.isStaticHtmlFileExt = isStaticHtmlFileExt;
exports.getDirectoryPath = getDirectoryPath;
exports.getParentPath = getParentPath;
exports.getBaseName = getBaseName;
exports.getRelativeFilename = getRelativeFilename;
exports.getFilenameWithoutExtension = getFilenameWithoutExtension;
exports.getFileExtension = getFileExtension;
exports.getSmartFileExtension = getSmartFileExtension;
exports.compareFilenames = compareFilenames;
exports.comparePaths = comparePaths;
exports.MAX_FILE_SIZE = MAX_FILE_SIZE;
exports.encodeFilePath = encodeFilePath;
});
Get the name of a file or a directory, removing any preceding path.
function getBaseName(fullPath) {
var lastSlash = fullPath.lastIndexOf("/");
if (lastSlash === fullPath.length - 1) { // directory: exclude trailing "/" too
return fullPath.slice(fullPath.lastIndexOf("/", fullPath.length - 2) + 1, -1);
} else {
return fullPath.slice(lastSlash + 1);
}
}
Get the parent directory of a file. If a directory is passed, the SAME directory is returned.
function getDirectoryPath(fullPath) {
return fullPath.substr(0, fullPath.lastIndexOf("/") + 1);
}
function getFileErrorString(name) {
// There are a few error codes that we have specific error messages for. The rest are
// displayed with a generic "(error N)" message.
var result;
if (name === FileSystemError.NOT_FOUND) {
result = Strings.NOT_FOUND_ERR;
} else if (name === FileSystemError.NOT_READABLE) {
result = Strings.NOT_READABLE_ERR;
} else if (name === FileSystemError.NOT_WRITABLE) {
result = Strings.NO_MODIFICATION_ALLOWED_ERR_FILE;
} else if (name === FileSystemError.CONTENTS_MODIFIED) {
result = Strings.CONTENTS_MODIFIED_ERR;
} else if (name === FileSystemError.UNSUPPORTED_ENCODING) {
result = Strings.UNSUPPORTED_ENCODING_ERR;
} else if (name === FileSystemError.EXCEEDS_MAX_FILE_SIZE) {
result = StringUtils.format(Strings.EXCEEDS_MAX_FILE_SIZE, MAX_FILE_SIZE_MB);
} else if (name === FileSystemError.ENCODE_FILE_FAILED) {
result = Strings.ENCODE_FILE_FAILED_ERR;
} else if (name === FileSystemError.DECODE_FILE_FAILED) {
result = Strings.DECODE_FILE_FAILED_ERR;
} else if (name === FileSystemError.UNSUPPORTED_UTF16_ENCODING) {
result = Strings.UNSUPPORTED_UTF16_ENCODING_ERR;
} else {
result = StringUtils.format(Strings.GENERIC_ERROR, name);
}
return result;
}
Get the file extension (excluding ".") given a path OR a bare filename. Returns "" for names with no extension. If the name starts with ".", the full remaining text is considered the extension.
function getFileExtension(fullPath) {
var baseName = getBaseName(fullPath),
idx = baseName.lastIndexOf(".");
if (idx === -1) {
return "";
}
return baseName.substr(idx + 1);
}
Get the file name without the extension. Returns "" if name starts with "."
function getFilenameWithoutExtension(filename) {
var index = filename.lastIndexOf(".");
return index === -1 ? filename : filename.slice(0, index);
}
Returns a native absolute path to the 'brackets' source directory. Note that this only works when run in brackets/src/index.html, so it does not work for unit tests (which is run from brackets/test/SpecRunner.html)
WARNING: unlike most paths in Brackets, this path EXCLUDES the trailing "/".
function getNativeBracketsDirectoryPath() {
var pathname = decodeURI(window.location.pathname);
var directory = pathname.substr(0, pathname.lastIndexOf("/"));
return convertToNativePath(directory);
}
Given the module object passed to JS module define function, convert the path to a native absolute path. Returns a native absolute path to the module folder.
WARNING: unlike most paths in Brackets, this path EXCLUDES the trailing "/".
function getNativeModuleDirectoryPath(module) {
var path;
if (module && module.uri) {
path = decodeURI(module.uri);
// Remove module name and trailing slash from path.
path = path.substr(0, path.lastIndexOf("/"));
}
return path;
}
Get the parent folder of the given file/folder path. Differs from getDirectoryPath() when 'fullPath' is a directory itself: returns its parent instead of the original path. (Note: if you already have a FileSystemEntry, it's faster to use entry.parentPath instead).
function getParentPath(fullPath) {
if (fullPath === "/") {
return "";
}
return fullPath.substring(0, fullPath.lastIndexOf("/", fullPath.length - 2) + 1);
}
Returns the standard line endings for the current platform
function getPlatformLineEndings() {
return brackets.platform === "win" ? LINE_ENDINGS_CRLF : LINE_ENDINGS_LF;
}
Computes filename as relative to the basePath. For example: basePath: /foo/bar/, filename: /foo/bar/baz.txt returns: baz.txt
The net effect is that the common prefix is stripped away. If basePath is not a prefix of filename, then undefined is returned.
function getRelativeFilename(basePath, filename) {
if (!filename || filename.substr(0, basePath.length) !== basePath) {
return;
}
return filename.substr(basePath.length);
}
Get the file extension (excluding ".") given a path OR a bare filename.
Returns "" for names with no extension.
If the only .
in the file is the first character,
returns "" as this is not considered an extension.
This method considers known extensions which include .
in them.
function getSmartFileExtension(fullPath) {
DeprecationWarning.deprecationWarning("FileUtils.getSmartFileExtension() has been deprecated. " +
"Please use LanguageManager.getCompoundFileExtension() instead.");
return LanguageManager.getCompoundFileExtension(fullPath);
}
Determine if file extension is a static html file extension.
function isStaticHtmlFileExt(filePath) {
DeprecationWarning.deprecationWarning("FileUtils.isStaticHtmlFileExt() has been deprecated. " +
"Please use LiveDevelopmentUtils.isStaticHtmlFileExt() instead.");
return LiveDevelopmentUtils.isStaticHtmlFileExt(filePath);
}
Creates an HTML string for a list of files to be reported on, suitable for use in a dialog.
function makeDialogFileList(paths) {
var result = "<ul class='dialog-list'>";
paths.forEach(function (path) {
result += "<li><span class='dialog-filename'>";
result += StringUtils.breakableUrl(path);
result += "</span></li>";
});
result += "</ul>";
return result;
}
Asynchronously reads a file as UTF-8 encoded text.
function readAsText(file) {
var result = new $.Deferred();
// Measure performance
var perfTimerName = PerfUtils.markStart("readAsText:\t" + file.fullPath);
result.always(function () {
PerfUtils.addMeasurement(perfTimerName);
});
// Read file
file.read(function (err, data, encoding, stat) {
if (!err) {
result.resolve(data, stat.mtime);
} else {
result.reject(err);
}
});
return result.promise();
}
Shows an error dialog indicating that the given file could not be opened due to the given error
function showFileOpenError(name, path) {
DeprecationWarning.deprecationWarning("FileUtils.showFileOpenError() has been deprecated. " +
"Please use DocumentCommandHandlers.showFileOpenError() instead.");
return DocumentCommandHandlers.showFileOpenError(name, path);
}
Scans the first 1000 chars of the text to determine how it encodes line endings. Returns null if usage is mixed or if no line endings found.
function sniffLineEndings(text) {
var subset = text.substr(0, 1000); // (length is clipped to text.length)
var hasCRLF = /\r\n/.test(subset);
var hasLF = /[^\r]\n/.test(subset);
if ((hasCRLF && hasLF) || (!hasCRLF && !hasLF)) {
return null;
} else {
return hasCRLF ? LINE_ENDINGS_CRLF : LINE_ENDINGS_LF;
}
}
Removes the trailing slash from a path, if it has one. Warning: this differs from the format of most paths used in Brackets! Use paths ending in "/" normally, as this is the format used by Directory.fullPath.
function stripTrailingSlash(path) {
if (path && path[path.length - 1] === "/") {
return path.slice(0, -1);
} else {
return path;
}
}
Translates any line ending types in the given text to the be the single form specified
function translateLineEndings(text, lineEndings) {
if (lineEndings !== LINE_ENDINGS_CRLF && lineEndings !== LINE_ENDINGS_LF) {
lineEndings = getPlatformLineEndings();
}
var eolStr = (lineEndings === LINE_ENDINGS_CRLF ? "\r\n" : "\n");
var findAnyEol = /\r\n|\r|\n/g;
return text.replace(findAnyEol, eolStr);
}
Asynchronously writes a file as UTF-8 encoded text.
function writeText(file, text, allowBlindWrite) {
var result = new $.Deferred(),
options = {};
if (allowBlindWrite) {
options.blind = true;
}
file.write(text, options, function (err) {
if (!err) {
result.resolve();
} else {
result.reject(err);
}
});
return result.promise();
}