Add a way to display unrelated to language support language servers' logs (#2991)
Copilot is being used in every buffer, but we do not see its logs that easily. In the future, prettier wrapper will pretend to be an LSP server, it is better to log its messages somewhere, so prepare an infrastructure for that. <img width="1727" alt="image" src="https://github.com/zed-industries/zed/assets/2690773/d31a257c-9608-46fa-8be1-f0a2a2bdbdb7"> Copilot seem to have no rpc messages logged for some reason now, prettier wrapper might be a better case to investigate this, so leaving as is. Release Notes: - N/A
This commit is contained in:
commit
a366ad02ce
6 changed files with 189 additions and 78 deletions
|
@ -11,13 +11,12 @@ use gpui::{
|
|||
};
|
||||
use language::{
|
||||
language_settings::{all_language_settings, language_settings},
|
||||
point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language, PointUtf16,
|
||||
ToPointUtf16,
|
||||
point_from_lsp, point_to_lsp, Anchor, Bias, Buffer, BufferSnapshot, Language,
|
||||
LanguageServerName, PointUtf16, ToPointUtf16,
|
||||
};
|
||||
use log::{debug, error};
|
||||
use lsp::{LanguageServer, LanguageServerBinary, LanguageServerId};
|
||||
use node_runtime::NodeRuntime;
|
||||
use request::{LogMessage, StatusNotification};
|
||||
use request::StatusNotification;
|
||||
use settings::SettingsStore;
|
||||
use smol::{fs, io::BufReader, stream::StreamExt};
|
||||
use std::{
|
||||
|
@ -41,10 +40,15 @@ actions!(
|
|||
[Suggest, NextSuggestion, PreviousSuggestion, Reinstall]
|
||||
);
|
||||
|
||||
pub fn init(http: Arc<dyn HttpClient>, node_runtime: Arc<dyn NodeRuntime>, cx: &mut AppContext) {
|
||||
pub fn init(
|
||||
new_server_id: LanguageServerId,
|
||||
http: Arc<dyn HttpClient>,
|
||||
node_runtime: Arc<dyn NodeRuntime>,
|
||||
cx: &mut AppContext,
|
||||
) {
|
||||
let copilot = cx.add_model({
|
||||
let node_runtime = node_runtime.clone();
|
||||
move |cx| Copilot::start(http, node_runtime, cx)
|
||||
move |cx| Copilot::start(new_server_id, http, node_runtime, cx)
|
||||
});
|
||||
cx.set_global(copilot.clone());
|
||||
|
||||
|
@ -125,6 +129,7 @@ impl CopilotServer {
|
|||
}
|
||||
|
||||
struct RunningCopilotServer {
|
||||
name: LanguageServerName,
|
||||
lsp: Arc<LanguageServer>,
|
||||
sign_in_status: SignInStatus,
|
||||
registered_buffers: HashMap<usize, RegisteredBuffer>,
|
||||
|
@ -268,10 +273,15 @@ pub struct Copilot {
|
|||
node_runtime: Arc<dyn NodeRuntime>,
|
||||
server: CopilotServer,
|
||||
buffers: HashSet<WeakModelHandle<Buffer>>,
|
||||
server_id: LanguageServerId,
|
||||
}
|
||||
|
||||
pub enum Event {
|
||||
CopilotLanguageServerStarted,
|
||||
}
|
||||
|
||||
impl Entity for Copilot {
|
||||
type Event = ();
|
||||
type Event = Event;
|
||||
|
||||
fn app_will_quit(
|
||||
&mut self,
|
||||
|
@ -298,11 +308,13 @@ impl Copilot {
|
|||
}
|
||||
|
||||
fn start(
|
||||
new_server_id: LanguageServerId,
|
||||
http: Arc<dyn HttpClient>,
|
||||
node_runtime: Arc<dyn NodeRuntime>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Self {
|
||||
let mut this = Self {
|
||||
server_id: new_server_id,
|
||||
http,
|
||||
node_runtime,
|
||||
server: CopilotServer::Disabled,
|
||||
|
@ -315,13 +327,16 @@ impl Copilot {
|
|||
}
|
||||
|
||||
fn enable_or_disable_copilot(&mut self, cx: &mut ModelContext<Copilot>) {
|
||||
let server_id = self.server_id;
|
||||
let http = self.http.clone();
|
||||
let node_runtime = self.node_runtime.clone();
|
||||
if all_language_settings(None, cx).copilot_enabled(None, None) {
|
||||
if matches!(self.server, CopilotServer::Disabled) {
|
||||
let start_task = cx
|
||||
.spawn({
|
||||
move |this, cx| Self::start_language_server(http, node_runtime, this, cx)
|
||||
move |this, cx| {
|
||||
Self::start_language_server(server_id, http, node_runtime, this, cx)
|
||||
}
|
||||
})
|
||||
.shared();
|
||||
self.server = CopilotServer::Starting { task: start_task };
|
||||
|
@ -342,9 +357,11 @@ impl Copilot {
|
|||
let http = util::http::FakeHttpClient::create(|_| async { unreachable!() });
|
||||
let node_runtime = FakeNodeRuntime::new();
|
||||
let this = cx.add_model(|_| Self {
|
||||
server_id: LanguageServerId(0),
|
||||
http: http.clone(),
|
||||
node_runtime,
|
||||
server: CopilotServer::Running(RunningCopilotServer {
|
||||
name: LanguageServerName(Arc::from("copilot")),
|
||||
lsp: Arc::new(server),
|
||||
sign_in_status: SignInStatus::Authorized,
|
||||
registered_buffers: Default::default(),
|
||||
|
@ -355,6 +372,7 @@ impl Copilot {
|
|||
}
|
||||
|
||||
fn start_language_server(
|
||||
new_server_id: LanguageServerId,
|
||||
http: Arc<dyn HttpClient>,
|
||||
node_runtime: Arc<dyn NodeRuntime>,
|
||||
this: ModelHandle<Self>,
|
||||
|
@ -369,27 +387,8 @@ impl Copilot {
|
|||
path: node_path,
|
||||
arguments,
|
||||
};
|
||||
let server = LanguageServer::new(
|
||||
LanguageServerId(0),
|
||||
binary,
|
||||
Path::new("/"),
|
||||
None,
|
||||
cx.clone(),
|
||||
)?;
|
||||
|
||||
server
|
||||
.on_notification::<LogMessage, _>(|params, _cx| {
|
||||
match params.level {
|
||||
// Copilot is pretty aggressive about logging
|
||||
0 => debug!("copilot: {}", params.message),
|
||||
1 => debug!("copilot: {}", params.message),
|
||||
_ => error!("copilot: {}", params.message),
|
||||
}
|
||||
|
||||
debug!("copilot metadata: {}", params.metadata_str);
|
||||
debug!("copilot extra: {:?}", params.extra);
|
||||
})
|
||||
.detach();
|
||||
let server =
|
||||
LanguageServer::new(new_server_id, binary, Path::new("/"), None, cx.clone())?;
|
||||
|
||||
server
|
||||
.on_notification::<StatusNotification, _>(
|
||||
|
@ -427,10 +426,12 @@ impl Copilot {
|
|||
match server {
|
||||
Ok((server, status)) => {
|
||||
this.server = CopilotServer::Running(RunningCopilotServer {
|
||||
name: LanguageServerName(Arc::from("copilot")),
|
||||
lsp: server,
|
||||
sign_in_status: SignInStatus::SignedOut,
|
||||
registered_buffers: Default::default(),
|
||||
});
|
||||
cx.emit(Event::CopilotLanguageServerStarted);
|
||||
this.update_sign_in_status(status, cx);
|
||||
}
|
||||
Err(error) => {
|
||||
|
@ -547,9 +548,10 @@ impl Copilot {
|
|||
.spawn({
|
||||
let http = self.http.clone();
|
||||
let node_runtime = self.node_runtime.clone();
|
||||
let server_id = self.server_id;
|
||||
move |this, cx| async move {
|
||||
clear_copilot_dir().await;
|
||||
Self::start_language_server(http, node_runtime, this, cx).await
|
||||
Self::start_language_server(server_id, http, node_runtime, this, cx).await
|
||||
}
|
||||
})
|
||||
.shared();
|
||||
|
@ -563,6 +565,14 @@ impl Copilot {
|
|||
cx.foreground().spawn(start_task)
|
||||
}
|
||||
|
||||
pub fn language_server(&self) -> Option<(&LanguageServerName, &Arc<LanguageServer>)> {
|
||||
if let CopilotServer::Running(server) = &self.server {
|
||||
Some((&server.name, &server.lsp))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register_buffer(&mut self, buffer: &ModelHandle<Buffer>, cx: &mut ModelContext<Self>) {
|
||||
let weak_buffer = buffer.downgrade();
|
||||
self.buffers.insert(weak_buffer.clone());
|
||||
|
|
|
@ -1018,6 +1018,10 @@ impl LanguageRegistry {
|
|||
.log_err();
|
||||
})
|
||||
}
|
||||
|
||||
pub fn next_language_server_id(&self) -> LanguageServerId {
|
||||
self.state.write().next_language_server_id()
|
||||
}
|
||||
}
|
||||
|
||||
impl LanguageRegistryState {
|
||||
|
|
|
@ -13,7 +13,7 @@ use gpui::{
|
|||
};
|
||||
use language::{Buffer, LanguageServerId, LanguageServerName};
|
||||
use lsp::IoKind;
|
||||
use project::{search::SearchQuery, Project, Worktree};
|
||||
use project::{search::SearchQuery, Project};
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
use theme::{ui, Theme};
|
||||
use workspace::{
|
||||
|
@ -38,7 +38,8 @@ struct ProjectState {
|
|||
struct LanguageServerState {
|
||||
log_buffer: ModelHandle<Buffer>,
|
||||
rpc_state: Option<LanguageServerRpcState>,
|
||||
_subscription: Option<lsp::Subscription>,
|
||||
_io_logs_subscription: Option<lsp::Subscription>,
|
||||
_lsp_logs_subscription: Option<lsp::Subscription>,
|
||||
}
|
||||
|
||||
struct LanguageServerRpcState {
|
||||
|
@ -69,7 +70,7 @@ enum MessageKind {
|
|||
pub(crate) struct LogMenuItem {
|
||||
pub server_id: LanguageServerId,
|
||||
pub server_name: LanguageServerName,
|
||||
pub worktree: ModelHandle<Worktree>,
|
||||
pub worktree_root_name: String,
|
||||
pub rpc_trace_enabled: bool,
|
||||
pub rpc_trace_selected: bool,
|
||||
pub logs_selected: bool,
|
||||
|
@ -134,8 +135,6 @@ impl LogStore {
|
|||
}
|
||||
|
||||
pub fn add_project(&mut self, project: &ModelHandle<Project>, cx: &mut ModelContext<Self>) {
|
||||
use project::Event::*;
|
||||
|
||||
let weak_project = project.downgrade();
|
||||
self.projects.insert(
|
||||
weak_project,
|
||||
|
@ -146,13 +145,13 @@ impl LogStore {
|
|||
this.projects.remove(&weak_project);
|
||||
}),
|
||||
cx.subscribe(project, |this, project, event, cx| match event {
|
||||
LanguageServerAdded(id) => {
|
||||
project::Event::LanguageServerAdded(id) => {
|
||||
this.add_language_server(&project, *id, cx);
|
||||
}
|
||||
LanguageServerRemoved(id) => {
|
||||
project::Event::LanguageServerRemoved(id) => {
|
||||
this.remove_language_server(&project, *id, cx);
|
||||
}
|
||||
LanguageServerLog(id, message) => {
|
||||
project::Event::LanguageServerLog(id, message) => {
|
||||
this.add_language_server_log(&project, *id, message, cx);
|
||||
}
|
||||
_ => {}
|
||||
|
@ -176,21 +175,37 @@ impl LogStore {
|
|||
log_buffer: cx
|
||||
.add_model(|cx| Buffer::new(0, cx.model_id() as u64, ""))
|
||||
.clone(),
|
||||
_subscription: None,
|
||||
_io_logs_subscription: None,
|
||||
_lsp_logs_subscription: None,
|
||||
}
|
||||
});
|
||||
|
||||
let server = project.read(cx).language_server_for_id(id);
|
||||
let weak_project = project.downgrade();
|
||||
let io_tx = self.io_tx.clone();
|
||||
server_state._subscription = server.map(|server| {
|
||||
server_state._io_logs_subscription = server.as_ref().map(|server| {
|
||||
server.on_io(move |io_kind, message| {
|
||||
io_tx
|
||||
.unbounded_send((weak_project, id, io_kind, message.to_string()))
|
||||
.ok();
|
||||
})
|
||||
});
|
||||
|
||||
let this = cx.weak_handle();
|
||||
let weak_project = project.downgrade();
|
||||
server_state._lsp_logs_subscription = server.map(|server| {
|
||||
let server_id = server.server_id();
|
||||
server.on_notification::<lsp::notification::LogMessage, _>({
|
||||
move |params, mut cx| {
|
||||
if let Some((project, this)) =
|
||||
weak_project.upgrade(&mut cx).zip(this.upgrade(&mut cx))
|
||||
{
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.add_language_server_log(&project, server_id, ¶ms.message, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
Some(server_state.log_buffer.clone())
|
||||
}
|
||||
|
||||
|
@ -201,7 +216,16 @@ impl LogStore {
|
|||
message: &str,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Option<()> {
|
||||
let buffer = self.add_language_server(&project, id, cx)?;
|
||||
let buffer = match self
|
||||
.projects
|
||||
.get_mut(&project.downgrade())?
|
||||
.servers
|
||||
.get(&id)
|
||||
.map(|state| state.log_buffer.clone())
|
||||
{
|
||||
Some(existing_buffer) => existing_buffer,
|
||||
None => self.add_language_server(&project, id, cx)?,
|
||||
};
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
let len = buffer.len();
|
||||
let has_newline = message.ends_with("\n");
|
||||
|
@ -288,19 +312,15 @@ impl LogStore {
|
|||
language_server_id: LanguageServerId,
|
||||
io_kind: IoKind,
|
||||
message: &str,
|
||||
cx: &mut AppContext,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Option<()> {
|
||||
let is_received = match io_kind {
|
||||
IoKind::StdOut => true,
|
||||
IoKind::StdIn => false,
|
||||
IoKind::StdErr => {
|
||||
let project = project.upgrade(cx)?;
|
||||
project.update(cx, |_, cx| {
|
||||
cx.emit(project::Event::LanguageServerLog(
|
||||
language_server_id,
|
||||
format!("stderr: {}\n", message.trim()),
|
||||
))
|
||||
});
|
||||
let message = format!("stderr: {}\n", message.trim());
|
||||
self.add_language_server_log(&project, language_server_id, &message, cx);
|
||||
return Some(());
|
||||
}
|
||||
};
|
||||
|
@ -388,7 +408,7 @@ impl LspLogView {
|
|||
Some(LogMenuItem {
|
||||
server_id,
|
||||
server_name: language_server_name,
|
||||
worktree,
|
||||
worktree_root_name: worktree.read(cx).root_name().to_string(),
|
||||
rpc_trace_enabled: state.rpc_state.is_some(),
|
||||
rpc_trace_selected: self.is_showing_rpc_trace
|
||||
&& self.current_server_id == Some(server_id),
|
||||
|
@ -396,6 +416,24 @@ impl LspLogView {
|
|||
&& self.current_server_id == Some(server_id),
|
||||
})
|
||||
})
|
||||
.chain(
|
||||
self.project
|
||||
.read(cx)
|
||||
.supplementary_language_servers()
|
||||
.filter_map(|(&server_id, (name, _))| {
|
||||
let state = state.servers.get(&server_id)?;
|
||||
Some(LogMenuItem {
|
||||
server_id,
|
||||
server_name: name.clone(),
|
||||
worktree_root_name: "supplementary".to_string(),
|
||||
rpc_trace_enabled: state.rpc_state.is_some(),
|
||||
rpc_trace_selected: self.is_showing_rpc_trace
|
||||
&& self.current_server_id == Some(server_id),
|
||||
logs_selected: !self.is_showing_rpc_trace
|
||||
&& self.current_server_id == Some(server_id),
|
||||
})
|
||||
}),
|
||||
)
|
||||
.collect::<Vec<_>>();
|
||||
rows.sort_by_key(|row| row.server_id);
|
||||
rows.dedup_by_key(|row| row.server_id);
|
||||
|
@ -613,7 +651,7 @@ impl View for LspLogToolbarItemView {
|
|||
Self::render_language_server_menu_item(
|
||||
row.server_id,
|
||||
row.server_name,
|
||||
row.worktree,
|
||||
&row.worktree_root_name,
|
||||
row.rpc_trace_enabled,
|
||||
row.logs_selected,
|
||||
row.rpc_trace_selected,
|
||||
|
@ -745,15 +783,14 @@ impl LspLogToolbarItemView {
|
|||
cx: &mut ViewContext<Self>,
|
||||
) -> impl Element<Self> {
|
||||
enum ToggleMenu {}
|
||||
MouseEventHandler::new::<ToggleMenu, _>(0, cx, move |state, cx| {
|
||||
MouseEventHandler::new::<ToggleMenu, _>(0, cx, move |state, _| {
|
||||
let label: Cow<str> = current_server
|
||||
.and_then(|row| {
|
||||
let worktree = row.worktree.read(cx);
|
||||
Some(
|
||||
format!(
|
||||
"{} ({}) - {}",
|
||||
row.server_name.0,
|
||||
worktree.root_name(),
|
||||
row.worktree_root_name,
|
||||
if row.rpc_trace_selected {
|
||||
RPC_MESSAGES
|
||||
} else {
|
||||
|
@ -778,7 +815,7 @@ impl LspLogToolbarItemView {
|
|||
fn render_language_server_menu_item(
|
||||
id: LanguageServerId,
|
||||
name: LanguageServerName,
|
||||
worktree: ModelHandle<Worktree>,
|
||||
worktree_root_name: &str,
|
||||
rpc_trace_enabled: bool,
|
||||
logs_selected: bool,
|
||||
rpc_trace_selected: bool,
|
||||
|
@ -792,7 +829,7 @@ impl LspLogToolbarItemView {
|
|||
.with_child({
|
||||
let style = &theme.toolbar_dropdown_menu.section_header;
|
||||
Label::new(
|
||||
format!("{} ({})", name.0, worktree.read(cx).root_name()),
|
||||
format!("{} ({})", name.0, worktree_root_name),
|
||||
style.text.clone(),
|
||||
)
|
||||
.contained()
|
||||
|
|
|
@ -77,7 +77,14 @@ async fn test_lsp_logs(cx: &mut TestAppContext) {
|
|||
&[LogMenuItem {
|
||||
server_id: language_server.server.server_id(),
|
||||
server_name: LanguageServerName("the-rust-language-server".into()),
|
||||
worktree: project.read(cx).worktrees(cx).next().unwrap(),
|
||||
worktree_root_name: project
|
||||
.read(cx)
|
||||
.worktrees(cx)
|
||||
.next()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.root_name()
|
||||
.to_string(),
|
||||
rpc_trace_enabled: false,
|
||||
rpc_trace_selected: false,
|
||||
logs_selected: true,
|
||||
|
|
|
@ -108,6 +108,8 @@ pub struct Project {
|
|||
active_entry: Option<ProjectEntryId>,
|
||||
buffer_ordered_messages_tx: mpsc::UnboundedSender<BufferOrderedMessage>,
|
||||
languages: Arc<LanguageRegistry>,
|
||||
supplementary_language_servers:
|
||||
HashMap<LanguageServerId, (LanguageServerName, Arc<LanguageServer>)>,
|
||||
language_servers: HashMap<LanguageServerId, LanguageServerState>,
|
||||
language_server_ids: HashMap<(WorktreeId, LanguageServerName), LanguageServerId>,
|
||||
language_server_statuses: BTreeMap<LanguageServerId, LanguageServerStatus>,
|
||||
|
@ -147,7 +149,8 @@ pub struct Project {
|
|||
_maintain_buffer_languages: Task<()>,
|
||||
_maintain_workspace_config: Task<()>,
|
||||
terminals: Terminals,
|
||||
copilot_enabled: bool,
|
||||
copilot_lsp_subscription: Option<gpui::Subscription>,
|
||||
copilot_log_subscription: Option<lsp::Subscription>,
|
||||
current_lsp_settings: HashMap<Arc<str>, LspSettings>,
|
||||
}
|
||||
|
||||
|
@ -618,6 +621,8 @@ impl Project {
|
|||
let (tx, rx) = mpsc::unbounded();
|
||||
cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
|
||||
.detach();
|
||||
let copilot_lsp_subscription =
|
||||
Copilot::global(cx).map(|copilot| subscribe_for_copilot_events(&copilot, cx));
|
||||
Self {
|
||||
worktrees: Default::default(),
|
||||
buffer_ordered_messages_tx: tx,
|
||||
|
@ -647,6 +652,7 @@ impl Project {
|
|||
fs,
|
||||
next_entry_id: Default::default(),
|
||||
next_diagnostic_group_id: Default::default(),
|
||||
supplementary_language_servers: HashMap::default(),
|
||||
language_servers: Default::default(),
|
||||
language_server_ids: Default::default(),
|
||||
language_server_statuses: Default::default(),
|
||||
|
@ -658,7 +664,8 @@ impl Project {
|
|||
terminals: Terminals {
|
||||
local_handles: Vec::new(),
|
||||
},
|
||||
copilot_enabled: Copilot::global(cx).is_some(),
|
||||
copilot_lsp_subscription,
|
||||
copilot_log_subscription: None,
|
||||
current_lsp_settings: settings::get::<ProjectSettings>(cx).lsp.clone(),
|
||||
}
|
||||
})
|
||||
|
@ -694,6 +701,8 @@ impl Project {
|
|||
let (tx, rx) = mpsc::unbounded();
|
||||
cx.spawn_weak(|this, cx| Self::send_buffer_ordered_messages(this, rx, cx))
|
||||
.detach();
|
||||
let copilot_lsp_subscription =
|
||||
Copilot::global(cx).map(|copilot| subscribe_for_copilot_events(&copilot, cx));
|
||||
let mut this = Self {
|
||||
worktrees: Vec::new(),
|
||||
buffer_ordered_messages_tx: tx,
|
||||
|
@ -723,6 +732,7 @@ impl Project {
|
|||
remote_id,
|
||||
replica_id,
|
||||
}),
|
||||
supplementary_language_servers: HashMap::default(),
|
||||
language_servers: Default::default(),
|
||||
language_server_ids: Default::default(),
|
||||
language_server_statuses: response
|
||||
|
@ -751,7 +761,8 @@ impl Project {
|
|||
terminals: Terminals {
|
||||
local_handles: Vec::new(),
|
||||
},
|
||||
copilot_enabled: Copilot::global(cx).is_some(),
|
||||
copilot_lsp_subscription,
|
||||
copilot_log_subscription: None,
|
||||
current_lsp_settings: settings::get::<ProjectSettings>(cx).lsp.clone(),
|
||||
};
|
||||
for worktree in worktrees {
|
||||
|
@ -882,12 +893,14 @@ impl Project {
|
|||
self.restart_language_servers(worktree, language, cx);
|
||||
}
|
||||
|
||||
if !self.copilot_enabled && Copilot::global(cx).is_some() {
|
||||
self.copilot_enabled = true;
|
||||
for buffer in self.opened_buffers.values() {
|
||||
if let Some(buffer) = buffer.upgrade(cx) {
|
||||
self.register_buffer_with_copilot(&buffer, cx);
|
||||
if self.copilot_lsp_subscription.is_none() {
|
||||
if let Some(copilot) = Copilot::global(cx) {
|
||||
for buffer in self.opened_buffers.values() {
|
||||
if let Some(buffer) = buffer.upgrade(cx) {
|
||||
self.register_buffer_with_copilot(&buffer, cx);
|
||||
}
|
||||
}
|
||||
self.copilot_lsp_subscription = Some(subscribe_for_copilot_events(&copilot, cx));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2789,18 +2802,6 @@ impl Project {
|
|||
None => return Ok(None),
|
||||
};
|
||||
|
||||
language_server
|
||||
.on_notification::<lsp::notification::LogMessage, _>({
|
||||
move |params, mut cx| {
|
||||
if let Some(this) = this.upgrade(&cx) {
|
||||
this.update(&mut cx, |_, cx| {
|
||||
cx.emit(Event::LanguageServerLog(server_id, params.message))
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
language_server
|
||||
.on_notification::<lsp::notification::PublishDiagnostics, _>({
|
||||
let adapter = adapter.clone();
|
||||
|
@ -7954,9 +7955,23 @@ impl Project {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn supplementary_language_servers(
|
||||
&self,
|
||||
) -> impl '_
|
||||
+ Iterator<
|
||||
Item = (
|
||||
&LanguageServerId,
|
||||
&(LanguageServerName, Arc<LanguageServer>),
|
||||
),
|
||||
> {
|
||||
self.supplementary_language_servers.iter()
|
||||
}
|
||||
|
||||
pub fn language_server_for_id(&self, id: LanguageServerId) -> Option<Arc<LanguageServer>> {
|
||||
if let LanguageServerState::Running { server, .. } = self.language_servers.get(&id)? {
|
||||
Some(server.clone())
|
||||
} else if let Some((_, server)) = self.supplementary_language_servers.get(&id) {
|
||||
Some(Arc::clone(server))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
@ -8016,6 +8031,43 @@ impl Project {
|
|||
}
|
||||
}
|
||||
|
||||
fn subscribe_for_copilot_events(
|
||||
copilot: &ModelHandle<Copilot>,
|
||||
cx: &mut ModelContext<'_, Project>,
|
||||
) -> gpui::Subscription {
|
||||
cx.subscribe(
|
||||
copilot,
|
||||
|project, copilot, copilot_event, cx| match copilot_event {
|
||||
copilot::Event::CopilotLanguageServerStarted => {
|
||||
if let Some((name, copilot_server)) = copilot.read(cx).language_server() {
|
||||
let new_server_id = copilot_server.server_id();
|
||||
if let hash_map::Entry::Vacant(v) =
|
||||
project.supplementary_language_servers.entry(new_server_id)
|
||||
{
|
||||
let weak_project = cx.weak_handle();
|
||||
let copilot_log_subscription = copilot_server
|
||||
.on_notification::<copilot::request::LogMessage, _>(
|
||||
move |params, mut cx| {
|
||||
if let Some(project) = weak_project.upgrade(&mut cx) {
|
||||
project.update(&mut cx, |_, cx| {
|
||||
cx.emit(Event::LanguageServerLog(
|
||||
new_server_id,
|
||||
params.message,
|
||||
));
|
||||
})
|
||||
}
|
||||
},
|
||||
);
|
||||
project.copilot_log_subscription = Some(copilot_log_subscription);
|
||||
v.insert((name.clone(), Arc::clone(copilot_server)));
|
||||
cx.emit(Event::LanguageServerAdded(new_server_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn glob_literal_prefix<'a>(glob: &'a str) -> &'a str {
|
||||
let mut literal_end = 0;
|
||||
for (i, part) in glob.split(path::MAIN_SEPARATOR).enumerate() {
|
||||
|
|
|
@ -129,6 +129,7 @@ fn main() {
|
|||
|
||||
let client = client::Client::new(http.clone(), cx);
|
||||
let mut languages = LanguageRegistry::new(login_shell_env_loaded);
|
||||
let copilot_language_server_id = languages.next_language_server_id();
|
||||
languages.set_executor(cx.background().clone());
|
||||
languages.set_language_server_download_dir(paths::LANGUAGES_DIR.clone());
|
||||
let languages = Arc::new(languages);
|
||||
|
@ -159,7 +160,7 @@ fn main() {
|
|||
semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx);
|
||||
vim::init(cx);
|
||||
terminal_view::init(cx);
|
||||
copilot::init(http.clone(), node_runtime, cx);
|
||||
copilot::init(copilot_language_server_id, http.clone(), node_runtime, cx);
|
||||
ai::init(cx);
|
||||
component_test::init(cx);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue