inline_completion_registry.rs

  1use std::{cell::RefCell, rc::Rc, sync::Arc};
  2
  3use client::telemetry::Telemetry;
  4use collections::HashMap;
  5use copilot::{Copilot, CopilotCompletionProvider};
  6use editor::{Editor, EditorMode};
  7use gpui::{AnyWindowHandle, AppContext, Context, ViewContext, WeakView};
  8use language::language_settings::all_language_settings;
  9use settings::SettingsStore;
 10use supermaven::{Supermaven, SupermavenCompletionProvider};
 11
 12pub fn init(telemetry: Arc<Telemetry>, cx: &mut AppContext) {
 13    let editors: Rc<RefCell<HashMap<WeakView<Editor>, AnyWindowHandle>>> = Rc::default();
 14    cx.observe_new_views({
 15        let editors = editors.clone();
 16        let telemetry = telemetry.clone();
 17        move |editor: &mut Editor, cx: &mut ViewContext<Editor>| {
 18            if editor.mode() != EditorMode::Full {
 19                return;
 20            }
 21
 22            register_backward_compatible_actions(editor, cx);
 23
 24            let editor_handle = cx.view().downgrade();
 25            cx.on_release({
 26                let editor_handle = editor_handle.clone();
 27                let editors = editors.clone();
 28                move |_, _, _| {
 29                    editors.borrow_mut().remove(&editor_handle);
 30                }
 31            })
 32            .detach();
 33            editors
 34                .borrow_mut()
 35                .insert(editor_handle, cx.window_handle());
 36            let provider = all_language_settings(None, cx).inline_completions.provider;
 37            assign_inline_completion_provider(editor, provider, &telemetry, cx);
 38        }
 39    })
 40    .detach();
 41
 42    let mut provider = all_language_settings(None, cx).inline_completions.provider;
 43    for (editor, window) in editors.borrow().iter() {
 44        _ = window.update(cx, |_window, cx| {
 45            _ = editor.update(cx, |editor, cx| {
 46                assign_inline_completion_provider(editor, provider, &telemetry, cx);
 47            })
 48        });
 49    }
 50
 51    cx.observe_global::<SettingsStore>(move |cx| {
 52        let new_provider = all_language_settings(None, cx).inline_completions.provider;
 53        if new_provider != provider {
 54            provider = new_provider;
 55            for (editor, window) in editors.borrow().iter() {
 56                _ = window.update(cx, |_window, cx| {
 57                    _ = editor.update(cx, |editor, cx| {
 58                        assign_inline_completion_provider(editor, provider, &telemetry, cx);
 59                    })
 60                });
 61            }
 62        }
 63    })
 64    .detach();
 65}
 66
 67fn register_backward_compatible_actions(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
 68    // We renamed some of these actions to not be copilot-specific, but that
 69    // would have not been backwards-compatible. So here we are re-registering
 70    // the actions with the old names to not break people's keymaps.
 71    editor
 72        .register_action(cx.listener(
 73            |editor, _: &copilot::Suggest, cx: &mut ViewContext<Editor>| {
 74                editor.show_inline_completion(&Default::default(), cx);
 75            },
 76        ))
 77        .detach();
 78    editor
 79        .register_action(cx.listener(
 80            |editor, _: &copilot::NextSuggestion, cx: &mut ViewContext<Editor>| {
 81                editor.next_inline_completion(&Default::default(), cx);
 82            },
 83        ))
 84        .detach();
 85    editor
 86        .register_action(cx.listener(
 87            |editor, _: &copilot::PreviousSuggestion, cx: &mut ViewContext<Editor>| {
 88                editor.previous_inline_completion(&Default::default(), cx);
 89            },
 90        ))
 91        .detach();
 92    editor
 93        .register_action(cx.listener(
 94            |editor,
 95             _: &editor::actions::AcceptPartialCopilotSuggestion,
 96             cx: &mut ViewContext<Editor>| {
 97                editor.accept_partial_inline_completion(&Default::default(), cx);
 98            },
 99        ))
100        .detach();
101}
102
103fn assign_inline_completion_provider(
104    editor: &mut Editor,
105    provider: language::language_settings::InlineCompletionProvider,
106    telemetry: &Arc<Telemetry>,
107    cx: &mut ViewContext<Editor>,
108) {
109    match provider {
110        language::language_settings::InlineCompletionProvider::None => {}
111        language::language_settings::InlineCompletionProvider::Copilot => {
112            if let Some(copilot) = Copilot::global(cx) {
113                if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
114                    if buffer.read(cx).file().is_some() {
115                        copilot.update(cx, |copilot, cx| {
116                            copilot.register_buffer(&buffer, cx);
117                        });
118                    }
119                }
120                let provider = cx.new_model(|_| {
121                    CopilotCompletionProvider::new(copilot).with_telemetry(telemetry.clone())
122                });
123                editor.set_inline_completion_provider(Some(provider), cx);
124            }
125        }
126        language::language_settings::InlineCompletionProvider::Supermaven => {
127            if let Some(supermaven) = Supermaven::global(cx) {
128                let provider = cx.new_model(|_| {
129                    SupermavenCompletionProvider::new(supermaven).with_telemetry(telemetry.clone())
130                });
131                editor.set_inline_completion_provider(Some(provider), cx);
132            }
133        }
134    }
135}