diff --git a/src/extensionsIntegrated/TabBar/main.js b/src/extensionsIntegrated/TabBar/main.js
index b1a778f93b..eaec425696 100644
--- a/src/extensionsIntegrated/TabBar/main.js
+++ b/src/extensionsIntegrated/TabBar/main.js
@@ -23,9 +23,9 @@ define(function (require, exports, module) {
const _ = require("thirdparty/lodash");
const AppInit = require("utils/AppInit");
const MainViewManager = require("view/MainViewManager");
- const EditorManager = require("editor/EditorManager");
const FileSystem = require("filesystem/FileSystem");
const PreferencesManager = require("preferences/PreferencesManager");
+ const FileUtils = require("file/FileUtils");
const CommandManager = require("command/CommandManager");
const Commands = require("command/Commands");
const DocumentManager = require("document/DocumentManager");
@@ -135,16 +135,20 @@ define(function (require, exports, module) {
const isPaneActive = (paneId === currentActivePane);
const isDirty = Helper._isFileModified(FileSystem.getFileForPath(entry.path));
+ const isPlaceholder = entry.isPlaceholder === true;
- // create tab with active class
+ // create tab with all the appropriate classes
const $tab = $(
`
`
+ ${isActive ? 'active' : ''}
+ ${isDirty ? 'dirty' : ''}
+ ${isPlaceholder ? 'placeholder' : ''}"
+ data-path="${entry.path}"
+ title="${entry.path}">
+
+
+
+ `
);
// Add the file icon
@@ -173,6 +177,13 @@ define(function (require, exports, module) {
$tab.addClass('active-in-inactive-pane');
}
+ // if this is a placeholder tab in inactive pane, we need to use the brown styling
+ // instead of the blue one for active tabs
+ if (isPlaceholder && isActive && !isPaneActive) {
+ $tab.removeClass('active');
+ $tab.addClass('active-in-inactive-pane');
+ }
+
return $tab;
}
@@ -218,17 +229,78 @@ define(function (require, exports, module) {
// Get all files from the working set. refer to `global.js`
getAllFilesFromWorkingSet();
- // When there is only one file, we enforce the creation of the tab bar
- // this is done because, given the situation:
- // In a vertical split, when no files are present in 'second-pane' so the tab bar is hidden.
- // Now, when the user adds a file in 'second-pane', the tab bar should be shown but since updateTabs() only,
- // updates the tabs, so the tab bar never gets created.
- if (Global.firstPaneWorkingSet.length === 1 &&
+ // Check for active files not in working set in any pane
+ const activePane = MainViewManager.getActivePaneId();
+ const firstPaneFile = MainViewManager.getCurrentlyViewedFile("first-pane");
+ const secondPaneFile = MainViewManager.getCurrentlyViewedFile("second-pane");
+
+ // when a file is opened from the filetree and is not present in the working set, then it is a placeholder
+ let firstPanePlaceholder = null;
+ let secondPanePlaceholder = null;
+
+ // Check if active file in first pane is not in the working set
+ if (firstPaneFile &&
+ !Global.firstPaneWorkingSet.some(entry => entry.path === firstPaneFile.fullPath)) {
+ firstPanePlaceholder = {
+ path: firstPaneFile.fullPath,
+ name: firstPaneFile.name,
+ isPlaceholder: true,
+ displayName: firstPaneFile.name // for now we initialize with name, will check for duplicates later
+ };
+ }
+
+ // Check if active file in second pane is not in the working set
+ if (secondPaneFile &&
+ !Global.secondPaneWorkingSet.some(entry => entry.path === secondPaneFile.fullPath)) {
+ secondPanePlaceholder = {
+ path: secondPaneFile.fullPath,
+ name: secondPaneFile.name,
+ isPlaceholder: true,
+ displayName: secondPaneFile.name
+ };
+ }
+
+ // check for duplicate file names between placeholder tabs and working set entries
+ if (firstPanePlaceholder) {
+ // if any working set file has the same name as the placeholder
+ const hasDuplicate = Global.firstPaneWorkingSet.some(entry =>
+ entry.name === firstPanePlaceholder.name
+ );
+
+ if (hasDuplicate) {
+ // extract directory name from path
+ const path = firstPanePlaceholder.path;
+ const parentDir = FileUtils.getDirectoryPath(path);
+ const dirParts = parentDir.split("/");
+ const parentDirName = dirParts[dirParts.length - 2] || "";
+
+ // Update displayName with directory
+ firstPanePlaceholder.displayName = parentDirName + "/" + firstPanePlaceholder.name;
+ }
+ }
+
+ if (secondPanePlaceholder) {
+ const hasDuplicate = Global.secondPaneWorkingSet.some(entry =>
+ entry.name === secondPanePlaceholder.name
+ );
+
+ if (hasDuplicate) {
+ const path = secondPanePlaceholder.path;
+ const parentDir = FileUtils.getDirectoryPath(path);
+ const dirParts = parentDir.split("/");
+ const parentDirName = dirParts[dirParts.length - 2] || "";
+
+ secondPanePlaceholder.displayName = parentDirName + "/" + secondPanePlaceholder.name;
+ }
+ }
+
+ // Create tab bar if there's a placeholder or a file in the working set
+ if ((Global.firstPaneWorkingSet.length > 0 || firstPanePlaceholder) &&
(!$('#phoenix-tab-bar').length || $('#phoenix-tab-bar').is(':hidden'))) {
createTabBar();
}
- if (Global.secondPaneWorkingSet.length === 1 &&
+ if ((Global.secondPaneWorkingSet.length > 0 || secondPanePlaceholder) &&
(!$('#phoenix-tab-bar-2').length || $('#phoenix-tab-bar-2').is(':hidden'))) {
createTabBar();
}
@@ -237,7 +309,7 @@ define(function (require, exports, module) {
// Update first pane's tabs
if ($firstTabBar.length) {
$firstTabBar.empty();
- if (Global.firstPaneWorkingSet.length > 0) {
+ if (Global.firstPaneWorkingSet.length > 0 || firstPanePlaceholder) {
// get the count of tabs that we want to display in the tab bar (from preference settings)
// from preference settings or working set whichever smaller
@@ -251,17 +323,15 @@ define(function (require, exports, module) {
let displayedEntries = Global.firstPaneWorkingSet.slice(0, tabsCountP1);
- const activeEditor = EditorManager.getActiveEditor();
- const activePath = activeEditor ? activeEditor.document.file.fullPath : null;
- if (activePath && !displayedEntries.some(entry => entry.path === activePath)) {
- let activeEntry = Global.firstPaneWorkingSet.find(entry => entry.path === activePath);
- if (activeEntry) {
- displayedEntries[displayedEntries.length - 1] = activeEntry;
- }
- }
+ // Add working set tabs
displayedEntries.forEach(function (entry) {
$firstTabBar.append(createTab(entry, "first-pane"));
});
+
+ // Add placeholder tab if needed
+ if (firstPanePlaceholder) {
+ $firstTabBar.append(createTab(firstPanePlaceholder, "first-pane"));
+ }
}
}
@@ -269,7 +339,7 @@ define(function (require, exports, module) {
// Update second pane's tabs
if ($secondTabBar.length) {
$secondTabBar.empty();
- if (Global.secondPaneWorkingSet.length > 0) {
+ if (Global.secondPaneWorkingSet.length > 0 || secondPanePlaceholder) {
let tabsCountP2 = Math.min(Global.secondPaneWorkingSet.length, Preference.tabBarNumberOfTabs);
if (Preference.tabBarNumberOfTabs < 0) {
@@ -277,31 +347,28 @@ define(function (require, exports, module) {
}
let displayedEntries2 = Global.secondPaneWorkingSet.slice(0, tabsCountP2);
- const activeEditor = EditorManager.getActiveEditor();
- const activePath = activeEditor ? activeEditor.document.file.fullPath : null;
- if (activePath && !displayedEntries2.some(entry => entry.path === activePath)) {
- let activeEntry = Global.secondPaneWorkingSet.find(entry => entry.path === activePath);
- if (activeEntry) {
- displayedEntries2[displayedEntries2.length - 1] = activeEntry;
- }
- }
+
+ // Add working set tabs
displayedEntries2.forEach(function (entry) {
$secondTabBar.append(createTab(entry, "second-pane"));
});
+
+ // Add placeholder tab if needed
+ if (secondPanePlaceholder) {
+ $secondTabBar.append(createTab(secondPanePlaceholder, "second-pane"));
+ }
}
}
- // if no files are present in a pane, we want to hide the tab bar for that pane
- if (Global.firstPaneWorkingSet.length === 0 && ($('#phoenix-tab-bar'))) {
+ // if no files are present in a pane and no placeholder, we want to hide the tab bar for that pane
+ if (Global.firstPaneWorkingSet.length === 0 && !firstPanePlaceholder && ($('#phoenix-tab-bar'))) {
Helper._hideTabBar($('#phoenix-tab-bar'), $('#overflow-button'));
}
- if (Global.secondPaneWorkingSet.length === 0 && ($('#phoenix-tab-bar-2'))) {
+ if (Global.secondPaneWorkingSet.length === 0 && !secondPanePlaceholder && ($('#phoenix-tab-bar-2'))) {
Helper._hideTabBar($('#phoenix-tab-bar-2'), $('#overflow-button-2'));
}
- const activePane = MainViewManager.getActivePaneId();
-
// Now that tabs are updated, scroll to the active tab if necessary.
if ($firstTabBar.length) {
Overflow.toggleOverflowVisibility("first-pane");
@@ -396,7 +463,15 @@ define(function (require, exports, module) {
const currentActivePane = MainViewManager.getActivePaneId();
const isPaneActive = (paneId === currentActivePane);
const currentFile = MainViewManager.getCurrentlyViewedFile(currentActivePane);
- if(isPaneActive && currentFile && currentFile.fullPath === filePath) {
+
+ // Check if this is a placeholder tab
+ if ($(this).hasClass('placeholder')) {
+ // Add the file to the working set when placeholder tab is clicked
+ const fileObj = FileSystem.getFileForPath(filePath);
+ MainViewManager.addToWorkingSet(paneId, fileObj);
+ }
+
+ if (isPaneActive && currentFile && currentFile.fullPath === filePath) {
return;
}
CommandManager.execute(Commands.FILE_OPEN, { fullPath: filePath, paneId: paneId });
diff --git a/src/extensionsIntegrated/TabBar/overflow.js b/src/extensionsIntegrated/TabBar/overflow.js
index 317989e877..169e6e63fd 100644
--- a/src/extensionsIntegrated/TabBar/overflow.js
+++ b/src/extensionsIntegrated/TabBar/overflow.js
@@ -75,6 +75,7 @@ define(function (require, exports, module) {
name: $tab.find('.tab-name').text(),
isActive: $tab.hasClass('active'),
isDirty: $tab.hasClass('dirty'),
+ isPlaceholder: $tab.hasClass('placeholder'),
$icon: $tab.find('.tab-icon').clone()
};
@@ -148,17 +149,22 @@ define(function (require, exports, module) {
`;
+ // add placeholder class to style it differently
+ const placeholderClass = item.isPlaceholder ? ' placeholder-name' : '';
+
// return html for this item
return {
html:
- `
-
- ${dirtyHtml}
- ${iconHtml}
- ${item.name}
-
- ${closeIconHtml}
-
`,
+ `
+
+ ${dirtyHtml}
+ ${iconHtml}
+ ${item.name}
+
+ ${closeIconHtml}
+
`,
enabled: true
};
});
@@ -223,6 +229,14 @@ define(function (require, exports, module) {
// Set the active pane and open the file
MainViewManager.setActivePaneId(paneId);
CommandManager.execute(Commands.FILE_OPEN, { fullPath: filePath });
+
+ // get the tab bar element based on paneId and scroll to the active tab
+ // we use setTimeout to ensure that the DOM has updated after the file open command
+ setTimeout(function () {
+ const $tabBarElement = paneId === "first-pane" ?
+ $("#phoenix-tab-bar") : $("#phoenix-tab-bar-2");
+ scrollToActiveTab($tabBarElement);
+ }, 100);
}
});
diff --git a/src/styles/Extn-TabBar.less b/src/styles/Extn-TabBar.less
index 2087ab7a2a..fb4288f541 100644
--- a/src/styles/Extn-TabBar.less
+++ b/src/styles/Extn-TabBar.less
@@ -240,6 +240,45 @@
background-color: rgba(255, 255, 255, 0.1);
}
+.tab.placeholder .tab-name {
+ font-style: italic;
+ color: #888;
+}
+
+.dark .tab.placeholder .tab-name {
+ color: #888;
+}
+
+.tab.placeholder.active .tab-name {
+ color: #666;
+}
+
+.dark .tab.placeholder.active .tab-name {
+ color: #aaa;
+}
+
+.tab.placeholder::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 0.12rem;
+ background-color: #b4b2b2;
+}
+
+.dark .tab.placeholder::after {
+ background-color: #666;
+}
+
+.tab.placeholder.active::after {
+ background-color: #0078D7;
+}
+
+.dark .tab.placeholder.active::after {
+ background-color: #75BEFF;
+}
+
.tab.dragging {
opacity: 0.7;
transform: scale(0.95);
@@ -364,4 +403,9 @@
.empty-pane-drop-target {
border: 2px dashed #6db6ff !important;
+}
+
+.dropdown-tab-item.placeholder-item .tab-name-container,
+.tab-name-container.placeholder-name {
+ font-style: italic;
}
\ No newline at end of file