Skip to content
Merged
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
153 changes: 114 additions & 39 deletions src/extensionsIntegrated/TabBar/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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 = $(
`<div class="tab
${isActive ? 'active' : ''}
${isDirty ? 'dirty' : ''}" data-path="${entry.path}" title="${entry.path}">
<div class="tab-icon"></div>
<div class="tab-name"></div>
<div class="tab-close"><i class="fa-solid fa-times"></i></div>
</div>`
${isActive ? 'active' : ''}
${isDirty ? 'dirty' : ''}
${isPlaceholder ? 'placeholder' : ''}"
data-path="${entry.path}"
title="${entry.path}">
<div class="tab-icon"></div>
<div class="tab-name"></div>
<div class="tab-close"><i class="fa-solid fa-times"></i></div>
</div>`
);

// Add the file icon
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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();
}
Expand All @@ -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
Expand All @@ -251,57 +323,52 @@ 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"));
}
}
}

const $secondTabBar = $('#phoenix-tab-bar-2');
// 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) {
tabsCountP2 = Global.secondPaneWorkingSet.length;
}

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");
Expand Down Expand Up @@ -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 });
Expand Down
30 changes: 22 additions & 8 deletions src/extensionsIntegrated/TabBar/overflow.js
Original file line number Diff line number Diff line change
Expand Up @@ -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()
};

Expand Down Expand Up @@ -148,17 +149,22 @@ define(function (require, exports, module) {
<i class="fa-solid fa-times"></i>
</span>`;

// add placeholder class to style it differently
const placeholderClass = item.isPlaceholder ? ' placeholder-name' : '';

// return html for this item
return {
html:
`<div class="dropdown-tab-item" data-tab-path="${item.path}">
<div class="tab-info-container">
${dirtyHtml}
<span class="tab-icon-container">${iconHtml}</span>
<span class="tab-name-container">${item.name}</span>
</div>
${closeIconHtml}
</div>`,
`<div class="dropdown-tab-item${item.isPlaceholder
? ' placeholder-item' : ''
}" data-tab-path="${item.path}">
<div class="tab-info-container">
${dirtyHtml}
<span class="tab-icon-container">${iconHtml}</span>
<span class="tab-name-container${placeholderClass}">${item.name}</span>
</div>
${closeIconHtml}
</div>`,
enabled: true
};
});
Expand Down Expand Up @@ -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);
}
});

Expand Down
44 changes: 44 additions & 0 deletions src/styles/Extn-TabBar.less
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Loading