Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit e5ff7d2

Browse files
authored
Merge pull request #15088 from niteskum/OpenWithExternalEditor
Feature to associate file types with external editors
2 parents 3ae5417 + 13bf4d2 commit e5ff7d2

File tree

9 files changed

+214
-4
lines changed

9 files changed

+214
-4
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2013 - present Adobe Systems Incorporated. All rights reserved.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a
5+
* copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the
9+
* Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+
* DEALINGS IN THE SOFTWARE.
21+
*
22+
*/
23+
24+
define(function (require, exports, module) {
25+
"use strict";
26+
27+
28+
var AppInit = brackets.getModule("utils/AppInit"),
29+
PreferencesManager = brackets.getModule("preferences/PreferencesManager"),
30+
Strings = brackets.getModule("strings"),
31+
FileViewController = brackets.getModule("project/FileViewController"),
32+
ExtensionUtils = brackets.getModule("utils/ExtensionUtils"),
33+
NodeDomain = brackets.getModule("utils/NodeDomain"),
34+
FileUtils = brackets.getModule("file/FileUtils");
35+
36+
/**
37+
* @private
38+
* @type {string} fullPath of the OpenWithExternalEditor Domain implementation
39+
*/
40+
var _domainPath = ExtensionUtils.getModulePath(module, "node/OpenWithExternalApplicationDomain");
41+
42+
/**
43+
* @private
44+
* @type {NodeDomain}
45+
*/
46+
var _nodeDomain = new NodeDomain("OpenWithExternalApplication", _domainPath);
47+
48+
var extensionToExtApplicationMap = {};
49+
50+
function _openWithExternalApplication(event, path) {
51+
_nodeDomain.exec("open", {
52+
path: path,
53+
app: extensionToExtApplicationMap[FileUtils.getFileExtension(path).toLowerCase()]
54+
});
55+
}
56+
57+
PreferencesManager.definePreference("externalApplications", "object", {}, {
58+
description: Strings.DESCRIPTION_EXTERNAL_APPLICATION_ASSOCIATE
59+
});
60+
61+
PreferencesManager.on("change", "externalApplications", function () {
62+
extensionToExtApplicationMap = PreferencesManager.get("externalApplications");
63+
FileUtils.addExtensionToExternalAppList(Object.keys(extensionToExtApplicationMap));
64+
});
65+
66+
FileViewController.on("openWithExternalApplication", _openWithExternalApplication);
67+
68+
AppInit.appReady(function () {
69+
extensionToExtApplicationMap = PreferencesManager.get("externalApplications");
70+
FileUtils.addExtensionToExternalAppList(Object.keys(extensionToExtApplicationMap));
71+
});
72+
});
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2012 - present Adobe Systems Incorporated. All rights reserved.
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a
5+
* copy of this software and associated documentation files (the "Software"),
6+
* to deal in the Software without restriction, including without limitation
7+
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8+
* and/or sell copies of the Software, and to permit persons to whom the
9+
* Software is furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19+
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20+
* DEALINGS IN THE SOFTWARE.
21+
*
22+
*/
23+
24+
/*eslint-env node */
25+
/*jslint node: true */
26+
"use strict";
27+
28+
var open = require("open");
29+
30+
var _domainManager;
31+
32+
/**
33+
* @private
34+
*
35+
* @param {Object} params Object to use
36+
*/
37+
function _openWithExternalApplication(params) {
38+
var application = "default" === params.app ? "": params.app;
39+
open(params.path, application);
40+
}
41+
42+
43+
/**
44+
* Initializes the OpenWithExternalEditor domain with its commands.
45+
* @param {DomainManager} domainManager The DomainManager for the server
46+
*/
47+
function init(domainManager) {
48+
_domainManager = domainManager;
49+
50+
if (!domainManager.hasDomain("OpenWithExternalApplication")) {
51+
domainManager.registerDomain("OpenWithExternalApplication", {major: 0, minor: 1});
52+
}
53+
_domainManager.registerCommand(
54+
"OpenWithExternalApplication",
55+
"open",
56+
_openWithExternalApplication,
57+
true,
58+
"open document with External Application.",
59+
[{
60+
name: "params",
61+
type: "object",
62+
description: "Params Object having document and App Path."
63+
}],
64+
[]
65+
);
66+
}
67+
68+
exports.init = init;
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "brackets-open-external_application",
3+
"dependencies": {
4+
"open": "0.0.5"
5+
}
6+
}

