repl: Refactor editor registration (#14819)
Cleans up action registration with the editors and also fixes a major bug where only one workspace's panel was getting session info (due to my not understanding that `cx.observe_new_views` is for the whole app). Release Notes: - N/A Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
@@ -6,7 +6,6 @@ use crate::{
|
||||
use anyhow::{Context as _, Result};
|
||||
use collections::HashMap;
|
||||
use editor::{Anchor, Editor, RangeToAnchorExt};
|
||||
use futures::StreamExt as _;
|
||||
use gpui::{
|
||||
actions, prelude::*, AppContext, AsyncWindowContext, EntityId, EventEmitter, FocusHandle,
|
||||
FocusOutEvent, FocusableView, Subscription, Task, View, WeakView,
|
||||
@@ -46,6 +45,102 @@ pub fn init(cx: &mut AppContext) {
|
||||
},
|
||||
)
|
||||
.detach();
|
||||
|
||||
cx.observe_new_views(move |editor: &mut Editor, cx: &mut ViewContext<Editor>| {
|
||||
// Only allow editors that support vim mode and are singleton buffers
|
||||
if !editor.use_modal_editing() || !editor.buffer().read(cx).is_singleton() {
|
||||
return;
|
||||
}
|
||||
|
||||
editor
|
||||
.register_action(cx.listener(
|
||||
move |editor: &mut Editor, _: &Run, cx: &mut ViewContext<Editor>| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
let Some(workspace) = editor.workspace() else {
|
||||
return;
|
||||
};
|
||||
let Some(panel) = workspace.read(cx).panel::<RuntimePanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
let weak_editor = cx.view().downgrade();
|
||||
panel.update(cx, |_, cx| {
|
||||
cx.defer(|panel, cx| {
|
||||
panel.run(weak_editor, cx).log_err();
|
||||
});
|
||||
})
|
||||
},
|
||||
))
|
||||
.detach();
|
||||
|
||||
editor
|
||||
.register_action(cx.listener(
|
||||
move |editor: &mut Editor, _: &ClearOutputs, cx: &mut ViewContext<Editor>| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
let Some(workspace) = editor.workspace() else {
|
||||
return;
|
||||
};
|
||||
let Some(panel) = workspace.read(cx).panel::<RuntimePanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
let weak_editor = cx.view().downgrade();
|
||||
panel.update(cx, |_, cx| {
|
||||
cx.defer(|panel, cx| {
|
||||
panel.clear_outputs(weak_editor, cx);
|
||||
});
|
||||
})
|
||||
},
|
||||
))
|
||||
.detach();
|
||||
|
||||
editor
|
||||
.register_action(cx.listener(
|
||||
move |editor: &mut Editor, _: &Interrupt, cx: &mut ViewContext<Editor>| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
let Some(workspace) = editor.workspace() else {
|
||||
return;
|
||||
};
|
||||
let Some(panel) = workspace.read(cx).panel::<RuntimePanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
let weak_editor = cx.view().downgrade();
|
||||
panel.update(cx, |_, cx| {
|
||||
cx.defer(|panel, cx| {
|
||||
panel.interrupt(weak_editor, cx);
|
||||
});
|
||||
})
|
||||
},
|
||||
))
|
||||
.detach();
|
||||
|
||||
editor
|
||||
.register_action(cx.listener(
|
||||
move |editor: &mut Editor, _: &Shutdown, cx: &mut ViewContext<Editor>| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
let Some(workspace) = editor.workspace() else {
|
||||
return;
|
||||
};
|
||||
let Some(panel) = workspace.read(cx).panel::<RuntimePanel>(cx) else {
|
||||
return;
|
||||
};
|
||||
let weak_editor = cx.view().downgrade();
|
||||
panel.update(cx, |_, cx| {
|
||||
cx.defer(|panel, cx| {
|
||||
panel.shutdown(weak_editor, cx);
|
||||
});
|
||||
})
|
||||
},
|
||||
))
|
||||
.detach();
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
|
||||
pub struct RuntimePanel {
|
||||
@@ -56,14 +151,6 @@ pub struct RuntimePanel {
|
||||
sessions: HashMap<EntityId, View<Session>>,
|
||||
kernel_specifications: Vec<KernelSpecification>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
_editor_events_task: Task<()>,
|
||||
}
|
||||
|
||||
pub enum ReplEvent {
|
||||
Run(WeakView<Editor>),
|
||||
ClearOutputs(WeakView<Editor>),
|
||||
Interrupt(WeakView<Editor>),
|
||||
Shutdown(WeakView<Editor>),
|
||||
}
|
||||
|
||||
impl RuntimePanel {
|
||||
@@ -78,110 +165,14 @@ impl RuntimePanel {
|
||||
|
||||
let fs = workspace.app_state().fs.clone();
|
||||
|
||||
// Make a channel that we receive editor events on (for repl::Run, repl::ClearOutputs)
|
||||
// This allows us to inject actions on the editor from the repl panel without requiring the editor to
|
||||
// depend on the `repl` crate.
|
||||
let (repl_editor_event_tx, mut repl_editor_event_rx) =
|
||||
futures::channel::mpsc::unbounded::<ReplEvent>();
|
||||
|
||||
let subscriptions = vec![
|
||||
cx.on_focus_in(&focus_handle, Self::focus_in),
|
||||
cx.on_focus_out(&focus_handle, Self::focus_out),
|
||||
cx.observe_global::<SettingsStore>(move |this, cx| {
|
||||
this.set_enabled(JupyterSettings::enabled(cx), cx);
|
||||
}),
|
||||
cx.observe_new_views(
|
||||
move |editor: &mut Editor, cx: &mut ViewContext<Editor>| {
|
||||
let editor_view = cx.view().downgrade();
|
||||
let run_event_tx = repl_editor_event_tx.clone();
|
||||
let clear_event_tx = repl_editor_event_tx.clone();
|
||||
editor
|
||||
.register_action(move |_: &Run, cx: &mut WindowContext| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
run_event_tx
|
||||
.unbounded_send(ReplEvent::Run(editor_view.clone()))
|
||||
.ok();
|
||||
})
|
||||
.detach();
|
||||
|
||||
let editor_view = cx.view().downgrade();
|
||||
editor
|
||||
.register_action(
|
||||
move |_: &ClearOutputs, cx: &mut WindowContext| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
clear_event_tx
|
||||
.unbounded_send(ReplEvent::ClearOutputs(
|
||||
editor_view.clone(),
|
||||
))
|
||||
.ok();
|
||||
},
|
||||
)
|
||||
.detach();
|
||||
|
||||
editor
|
||||
.register_action({
|
||||
let editor = cx.view().downgrade();
|
||||
let repl_editor_event_tx = repl_editor_event_tx.clone();
|
||||
|
||||
move |_: &Interrupt, cx: &mut WindowContext| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
repl_editor_event_tx
|
||||
.unbounded_send(ReplEvent::Interrupt(
|
||||
editor.clone(),
|
||||
))
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
editor
|
||||
.register_action({
|
||||
let editor = cx.view().downgrade();
|
||||
let repl_editor_event_tx = repl_editor_event_tx.clone();
|
||||
|
||||
move |_: &Shutdown, cx: &mut WindowContext| {
|
||||
if !JupyterSettings::enabled(cx) {
|
||||
return;
|
||||
}
|
||||
repl_editor_event_tx
|
||||
.unbounded_send(ReplEvent::Shutdown(editor.clone()))
|
||||
.ok();
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
// Listen for events from the editor on the `repl_editor_event_rx` channel
|
||||
let _editor_events_task = cx.spawn(
|
||||
move |this: WeakView<RuntimePanel>, mut cx: AsyncWindowContext| async move {
|
||||
while let Some(event) = repl_editor_event_rx.next().await {
|
||||
this.update(&mut cx, |runtime_panel, cx| match event {
|
||||
ReplEvent::Run(editor) => {
|
||||
runtime_panel.run(editor, cx).log_err();
|
||||
}
|
||||
ReplEvent::ClearOutputs(editor) => {
|
||||
runtime_panel.clear_outputs(editor, cx);
|
||||
}
|
||||
ReplEvent::Interrupt(editor) => {
|
||||
runtime_panel.interrupt(editor, cx);
|
||||
}
|
||||
ReplEvent::Shutdown(editor) => {
|
||||
runtime_panel.shutdown(editor, cx);
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let runtime_panel = Self {
|
||||
fs: fs.clone(),
|
||||
width: None,
|
||||
@@ -190,7 +181,6 @@ impl RuntimePanel {
|
||||
sessions: Default::default(),
|
||||
_subscriptions: subscriptions,
|
||||
enabled: JupyterSettings::enabled(cx),
|
||||
_editor_events_task,
|
||||
};
|
||||
|
||||
runtime_panel
|
||||
|
||||
Reference in New Issue
Block a user