Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions src/project/WorkingSetView.js
Original file line number Diff line number Diff line change
Expand Up @@ -1000,27 +1000,43 @@ define(function (require, exports, module) {
}
};


/**
* Adds full directory names to elements representing passed files in working tree
* adds the directory name to external project files
* when the directory length is more than 3, we show it in this format: `<root directory>/.../<parent directory>`
* otherwise the full path
* @private
* @param {Array.<string>} filesPathList - list of fullPath strings
* @param {Array.<string>} externalProjectFiles - the list of the external project files
*/
WorkingSetView.prototype._addFullDirectoryNamesToWorkingTreeFiles = function (filesPathList) {
// filesList must have at least two files in it for this to make sense
if (!filesPathList.length) {
WorkingSetView.prototype._addDirectoryNameToExternalProjectFiles = function (externalProjectFiles) {
if(!externalProjectFiles.length) {
return;
}

// Go through open files and add directories to appropriate entries
this.$openFilesContainer.find("ul > li").each(function () {
const $li = $(this);
let filePath = $li.data(_FILE_KEY).fullPath;
const io = filesPathList.indexOf(filePath);
const io = externalProjectFiles.indexOf(filePath);
if (io !== -1) {
let dirPath = path.dirname(filePath);
dirPath = Phoenix.app.getDisplayPath(dirPath);
const $dir = $(`<span title='${Phoenix.app.getDisplayPath(filePath)}' class='directory'/>`)
.html(" &mdash; " + dirPath);
// this will be displayed on hover
const displayPath = Phoenix.app.getDisplayPath(dirPath);

// use the platform specific separator for splitting
const separator = brackets.platform === "win" ? "\\" : "/";
let dirSplit = displayPath.split(separator);

let truncatedPath = displayPath; // truncatedPath value will be shown in the UI
if (dirSplit.length > 3) {
// dirSplit[0] maybe empty sometimes:
// - In browsers, for paths starting with "/" (e.g., "/fs/path/to/file")
// - In desktop app, for absolute paths on Linux/Mac (e.g., "/root/fs/path/to/file")
let rootDirName = dirSplit[0] ? dirSplit[0] : dirSplit[1];
truncatedPath = rootDirName + separator + "\u2026" + separator + dirSplit[dirSplit.length - 1];
}

const $dir = $(`<span title='${displayPath}' class='directory'/>`)
.html(" &mdash; " + truncatedPath);
$li.children("a").append($dir);
}
});
Expand Down Expand Up @@ -1084,7 +1100,7 @@ define(function (require, exports, module) {
}
});

self._addFullDirectoryNamesToWorkingTreeFiles(externalProjectFiles);
self._addDirectoryNameToExternalProjectFiles(externalProjectFiles);

// Go through the map and solve the arrays with length over 1. Ignore the rest.
_.forEach(map, function (value) {
Expand Down
109 changes: 98 additions & 11 deletions test/spec/WorkingSetView-integ-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -226,30 +226,117 @@ define(function (require, exports, module) {
expect($list.find(".directory").length).toBe(0);
});

it("should show full path next to the file name when file is outside current project", async function () {
// Count currently opened files
it("should show directory path for external files", async function () {
var workingSetListItemCountBeforeTest = workingSetListItemCount;

// First we need to open another file
// Open an external file (outside current project)
await openAndMakeDirty(externalProjectTestPath + "/test.js");

// Wait for file to be added to the working set
await awaitsFor(function () { return workingSetListItemCount === workingSetListItemCountBeforeTest + 1; });

// Two files with the same name file_one.js should be now opened
var $list = testWindow.$(".open-files-container > ul");
const fullPathSpan = $list.find(".directory");
expect(fullPathSpan.length).toBe(1);
expect(fullPathSpan[0].innerHTML.includes(Phoenix.app.getDisplayPath(externalProjectTestPath))).toBe(true);
const directorySpan = $list.find(".directory");

// Now close last opened file to hide the directories again
DocumentManager.getCurrentDocument()._markClean(); // so we can close without a save dialog
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE), "timeout on FILE_CLOSE", 1000);
// Should show directory information for external files
expect(directorySpan.length).toBe(1);

// there should be no more directories shown
// Verify the title attribute contains the full display path
const fullDisplayPath = directorySpan.attr('title');
expect(fullDisplayPath).toBe(testWindow.Phoenix.app.getDisplayPath(externalProjectTestPath));

// Verify the displayed text contains the expected format
const displayedText = directorySpan.text();
expect(displayedText.length).toBeGreaterThan(0);
expect(displayedText.includes(" — ")).toBe(true); // Should have the separator

// Clean up
DocumentManager.getCurrentDocument()._markClean();
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE), "timeout on FILE_CLOSE", 1000);
expect($list.find(".directory").length).toBe(0);
});

it("should truncate very long external file paths with ellipsis", async function () {
// Create platform-appropriate test paths
var isWindows = testWindow.brackets.platform === "win";
var isMac = testWindow.brackets.platform === "mac";
var separator = isWindows ? "\\" : "/";
var isNativeApp = testWindow.Phoenix.isNativeApp;

// Define expected path formats for different environments
var mockLongPath, expectedTruncatedPath;

if (isNativeApp) {
// Desktop app path formats
if (isWindows) {
mockLongPath = "C:\\Users\\TestUser\\Documents\\Very\\Long\\Project\\Structure\\Directory";
expectedTruncatedPath = "C:" + separator + "…" + separator + "Directory";
} else if (isMac) {
mockLongPath = "/Users/TestUser/Documents/Very/Long/Project/Structure/Directory";
expectedTruncatedPath = "Users" + separator + "…" + separator + "Directory";
} else { // Linux
mockLongPath = "/home/TestUser/Documents/Very/Long/Project/Structure/Directory";
expectedTruncatedPath = "home" + separator + "…" + separator + "Directory";
}
} else {
// Browser path formats
if (isWindows) {
// For default/internal projects in browser
mockLongPath = "/fs/Users/TestUser/Documents/Very/Long/Project/Structure/Directory";
expectedTruncatedPath = "fs" + separator + "…" + separator + "Directory";
} else {
// For Mac/Linux in browser
mockLongPath = "/fs/home/TestUser/Documents/Very/Long/Project/Structure/Directory";
expectedTruncatedPath = "fs" + separator + "…" + separator + "Directory";
}
}

// Now test the actual WorkingSetView implementation with a guaranteed long path
var workingSetListItemCountBeforeTest = workingSetListItemCount;

// Mock Phoenix.app.getDisplayPath to return our test path
var originalGetDisplayPath = testWindow.Phoenix.app.getDisplayPath;
testWindow.Phoenix.app.getDisplayPath = function(path) {
if (path.includes(externalProjectTestPath)) {
return mockLongPath;
}
return originalGetDisplayPath.call(this, path);
};

try {
await openAndMakeDirty(externalProjectTestPath + "/test.js");

// Wait for file to be added to the working set
await awaitsFor(function () { return workingSetListItemCount === workingSetListItemCountBeforeTest + 1; });

var $list = testWindow.$(".open-files-container > ul");
const directorySpan = $list.find(".directory");
expect(directorySpan.length).toBe(1);

// Verify the title attribute contains the full display path
const fullDisplayPath = directorySpan.attr('title');
expect(fullDisplayPath).toBe(mockLongPath);

// Get the displayed text
const displayedText = directorySpan.text();

// This is the critical test - if truncation is working, it MUST contain ellipsis
expect(displayedText.includes("…")).toBe(true);

// Should match our expected truncated path format
expect(displayedText.includes(expectedTruncatedPath)).toBe(true);

// Clean up
DocumentManager.getCurrentDocument()._markClean();
await awaitsForDone(CommandManager.execute(Commands.FILE_CLOSE), "timeout on FILE_CLOSE", 1000);
expect($list.find(".directory").length).toBe(0);

} finally {
// Restore original function
testWindow.Phoenix.app.getDisplayPath = originalGetDisplayPath;
}
});

it("should show different directory names, when two files of the same name are opened, located in folders with same name", async function () {
// Count currently opened files
var workingSetListItemCountBeforeTest = workingSetListItemCount;
Expand Down
Loading