src/file/FileUtils.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ define(function (require, exports, module) {
5959
*/
6060
var MAX_FILE_SIZE = MAX_FILE_SIZE_MB * 1024 * 1024;
6161

62+
/**
63+
* @const {List} list of File Extensions which will be opened in external Application
64+
*/
65+
var extListToBeOpenedInExtApp = [];
66+
6267

6368
/**
6469
* Asynchronously reads a file as UTF-8 encoded text.
@@ -526,6 +531,28 @@ define(function (require, exports, module) {
526531
return pathArray.join("/");
527532
}
528533

534+
/**
535+
* @param {string} ext extension string a file
536+
* @return {string} returns true If file to be opened in External Application.
537+
*
538+
*/
539+
function shouldOpenInExternalApplication(ext) {
540+
return extListToBeOpenedInExtApp.includes(ext);
541+
}
542+
543+
/**
544+
* @param {string} ext File Extensions to be added in External App List
545+
*
546+
*/
547+
function addExtensionToExternalAppList(ext) {
548+
549+
if(Array.isArray(ext)) {
550+
extListToBeOpenedInExtApp = ext;
551+
} else if (typeof ext === 'string'){
552+
extListToBeOpenedInExtApp.push(ext);
553+
}
554+
}
555+
529556
// Asynchronously load DocumentCommandHandlers
530557
// This avoids a temporary circular dependency created
531558
// by relocating showFileOpenError() until deprecation is over
@@ -568,4 +595,6 @@ define(function (require, exports, module) {
568595
exports.comparePaths = comparePaths;
569596
exports.MAX_FILE_SIZE = MAX_FILE_SIZE;
570597
exports.encodeFilePath = encodeFilePath;
598+
exports.shouldOpenInExternalApplication = shouldOpenInExternalApplication;
599+
exports.addExtensionToExternalAppList = addExtensionToExternalAppList;
571600
});

src/language/languages.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,7 @@
291291
"jsz", "lib", "mpeg", "mpg", "mp4", "msi", "node", "o", "obj", "odc",
292292
"odb", "odf", "odg", "odp", "ods", "odt", "otf", "pak", "pdb", "pdf",
293293
"pdi", "ppt", "pptx", "psd", "rar", "sdf", "so", "sqlite", "suo", "svgz",
294-
"swf", "tar", "tif", "tiff", "ttf", "woff", "xls", "xlsx", "zip"
294+
"swf", "tar", "tif", "tiff", "ttf", "woff", "xls", "xlsx", "zip", "xd"
295295
],
296296
"isBinary": true
297297
},

src/nls/root/strings.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -903,5 +903,8 @@ define({
903903
"REMOTE_DEBUGGING_ENABLED" : "Remote debugging enabled on localhost:",
904904

905905
// Remote debugging port argument is invalid
906-
"REMOTE_DEBUGGING_PORT_INVALID" : "Cannot enable remote debugging on port {0}. Port numbers should be between {1} and {2}."
906+
"REMOTE_DEBUGGING_PORT_INVALID" : "Cannot enable remote debugging on port {0}. Port numbers should be between {1} and {2}.",
907+
908+
//Associate File Type to External App
909+
"DESCRIPTION_EXTERNAL_APPLICATION_ASSOCIATE" : "Add File type association to external App here"
907910
});

src/project/FileTreeView.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ define(function (require, exports, module) {
3939
LanguageManager = require("language/LanguageManager"),
4040
FileTreeViewModel = require("project/FileTreeViewModel"),
4141
ViewUtils = require("utils/ViewUtils"),
42-
KeyEvent = require("utils/KeyEvent");
42+
KeyEvent = require("utils/KeyEvent"),
43+
PreferencesManager = require("preferences/PreferencesManager");
4344

4445
var DOM = Preact.DOM;
4546

@@ -554,7 +555,16 @@ define(function (require, exports, module) {
554555
});
555556
}
556557
} else {
557-
this.props.actions.setSelected(this.myPath());
558+
var language = LanguageManager.getLanguageForPath(this.myPath()),
559+
doNotOpen = false;
560+
if (language && language.isBinary() && "image" !== language.getId() &&
561+
FileUtils.shouldOpenInExternalApplication(
562+
FileUtils.getFileExtension(this.myPath()).toLowerCase()
563+
)
564+
) {
565+
doNotOpen = true;
566+
}
567+
this.props.actions.setSelected(this.myPath(), doNotOpen);
558568
}
559569
e.stopPropagation();
560570
e.preventDefault();
@@ -569,6 +579,12 @@ define(function (require, exports, module) {
569579
if (this.state.clickTimer !== null) {
570580
this.clearTimer();
571581
}
582+
if (FileUtils.shouldOpenInExternalApplication(
583+
FileUtils.getFileExtension(this.myPath()).toLowerCase()
584+
)) {
585+
this.props.actions.openWithExternalApplication(this.myPath());
586+
return;
587+
}
572588
this.props.actions.selectInWorkingSet(this.myPath());
573589
}
574590
},

src/project/FileViewController.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,13 @@ define(function (require, exports, module) {
226226
return result.promise();
227227
}
228228

229+
/**
230+
* Opens the specified document with its associated external editor,
231+
*/
232+
function openWithExternalApplication(fullPath) {
233+
exports.trigger("openWithExternalApplication", fullPath);
234+
}
235+
229236
/**
230237
* Opens the specified document if it's not already open, adds it to the working set,
231238
* and selects it in the WorkingSetView
@@ -275,4 +282,5 @@ define(function (require, exports, module) {
275282
exports.setFileViewFocus = setFileViewFocus;
276283
exports.WORKING_SET_VIEW = WORKING_SET_VIEW;
277284
exports.PROJECT_MANAGER = PROJECT_MANAGER;
285+
exports.openWithExternalApplication = openWithExternalApplication;
278286
});

src/project/ProjectManager.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,14 @@ define(function (require, exports, module) {
280280
this.model.selectInWorkingSet(path);
281281
};
282282

283+
/**
284+
* See `FileViewController.openWithExternalApplication`
285+
*/
286+
ActionCreator.prototype.openWithExternalApplication = function (path) {
287+
FileViewController.openWithExternalApplication(path);
288+
};
289+
290+
283291
/**
284292
* See `ProjectModel.setContext`
285293
*/

0 commit comments

Comments
 (0)