Skip to content

Commit

Permalink
Implement RunningKernel trait for native and remote kernels (#20934)
Browse files Browse the repository at this point in the history
This PR introduces a unified interface for both native and remote
kernels through the `RunningKernel` trait. When either the native kernel
or the remote kernels are started, they return a `Box<dyn
RunningKernel>` to make it easier to work with the session. As a bonus
of this refactor, I've dropped some of the mpsc channels to instead opt
for passing messages directly to `session.route(message)`. There was a
lot of simplification of `Session` by moving responsibilities to
`NativeRunningKernel`.

No release notes yet until this is finalized.

* [x] Detect remote kernelspecs from configured remote servers
* [x] Launch kernel on demand

For now, this allows you to set env vars `JUPYTER_SERVER` and
`JUPYTER_TOKEN` to access a remote server. `JUPYTER_SERVER` should be a
base path like `http://localhost:8888` or
`https://notebooks.gesis.org/binder/jupyter/user/rubydata-binder-w6igpy4l/`

Release Notes:

- N/A
  • Loading branch information
rgbkrk authored Nov 21, 2024
1 parent f74f670 commit 72613b7
Show file tree
Hide file tree
Showing 8 changed files with 477 additions and 229 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/repl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ collections.workspace = true
command_palette_hooks.workspace = true
editor.workspace = true
feature_flags.workspace = true
file_icons.workspace = true
futures.workspace = true
gpui.workspace = true
http_client.workspace = true
image.workspace = true
jupyter-websocket-client.workspace = true
jupyter-protocol.workspace = true
Expand Down
83 changes: 65 additions & 18 deletions crates/repl/src/components/kernel_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ pub struct KernelPickerDelegate {
on_select: OnSelect,
}

// Helper function to truncate long paths
fn truncate_path(path: &SharedString, max_length: usize) -> SharedString {
if path.len() <= max_length {
path.to_string().into()
} else {
let truncated = path.chars().rev().take(max_length - 3).collect::<String>();
format!("...{}", truncated.chars().rev().collect::<String>()).into()
}
}

impl<T: PopoverTrigger> KernelSelector<T> {
pub fn new(on_select: OnSelect, worktree_id: WorktreeId, trigger: T) -> Self {
KernelSelector {
Expand Down Expand Up @@ -116,37 +126,72 @@ impl PickerDelegate for KernelPickerDelegate {
&self,
ix: usize,
selected: bool,
_cx: &mut ViewContext<Picker<Self>>,
cx: &mut ViewContext<Picker<Self>>,
) -> Option<Self::ListItem> {
let kernelspec = self.filtered_kernels.get(ix)?;

let is_selected = self.selected_kernelspec.as_ref() == Some(kernelspec);
let icon = kernelspec.icon(cx);

let (name, kernel_type, path_or_url) = match kernelspec {
KernelSpecification::Jupyter(_) => (kernelspec.name(), "Jupyter", None),
KernelSpecification::PythonEnv(_) => (
kernelspec.name(),
"Python Env",
Some(truncate_path(&kernelspec.path(), 42)),
),
KernelSpecification::Remote(_) => (
kernelspec.name(),
"Remote",
Some(truncate_path(&kernelspec.path(), 42)),
),
};

Some(
ListItem::new(ix)
.inset(true)
.spacing(ListItemSpacing::Sparse)
.selected(selected)
.child(
v_flex()
.min_w(px(600.))
h_flex()
.w_full()
.gap_0p5()
.gap_3()
.child(icon.color(Color::Default).size(IconSize::Medium))
.child(
h_flex()
.w_full()
.gap_1()
.child(Label::new(kernelspec.name()).weight(FontWeight::MEDIUM))
v_flex()
.flex_grow()
.gap_0p5()
.child(
Label::new(kernelspec.language())
.size(LabelSize::Small)
.color(Color::Muted),
h_flex()
.justify_between()
.child(
div().w_48().text_ellipsis().child(
Label::new(name)
.weight(FontWeight::MEDIUM)
.size(LabelSize::Default),
),
)
.when_some(path_or_url.clone(), |flex, path| {
flex.text_ellipsis().child(
Label::new(path)
.size(LabelSize::Small)
.color(Color::Muted),
)
}),
)
.child(
h_flex()
.gap_1()
.child(
Label::new(kernelspec.language())
.size(LabelSize::Small)
.color(Color::Muted),
)
.child(
Label::new(kernel_type)
.size(LabelSize::Small)
.color(Color::Muted),
),
),
)
.child(
Label::new(kernelspec.path())
.size(LabelSize::XSmall)
.color(Color::Muted),
),
)
.when(is_selected, |item| {
Expand Down Expand Up @@ -199,7 +244,9 @@ impl<T: PopoverTrigger> RenderOnce for KernelSelector<T> {
};

let picker_view = cx.new_view(|cx| {
let picker = Picker::uniform_list(delegate, cx).max_height(Some(rems(20.).into()));
let picker = Picker::uniform_list(delegate, cx)
.width(rems(30.))
.max_height(Some(rems(20.).into()));
picker
});

Expand Down
19 changes: 16 additions & 3 deletions crates/repl/src/kernels/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use futures::{
future::Shared,
stream,
};
use gpui::{AppContext, Model, Task};
use gpui::{AppContext, Model, Task, WindowContext};
use language::LanguageName;
pub use native_kernel::*;

Expand All @@ -16,7 +16,7 @@ pub use remote_kernels::*;

use anyhow::Result;
use runtimelib::{ExecutionState, JupyterKernelspec, JupyterMessage, KernelInfoReply};
use ui::SharedString;
use ui::{Icon, IconName, SharedString};

pub type JupyterMessageChannel = stream::SelectAll<Receiver<JupyterMessage>>;

Expand Down Expand Up @@ -59,6 +59,19 @@ impl KernelSpecification {
Self::Remote(spec) => spec.kernelspec.language.clone(),
})
}

pub fn icon(&self, cx: &AppContext) -> Icon {
let lang_name = match self {
Self::Jupyter(spec) => spec.kernelspec.language.clone(),
Self::PythonEnv(spec) => spec.kernelspec.language.clone(),
Self::Remote(spec) => spec.kernelspec.language.clone(),
};

file_icons::FileIcons::get(cx)
.get_type_icon(&lang_name.to_lowercase())
.map(Icon::from_path)
.unwrap_or(Icon::new(IconName::ReplNeutral))
}
}

pub fn python_env_kernel_specifications(
Expand Down Expand Up @@ -134,7 +147,7 @@ pub trait RunningKernel: Send + Debug {
fn set_execution_state(&mut self, state: ExecutionState);
fn kernel_info(&self) -> Option<&KernelInfoReply>;
fn set_kernel_info(&mut self, info: KernelInfoReply);
fn force_shutdown(&mut self) -> anyhow::Result<()>;
fn force_shutdown(&mut self, cx: &mut WindowContext) -> Task<anyhow::Result<()>>;
}

#[derive(Debug, Clone)]
Expand Down
Loading

0 comments on commit 72613b7

Please sign in to comment.