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 cx.set_global(GlobalReplStore(store))
32 }
33
34 pub fn global(cx: &AppContext) -> Model<Self> {
35 cx.global::<GlobalReplStore>().0.clone()
36 }
37
38 pub fn new(fs: Arc<dyn Fs>, cx: &mut ModelContext<Self>) -> Self {
39 let subscriptions = vec![cx.observe_global::<SettingsStore>(move |this, cx| {
40 this.set_enabled(JupyterSettings::enabled(cx), cx);
41 })];
42
43 Self {
44 fs,
45 enabled: JupyterSettings::enabled(cx),
46 sessions: HashMap::default(),
47 kernel_specifications: Vec::new(),
48 _subscriptions: subscriptions,
49 }
50 }
51
52 pub fn is_enabled(&self) -> bool {
53 self.enabled
54 }
55
56 pub fn kernel_specifications(&self) -> impl Iterator<Item = &KernelSpecification> {
57 self.kernel_specifications.iter()
58 }
59
60 pub fn sessions(&self) -> impl Iterator<Item = &View<Session>> {
61 self.sessions.values()
62 }
63
64 fn set_enabled(&mut self, enabled: bool, cx: &mut ModelContext<Self>) {
65 if self.enabled != enabled {
66 self.enabled = enabled;
67 cx.notify();
68 }
69 }
70
71 pub fn refresh_kernelspecs(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
72 let kernel_specifications = kernel_specifications(self.fs.clone());
73 cx.spawn(|this, mut cx| async move {
74 let kernel_specifications = kernel_specifications.await?;
75
76 this.update(&mut cx, |this, cx| {
77 this.kernel_specifications = kernel_specifications;
78 cx.notify();
79 })
80 })
81 }
82
83 pub fn kernelspec(
84 &self,
85 language: &Language,
86 cx: &mut ModelContext<Self>,
87 ) -> Option<KernelSpecification> {
88 let settings = JupyterSettings::get_global(cx);
89 let language_name = language.code_fence_block_name();
90 let selected_kernel = settings.kernel_selections.get(language_name.as_ref());
91
92 self.kernel_specifications
93 .iter()
94 .find(|runtime_specification| {
95 if let Some(selected) = selected_kernel {
96 // Top priority is the selected kernel
97 runtime_specification.name.to_lowercase() == selected.to_lowercase()
98 } else {
99 // Otherwise, we'll try to find a kernel that matches the language
100 runtime_specification.kernelspec.language.to_lowercase()
101 == language_name.to_lowercase()
102 }
103 })
104 .cloned()
105 }
106
107 pub fn get_session(&self, entity_id: EntityId) -> Option<&View<Session>> {
108 self.sessions.get(&entity_id)
109 }
110
111 pub fn insert_session(&mut self, entity_id: EntityId, session: View<Session>) {
112 self.sessions.insert(entity_id, session);
113 }
114
115 pub fn remove_session(&mut self, entity_id: EntityId) {
116 self.sessions.remove(&entity_id);
117 }
118}