New shortcuts: switch to previous/next opened tab

This commit is contained in:
aleksey-hoffman committed 2026-08-21 19:06:41 +03:00
1 parent 7f7be33aed
commit 5b3137c8c7
25 files changed
+266 -13

No files matched your search

+3 -1
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "用户界面缩放减少",
"closeCurrentTab": "关闭当前选项卡/关闭应用程序窗口",
"restoreLastClosedTab": "恢复上次关闭的标签页",
"switchToNextTab": "切换到下一个标签页",
"switchToPreviousTab": "切换到上一个标签页",
"toggleAddressBar": "使用当前路径打开地址编辑器",
"openEntry": "打开地址编辑器",
"copyCurrentDirectoryPathToClipboard": "复制当前目录路径到剪贴板",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "文件已在网络上共享。当前共享将被停止并替换为新的共享。",
"replaceShareDialogConfirm": "替换"
}
}
}
+2
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "UI-Zoom verringern",
"closeCurrentTab": "Aktuellen Tab schließen / App-Fenster schließen",
"restoreLastClosedTab": "Zuletzt geschlossenen Tab wiederherstellen",
"switchToNextTab": "Zum nächsten Tab wechseln",
"switchToPreviousTab": "Zum vorherigen Tab wechseln",
"toggleAddressBar": "Adresseditor mit aktuellem Pfad öffnen",
"openEntry": "Adresseditor öffnen",
"copyCurrentDirectoryPathToClipboard": "Aktuellen Verzeichnispfad in die Zwischenablage kopieren",
+2
View File
@@ -564,6 +564,8 @@
"uiZoomDecrease": "UI zoom decrease",
"closeCurrentTab": "Close current tab / close app window",
"restoreLastClosedTab": "Restore last closed tab",
"switchToNextTab": "Switch to next tab",
"switchToPreviousTab": "Switch to previous tab",
"toggleAddressBar": "Open address editor with the current path",
"openEntry": "Open address editor",
"copyCurrentDirectoryPathToClipboard": "Copy current directory path to clipboard",
+2
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "Disminución del zoom de la interfaz de usuario",
"closeCurrentTab": "Cerrar pestaña actual/cerrar ventana de aplicación",
"restoreLastClosedTab": "Restaurar la última pestaña cerrada",
"switchToNextTab": "Cambiar a la pestaña siguiente",
"switchToPreviousTab": "Cambiar a la pestaña anterior",
"toggleAddressBar": "Abrir editor de dirección con la ruta actual",
"openEntry": "Abrir editor de dirección",
"copyCurrentDirectoryPathToClipboard": "Copiar la ruta del directorio actual al portapapeles",
+3 -1
View File
@@ -531,6 +531,8 @@
"uiZoomDecrease": "کاهش زوم UI",
"closeCurrentTab": "بستن برگه فعلی / بستن پنجره برنامه",
"restoreLastClosedTab": "بازگرداندن آخرین برگه بسته شده",
"switchToNextTab": "رفتن به برگه بعدی",
"switchToPreviousTab": "رفتن به برگه قبلی",
"toggleAddressBar": "باز کردن ویرایشگر آدرس با مسیر فعلی",
"openEntry": "باز کردن ویرایشگر آدرس",
"copyCurrentDirectoryPathToClipboard": "کپی مسیر دایرکتوری فعلی در کلیپ بورد",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "فایل‌ها از قبل از طریق شبکه به اشتراک گذاشته شده‌اند. اشتراک‌گذاری فعلی متوقف و با مورد جدید جایگزین خواهد شد.",
"replaceShareDialogConfirm": "جایگزینی"
}
}
}
+2
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "diminution du zoom de l'interface utilisateur",
"closeCurrentTab": "Fermer l'onglet actuel / fermer la fenêtre de l'application",
"restoreLastClosedTab": "Restaurer le dernier onglet fermé",
"switchToNextTab": "Passer à l'onglet suivant",
"switchToPreviousTab": "Passer à l'onglet précédent",
"toggleAddressBar": "Ouvrir l'éditeur d'adresse avec le chemin actuel",
"openEntry": "Ouvrir l'éditeur d'adresse",
"copyCurrentDirectoryPathToClipboard": "Copier le chemin du répertoire actuel dans le presse-papiers",
+3 -1
View File
@@ -564,6 +564,8 @@
"uiZoomDecrease": "הקטן את זום הממשק",
"closeCurrentTab": "סגור את הלשונית הנוכחית / סגור את חלון היישום",
"restoreLastClosedTab": "שחזר את הלשונית האחרונה שנסגרה",
"switchToNextTab": "עבור ללשונית הבאה",
"switchToPreviousTab": "עבור ללשונית הקודמת",
"toggleAddressBar": "פתח את עורך הכתובת עם הנתיב הנוכחי",
"openEntry": "פתח את עורך הכתובת",
"copyCurrentDirectoryPathToClipboard": "העתק את נתיב התיקייה הנוכחית ללוח",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "קבצים כבר משותפים ברשת. השיתוף הנוכחי ייעצר ויוחלף בחדש.",
"replaceShareDialogConfirm": "החלף"
}
}
}
+3 -1
View File
@@ -564,6 +564,8 @@
"uiZoomDecrease": "यूआई ज़ूम में कमी",
"closeCurrentTab": "वर्तमान टैब बंद करें / ऐप विंडो बंद करें",
"restoreLastClosedTab": "अंतिम बंद टैब पुनर्स्थापित करें",
"switchToNextTab": "अगले टैब पर स्विच करें",
"switchToPreviousTab": "पिछले टैब पर स्विच करें",
"toggleAddressBar": "वर्तमान पथ के साथ पता संपादक खोलें",
"openEntry": "पता संपादक खोलें",
"copyCurrentDirectoryPathToClipboard": "वर्तमान निर्देशिका पथ को क्लिपबोर्ड पर कॉपी करें",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "फ़ाइलें पहले से ही नेटवर्क पर साझा की जा रही हैं. वर्तमान शेयर बंद कर दिया जाएगा और उसके स्थान पर नया शेयर ले लिया जाएगा।",
"replaceShareDialogConfirm": "प्रतिस्थापित करें"
}
}
}
+3 -1
View File
@@ -564,6 +564,8 @@
"uiZoomDecrease": "Մասշտաբի իջեցում",
"closeCurrentTab": "Փակել ընթացիկ թաբը/փակել ծրագիրը",
"restoreLastClosedTab": "Վերաբացել վերջին փակված թաբը",
"switchToNextTab": "Անցնել հաջորդ թաբ",
"switchToPreviousTab": "Անցնել նախորդ թաբ",
"toggleAddressBar": "Բացել այս հասցեի փոփոխման էջը",
"openEntry": "Փոփոխել հասցեն",
"copyCurrentDirectoryPathToClipboard": "Պատճենել ընտրված պանակի ուղին",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "Ֆայլերն արդեն կիսվում են ցանցում: Ընթացիկ կիսումը կդադարեցվի և կփոխարինվի նորով:",
"replaceShareDialogConfirm": "Փոխարինել"
}
}
}
+2
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "Diminuzione zoom della UI",
"closeCurrentTab": "Chiudi la scheda attuale / chiudi la finestra dell'app",
"restoreLastClosedTab": "Ripristina l'ultima scheda chiusa",
"switchToNextTab": "Passa alla scheda successiva",
"switchToPreviousTab": "Passa alla scheda precedente",
"toggleAddressBar": "Apri l'editor dell'indirizzo con il percorso corrente",
"openEntry": "Apri l'editor dell'indirizzo",
"copyCurrentDirectoryPathToClipboard": "Copia il percorso della directory corrente negli appunti",
+2
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "UIズーム減少",
"closeCurrentTab": "現在のタブを閉じる / アプリ ウィンドウを閉じる",
"restoreLastClosedTab": "最後に閉じたタブを復元",
"switchToNextTab": "次のタブに切り替え",
"switchToPreviousTab": "前のタブに切り替え",
"toggleAddressBar": "現在のパスでアドレスエディターを開く",
"openEntry": "アドレスエディターを開く",
"copyCurrentDirectoryPathToClipboard": "現在のディレクトリパスをクリップボードにコピー",
+2
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "Diminuir zoom da interface do usuário",
"closeCurrentTab": "Fechar aba atual/fechar janela do aplicativo",
"restoreLastClosedTab": "Restaurar última aba fechada",
"switchToNextTab": "Mudar para a aba seguinte",
"switchToPreviousTab": "Mudar para a aba anterior",
"toggleAddressBar": "Abrir editor de endereço com o caminho atual",
"openEntry": "Abrir editor de endereço",
"copyCurrentDirectoryPathToClipboard": "Copiar caminho do diretório atual para a área de transferência",
+2
View File
@@ -564,6 +564,8 @@
"uiZoomDecrease": "уменьшение масштаба интерфейса",
"closeCurrentTab": "Закрыть текущую вкладку/закрыть окно приложения",
"restoreLastClosedTab": "Восстановить последнюю закрытую вкладку",
"switchToNextTab": "Переключиться на следующую вкладку",
"switchToPreviousTab": "Переключиться на предыдущую вкладку",
"toggleAddressBar": "Открыть редактор адреса с текущим путём",
"openEntry": "Открыть редактор адреса",
"copyCurrentDirectoryPathToClipboard": "Скопировать текущий путь к папке в буфер обмена",
+3 -1
View File
@@ -564,6 +564,8 @@
"uiZoomDecrease": "Zmanjšaj UI povečavo",
"closeCurrentTab": "Zapri trenutni zavihek / zapri okno aplikacije",
"restoreLastClosedTab": "Obnovi zadnji zaprti zavihek",
"switchToNextTab": "Preklopi na naslednji zavihek",
"switchToPreviousTab": "Preklopi na prejšnji zavihek",
"toggleAddressBar": "Odpri urejevalnik naslova s trenutno potjo",
"openEntry": "Odpri urejevalnik naslova",
"copyCurrentDirectoryPathToClipboard": "Kopiraj pot trenutne mape v odložišče",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "Datoteke se že delijo po omrežju. Trenutno deljenje bo ustavljeno in zamenjano z novim.",
"replaceShareDialogConfirm": "Zamenjaj"
}
}
}
+3 -1
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "UI yakınlaştırma azaltma",
"closeCurrentTab": "Geçerli sekmeyi kapat / uygulama penceresini kapat",
"restoreLastClosedTab": "Son kapatılan sekmeyi geri yükle",
"switchToNextTab": "Sonraki sekmeye geç",
"switchToPreviousTab": "Önceki sekmeye geç",
"toggleAddressBar": "Geçerli yolla adres düzenleyiciyi aç",
"openEntry": "Adres düzenleyiciyi aç",
"copyCurrentDirectoryPathToClipboard": "Geçerli dizin yolunu panoya kopyala",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "Ağ üzerinden zaten dosyalar paylaşılıyor. Mevcut paylaşım durdurulup yenisiyle değiştirilecek.",
"replaceShareDialogConfirm": "Değiştir"
}
}
}
+3 -1
View File
@@ -564,6 +564,8 @@
"uiZoomDecrease": "UI زوم کم کریں",
"closeCurrentTab": "موجودہ ٹیب بند کریں / ایپ ونڈو بند کریں",
"restoreLastClosedTab": "آخری بند ٹیب بحال کریں",
"switchToNextTab": "اگلے ٹیب پر جائیں",
"switchToPreviousTab": "پچھلے ٹیب پر جائیں",
"toggleAddressBar": "موجودہ راستے کے ساتھ پتہ ایڈیٹر کھولیں",
"openEntry": "پتہ ایڈیٹر کھولیں",
"copyCurrentDirectoryPathToClipboard": "موجودہ فولڈر کا راستہ کلپ بورڈ پر کاپی کریں",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "فائلیں پہلے سے نیٹ ورک پر ہیں۔ موجودہ شیئر بند ہو کر نئے سے بدل جائے گا۔",
"replaceShareDialogConfirm": "بدل دیں"
}
}
}
+3 -1
View File
@@ -535,6 +535,8 @@
"uiZoomDecrease": "Giảm thu phóng giao diện người dùng",
"closeCurrentTab": "Đóng thẻ hiện tại / đóng cửa sổ ứng dụng",
"restoreLastClosedTab": "Khôi phục thẻ đã đóng gần nhất",
"switchToNextTab": "Chuyển sang thẻ tiếp theo",
"switchToPreviousTab": "Chuyển sang thẻ trước",
"toggleAddressBar": "Chuyển đổi thanh địa chỉ",
"openEntry": "Mở trình chỉnh sửa địa chỉ",
"copyCurrentDirectoryPathToClipboard": "Sao chép đường dẫn thư mục hiện tại vào clipboard",
@@ -1240,4 +1242,4 @@
"replaceShareDialogDescription": "Các tập tin đang được chia sẻ qua mạng. Chia sẻ hiện tại sẽ bị dừng và thay thế bằng chia sẻ mới.",
"replaceShareDialogConfirm": "Thay thế"
}
}
}
+10
View File
@@ -981,6 +981,14 @@ async function handleRestoreLastClosedTabShortcut() {
return workspacesStore.restoreLastClosedTabGroup();
}
async function handleSwitchToNextTabShortcut() {
return workspacesStore.switchToAdjacentTabGroup('next');
}
async function handleSwitchToPreviousTabShortcut() {
return workspacesStore.switchToAdjacentTabGroup('previous');
}
async function handleOpenTerminalShortcut() {
await openTerminalWithOptions(false);
}
@@ -1113,6 +1121,8 @@ function registerShortcutHandlers() {
shortcutsStore.registerHandler('openNewTab', handleOpenNewTabShortcut);
shortcutsStore.registerHandler('closeCurrentTab', handleCloseCurrentTabShortcut);
shortcutsStore.registerHandler('restoreLastClosedTab', handleRestoreLastClosedTabShortcut);
shortcutsStore.registerHandler('switchToNextTab', handleSwitchToNextTabShortcut);
shortcutsStore.registerHandler('switchToPreviousTab', handleSwitchToPreviousTabShortcut);
shortcutsStore.registerHandler('openTerminal', handleOpenTerminalShortcut);
shortcutsStore.registerHandler('openTerminalAdmin', handleOpenTerminalAdminShortcut);
shortcutsStore.registerHandler('navigateUp', () => callActivePaneMethod('navigateUp'));
@@ -64,6 +64,8 @@ import {
HomeIcon,
FolderClosedIcon,
BookmarkIcon,
ChevronsRightIcon,
ChevronsLeftIcon,
} from '@lucide/vue';
import type { Component } from 'vue';
import {
@@ -127,6 +129,8 @@ const shortcutIcons: Record<ShortcutId, Component> = {
openNewTab: PlusIcon,
closeCurrentTab: XIcon,
restoreLastClosedTab: RotateCcwIcon,
switchToNextTab: ChevronsRightIcon,
switchToPreviousTab: ChevronsLeftIcon,
openTerminal: TerminalSquareIcon,
openTerminalAdmin: TerminalSquareIcon,
navigateUp: ArrowUpIcon,
@@ -164,8 +168,16 @@ let recordCaptureKeyDown: ((event: KeyboardEvent) => void) | null = null;
let recordCaptureKeyUp: ((event: KeyboardEvent) => void) | null = null;
let recordCaptureMouseDown: ((event: MouseEvent) => void) | null = null;
function shouldIgnorePhysicalCodeForCaptureTracking(code: string): boolean {
return code === 'Tab' || code === 'Enter';
function isBareTabKey(event: KeyboardEvent): boolean {
return event.key === 'Tab' && !event.ctrlKey && !event.altKey && !event.metaKey;
}
function shouldIgnorePhysicalCodeForCaptureTracking(event: KeyboardEvent): boolean {
if (event.code === 'Enter') {
return true;
}
return isBareTabKey(event);
}
function updateCaptureDisplayLabel() {
@@ -301,10 +313,26 @@ function attachRecordCaptureListeners() {
recordedKeys.value = null;
}
if (!shouldIgnorePhysicalCodeForCaptureTracking(event.code)) {
if (!shouldIgnorePhysicalCodeForCaptureTracking(event)) {
pressedPhysicalCodes.add(event.code);
}
if (event.key === 'Tab' && !isBareTabKey(event) && !event.repeat) {
const mainKey = resolveShortcutKeyFromKeyboardEvent(event, {
preferPhysicalMainKey: true,
});
if (mainKey !== null) {
recordedKeys.value = {
key: mainKey,
ctrl: event.ctrlKey,
alt: event.altKey,
shift: event.shiftKey,
meta: event.metaKey,
};
}
}
lastCaptureKeyboardEvent.value = event;
updateCaptureDisplayLabel();
refocusRecordControl();
@@ -681,7 +709,7 @@ function handleRecordKeyDown(event: KeyboardEvent) {
return;
}
if (key === 'Tab') {
if (isBareTabKey(event)) {
return;
}
+11
View File
@@ -59,6 +59,17 @@ watch(tabGroupCount, (newCount, previousCount) => {
});
});
watch(
() => workspacesStore.currentTabGroup?.[0]?.id,
(currentTabId, previousTabId) => {
if (!currentTabId || currentTabId === previousTabId) {
return;
}
scrollSelectedTabGroupIntoView();
},
);
function handleScrollActivity() {
previewEnabled.value = false;
@@ -598,6 +598,71 @@ describe('shortcuts store', () => {
expect(event.defaultPrevented).toBe(true);
});
it('matches Ctrl+Tab and Ctrl+Shift+Tab for switching opened tabs', async () => {
const shortcutsStore = useShortcutsStore();
const switchToNextTabHandler = vi.fn();
const switchToPreviousTabHandler = vi.fn();
shortcutsStore.registerHandler('switchToNextTab', switchToNextTabHandler);
shortcutsStore.registerHandler('switchToPreviousTab', switchToPreviousTabHandler);
expect(shortcutsStore.getShortcutLabel('switchToNextTab')).toBe('Ctrl+Tab');
expect(shortcutsStore.getShortcutLabel('switchToPreviousTab')).toBe('Ctrl+Shift+Tab');
const nextTabEvent = new KeyboardEvent('keydown', {
key: 'Tab',
code: 'Tab',
ctrlKey: true,
bubbles: true,
cancelable: true,
});
const previousTabEvent = new KeyboardEvent('keydown', {
key: 'Tab',
code: 'Tab',
ctrlKey: true,
shiftKey: true,
bubbles: true,
cancelable: true,
});
await expect(shortcutsStore.handleKeydown(nextTabEvent)).resolves.toBe(true);
await expect(shortcutsStore.handleKeydown(previousTabEvent)).resolves.toBe(true);
expect(switchToNextTabHandler).toHaveBeenCalledTimes(1);
expect(switchToPreviousTabHandler).toHaveBeenCalledTimes(1);
expect(nextTabEvent.defaultPrevented).toBe(true);
expect(previousTabEvent.defaultPrevented).toBe(true);
});
it('prevents Ctrl+Tab default behavior before async shortcut handlers finish', async () => {
const shortcutsStore = useShortcutsStore();
let resolveHandler: (value: boolean) => void = () => {};
const switchToNextTabHandler = vi.fn(() => new Promise<boolean>((resolve) => {
resolveHandler = resolve;
}));
shortcutsStore.registerHandler('switchToNextTab', switchToNextTabHandler);
const event = new KeyboardEvent('keydown', {
key: 'Tab',
code: 'Tab',
ctrlKey: true,
bubbles: true,
cancelable: true,
});
const handledPromise = shortcutsStore.handleKeydown(event);
expect(event.defaultPrevented).toBe(true);
await Promise.resolve();
expect(switchToNextTabHandler).toHaveBeenCalledTimes(1);
resolveHandler(true);
await expect(handledPromise).resolves.toBe(true);
});
it('prevents default when an async shortcut handler resolves true', async () => {
const shortcutsStore = useShortcutsStore();
const restoreLastClosedTabHandler = vi.fn(() => Promise.resolve(true));
+31
View File
@@ -493,6 +493,35 @@ const DEFAULT_SHORTCUTS: ShortcutDefinition[] = [
},
isReadOnly: false,
},
{
id: 'switchToNextTab',
labelKey: 'shortcuts.switchToNextTab',
defaultKeys: {
ctrl: true,
key: 'Tab',
},
scope: 'navigator',
conditions: {
inputFieldIsActive: false,
dialogIsOpened: false,
},
isReadOnly: false,
},
{
id: 'switchToPreviousTab',
labelKey: 'shortcuts.switchToPreviousTab',
defaultKeys: {
ctrl: true,
shift: true,
key: 'Tab',
},
scope: 'navigator',
conditions: {
inputFieldIsActive: false,
dialogIsOpened: false,
},
isReadOnly: false,
},
{
id: 'openTerminal',
labelKey: 'shortcuts.openCurrentDirInTerminal',
@@ -1157,6 +1186,8 @@ const ADDRESS_BAR_PATH_EDITOR_YIELD_NAVIGATOR_IDS: ReadonlySet<ShortcutId> = new
const EARLY_PREVENT_DEFAULT_SHORTCUT_IDS: ReadonlySet<ShortcutId> = new Set([
'copyCurrentDirectoryPath',
'switchToNextTab',
'switchToPreviousTab',
]);
function keyboardEventTouchesAddressBarPathEditor(event: KeyboardEvent): boolean {
@@ -323,6 +323,52 @@ describe('workspaces storage duplicate tabs', () => {
expect(workspacesStore.currentTabGroup?.[0]?.id).not.toBe(secondTab.id);
});
it('switches to the next and previous opened tab groups and wraps around', async () => {
mockDirectoryReadResponses();
const firstTab = createTab('first-tab', 'C:/Users/aleks/First');
const secondTab = createTab('second-tab', 'C:/Users/aleks/Second');
const thirdTab = createTab('third-tab', 'C:/Users/aleks/Third');
const workspacesStore = useWorkspacesStore();
workspacesStore.workspaces = [
createWorkspace([
[firstTab],
[secondTab],
[thirdTab],
]),
];
await expect(workspacesStore.switchToAdjacentTabGroup('next')).resolves.toBe(true);
expect(workspacesStore.currentWorkspace?.currentTabGroupIndex).toBe(1);
expect(workspacesStore.currentTabGroup?.[0]?.id).toBe('second-tab');
await expect(workspacesStore.switchToAdjacentTabGroup('next')).resolves.toBe(true);
await expect(workspacesStore.switchToAdjacentTabGroup('next')).resolves.toBe(true);
expect(workspacesStore.currentWorkspace?.currentTabGroupIndex).toBe(0);
expect(workspacesStore.currentTabGroup?.[0]?.id).toBe('first-tab');
await expect(workspacesStore.switchToAdjacentTabGroup('previous')).resolves.toBe(true);
expect(workspacesStore.currentWorkspace?.currentTabGroupIndex).toBe(2);
expect(workspacesStore.currentTabGroup?.[0]?.id).toBe('third-tab');
});
it('keeps the current tab when only one tab group is open', async () => {
mockDirectoryReadResponses();
const onlyTab = createTab('only-tab', 'C:/Users/aleks/Only');
const workspacesStore = useWorkspacesStore();
workspacesStore.workspaces = [
createWorkspace([
[onlyTab],
]),
];
await expect(workspacesStore.switchToAdjacentTabGroup('next')).resolves.toBe(true);
await expect(workspacesStore.switchToAdjacentTabGroup('previous')).resolves.toBe(true);
expect(workspacesStore.currentWorkspace?.currentTabGroupIndex).toBe(0);
expect(workspacesStore.currentTabGroup?.[0]?.id).toBe('only-tab');
});
it('shows the restored path when restoring a closed tab group', async () => {
mockDirectoryReadResponses();
+26
View File
@@ -550,6 +550,31 @@ export const useWorkspacesStore = defineStore('workspaces', () => {
) ?? -1;
}
async function switchToAdjacentTabGroup(direction: 'next' | 'previous'): Promise<boolean> {
if (!currentWorkspace.value) {
return false;
}
const tabGroups = currentWorkspace.value.tabGroups;
const tabGroupTotal = tabGroups.length;
if (tabGroupTotal < 2) {
return true;
}
const currentIndex = currentWorkspace.value.currentTabGroupIndex || 0;
const offset = direction === 'next' ? 1 : -1;
const nextIndex = (currentIndex + offset + tabGroupTotal) % tabGroupTotal;
const nextTabGroup = tabGroups[nextIndex];
if (!nextTabGroup) {
return false;
}
await openTabGroup(nextTabGroup);
return true;
}
async function openOrFocusTabGroup(path: string) {
const existingIndex = findTabGroupIndexByPath(path);
@@ -958,6 +983,7 @@ export const useWorkspacesStore = defineStore('workspaces', () => {
openPathInCurrentTab,
consumeCurrentTabPathNavigationRequest,
restoreLastClosedTabGroup,
switchToAdjacentTabGroup,
openOrFocusTabGroup,
preloadDefaultTab,
getDirEntry,
+2
View File
@@ -123,6 +123,8 @@ export type ShortcutId
| 'openNewTab'
| 'closeCurrentTab'
| 'restoreLastClosedTab'
| 'switchToNextTab'
| 'switchToPreviousTab'
| 'openTerminal'
| 'openTerminalAdmin'
| 'navigateUp'