ZIm/crates/repl/src/jupyter_settings.rs
Kyle Kelley c77ea47f43
Runtimes UI Starter (#13625)
Initial runtimes UI panel. The main draw here is that all message
subscription occurs with two background tasks that run for the life of
the kernel. Follow on to #12062

* [x] Disable previous cmd-enter behavior only if runtimes are enabled
in settings
* [x] Only show the runtimes panel if it is enabled via settings
* [x] Create clean UI for the current sessions

### Running Kernels UI

<img width="205" alt="image"
src="https://github.com/zed-industries/zed/assets/836375/814ae79b-0807-4e23-bc95-77ce64f9d732">

* [x] List running kernels
* [x] Implement shutdown
* [x] Delete connection file on `drop` of `RunningKernel`
* [x] Implement interrupt

#### Project-specific Kernel Settings

- [x] Modify JupyterSettings to include a `kernel_selections` field
(`HashMap<String, String>`).
- [x] Implement saving and loading of kernel selections to/from
`.zed/settings.json` (by default, rather than global settings?)

#### Kernel Selection Persistence

- [x] Save the selected kernel for each language when the user makes a
choice.
- [x] Load these selections when the RuntimePanel is initialized.

#### Use Selected Kernels

- [x] Modify kernel launch to use the selected kernel for the detected
language.
- [x] Fallback to default behavior if no selection is made.

### Empty states

- [x] Create helpful UI for when the user has 0 kernels they can launch
and/or 0 kernels running

<img width="694" alt="image"
src="https://github.com/zed-industries/zed/assets/836375/d6a75939-e4e4-40fb-80fe-014da041cc3c">

## Future work

### Kernel Discovery

- Improve the kernel discovery process to handle various installation
methods (system, virtualenv, poetry, etc.).
- Create a way to refresh the available kernels on demand

### Documentation:

- Update documentation to explain how users can configure kernels for
their projects.
- Provide examples of .zed/settings.json configurations for kernel
selection.

### Kernel Selection UI

- Implement a new section in the RuntimePanel to display available
kernels.
- Group on the language name from the kernel specification 
- Create a dropdown for each language group to select the default
kernel.


Release Notes:

- N/A

---------

Co-authored-by: Kirill <kirill@zed.dev>
2024-07-05 08:15:50 -07:00

149 lines
4 KiB
Rust

use std::collections::HashMap;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsSources};
use ui::Pixels;
#[derive(Copy, Clone, Default, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum JupyterDockPosition {
Left,
#[default]
Right,
Bottom,
}
#[derive(Debug, Default)]
pub struct JupyterSettings {
pub enabled: bool,
pub dock: JupyterDockPosition,
pub default_width: Pixels,
pub kernel_selections: HashMap<String, String>,
}
#[derive(Clone, Serialize, Deserialize, JsonSchema, Debug)]
pub struct JupyterSettingsContent {
/// Whether the Jupyter feature is enabled.
///
/// Default: `false`
enabled: Option<bool>,
/// Where to dock the Jupyter panel.
///
/// Default: `right`
dock: Option<JupyterDockPosition>,
/// Default width in pixels when the jupyter panel is docked to the left or right.
///
/// Default: 640
pub default_width: Option<f32>,
/// Default kernels to select for each language.
///
/// Default: `{}`
pub kernel_selections: Option<HashMap<String, String>>,
}
impl JupyterSettingsContent {
pub fn set_dock(&mut self, dock: JupyterDockPosition) {
self.dock = Some(dock);
}
}
impl Default for JupyterSettingsContent {
fn default() -> Self {
JupyterSettingsContent {
enabled: Some(false),
dock: Some(JupyterDockPosition::Right),
default_width: Some(640.0),
kernel_selections: Some(HashMap::new()),
}
}
}
impl Settings for JupyterSettings {
const KEY: Option<&'static str> = Some("jupyter");
type FileContent = JupyterSettingsContent;
fn load(
sources: SettingsSources<Self::FileContent>,
_cx: &mut gpui::AppContext,
) -> anyhow::Result<Self>
where
Self: Sized,
{
let mut settings = JupyterSettings::default();
for value in sources.defaults_and_customizations() {
if let Some(enabled) = value.enabled {
settings.enabled = enabled;
}
if let Some(dock) = value.dock {
settings.dock = dock;
}
if let Some(default_width) = value.default_width {
settings.default_width = Pixels::from(default_width);
}
if let Some(source) = &value.kernel_selections {
for (k, v) in source {
settings.kernel_selections.insert(k.clone(), v.clone());
}
}
}
Ok(settings)
}
}
#[cfg(test)]
mod tests {
use gpui::{AppContext, UpdateGlobal};
use settings::SettingsStore;
use super::*;
#[gpui::test]
fn test_deserialize_jupyter_settings(cx: &mut AppContext) {
let store = settings::SettingsStore::test(cx);
cx.set_global(store);
JupyterSettings::register(cx);
assert_eq!(JupyterSettings::get_global(cx).enabled, false);
assert_eq!(
JupyterSettings::get_global(cx).dock,
JupyterDockPosition::Right
);
assert_eq!(
JupyterSettings::get_global(cx).default_width,
Pixels::from(640.0)
);
// Setting a custom setting through user settings
SettingsStore::update_global(cx, |store, cx| {
store
.set_user_settings(
r#"{
"jupyter": {
"enabled": true,
"dock": "left",
"default_width": 800.0
}
}"#,
cx,
)
.unwrap();
});
assert_eq!(JupyterSettings::get_global(cx).enabled, true);
assert_eq!(
JupyterSettings::get_global(cx).dock,
JupyterDockPosition::Left
);
assert_eq!(
JupyterSettings::get_global(cx).default_width,
Pixels::from(800.0)
);
}
}