D-50 behavior 4: opening a renderable .md in the editor now auto-reveals the context-panel reader, which mirrors the buffer read-only and re-renders as the user types — rather than a one-shot disk read. The extension reveals the tab on editor.opened (renderable only — D-50 behavior 5 leaves non-.md files alone). The viewer owns the mirror: on mount it picks up the active buffer (editor.read, no id), enters mirror mode on editor.opened / active-changed for a renderable file, re-reads the in-memory buffer on editor.edited, and drops the mirror (with its edit affordance back) on a disk load or a switch to a non-renderable buffer. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
60 lines
2.0 KiB
Dart
60 lines
2.0 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:clide/builtin/markdown/src/markdown_viewer.dart';
|
|
import 'package:clide/extension/extension.dart';
|
|
import 'package:clide/kernel/kernel.dart';
|
|
import 'package:clide/widgets/widgets.dart';
|
|
|
|
class MarkdownExtension extends ClideExtension {
|
|
@override
|
|
String get id => 'builtin.markdown';
|
|
@override
|
|
String get title => 'Markdown';
|
|
@override
|
|
String get version => '0.3.0';
|
|
@override
|
|
List<String> get dependsOn => const [];
|
|
|
|
StreamSubscription<Message>? _sub;
|
|
StreamSubscription<DaemonEvent>? _editorSub;
|
|
|
|
@override
|
|
List<ContributionPoint> get contributions => [
|
|
TabContribution(
|
|
id: 'markdown.viewer',
|
|
slot: Slots.contextPanel,
|
|
title: 'Markdown',
|
|
icon: PhosphorIcons.byName('file-text'),
|
|
build: (_) => const MarkdownViewer(),
|
|
),
|
|
];
|
|
|
|
@override
|
|
Future<void> activate(ClideExtensionContext ctx) async {
|
|
// Ensure the retained nav exists so it records selections + emits
|
|
// loads whether or not the viewer is mounted (T-196). This handler
|
|
// only reveals the tab; the nav owns load + history.
|
|
ctx.readerNav.navFor(id, dataKey: 'path');
|
|
_sub = ctx.messages.subscribe(publisher: id, channel: 'selection').listen((msg) {
|
|
if (msg.data['path'] is! String) return;
|
|
ctx.panels.activateTab(Slots.contextPanel, 'markdown.viewer');
|
|
});
|
|
// Live-sync read-mirror (T-36, D-50 behavior 4): opening a renderable .md in
|
|
// the editor auto-reveals the reader, which then mirrors the buffer live.
|
|
// Non-renderable files reveal nothing (D-50 behavior 5).
|
|
_editorSub = ctx.events.on<DaemonEvent>().listen((e) {
|
|
if (e.subsystem != 'editor' || e.kind != 'editor.opened') return;
|
|
final path = e.data['path'] as String?;
|
|
if (path != null && isRenderableMarkdownPath(path)) {
|
|
ctx.panels.activateTab(Slots.contextPanel, 'markdown.viewer');
|
|
}
|
|
});
|
|
}
|
|
|
|
@override
|
|
Future<void> deactivate() async {
|
|
await _sub?.cancel();
|
|
await _editorSub?.cancel();
|
|
}
|
|
}
|