repl_store.rs

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