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>
75 lines
2.3 KiB
Dart
75 lines
2.3 KiB
Dart
/// The status-bar "in-pane context" slot (T-145).
|
|
///
|
|
/// A generic, publisher-agnostic slot: a pane publishes a short status
|
|
/// string to [paneContextChannel] on the MessageBus, and the bottom
|
|
/// status bar shows the latest one. The active pane publishes (an
|
|
/// inactive pane stays quiet), so switching tabs swaps the slot to the
|
|
/// newly-active pane's message. The Claude pane is the first publisher
|
|
/// (model · permission-mode · context); other panes can use the same
|
|
/// channel.
|
|
library;
|
|
|
|
import 'dart:async';
|
|
|
|
import 'package:clide/kernel/kernel.dart';
|
|
import 'package:clide/widgets/widgets.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
/// MessageBus channel for the status-bar context slot. Data: `{'text': String}`.
|
|
const paneContextChannel = 'statusbar.context';
|
|
|
|
/// Publish [text] to the context slot (empty string clears it).
|
|
void publishPaneContext(MessageBus messages, String publisher, String text) {
|
|
messages.publish(publisher, paneContextChannel, {'text': text});
|
|
}
|
|
|
|
/// Status-bar item that shows the latest pane-context message (nothing
|
|
/// when empty). Subscribes to the bus itself via the ambient kernel.
|
|
class PaneContextStatusItem extends StatefulWidget {
|
|
const PaneContextStatusItem({super.key});
|
|
|
|
@override
|
|
State<PaneContextStatusItem> createState() => _PaneContextStatusItemState();
|
|
}
|
|
|
|
class _PaneContextStatusItemState extends State<PaneContextStatusItem> {
|
|
StreamSubscription<Message>? _sub;
|
|
String _text = '';
|
|
bool _subscribed = false;
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
if (_subscribed) return;
|
|
_subscribed = true;
|
|
final messages = ClideKernel.of(context).messages;
|
|
_sub = messages.subscribe(channel: paneContextChannel).listen((m) {
|
|
final t = (m.data['text'] as String?) ?? '';
|
|
if (t == _text || !mounted) return;
|
|
setState(() => _text = t);
|
|
});
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_sub?.cancel();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
if (_text.isEmpty) return const SizedBox.shrink();
|
|
final tokens = ClideTheme.of(context).surface;
|
|
return Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 8),
|
|
child: ClideText(
|
|
_text,
|
|
fontSize: clideFontSmall,
|
|
fontFamily: clideMonoFamily,
|
|
color: tokens.statusBarForeground,
|
|
maxLines: 1,
|
|
),
|
|
);
|
|
}
|
|
}
|