This commit is contained in:
@@ -123,3 +123,38 @@ describe('terminal state reconciliation', () => {
|
|||||||
expect(useTerminalStore.getState().buffers.size).toBe(0);
|
expect(useTerminalStore.getState().buffers.size).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('default terminal tab labels', () => {
|
||||||
|
afterEach(() => useTerminalStore.getState().clearAll());
|
||||||
|
|
||||||
|
const labels = () =>
|
||||||
|
useTerminalStore.getState().getDirectoryState('/repo')!.tabs.map((tab) => tab.label);
|
||||||
|
|
||||||
|
// Regression for https://github.com/openchamber/openchamber/issues/2718
|
||||||
|
test('does not reuse the number of a closed tab', () => {
|
||||||
|
const first = setup();
|
||||||
|
useTerminalStore.getState().createTab('/repo');
|
||||||
|
expect(labels()).toEqual(['Terminal', 'Terminal 2']);
|
||||||
|
|
||||||
|
useTerminalStore.getState().closeTab('/repo', first);
|
||||||
|
useTerminalStore.getState().createTab('/repo');
|
||||||
|
|
||||||
|
expect(labels()).toEqual(['Terminal 2', 'Terminal 3']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('numbers past a user-renamed "Terminal N" label instead of duplicating it', () => {
|
||||||
|
const first = setup();
|
||||||
|
useTerminalStore.getState().setTabLabel('/repo', first, 'Terminal 5');
|
||||||
|
useTerminalStore.getState().createTab('/repo');
|
||||||
|
|
||||||
|
expect(labels()).toEqual(['Terminal 5', 'Terminal 6']);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('ignores custom labels and starts over at "Terminal" when no default-labeled tabs remain', () => {
|
||||||
|
const first = setup();
|
||||||
|
useTerminalStore.getState().setTabLabel('/repo', first, 'build');
|
||||||
|
useTerminalStore.getState().createTab('/repo');
|
||||||
|
|
||||||
|
expect(labels()).toEqual(['build', 'Terminal']);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -157,6 +157,27 @@ function normalizeDirectory(dir: string): string {
|
|||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_TAB_LABEL_PATTERN = /^Terminal(?: (\d+))?$/;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default labels must stay unique among the directory's open tabs even after
|
||||||
|
* closes (#2718), so number from the highest existing "Terminal N" suffix
|
||||||
|
* instead of the live tab count. Labels are persisted with the tabs, so the
|
||||||
|
* derivation also survives reloads without a dedicated counter. User-renamed
|
||||||
|
* labels only participate when they match the default pattern; they are never
|
||||||
|
* rewritten.
|
||||||
|
*/
|
||||||
|
const nextDefaultTabLabel = (tabs: readonly TerminalTab[]): string => {
|
||||||
|
let highest = 0;
|
||||||
|
for (const tab of tabs) {
|
||||||
|
const match = DEFAULT_TAB_LABEL_PATTERN.exec(tab.label);
|
||||||
|
if (!match) continue;
|
||||||
|
const value = match[1] ? Number.parseInt(match[1], 10) : 1;
|
||||||
|
if (Number.isSafeInteger(value)) highest = Math.max(highest, value);
|
||||||
|
}
|
||||||
|
return highest === 0 ? 'Terminal' : `Terminal ${highest + 1}`;
|
||||||
|
};
|
||||||
|
|
||||||
const createEmptyTab = (id: string, label: string): TerminalTab => ({
|
const createEmptyTab = (id: string, label: string): TerminalTab => ({
|
||||||
id,
|
id,
|
||||||
terminalSessionId: null,
|
terminalSessionId: null,
|
||||||
@@ -295,8 +316,7 @@ export const useTerminalStore = create<TerminalStore>()(
|
|||||||
const existing = newSessions.get(key);
|
const existing = newSessions.get(key);
|
||||||
|
|
||||||
const nextTabId = state.nextTabId + 1;
|
const nextTabId = state.nextTabId + 1;
|
||||||
const labelIndex = (existing?.tabs.length ?? 0) + 1;
|
const label = nextDefaultTabLabel(existing?.tabs ?? []);
|
||||||
const label = `Terminal ${labelIndex}`;
|
|
||||||
const tab = createEmptyTab(tabId, label);
|
const tab = createEmptyTab(tabId, label);
|
||||||
|
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
|
|||||||
Reference in New Issue
Block a user