diff --git a/src/utils/__tests__/renderer-separator-collapse.test.ts b/src/utils/__tests__/renderer-separator-collapse.test.ts index b5188e1c..8fd7d2c7 100644 --- a/src/utils/__tests__/renderer-separator-collapse.test.ts +++ b/src/utils/__tests__/renderer-separator-collapse.test.ts @@ -199,6 +199,41 @@ describe('renderer separator collapse around empty widgets', () => { expect(out).toContain('C'); }); + it('drops a spacing separator stranded against a flex separator when the widget between renders empty', () => { + const space: WidgetItem = { id: 'space', type: 'separator', character: ' ' }; + const widgets: WidgetItem[] = [ + T('a'), + space, + T('b'), + { id: 'flex', type: 'flex-separator' }, + T('c') + ]; + const settings = createSettings({ colorLevel: 0 }); + const context: RenderContext = { isPreview: false, terminalWidth: 0 }; + const preRenderedWidgets = makePreRendered(widgets, { 0: 'A', 2: '', 4: 'C' }); + const out = stripSgrCodes(renderStatusLine(widgets, settings, context, preRenderedWidgets, [])); + + expect(out).toBe('A | C'); + }); + + it('keeps a stranded spacing separator when a known-width flex separator allocates no space', () => { + const space: WidgetItem = { id: 'space', type: 'separator', character: ' ' }; + const widgets: WidgetItem[] = [ + T('a'), + space, + T('hidden'), + { id: 'flex', type: 'flex-separator' }, + T('c') + ]; + const settings = createSettings({ colorLevel: 0, flexMode: 'full' }); + // Full mode reserves six columns, leaving a ten-column render width. + const context: RenderContext = { isPreview: false, terminalWidth: 16 }; + const preRenderedWidgets = makePreRendered(widgets, { 0: 'AAAAA', 2: '', 4: 'CCCCC' }); + const out = stripSgrCodes(renderStatusLine(widgets, settings, context, preRenderedWidgets, [])); + + expect(out).toBe('AAAAA C...'); + }); + it('does not borrow visible content across a flex separator', () => { const widgets: WidgetItem[] = [ T('left'), diff --git a/src/utils/renderer.ts b/src/utils/renderer.ts index 5d632b34..d7bbae3c 100644 --- a/src/utils/renderer.ts +++ b/src/utils/renderer.ts @@ -1196,6 +1196,23 @@ export function renderStatusLine( elements.pop(); } + // When width detection fails, flex separators fall back to their own ' | ' + // boundary. Drop any spacing-only separator stranded directly beside one so + // that fallback does not render a duplicate space. With a known width, keep + // the separator: a fully occupied line can leave the flex gap at zero columns, + // making this space the only boundary between the surrounding content. + if (!terminalWidth) { + for (let i = elements.length - 1; i >= 0; i--) { + if (elements[i]?.type !== 'separator' + || !isSpacingSeparator(elements[i]?.widget, settings.defaultSeparator)) { + continue; + } + if (elements[i - 1]?.type === 'flex-separator' || elements[i + 1]?.type === 'flex-separator') { + elements.splice(i, 1); + } + } + } + // Apply default padding and separators const finalElements: string[] = []; const padding = settings.defaultPadding ?? '';