Files
clide/lib/builtin/claude/src/claude_session_host.dart
T
jpmschweitzerandClaude Opus 4.7 b0d5aa36f4 move the per-session status to the bottom status bar (T-145)
Per feedback, the model · permission-mode · context line reads better in
the status bar than as a strip above the conversation. Adds a generic,
publisher-agnostic status-bar context slot: a pane publishes a short
string to the `statusbar.context` MessageBus channel and the bar shows
the latest. The active Claude sub-tab publishes (inactive panes stay
quiet, so no race); switching tabs swaps the slot to the focused pane.

Replaces the in-pane ClaudeStatusStrip with a formatStatusLine helper +
PaneContextStatusItem (the status-bar widget) and a StatusItemContribution.
ClaudeSessionHost passes `active` so only the visible sub-tab publishes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 10:37:16 +02:00

85 lines
2.4 KiB
Dart
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import 'package:clide/widgets/widgets.dart';
import 'package:flutter/widgets.dart';
import 'claude_pane.dart';
/// Hosts the primary Claude pane plus N user-spawned secondary
/// sessions per D-41. Uses [MultitabPane] for the tab strip
/// (drag-reorder, close ×, + button) and [IndexedStack]-mode
/// keep-alive so switching tabs doesn't tear down the underlying
/// PTY-backed terminal.
class ClaudeSessionHost extends StatefulWidget {
const ClaudeSessionHost({super.key});
@override
State<ClaudeSessionHost> createState() => ClaudeSessionHostState();
}
class ClaudeSessionHostState extends State<ClaudeSessionHost> {
static const _primaryId = 'primary';
late final MultitabController<_Session> _controller;
int _nextSecondary = 1;
@override
void initState() {
super.initState();
_controller = MultitabController<_Session>(
initial: [
MultitabEntry<_Session>(
id: _primaryId,
title: 'primary',
payload: const _Session(isPrimary: true),
// Primary persists across clide restarts and never gets a
// close affordance (D-41).
closeable: false,
reorderable: false,
),
],
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
/// Public entry point used by the `claude.new-secondary` command.
void addSecondary() {
final index = _nextSecondary++;
_controller.add(MultitabEntry<_Session>(
id: 'secondary-$index',
title: 'session $index',
payload: _Session(isPrimary: false, secondaryIndex: index),
));
}
@override
Widget build(BuildContext context) {
return MultitabPane<_Session>(
controller: _controller,
keepAlive: true,
onAddRequested: addSecondary,
bodyBuilder: (ctx, entry) {
final s = entry.payload;
return ClaudePane(
isPrimary: s.isPrimary,
secondaryIndex: s.secondaryIndex,
// The MultitabPane already provides the tab strip header;
// suppressing the ClaudePane's own chrome avoids a double row.
showChrome: false,
// Only the visible sub-tab publishes to the status-bar slot.
active: entry.id == _controller.activeId,
);
},
);
}
}
class _Session {
const _Session({required this.isPrimary, this.secondaryIndex});
final bool isPrimary;
final int? secondaryIndex;
}