diff --git a/lib/builtin/decisions/src/extension.dart b/lib/builtin/decisions/src/extension.dart index 08f76e1e..4f76a978 100644 --- a/lib/builtin/decisions/src/extension.dart +++ b/lib/builtin/decisions/src/extension.dart @@ -1,7 +1,10 @@ +import 'dart:async'; + import 'package:clide/builtin/decisions/src/decision_detail_view.dart'; import 'package:clide/builtin/decisions/src/decisions_view.dart'; import 'package:clide/extension/extension.dart'; import 'package:clide/kernel/kernel.dart'; +import 'package:clide/kernel/src/events/message_bus.dart'; class DecisionsExtension extends ClideExtension { @override @@ -9,10 +12,14 @@ class DecisionsExtension extends ClideExtension { @override String get title => 'Decisions'; @override - String get version => '0.2.0'; + String get version => '0.3.0'; @override List get dependsOn => const []; + ClideExtensionContext? _ctx; + StreamSubscription? _selectionSub; + bool _detailSpawned = false; + @override List get contributions => [ TabContribution( @@ -24,12 +31,40 @@ class DecisionsExtension extends ClideExtension { priority: -20, build: (_) => const DecisionsView(), ), - TabContribution( - id: 'decisions.detail', - slot: Slots.contextPanel, - title: 'Decision', - priority: -50, - build: (_) => const DecisionDetailView(), - ), ]; + + @override + Future activate(ClideExtensionContext ctx) async { + _ctx = ctx; + _selectionSub = ctx.messages.subscribe(publisher: id, channel: 'selection').listen(_onSelection); + } + + @override + Future deactivate() async { + _selectionSub?.cancel(); + _despawnDetail(); + } + + void _onSelection(Message msg) { + final ctx = _ctx; + if (ctx == null) return; + if (!_detailSpawned) { + ctx.panels.contribute(TabContribution( + id: 'decisions.detail', + slot: Slots.contextPanel, + title: 'Decision', + priority: -50, + build: (_) => const DecisionDetailView(), + )); + _detailSpawned = true; + } + ctx.panels.activateTab(Slots.contextPanel, 'decisions.detail'); + } + + void _despawnDetail() { + if (_detailSpawned) { + _ctx?.panels.uncontribute('decisions.detail'); + _detailSpawned = false; + } + } } diff --git a/lib/builtin/graph/src/extension.dart b/lib/builtin/graph/src/extension.dart index 49708e53..32f0de21 100644 --- a/lib/builtin/graph/src/extension.dart +++ b/lib/builtin/graph/src/extension.dart @@ -1,6 +1,4 @@ -import 'package:clide/builtin/graph/src/graph_view.dart'; import 'package:clide/extension/extension.dart'; -import 'package:clide/kernel/kernel.dart'; class GraphExtension extends ClideExtension { @override @@ -13,15 +11,5 @@ class GraphExtension extends ClideExtension { List get dependsOn => const ['builtin.pql']; @override - List get contributions => [ - TabContribution( - id: 'graph.view', - slot: Slots.contextPanel, - title: 'Graph', - titleKey: 'tab.graph', - i18nNamespace: id, - priority: -80, - build: (_) => const GraphView(), - ), - ]; + List get contributions => const []; } diff --git a/lib/builtin/markdown/src/extension.dart b/lib/builtin/markdown/src/extension.dart index 42e13c6c..b00b7b41 100644 --- a/lib/builtin/markdown/src/extension.dart +++ b/lib/builtin/markdown/src/extension.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:clide/builtin/markdown/src/markdown_viewer.dart'; import 'package:clide/extension/extension.dart'; import 'package:clide/kernel/kernel.dart'; @@ -8,20 +10,51 @@ class MarkdownExtension extends ClideExtension { @override String get title => 'Markdown'; @override - String get version => '0.1.0'; + String get version => '0.2.0'; @override List get dependsOn => const ['builtin.editor']; + ClideExtensionContext? _ctx; + StreamSubscription? _editorSub; + bool _viewerSpawned = false; + @override - List get contributions => [ - TabContribution( - id: 'markdown.viewer', - slot: Slots.contextPanel, - title: 'Viewer', - titleKey: 'tab.viewer', - i18nNamespace: id, - priority: -100, - build: (_) => const MarkdownViewer(), - ), - ]; + List get contributions => const []; + + @override + Future activate(ClideExtensionContext ctx) async { + _ctx = ctx; + _editorSub = ctx.events.on().listen((e) { + if (e.subsystem != 'editor') return; + if (e.kind == 'editor.active-changed' || e.kind == 'editor.opened') { + final path = e.data['path'] as String?; + if (path != null && path.endsWith('.md')) { + _spawnViewer(); + } + } + }); + } + + @override + Future deactivate() async { + _editorSub?.cancel(); + if (_viewerSpawned) { + _ctx?.panels.uncontribute('markdown.viewer'); + _viewerSpawned = false; + } + } + + void _spawnViewer() { + final ctx = _ctx; + if (ctx == null || _viewerSpawned) return; + ctx.panels.contribute(TabContribution( + id: 'markdown.viewer', + slot: Slots.contextPanel, + title: 'Viewer', + priority: -100, + build: (_) => const MarkdownViewer(), + )); + _viewerSpawned = true; + ctx.panels.activateTab(Slots.contextPanel, 'markdown.viewer'); + } } diff --git a/lib/builtin/pql/src/extension.dart b/lib/builtin/pql/src/extension.dart index e1887bb1..32985f2e 100644 --- a/lib/builtin/pql/src/extension.dart +++ b/lib/builtin/pql/src/extension.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:clide/builtin/pql/src/backlinks_view.dart'; import 'package:clide/builtin/pql/src/pql_panel_view.dart'; import 'package:clide/extension/extension.dart'; @@ -9,10 +11,14 @@ class PqlExtension extends ClideExtension { @override String get title => 'pql'; @override - String get version => '0.1.0'; + String get version => '0.2.0'; @override List get dependsOn => const []; + ClideExtensionContext? _ctx; + StreamSubscription? _editorSub; + bool _backlinksSpawned = false; + @override List get contributions => [ TabContribution( @@ -24,14 +30,43 @@ class PqlExtension extends ClideExtension { priority: -60, build: (_) => const PqlPanelView(), ), - TabContribution( - id: 'pql.backlinks', - slot: Slots.contextPanel, - title: 'Links', - titleKey: 'tab.links', - i18nNamespace: id, - priority: -80, - build: (_) => const BacklinksView(), - ), ]; + + @override + Future activate(ClideExtensionContext ctx) async { + _ctx = ctx; + _editorSub = ctx.events.on().listen((e) { + if (e.subsystem != 'editor') return; + if (e.kind == 'editor.active-changed' || e.kind == 'editor.opened') { + _spawnBacklinks(); + } + }); + } + + @override + Future deactivate() async { + _editorSub?.cancel(); + _despawnBacklinks(); + } + + void _spawnBacklinks() { + final ctx = _ctx; + if (ctx == null || _backlinksSpawned) return; + ctx.panels.contribute(TabContribution( + id: 'pql.backlinks', + slot: Slots.contextPanel, + title: 'Links', + priority: -80, + build: (_) => const BacklinksView(), + )); + _backlinksSpawned = true; + ctx.panels.activateTab(Slots.contextPanel, 'pql.backlinks'); + } + + void _despawnBacklinks() { + if (_backlinksSpawned) { + _ctx?.panels.uncontribute('pql.backlinks'); + _backlinksSpawned = false; + } + } } diff --git a/lib/builtin/tickets/src/extension.dart b/lib/builtin/tickets/src/extension.dart index 6779a56f..a1db09e2 100644 --- a/lib/builtin/tickets/src/extension.dart +++ b/lib/builtin/tickets/src/extension.dart @@ -1,7 +1,10 @@ +import 'dart:async'; + import 'package:clide/builtin/tickets/src/ticket_detail_view.dart'; import 'package:clide/builtin/tickets/src/tickets_view.dart'; import 'package:clide/extension/extension.dart'; import 'package:clide/kernel/kernel.dart'; +import 'package:clide/kernel/src/events/message_bus.dart'; class TicketsExtension extends ClideExtension { @override @@ -9,10 +12,14 @@ class TicketsExtension extends ClideExtension { @override String get title => 'Tickets'; @override - String get version => '0.2.0'; + String get version => '0.3.0'; @override List get dependsOn => const []; + ClideExtensionContext? _ctx; + StreamSubscription? _selectionSub; + bool _detailSpawned = false; + @override List get contributions => [ TabContribution( @@ -24,12 +31,40 @@ class TicketsExtension extends ClideExtension { priority: -10, build: (_) => const TicketsView(), ), - TabContribution( - id: 'tickets.detail', - slot: Slots.contextPanel, - title: 'Ticket', - priority: -60, - build: (_) => const TicketDetailView(), - ), ]; + + @override + Future activate(ClideExtensionContext ctx) async { + _ctx = ctx; + _selectionSub = ctx.messages.subscribe(publisher: id, channel: 'selection').listen(_onSelection); + } + + @override + Future deactivate() async { + _selectionSub?.cancel(); + _despawnDetail(); + } + + void _onSelection(Message msg) { + final ctx = _ctx; + if (ctx == null) return; + if (!_detailSpawned) { + ctx.panels.contribute(TabContribution( + id: 'tickets.detail', + slot: Slots.contextPanel, + title: 'Ticket', + priority: -60, + build: (_) => const TicketDetailView(), + )); + _detailSpawned = true; + } + ctx.panels.activateTab(Slots.contextPanel, 'tickets.detail'); + } + + void _despawnDetail() { + if (_detailSpawned) { + _ctx?.panels.uncontribute('tickets.detail'); + _detailSpawned = false; + } + } }