repl_store.rs

  1use std::sync::Arc;
  2
  3use anyhow::Result;
  4use collections::HashMap;
  5use gpui::{
  6    prelude::*, AppContext, EntityId, Global, Model, ModelContext, Subscription, Task, View,
  7};
  8use language::Language;
  9use project::Fs;
 10use settings::{Settings, SettingsStore};
 11
 12use crate::kernels::kernel_specifications;
 13use crate::{JupyterSettings, KernelSpecification, Session};
 14
 15struct GlobalReplStore(Model<ReplStore>);
 16
 17impl Global for GlobalReplStore {}
 18
 19pub struct ReplStore {
 20    fs: Arc<dyn Fs>,
 21    enabled: bool,
 22    sessions: HashMap<EntityId, View<Session>>,
 23    kernel_specifications: Vec<KernelSpecification>,
 24    _subscriptions: Vec<Subscription>,
 25}
 26
 27impl ReplStore {
 28    pub(crate) fn init(fs: Arc<dyn Fs>, cx: &mut AppContext) {
 29        let store = cx.new_model(move |cx| Self::new(fs, cx));
 30
 31        store
 32            .update(cx, |store, cx| store.refresh_kernelspecs(cx))
 33            .detach_and_log_err(cx);
 34
 35        cx.set_global(GlobalReplStore(store))
 36    }
 37
 38    pub fn global(cx: &AppContext) -> Model<Self> {
 39        cx.global::<GlobalReplStore>().0.clone()
 40    }
 41
 42    pub fn new(fs: Arc<dyn Fs>, cx: &mut ModelContext<Self>) -> Self {
 43        let subscriptions = vec![cx.observe_global::<SettingsStore>(move |this, cx| {
 44            this.set_enabled(JupyterSettings::enabled(cx), cx);
 45        })];
 46
 47        Self {
 48            fs,
 49            enabled: JupyterSettings::enabled(cx),
 50            sessions: HashMap::default(),
 51            kernel_specifications: Vec::new(),
 52            _subscriptions: subscriptions,
 53        }
 54    }
 55
 56    pub fn fs(&self) -> &Arc<dyn Fs> {
 57        &self.fs
 58    }
 59
 60    pub fn is_enabled(&self) -> bool {
 61        self.enabled
 62    }
 63
 64    pub fn kernel_specifications(&self) -> impl Iterator<Item = &KernelSpecification> {
 65        self.kernel_specifications.iter()
 66    }
 67
 68    pub fn sessions(&self) -> impl Iterator<Item = &View<Session>> {
 69        self.sessions.values()
 70    }
 71
 72    fn set_enabled(&mut self, enabled: bool, cx: &mut ModelContext<Self>) {
 73        if self.enabled != enabled {
 74            self.enabled = enabled;
 75            cx.notify();
 76        }
 77    }
 78
 79    pub fn refresh_kernelspecs(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
 80        let kernel_specifications = kernel_specifications(self.fs.clone());
 81        cx.spawn(|this, mut cx| async move {
 82            let kernel_specifications = kernel_specifications.await?;
 83
 84            this.update(&mut cx, |this, cx| {
 85                this.kernel_specifications = kernel_specifications;
 86                cx.notify();
 87            })
 88        })
 89    }
 90
 91    pub fn kernelspec(
 92        &self,
 93        language: &Language,
 94        cx: &mut ModelContext<Self>,
 95    ) -> Option<KernelSpecification> {
 96        let settings = JupyterSettings::get_global(cx);
 97        let language_name = language.code_fence_block_name();
 98        let selected_kernel = settings.kernel_selections.get(language_name.as_ref());
 99
100        self.kernel_specifications
101            .iter()
102            .find(|runtime_specification| {
103                if let Some(selected) = selected_kernel {
104                    // Top priority is the selected kernel
105                    runtime_specification.name.to_lowercase() == selected.to_lowercase()
106                } else {
107                    // Otherwise, we'll try to find a kernel that matches the language
108                    runtime_specification.kernelspec.language.to_lowercase()
109                        == language_name.to_lowercase()
110                }
111            })
112            .cloned()
113    }
114
115    pub fn get_session(&self, entity_id: EntityId) -> Option<&View<Session>> {
116        self.sessions.get(&entity_id)
117    }
118
119    pub fn insert_session(&mut self, entity_id: EntityId, session: View<Session>) {
120        self.sessions.insert(entity_id, session);
121    }
122
123    pub fn remove_session(&mut self, entity_id: EntityId) {
124        self.sessions.remove(&entity_id);
125    }
126}