-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Enable opening of remote(http|https) files in Brackets #14153
Changes from 4 commits
bcc8913
b21c5e9
3e56f06
4ce8d63
a5bcabf
90e4a26
f0d02a4
7135ed8
2beea4a
516bc4c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
/* | ||
* Copyright (c) 2018 - present Adobe Systems Incorporated. All rights reserved. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
* DEALINGS IN THE SOFTWARE. | ||
* | ||
*/ | ||
|
||
define(function (require, exports, module) { | ||
"use strict"; | ||
|
||
var FileSystemError = brackets.getModule("filesystem/FileSystemError"), | ||
FileSystemStats = brackets.getModule("filesystem/FileSystemStats"); | ||
|
||
var SESSION_START_TIME = new Date(); | ||
|
||
/* | ||
* Create a new file stat. See the FileSystemStats class for more details. | ||
* | ||
* @param {!string} fullPath The full path for this File. | ||
* @return {FileSystemStats} stats. | ||
*/ | ||
function _getStats(uri) { | ||
return new FileSystemStats({ | ||
isFile: true, | ||
mtime: SESSION_START_TIME.toISOString(), | ||
size: 0, | ||
realPath: uri, | ||
hash: uri | ||
}); | ||
} | ||
|
||
/* | ||
* Model for a RemoteFile. | ||
* | ||
* This class should *not* be instantiated directly. Use FileSystem.getFileForPath | ||
* | ||
* See the FileSystem class for more details. | ||
* | ||
* @constructor | ||
* @param {!string} fullPath The full path for this File. | ||
* @param {!FileSystem} fileSystem The file system associated with this File. | ||
*/ | ||
function RemoteFile(fullPath, fileSystem) { | ||
this._isFile = true; | ||
this._isDirectory = false; | ||
this._path = fullPath; | ||
this._stat = _getStats(fullPath); | ||
this._id = fullPath; | ||
this._name = fullPath.split('/').pop(); | ||
this._fileSystem = fileSystem; | ||
this.donotWatch = true; | ||
} | ||
|
||
// Add "fullPath", "name", "parent", "id", "isFile" and "isDirectory" getters | ||
Object.defineProperties(RemoteFile.prototype, { | ||
"fullPath": { | ||
get: function () { return this._path; }, | ||
set: function () { throw new Error("Cannot set fullPath"); } | ||
}, | ||
"name": { | ||
get: function () { return this._name; }, | ||
set: function () { throw new Error("Cannot set name"); } | ||
}, | ||
"parentPath": { | ||
get: function () { return this._parentPath; }, | ||
set: function () { throw new Error("Cannot set parentPath"); } | ||
}, | ||
"id": { | ||
get: function () { return this._id; }, | ||
set: function () { throw new Error("Cannot set id"); } | ||
}, | ||
"isFile": { | ||
get: function () { return this._isFile; }, | ||
set: function () { throw new Error("Cannot set isFile"); } | ||
}, | ||
"isDirectory": { | ||
get: function () { return this._isDirectory; }, | ||
set: function () { throw new Error("Cannot set isDirectory"); } | ||
}, | ||
"_impl": { | ||
get: function () { return this._fileSystem._impl; }, | ||
set: function () { throw new Error("Cannot set _impl"); } | ||
} | ||
}); | ||
|
||
RemoteFile.prototype.exists = function (callback) { | ||
callback(null, true); | ||
}; | ||
|
||
/** | ||
* Helpful toString for debugging and equality check purposes | ||
*/ | ||
RemoteFile.prototype.toString = function () { | ||
return "[" + (this._isDirectory ? "Directory " : "File ") + this._path + "]"; | ||
}; | ||
|
||
RemoteFile.prototype.constructor = RemoteFile; | ||
|
||
/** | ||
* Cached contents of this file. This value is nullable but should NOT be undefined. | ||
* @private | ||
* @type {?string} | ||
*/ | ||
RemoteFile.prototype._contents = null; | ||
|
||
|
||
/** | ||
* @private | ||
* @type {?string} | ||
*/ | ||
RemoteFile.prototype._encoding = "utf8"; | ||
|
||
/** | ||
* @private | ||
* @type {?bool} | ||
*/ | ||
RemoteFile.prototype._preserveBOM = false; | ||
|
||
|
||
/** | ||
* Clear any cached data for this file. Note that this explicitly does NOT | ||
* clear the file's hash. | ||
* @private | ||
*/ | ||
RemoteFile.prototype._clearCachedData = function () { | ||
// no-op | ||
}; | ||
|
||
/** | ||
* Reads a remote file. | ||
* | ||
* @param {Object=} options Currently unused. | ||
* @param {function (?string, string=, FileSystemStats=)} callback Callback that is passed the | ||
* FileSystemError string or the file's contents and its stats. | ||
*/ | ||
RemoteFile.prototype.read = function (options, callback) { | ||
if (typeof (options) === "function") { | ||
callback = options; | ||
} | ||
this._encoding = "utf8"; | ||
|
||
if (this._contents !== null && this._stat) { | ||
callback(null, this._contents, this._encoding, this._stat); | ||
return; | ||
} | ||
|
||
var self = this; | ||
$.ajax({ | ||
url: this.fullPath | ||
}) | ||
.done(function (data) { | ||
self._contents = data; | ||
callback(null, data, self._encoding, self._stat); | ||
}) | ||
.fail(function (e) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}); | ||
}; | ||
|
||
/** | ||
* Write a file. | ||
* | ||
* @param {string} data Data to write. | ||
* @param {object=} options Currently unused. | ||
* @param {function (?string, FileSystemStats=)=} callback Callback that is passed the | ||
* FileSystemError string or the file's new stats. | ||
*/ | ||
RemoteFile.prototype.write = function (data, encoding, callback) { | ||
if (typeof (encoding) === "function") { | ||
callback = encoding; | ||
} | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
RemoteFile.prototype.exists = function (callback) { | ||
callback(null, false); | ||
}; | ||
|
||
RemoteFile.prototype.unlink = function (callback) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
RemoteFile.prototype.rename = function (newName, callback) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
RemoteFile.prototype.moveToTrash = function (callback) { | ||
callback(FileSystemError.NOT_FOUND); | ||
}; | ||
|
||
// Export this class | ||
module.exports = RemoteFile; | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
/* | ||
* Copyright (c) 2018 - present Adobe Systems Incorporated. All rights reserved. | ||
* | ||
* Permission is hereby granted, free of charge, to any person obtaining a | ||
* copy of this software and associated documentation files (the "Software"), | ||
* to deal in the Software without restriction, including without limitation | ||
* the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
* and/or sell copies of the Software, and to permit persons to whom the | ||
* Software is furnished to do so, subject to the following conditions: | ||
* | ||
* The above copyright notice and this permission notice shall be included in | ||
* all copies or substantial portions of the Software. | ||
* | ||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
* DEALINGS IN THE SOFTWARE. | ||
* | ||
*/ | ||
|
||
define(function (require, exports, module) { | ||
"use strict"; | ||
|
||
var AppInit = brackets.getModule("utils/AppInit"), | ||
FileSystem = brackets.getModule("filesystem/FileSystem"), | ||
QuickOpen = brackets.getModule("search/QuickOpen"), | ||
PathUtils = brackets.getModule("thirdparty/path-utils/path-utils"), | ||
CommandManager = brackets.getModule("command/CommandManager"), | ||
Commands = brackets.getModule("command/Commands"), | ||
RemoteFile = require("RemoteFile"); | ||
|
||
var HTTP_PROTOCOL = "http:", | ||
HTTPS_PROTOCOL = "https:"; | ||
|
||
AppInit.htmlReady(function () { | ||
var protocolAdapter = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this is an extension shouldn't the definition of ProtocolAdapter be provided by Brackets-Core for consistency. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @vickramdhawal Sorry for the confusion. // Register the custom object as HTTP and HTTPS protocol adapter
FileSystem.registerProtocolAdapter(HTTP_PROTOCOL, protocolAdapter);
FileSystem.registerProtocolAdapter(HTTPS_PROTOCOL, protocolAdapter); I can't really define an interface (which if was possible, would have been part of core) and For better understanding I have added a JSDoc @typedef /**
* Typical signature of a file protocol adapter.
* @typedef {Object} FileProtocol~Adapter
* @property {Number} priority - Indicates the priority.
* @property {Object} fileImpl - Handle for the custom file implementation prototype.
* @property {function} canRead - To check if this impl can read a file for a given path.
*/
/**
* FileSystem hook to register file protocol adapter
* @param {string} protocol ex: "https:"|"http:"|"ftp:"|"file:"
* @param {...FileProtocol~Adapter} adapter wrapper over file implementation
*/ |
||
priority: 0, // Default priority | ||
fileImpl: RemoteFile, | ||
canRead: function (filePath) { | ||
return true; // Always claim true, we are the default adpaters | ||
} | ||
}; | ||
|
||
QuickOpen.addQuickOpenPlugin( | ||
{ | ||
name: "Remote file URI input", | ||
languageIds: [], // for all language modes | ||
search: function () { | ||
return $.Deferred().resolve([arguments[0]]); | ||
}, | ||
match: function (query) { | ||
var protocol = PathUtils.parseUrl(query).protocol; | ||
return [HTTP_PROTOCOL, HTTPS_PROTOCOL].indexOf(protocol) !== -1; | ||
}, | ||
itemFocus: function (query) { | ||
}, // no op | ||
itemSelect: function () { | ||
CommandManager.execute(Commands.FILE_OPEN, {fullPath: arguments[0]}); | ||
} | ||
} | ||
); | ||
|
||
FileSystem.registerProtocolAdapter(HTTP_PROTOCOL, protocolAdapter); | ||
FileSystem.registerProtocolAdapter(HTTPS_PROTOCOL, protocolAdapter); | ||
}); | ||
|
||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
/**
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in latest commit 👍