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 project::Fs;
11use settings::{Settings, SettingsStore};
12
13use crate::kernels::local_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 telemetry: Arc<Telemetry>,
26 _subscriptions: Vec<Subscription>,
27}
28
29impl ReplStore {
30 const NAMESPACE: &'static str = "repl";
31
32 pub(crate) fn init(fs: Arc<dyn Fs>, telemetry: Arc<Telemetry>, cx: &mut AppContext) {
33 let store = cx.new_model(move |cx| Self::new(fs, telemetry, cx));
34
35 store
36 .update(cx, |store, cx| store.refresh_kernelspecs(cx))
37 .detach_and_log_err(cx);
38
39 cx.set_global(GlobalReplStore(store))
40 }
41
42 pub fn global(cx: &AppContext) -> Model<Self> {
43 cx.global::<GlobalReplStore>().0.clone()
44 }
45
46 pub fn new(fs: Arc<dyn Fs>, telemetry: Arc<Telemetry>, cx: &mut ModelContext<Self>) -> Self {
47 let subscriptions = vec![cx.observe_global::<SettingsStore>(move |this, cx| {
48 this.set_enabled(JupyterSettings::enabled(cx), cx);
49 })];
50
51 let this = Self {
52 fs,
53 telemetry,
54 enabled: JupyterSettings::enabled(cx),
55 sessions: HashMap::default(),
56 kernel_specifications: Vec::new(),
57 _subscriptions: subscriptions,
58 };
59 this.on_enabled_changed(cx);
60 this
61 }
62
63 pub fn fs(&self) -> &Arc<dyn Fs> {
64 &self.fs
65 }
66
67 pub fn telemetry(&self) -> &Arc<Telemetry> {
68 &self.telemetry
69 }
70
71 pub fn is_enabled(&self) -> bool {
72 self.enabled
73 }
74
75 pub fn kernel_specifications(&self) -> impl Iterator<Item = &KernelSpecification> {
76 self.kernel_specifications.iter()
77 }
78
79 pub fn sessions(&self) -> impl Iterator<Item = &View<Session>> {
80 self.sessions.values()
81 }
82
83 fn set_enabled(&mut self, enabled: bool, cx: &mut ModelContext<Self>) {
84 if self.enabled == enabled {
85 return;
86 }
87
88 self.enabled = enabled;
89 self.on_enabled_changed(cx);
90 }
91
92 fn on_enabled_changed(&self, cx: &mut ModelContext<Self>) {
93 if !self.enabled {
94 CommandPaletteFilter::update_global(cx, |filter, _cx| {
95 filter.hide_namespace(Self::NAMESPACE);
96 });
97
98 return;
99 }
100
101 CommandPaletteFilter::update_global(cx, |filter, _cx| {
102 filter.show_namespace(Self::NAMESPACE);
103 });
104
105 cx.notify();
106 }
107
108 pub fn refresh_kernelspecs(&mut self, cx: &mut ModelContext<Self>) -> Task<Result<()>> {
109 let local_kernel_specifications = local_kernel_specifications(self.fs.clone());
110 cx.spawn(|this, mut cx| async move {
111 let local_kernel_specifications = local_kernel_specifications.await?;
112
113 let mut kernel_options = Vec::new();
114 for kernel_specification in local_kernel_specifications {
115 kernel_options.push(KernelSpecification::Jupyter(kernel_specification));
116 }
117
118 this.update(&mut cx, |this, cx| {
119 this.kernel_specifications = kernel_options;
120 cx.notify();
121 })
122 })
123 }
124
125 pub fn kernelspec(&self, language_name: &str, cx: &AppContext) -> Option<KernelSpecification> {
126 let settings = JupyterSettings::get_global(cx);
127 let selected_kernel = settings.kernel_selections.get(language_name);
128
129 let found_by_name = self
130 .kernel_specifications
131 .iter()
132 .find(|runtime_specification| {
133 if let (Some(selected), KernelSpecification::Jupyter(runtime_specification)) =
134 (selected_kernel, runtime_specification)
135 {
136 // Top priority is the selected kernel
137 return runtime_specification.name.to_lowercase() == selected.to_lowercase();
138 }
139 false
140 })
141 .cloned();
142
143 if let Some(found_by_name) = found_by_name {
144 return Some(found_by_name);
145 }
146
147 self.kernel_specifications
148 .iter()
149 .find(|kernel_option| match kernel_option {
150 KernelSpecification::Jupyter(runtime_specification) => {
151 runtime_specification.kernelspec.language.to_lowercase()
152 == language_name.to_lowercase()
153 }
154 // todo!()
155 _ => false,
156 })
157 .cloned()
158 }
159
160 pub fn get_session(&self, entity_id: EntityId) -> Option<&View<Session>> {
161 self.sessions.get(&entity_id)
162 }
163
164 pub fn insert_session(&mut self, entity_id: EntityId, session: View<Session>) {
165 self.sessions.insert(entity_id, session);
166 }
167
168 pub fn remove_session(&mut self, entity_id: EntityId) {
169 self.sessions.remove(&entity_id);
170 }
171}