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

Commit af4e072

Browse files
committed
Merge pull request #7242 from adobe/zaggino/7209-followup
Correctly selects filename when known extension with a dot inside is used
2 parents f9667cb + 4b501a8 commit af4e072

5 files changed

Lines changed: 97 additions & 5 deletions

File tree

src/file/FileUtils.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ define(function (require, exports, module) {
3434
require("utils/Global");
3535

3636
var FileSystemError = require("filesystem/FileSystemError"),
37+
LanguageManager = require("language/LanguageManager"),
3738
PerfUtils = require("utils/PerfUtils"),
3839
Dialogs = require("widgets/Dialogs"),
3940
DefaultDialogs = require("widgets/DefaultDialogs"),
@@ -309,6 +310,40 @@ define(function (require, exports, module) {
309310
return baseName.substr(idx + 1);
310311
}
311312

313+
/**
314+
* Get the file extension (excluding ".") given a path OR a bare filename.
315+
* Returns "" for names with no extension.
316+
* If the only `.` in the file is the first character,
317+
* returns "" as this is not considered an extension.
318+
* This method considers known extensions which include `.` in them.
319+
*
320+
* @param {string} fullPath full path to a file or directory
321+
* @return {string} Returns the extension of a filename or empty string if
322+
* the argument is a directory or a filename with no extension
323+
*/
324+
function getSmartFileExtension(fullPath) {
325+
var baseName = getBaseName(fullPath),
326+
parts = baseName.split(".");
327+
328+
// get rid of file name
329+
parts.shift();
330+
if (baseName[0] === ".") {
331+
// if starts with a `.`, then still consider it as file name
332+
parts.shift();
333+
}
334+
335+
var extension = [parts.pop()], // last part is always an extension
336+
i = parts.length;
337+
while (i--) {
338+
if (LanguageManager.getLanguageForExtension(parts[i])) {
339+
extension.unshift(parts[i]);
340+
} else {
341+
break;
342+
}
343+
}
344+
return extension.join(".");
345+
}
346+
312347
/**
313348
* Computes filename as relative to the basePath. For example:
314349
* basePath: /foo/bar/, filename: /foo/bar/baz.txt
@@ -426,5 +461,6 @@ define(function (require, exports, module) {
426461
exports.getBaseName = getBaseName;
427462
exports.getRelativeFilename = getRelativeFilename;
428463
exports.getFileExtension = getFileExtension;
464+
exports.getSmartFileExtension = getSmartFileExtension;
429465
exports.compareFilenames = compareFilenames;
430466
});

src/language/LanguageManager.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,15 @@ define(function (require, exports, module) {
196196
return _languages[id];
197197
}
198198

199+
/**
200+
* Resolves a language to a file extension
201+
* @param {!string} extension Extension that language should be resolved for
202+
* @return {?Language} The language for the provided extension or null if none exists
203+
*/
204+
function getLanguageForExtension(extension) {
205+
return _fileExtensionToLanguageMap[extension.toLowerCase()];
206+
}
207+
199208
/**
200209
* Resolves a file path to a Language object.
201210
* @param {!string} path Path to the file to find a language for
@@ -804,5 +813,6 @@ define(function (require, exports, module) {
804813
exports.ready = _ready;
805814
exports.defineLanguage = defineLanguage;
806815
exports.getLanguage = getLanguage;
816+
exports.getLanguageForExtension = getLanguageForExtension;
807817
exports.getLanguageForPath = getLanguageForPath;
808818
});

src/project/ProjectManager.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,9 +1853,13 @@ define(function (require, exports, module) {
18531853
var escapedName = _.escape(entry.name);
18541854
_projectTree.jstree("set_text", $selected, escapedName);
18551855
_projectTree.jstree("rename");
1856-
var indexOfExtension = escapedName.lastIndexOf('.');
1857-
if (indexOfExtension > 0) {
1858-
$selected.children(".jstree-rename-input")[0].setSelectionRange(0, indexOfExtension);
1856+
1857+
var extension = FileUtils.getSmartFileExtension(entry.name);
1858+
if (extension) {
1859+
var indexOfExtension = escapedName.length - extension.length - 1;
1860+
if (indexOfExtension > 0) {
1861+
$selected.children(".jstree-rename-input")[0].setSelectionRange(0, indexOfExtension);
1862+
}
18591863
}
18601864
});
18611865
// No fail handler: silently no-op if file doesn't exist in tree

src/utils/ViewUtils.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
define(function (require, exports, module) {
2929
"use strict";
3030

31-
var _ = require("thirdparty/lodash");
31+
var _ = require("thirdparty/lodash"),
32+
FileUtils = require("file/FileUtils");
3233

3334
var SCROLL_SHADOW_HEIGHT = 5;
3435

@@ -393,7 +394,8 @@ define(function (require, exports, module) {
393394
*/
394395
function getFileEntryDisplay(entry) {
395396
var name = entry.name,
396-
i = name.lastIndexOf(".");
397+
ext = FileUtils.getSmartFileExtension(name),
398+
i = name.lastIndexOf("." + ext);
397399

398400
if (i >= 0) {
399401
// Escape all HTML-sensitive characters in filename.

test/spec/FileUtils-test.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,5 +125,45 @@ define(function (require, exports, module) {
125125
expect(FileUtils.getFileExtension("foo.bar.baz..jaz.txt")).toBe("txt");
126126
});
127127
});
128+
129+
describe("getSmartFileExtension", function () {
130+
131+
it("should get the extension of a normalized win file path", function () {
132+
expect(FileUtils.getSmartFileExtension("C:/foo/bar/baz.txt")).toBe("txt");
133+
});
134+
135+
it("should get the extension of a posix file path", function () {
136+
expect(FileUtils.getSmartFileExtension("/foo/bar/baz.txt")).toBe("txt");
137+
});
138+
139+
it("should return empty extension for a normalized win directory path", function () {
140+
expect(FileUtils.getSmartFileExtension("C:/foo/bar/")).toBe("");
141+
});
142+
143+
it("should return empty extension for a posix directory path", function () {
144+
expect(FileUtils.getSmartFileExtension("bar")).toBe("");
145+
});
146+
147+
it("should return the extension of a filename containing .", function () {
148+
expect(FileUtils.getSmartFileExtension("C:/foo/bar/.baz/jaz.txt")).toBe("txt");
149+
expect(FileUtils.getSmartFileExtension("foo/bar/baz/.jaz.txt")).toBe("txt");
150+
expect(FileUtils.getSmartFileExtension("foo.bar.baz..jaz.txt")).toBe("txt");
151+
});
152+
153+
it("should return no extension for files with only . as a first character", function () {
154+
expect(FileUtils.getSmartFileExtension("C:/foo/bar/.baz/.jaz")).toBe("");
155+
});
156+
157+
it("should return the extension containing . for known types", function () {
158+
expect(FileUtils.getSmartFileExtension("C:/foo/bar/.baz/jaz.scss.erb")).toBe("scss.erb");
159+
expect(FileUtils.getSmartFileExtension("foo/bar/baz/.jaz.js.erb")).toBe("js.erb");
160+
});
161+
162+
it("should return the extension combined from other known extensions", function () {
163+
expect(FileUtils.getSmartFileExtension("foo.bar.php.js")).toBe("php.js");
164+
expect(FileUtils.getSmartFileExtension("foo.bar.php.html.js")).toBe("php.html.js");
165+
expect(FileUtils.getSmartFileExtension("foo.bar.php.scss.erb")).toBe("php.scss.erb");
166+
});
167+
});
128168
});
129169
});

0 commit comments

Comments
 (0)