repl_store.rs

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