Supermaven (#10788)

Adds a supermaven provider for completions. There are various other
refactors amidst this branch, primarily to make copilot no longer a
dependency of project as well as show LSP Logs for global LSPs like
copilot properly.

This feature is not enabled by default. We're going to seek to refine it
in the coming weeks.

Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Nathan Sobo <nathan@zed.dev>
Co-authored-by: Max <max@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Kyle Kelley
2024-05-03 12:50:42 -07:00
committed by GitHub
co-authored by Antonio Scandurra Nathan Sobo Max Max Brunsfeld
parent 610968815c
commit 6563330239
47 changed files with 2242 additions and 827 deletions
+9 -48
View File
@@ -9,16 +9,14 @@ mod zed;
use anyhow::{anyhow, Context as _, Result};
use clap::{command, Parser};
use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
use client::{parse_zed_link, telemetry::Telemetry, Client, DevServerToken, UserStore};
use client::{parse_zed_link, Client, DevServerToken, UserStore};
use collab_ui::channel_view::ChannelView;
use copilot::Copilot;
use copilot_ui::CopilotCompletionProvider;
use db::kvp::KEY_VALUE_STORE;
use editor::{Editor, EditorMode};
use editor::Editor;
use env_logger::Builder;
use fs::RealFs;
use futures::{future, StreamExt};
use gpui::{App, AppContext, AsyncAppContext, Context, Task, ViewContext, VisualContext};
use gpui::{App, AppContext, AsyncAppContext, Context, Task, VisualContext};
use image_viewer;
use language::LanguageRegistry;
use log::LevelFilter;
@@ -55,6 +53,8 @@ use zed::{
OpenListener, OpenRequest,
};
use crate::zed::inline_completion_registry;
#[cfg(feature = "mimalloc")]
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
@@ -270,17 +270,20 @@ fn init_ui(args: Args) {
editor::init(cx);
image_viewer::init(cx);
diagnostics::init(cx);
// Initialize each completion provider. Settings are used for toggling between them.
copilot::init(
copilot_language_server_id,
client.http_client(),
node_runtime.clone(),
cx,
);
supermaven::init(client.clone(), cx);
assistant::init(client.clone(), cx);
assistant2::init(client.clone(), cx);
init_inline_completion_provider(client.telemetry().clone(), cx);
inline_completion_registry::init(client.telemetry().clone(), cx);
extension::init(
fs.clone(),
@@ -888,45 +891,3 @@ fn watch_file_types(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
#[cfg(not(debug_assertions))]
fn watch_file_types(_fs: Arc<dyn fs::Fs>, _cx: &mut AppContext) {}
fn init_inline_completion_provider(telemetry: Arc<Telemetry>, cx: &mut AppContext) {
if let Some(copilot) = Copilot::global(cx) {
cx.observe_new_views(move |editor: &mut Editor, cx: &mut ViewContext<Editor>| {
if editor.mode() == EditorMode::Full {
// We renamed some of these actions to not be copilot-specific, but that
// would have not been backwards-compatible. So here we are re-registering
// the actions with the old names to not break people's keymaps.
editor
.register_action(cx.listener(
|editor, _: &copilot::Suggest, cx: &mut ViewContext<Editor>| {
editor.show_inline_completion(&Default::default(), cx);
},
))
.register_action(cx.listener(
|editor, _: &copilot::NextSuggestion, cx: &mut ViewContext<Editor>| {
editor.next_inline_completion(&Default::default(), cx);
},
))
.register_action(cx.listener(
|editor, _: &copilot::PreviousSuggestion, cx: &mut ViewContext<Editor>| {
editor.previous_inline_completion(&Default::default(), cx);
},
))
.register_action(cx.listener(
|editor,
_: &editor::actions::AcceptPartialCopilotSuggestion,
cx: &mut ViewContext<Editor>| {
editor.accept_partial_inline_completion(&Default::default(), cx);
},
));
let provider = cx.new_model(|_| {
CopilotCompletionProvider::new(copilot.clone())
.with_telemetry(telemetry.clone())
});
editor.set_inline_completion_provider(provider, cx)
}
})
.detach();
}
}
+6 -2
View File
@@ -1,4 +1,5 @@
mod app_menus;
pub mod inline_completion_registry;
mod only_instance;
mod open_listener;
@@ -127,7 +128,10 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
})
.detach();
let copilot = cx.new_view(|cx| copilot_ui::CopilotButton::new(app_state.fs.clone(), cx));
let inline_completion_button = cx.new_view(|cx| {
inline_completion_button::InlineCompletionButton::new(app_state.fs.clone(), cx)
});
let diagnostic_summary =
cx.new_view(|cx| diagnostics::items::DiagnosticIndicator::new(workspace, cx));
let activity_indicator =
@@ -140,7 +144,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
workspace.status_bar().update(cx, |status_bar, cx| {
status_bar.add_left_item(diagnostic_summary, cx);
status_bar.add_left_item(activity_indicator, cx);
status_bar.add_right_item(copilot, cx);
status_bar.add_right_item(inline_completion_button, cx);
status_bar.add_right_item(active_buffer_language, cx);
status_bar.add_right_item(vim_mode_indicator, cx);
status_bar.add_right_item(cursor_position, cx);
@@ -0,0 +1,126 @@
use std::{cell::RefCell, rc::Rc, sync::Arc};
use client::telemetry::Telemetry;
use collections::HashMap;
use copilot::{Copilot, CopilotCompletionProvider};
use editor::{Editor, EditorMode};
use gpui::{AnyWindowHandle, AppContext, Context, ViewContext, WeakView};
use language::language_settings::all_language_settings;
use settings::SettingsStore;
use supermaven::{Supermaven, SupermavenCompletionProvider};
pub fn init(telemetry: Arc<Telemetry>, cx: &mut AppContext) {
let editors: Rc<RefCell<HashMap<WeakView<Editor>, AnyWindowHandle>>> = Rc::default();
cx.observe_new_views({
let editors = editors.clone();
let telemetry = telemetry.clone();
move |editor: &mut Editor, cx: &mut ViewContext<Editor>| {
if editor.mode() != EditorMode::Full {
return;
}
register_backward_compatible_actions(editor, cx);
let editor_handle = cx.view().downgrade();
cx.on_release({
let editor_handle = editor_handle.clone();
let editors = editors.clone();
move |_, _, _| {
editors.borrow_mut().remove(&editor_handle);
}
})
.detach();
editors
.borrow_mut()
.insert(editor_handle, cx.window_handle());
let provider = all_language_settings(None, cx).inline_completions.provider;
assign_inline_completion_provider(editor, provider, &telemetry, cx);
}
})
.detach();
let mut provider = all_language_settings(None, cx).inline_completions.provider;
for (editor, window) in editors.borrow().iter() {
_ = window.update(cx, |_window, cx| {
_ = editor.update(cx, |editor, cx| {
assign_inline_completion_provider(editor, provider, &telemetry, cx);
})
});
}
cx.observe_global::<SettingsStore>(move |cx| {
let new_provider = all_language_settings(None, cx).inline_completions.provider;
if new_provider != provider {
provider = new_provider;
for (editor, window) in editors.borrow().iter() {
_ = window.update(cx, |_window, cx| {
_ = editor.update(cx, |editor, cx| {
assign_inline_completion_provider(editor, provider, &telemetry, cx);
})
});
}
}
})
.detach();
}
fn register_backward_compatible_actions(editor: &mut Editor, cx: &mut ViewContext<Editor>) {
// We renamed some of these actions to not be copilot-specific, but that
// would have not been backwards-compatible. So here we are re-registering
// the actions with the old names to not break people's keymaps.
editor
.register_action(cx.listener(
|editor, _: &copilot::Suggest, cx: &mut ViewContext<Editor>| {
editor.show_inline_completion(&Default::default(), cx);
},
))
.register_action(cx.listener(
|editor, _: &copilot::NextSuggestion, cx: &mut ViewContext<Editor>| {
editor.next_inline_completion(&Default::default(), cx);
},
))
.register_action(cx.listener(
|editor, _: &copilot::PreviousSuggestion, cx: &mut ViewContext<Editor>| {
editor.previous_inline_completion(&Default::default(), cx);
},
))
.register_action(cx.listener(
|editor,
_: &editor::actions::AcceptPartialCopilotSuggestion,
cx: &mut ViewContext<Editor>| {
editor.accept_partial_inline_completion(&Default::default(), cx);
},
));
}
fn assign_inline_completion_provider(
editor: &mut Editor,
provider: language::language_settings::InlineCompletionProvider,
telemetry: &Arc<Telemetry>,
cx: &mut ViewContext<Editor>,
) {
match provider {
language::language_settings::InlineCompletionProvider::None => {}
language::language_settings::InlineCompletionProvider::Copilot => {
if let Some(copilot) = Copilot::global(cx) {
if let Some(buffer) = editor.buffer().read(cx).as_singleton() {
if buffer.read(cx).file().is_some() {
copilot.update(cx, |copilot, cx| {
copilot.register_buffer(&buffer, cx);
});
}
}
let provider = cx.new_model(|_| {
CopilotCompletionProvider::new(copilot).with_telemetry(telemetry.clone())
});
editor.set_inline_completion_provider(Some(provider), cx);
}
}
language::language_settings::InlineCompletionProvider::Supermaven => {
if let Some(supermaven) = Supermaven::global(cx) {
let provider = cx.new_model(|_| SupermavenCompletionProvider::new(supermaven));
editor.set_inline_completion_provider(Some(provider), cx);
}
}
}
}