wip
This commit is contained in:
parent
64b14ef848
commit
848d1101d3
9 changed files with 263 additions and 93 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -9213,6 +9213,7 @@ dependencies = [
|
||||||
"language",
|
"language",
|
||||||
"lsp",
|
"lsp",
|
||||||
"project",
|
"project",
|
||||||
|
"proto",
|
||||||
"release_channel",
|
"release_channel",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"settings",
|
"settings",
|
||||||
|
@ -13500,6 +13501,7 @@ dependencies = [
|
||||||
"language",
|
"language",
|
||||||
"language_extension",
|
"language_extension",
|
||||||
"language_model",
|
"language_model",
|
||||||
|
"language_tools",
|
||||||
"languages",
|
"languages",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
|
|
@ -24,6 +24,7 @@ itertools.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
lsp.workspace = true
|
lsp.workspace = true
|
||||||
project.workspace = true
|
project.workspace = true
|
||||||
|
proto.workspace = true
|
||||||
serde_json.workspace = true
|
serde_json.workspace = true
|
||||||
settings.workspace = true
|
settings.workspace = true
|
||||||
theme.workspace = true
|
theme.workspace = true
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
mod key_context_view;
|
mod key_context_view;
|
||||||
mod lsp_log;
|
pub mod lsp_log;
|
||||||
pub mod lsp_tool;
|
pub mod lsp_tool;
|
||||||
mod syntax_tree_view;
|
mod syntax_tree_view;
|
||||||
|
|
||||||
|
|
|
@ -12,9 +12,10 @@ use lsp::{
|
||||||
IoKind, LanguageServer, LanguageServerName, LanguageServerSelector, MessageType,
|
IoKind, LanguageServer, LanguageServerName, LanguageServerSelector, MessageType,
|
||||||
SetTraceParams, TraceValue, notification::SetTrace,
|
SetTraceParams, TraceValue, notification::SetTrace,
|
||||||
};
|
};
|
||||||
use project::{Project, WorktreeId, search::SearchQuery};
|
use project::{Project, WorktreeId, lsp_store::LanguageServerLogType, search::SearchQuery};
|
||||||
use std::{any::TypeId, borrow::Cow, sync::Arc};
|
use std::{any::TypeId, borrow::Cow, sync::Arc};
|
||||||
use ui::{Button, Checkbox, ContextMenu, Label, PopoverMenu, ToggleState, prelude::*};
|
use ui::{Button, Checkbox, ContextMenu, Label, PopoverMenu, ToggleState, prelude::*};
|
||||||
|
use util::ResultExt as _;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceId,
|
SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, WorkspaceId,
|
||||||
item::{Item, ItemHandle},
|
item::{Item, ItemHandle},
|
||||||
|
@ -36,7 +37,7 @@ pub struct LogStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProjectState {
|
struct ProjectState {
|
||||||
_subscriptions: [gpui::Subscription; 2],
|
_subscriptions: [gpui::Subscription; 3],
|
||||||
}
|
}
|
||||||
|
|
||||||
trait Message: AsRef<str> {
|
trait Message: AsRef<str> {
|
||||||
|
@ -102,6 +103,7 @@ impl Message for RpcMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) struct LanguageServerState {
|
pub(super) struct LanguageServerState {
|
||||||
|
project: WeakEntity<Project>,
|
||||||
name: Option<LanguageServerName>,
|
name: Option<LanguageServerName>,
|
||||||
worktree_id: Option<WorktreeId>,
|
worktree_id: Option<WorktreeId>,
|
||||||
kind: LanguageServerKind,
|
kind: LanguageServerKind,
|
||||||
|
@ -183,6 +185,13 @@ pub enum LogKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogKind {
|
impl LogKind {
|
||||||
|
fn from_server_log_type(log_type: &LanguageServerLogType) -> Self {
|
||||||
|
match log_type {
|
||||||
|
LanguageServerLogType::Log(_) => Self::Logs,
|
||||||
|
LanguageServerLogType::Trace(_) => Self::Trace,
|
||||||
|
LanguageServerLogType::Rpc { .. } => Self::Rpc,
|
||||||
|
}
|
||||||
|
}
|
||||||
fn label(&self) -> &'static str {
|
fn label(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
LogKind::Rpc => RPC_MESSAGES,
|
LogKind::Rpc => RPC_MESSAGES,
|
||||||
|
@ -212,10 +221,11 @@ actions!(
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
pub(super) struct GlobalLogStore(pub WeakEntity<LogStore>);
|
pub struct GlobalLogStore(pub WeakEntity<LogStore>);
|
||||||
|
|
||||||
impl Global for GlobalLogStore {}
|
impl Global for GlobalLogStore {}
|
||||||
|
|
||||||
|
// todo! do separate headless and local cases here: headless cares only about the downstream_client() part, NO log storage is needed
|
||||||
pub fn init(cx: &mut App) {
|
pub fn init(cx: &mut App) {
|
||||||
let log_store = cx.new(LogStore::new);
|
let log_store = cx.new(LogStore::new);
|
||||||
cx.set_global(GlobalLogStore(log_store.downgrade()));
|
cx.set_global(GlobalLogStore(log_store.downgrade()));
|
||||||
|
@ -311,6 +321,7 @@ impl LogStore {
|
||||||
|
|
||||||
pub fn add_project(&mut self, project: &Entity<Project>, cx: &mut Context<Self>) {
|
pub fn add_project(&mut self, project: &Entity<Project>, cx: &mut Context<Self>) {
|
||||||
let weak_project = project.downgrade();
|
let weak_project = project.downgrade();
|
||||||
|
let subscription_weak_project = weak_project.clone();
|
||||||
self.projects.insert(
|
self.projects.insert(
|
||||||
project.downgrade(),
|
project.downgrade(),
|
||||||
ProjectState {
|
ProjectState {
|
||||||
|
@ -356,13 +367,42 @@ impl LogStore {
|
||||||
this.add_language_server_log(*id, *typ, message, cx);
|
this.add_language_server_log(*id, *typ, message, cx);
|
||||||
}
|
}
|
||||||
project::LanguageServerLogType::Trace(_) => {
|
project::LanguageServerLogType::Trace(_) => {
|
||||||
|
// todo! do something with trace level
|
||||||
this.add_language_server_trace(*id, message, cx);
|
this.add_language_server_trace(*id, message, cx);
|
||||||
}
|
}
|
||||||
|
project::LanguageServerLogType::Rpc { received } => {
|
||||||
|
let kind = if *received {
|
||||||
|
MessageKind::Receive
|
||||||
|
} else {
|
||||||
|
MessageKind::Send
|
||||||
|
};
|
||||||
|
this.add_language_server_rpc(*id, kind, message, cx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
cx.subscribe_self(move |_, e, cx| match e {
|
||||||
|
Event::NewServerLogEntry { id, kind, text } => {
|
||||||
|
subscription_weak_project
|
||||||
|
.update(cx, |project, cx| {
|
||||||
|
if let Some((client, project_id)) =
|
||||||
|
project.lsp_store().read(cx).downstream_client()
|
||||||
|
{
|
||||||
|
client
|
||||||
|
.send(proto::LanguageServerLog {
|
||||||
|
project_id,
|
||||||
|
language_server_id: id.to_proto(),
|
||||||
|
message: text.clone(),
|
||||||
|
log_type: Some(kind.to_proto()),
|
||||||
|
})
|
||||||
|
.log_err();
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -382,6 +422,7 @@ impl LogStore {
|
||||||
name: Option<LanguageServerName>,
|
name: Option<LanguageServerName>,
|
||||||
worktree_id: Option<WorktreeId>,
|
worktree_id: Option<WorktreeId>,
|
||||||
server: Option<Arc<LanguageServer>>,
|
server: Option<Arc<LanguageServer>>,
|
||||||
|
project: WeakEntity<Project>,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Option<&mut LanguageServerState> {
|
) -> Option<&mut LanguageServerState> {
|
||||||
let server_state = self.language_servers.entry(server_id).or_insert_with(|| {
|
let server_state = self.language_servers.entry(server_id).or_insert_with(|| {
|
||||||
|
@ -390,6 +431,7 @@ impl LogStore {
|
||||||
name: None,
|
name: None,
|
||||||
worktree_id: None,
|
worktree_id: None,
|
||||||
kind,
|
kind,
|
||||||
|
project,
|
||||||
rpc_state: None,
|
rpc_state: None,
|
||||||
log_messages: VecDeque::with_capacity(MAX_STORED_LOG_ENTRIES),
|
log_messages: VecDeque::with_capacity(MAX_STORED_LOG_ENTRIES),
|
||||||
trace_messages: VecDeque::with_capacity(MAX_STORED_LOG_ENTRIES),
|
trace_messages: VecDeque::with_capacity(MAX_STORED_LOG_ENTRIES),
|
||||||
|
@ -429,17 +471,21 @@ impl LogStore {
|
||||||
let language_server_state = self.get_language_server_state(id)?;
|
let language_server_state = self.get_language_server_state(id)?;
|
||||||
|
|
||||||
let log_lines = &mut language_server_state.log_messages;
|
let log_lines = &mut language_server_state.log_messages;
|
||||||
Self::add_language_server_message(
|
if let Some(new_message) = Self::push_new_message(
|
||||||
log_lines,
|
log_lines,
|
||||||
id,
|
|
||||||
LogMessage {
|
LogMessage {
|
||||||
message: message.trim_end().to_string(),
|
message: message.trim_end().to_string(),
|
||||||
typ,
|
typ,
|
||||||
},
|
},
|
||||||
language_server_state.log_level,
|
language_server_state.log_level,
|
||||||
LogKind::Logs,
|
) {
|
||||||
cx,
|
cx.emit(Event::NewServerLogEntry {
|
||||||
);
|
id,
|
||||||
|
kind: LanguageServerLogType::Log(typ),
|
||||||
|
text: new_message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,38 +498,81 @@ impl LogStore {
|
||||||
let language_server_state = self.get_language_server_state(id)?;
|
let language_server_state = self.get_language_server_state(id)?;
|
||||||
|
|
||||||
let log_lines = &mut language_server_state.trace_messages;
|
let log_lines = &mut language_server_state.trace_messages;
|
||||||
Self::add_language_server_message(
|
if let Some(new_message) = Self::push_new_message(
|
||||||
log_lines,
|
log_lines,
|
||||||
id,
|
|
||||||
TraceMessage {
|
TraceMessage {
|
||||||
message: message.trim().to_string(),
|
message: message.trim().to_string(),
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
LogKind::Trace,
|
) {
|
||||||
cx,
|
cx.emit(Event::NewServerLogEntry {
|
||||||
);
|
id,
|
||||||
|
// todo! Ben, fix this here too!
|
||||||
|
kind: LanguageServerLogType::Trace(project::lsp_store::TraceLevel::Verbose),
|
||||||
|
text: new_message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Some(())
|
Some(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_language_server_message<T: Message>(
|
fn push_new_message<T: Message>(
|
||||||
log_lines: &mut VecDeque<T>,
|
log_lines: &mut VecDeque<T>,
|
||||||
id: LanguageServerId,
|
|
||||||
message: T,
|
message: T,
|
||||||
current_severity: <T as Message>::Level,
|
current_severity: <T as Message>::Level,
|
||||||
kind: LogKind,
|
) -> Option<String> {
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) {
|
|
||||||
while log_lines.len() + 1 >= MAX_STORED_LOG_ENTRIES {
|
while log_lines.len() + 1 >= MAX_STORED_LOG_ENTRIES {
|
||||||
log_lines.pop_front();
|
log_lines.pop_front();
|
||||||
}
|
}
|
||||||
let text = message.as_ref().to_string();
|
|
||||||
let visible = message.should_include(current_severity);
|
let visible = message.should_include(current_severity);
|
||||||
log_lines.push_back(message);
|
|
||||||
|
|
||||||
if visible {
|
let re = visible.then(|| message.as_ref().to_string());
|
||||||
cx.emit(Event::NewServerLogEntry { id, kind, text });
|
log_lines.push_back(message);
|
||||||
cx.notify();
|
re
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_language_server_rpc(
|
||||||
|
&mut self,
|
||||||
|
language_server_id: LanguageServerId,
|
||||||
|
kind: MessageKind,
|
||||||
|
message: &str,
|
||||||
|
cx: &mut Context<'_, LogStore>,
|
||||||
|
) {
|
||||||
|
let Some(state) = self
|
||||||
|
.get_language_server_state(language_server_id)
|
||||||
|
.and_then(|state| state.rpc_state.as_mut())
|
||||||
|
else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let rpc_log_lines = &mut state.rpc_messages;
|
||||||
|
if state.last_message_kind != Some(kind) {
|
||||||
|
while rpc_log_lines.len() + 1 >= MAX_STORED_LOG_ENTRIES {
|
||||||
|
rpc_log_lines.pop_front();
|
||||||
|
}
|
||||||
|
let line_before_message = match kind {
|
||||||
|
MessageKind::Send => SEND_LINE,
|
||||||
|
MessageKind::Receive => RECEIVE_LINE,
|
||||||
|
};
|
||||||
|
rpc_log_lines.push_back(RpcMessage {
|
||||||
|
message: line_before_message.to_string(),
|
||||||
|
});
|
||||||
|
cx.emit(Event::NewServerLogEntry {
|
||||||
|
id: language_server_id,
|
||||||
|
kind: LanguageServerLogType::Rpc {
|
||||||
|
received: kind == MessageKind::Receive,
|
||||||
|
},
|
||||||
|
text: line_before_message.to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while rpc_log_lines.len() + 1 >= MAX_STORED_LOG_ENTRIES {
|
||||||
|
rpc_log_lines.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
rpc_log_lines.push_back(RpcMessage {
|
||||||
|
message: message.trim().to_owned(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_language_server(&mut self, id: LanguageServerId, cx: &mut Context<Self>) {
|
fn remove_language_server(&mut self, id: LanguageServerId, cx: &mut Context<Self>) {
|
||||||
|
@ -520,7 +609,7 @@ impl LogStore {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_rpc_trace_for_language_server(
|
pub fn enable_rpc_trace_for_language_server(
|
||||||
&mut self,
|
&mut self,
|
||||||
server_id: LanguageServerId,
|
server_id: LanguageServerId,
|
||||||
) -> Option<&mut LanguageServerRpcState> {
|
) -> Option<&mut LanguageServerRpcState> {
|
||||||
|
@ -663,47 +752,19 @@ impl LogStore {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = self
|
|
||||||
.get_language_server_state(language_server_id)?
|
|
||||||
.rpc_state
|
|
||||||
.as_mut()?;
|
|
||||||
let kind = if is_received {
|
let kind = if is_received {
|
||||||
MessageKind::Receive
|
MessageKind::Receive
|
||||||
} else {
|
} else {
|
||||||
MessageKind::Send
|
MessageKind::Send
|
||||||
};
|
};
|
||||||
|
|
||||||
let rpc_log_lines = &mut state.rpc_messages;
|
self.add_language_server_rpc(language_server_id, kind, message, cx);
|
||||||
if state.last_message_kind != Some(kind) {
|
|
||||||
while rpc_log_lines.len() + 1 >= MAX_STORED_LOG_ENTRIES {
|
|
||||||
rpc_log_lines.pop_front();
|
|
||||||
}
|
|
||||||
let line_before_message = match kind {
|
|
||||||
MessageKind::Send => SEND_LINE,
|
|
||||||
MessageKind::Receive => RECEIVE_LINE,
|
|
||||||
};
|
|
||||||
rpc_log_lines.push_back(RpcMessage {
|
|
||||||
message: line_before_message.to_string(),
|
|
||||||
});
|
|
||||||
cx.emit(Event::NewServerLogEntry {
|
|
||||||
id: language_server_id,
|
|
||||||
kind: LogKind::Rpc,
|
|
||||||
text: line_before_message.to_string(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
while rpc_log_lines.len() + 1 >= MAX_STORED_LOG_ENTRIES {
|
|
||||||
rpc_log_lines.pop_front();
|
|
||||||
}
|
|
||||||
|
|
||||||
let message = message.trim();
|
|
||||||
rpc_log_lines.push_back(RpcMessage {
|
|
||||||
message: message.to_string(),
|
|
||||||
});
|
|
||||||
cx.emit(Event::NewServerLogEntry {
|
cx.emit(Event::NewServerLogEntry {
|
||||||
id: language_server_id,
|
id: language_server_id,
|
||||||
kind: LogKind::Rpc,
|
kind: LanguageServerLogType::Rpc {
|
||||||
text: message.to_string(),
|
received: is_received,
|
||||||
|
},
|
||||||
|
text: message.to_owned(),
|
||||||
});
|
});
|
||||||
cx.notify();
|
cx.notify();
|
||||||
Some(())
|
Some(())
|
||||||
|
@ -757,7 +818,7 @@ impl LspLogView {
|
||||||
move |log_view, _, e, window, cx| match e {
|
move |log_view, _, e, window, cx| match e {
|
||||||
Event::NewServerLogEntry { id, kind, text } => {
|
Event::NewServerLogEntry { id, kind, text } => {
|
||||||
if log_view.current_server_id == Some(*id)
|
if log_view.current_server_id == Some(*id)
|
||||||
&& *kind == log_view.active_entry_kind
|
&& LogKind::from_server_log_type(kind) == log_view.active_entry_kind
|
||||||
{
|
{
|
||||||
log_view.editor.update(cx, |editor, cx| {
|
log_view.editor.update(cx, |editor, cx| {
|
||||||
editor.set_read_only(false);
|
editor.set_read_only(false);
|
||||||
|
@ -1075,6 +1136,21 @@ impl LspLogView {
|
||||||
} else {
|
} else {
|
||||||
log_store.disable_rpc_trace_for_language_server(server_id);
|
log_store.disable_rpc_trace_for_language_server(server_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(server_state) = log_store.language_servers.get(server_id) {
|
||||||
|
server_state
|
||||||
|
.project
|
||||||
|
.update(cx, |project, cx| {
|
||||||
|
if let Some((client, project)) =
|
||||||
|
project.lsp_store().read(cx).upstream_client()
|
||||||
|
{
|
||||||
|
// todo! client.send a new proto message to propagate the enabled
|
||||||
|
// !!!! we have to have a handler on both headless and normal projects
|
||||||
|
// that handler has to touch the Global<LspLog> and amend the sending bit
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ok();
|
||||||
|
};
|
||||||
});
|
});
|
||||||
if !enabled && Some(server_id) == self.current_server_id {
|
if !enabled && Some(server_id) == self.current_server_id {
|
||||||
self.show_logs_for_server(server_id, window, cx);
|
self.show_logs_for_server(server_id, window, cx);
|
||||||
|
@ -1113,6 +1189,8 @@ impl LspLogView {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
|
// todo! there's no language server for the remote case, hence no server info!
|
||||||
|
// BUT we do have the capabilities info within the LspStore.lsp_server_capabilities
|
||||||
let lsp_store = self.project.read(cx).lsp_store();
|
let lsp_store = self.project.read(cx).lsp_store();
|
||||||
let Some(server) = lsp_store.read(cx).language_server_for_id(server_id) else {
|
let Some(server) = lsp_store.read(cx).language_server_for_id(server_id) else {
|
||||||
return;
|
return;
|
||||||
|
@ -1737,7 +1815,7 @@ impl LspLogToolbarItemView {
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
NewServerLogEntry {
|
NewServerLogEntry {
|
||||||
id: LanguageServerId,
|
id: LanguageServerId,
|
||||||
kind: LogKind,
|
kind: LanguageServerLogType,
|
||||||
text: String,
|
text: String,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -122,8 +122,7 @@ impl LanguageServerState {
|
||||||
let lsp_logs = cx
|
let lsp_logs = cx
|
||||||
.try_global::<GlobalLogStore>()
|
.try_global::<GlobalLogStore>()
|
||||||
.and_then(|lsp_logs| lsp_logs.0.upgrade());
|
.and_then(|lsp_logs| lsp_logs.0.upgrade());
|
||||||
let lsp_store = self.lsp_store.upgrade();
|
let Some(lsp_logs) = lsp_logs else {
|
||||||
let Some((lsp_logs, lsp_store)) = lsp_logs.zip(lsp_store) else {
|
|
||||||
return menu;
|
return menu;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -210,10 +209,7 @@ impl LanguageServerState {
|
||||||
};
|
};
|
||||||
|
|
||||||
let server_selector = server_info.server_selector();
|
let server_selector = server_info.server_selector();
|
||||||
// TODO currently, Zed remote does not work well with the LSP logs
|
let has_logs = lsp_logs.read(cx).has_server_logs(&server_selector);
|
||||||
// https://github.com/zed-industries/zed/issues/28557
|
|
||||||
let has_logs = lsp_store.read(cx).as_local().is_some()
|
|
||||||
&& lsp_logs.read(cx).has_server_logs(&server_selector);
|
|
||||||
|
|
||||||
let status_color = server_info
|
let status_color = server_info
|
||||||
.binary_status
|
.binary_status
|
||||||
|
|
|
@ -977,7 +977,13 @@ impl LocalLspStore {
|
||||||
this.update(&mut cx, |_, cx| {
|
this.update(&mut cx, |_, cx| {
|
||||||
cx.emit(LspStoreEvent::LanguageServerLog(
|
cx.emit(LspStoreEvent::LanguageServerLog(
|
||||||
server_id,
|
server_id,
|
||||||
LanguageServerLogType::Trace(params.verbose),
|
// todo! store verbose info on Verbose
|
||||||
|
LanguageServerLogType::Trace(
|
||||||
|
params
|
||||||
|
.verbose
|
||||||
|
.map(|_verbose_info| TraceLevel::Verbose)
|
||||||
|
.unwrap_or(TraceLevel::Messages),
|
||||||
|
),
|
||||||
params.message,
|
params.message,
|
||||||
));
|
));
|
||||||
})
|
})
|
||||||
|
@ -12168,6 +12174,10 @@ impl LspStore {
|
||||||
let data = self.lsp_code_lens.get_mut(&buffer_id)?;
|
let data = self.lsp_code_lens.get_mut(&buffer_id)?;
|
||||||
Some(data.update.take()?.1)
|
Some(data.update.take()?.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn downstream_client(&self) -> Option<(AnyProtoClient, u64)> {
|
||||||
|
self.downstream_client.clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Registration with registerOptions as null, should fallback to true.
|
// Registration with registerOptions as null, should fallback to true.
|
||||||
|
@ -12674,48 +12684,92 @@ impl PartialEq for LanguageServerPromptRequest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub enum TraceLevel {
|
||||||
|
Off,
|
||||||
|
Messages,
|
||||||
|
Verbose,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum LanguageServerLogType {
|
pub enum LanguageServerLogType {
|
||||||
Log(MessageType),
|
Log(MessageType),
|
||||||
Trace(Option<String>),
|
Trace(TraceLevel),
|
||||||
|
Rpc { received: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LanguageServerLogType {
|
impl LanguageServerLogType {
|
||||||
pub fn to_proto(&self) -> proto::language_server_log::LogType {
|
pub fn to_proto(&self) -> proto::language_server_log::LogType {
|
||||||
match self {
|
match self {
|
||||||
Self::Log(log_type) => {
|
Self::Log(log_type) => {
|
||||||
let message_type = match *log_type {
|
use proto::log_message::LogLevel;
|
||||||
MessageType::ERROR => 1,
|
let level = match *log_type {
|
||||||
MessageType::WARNING => 2,
|
MessageType::ERROR => LogLevel::Error,
|
||||||
MessageType::INFO => 3,
|
MessageType::WARNING => LogLevel::Warning,
|
||||||
MessageType::LOG => 4,
|
MessageType::INFO => LogLevel::Info,
|
||||||
|
MessageType::LOG => LogLevel::Log,
|
||||||
other => {
|
other => {
|
||||||
log::warn!("Unknown lsp log message type: {:?}", other);
|
log::warn!("Unknown lsp log message type: {other:?}");
|
||||||
4
|
LogLevel::Log
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
proto::language_server_log::LogType::LogMessageType(message_type)
|
proto::language_server_log::LogType::Log(proto::LogMessage {
|
||||||
}
|
level: level as i32,
|
||||||
Self::Trace(message) => {
|
|
||||||
proto::language_server_log::LogType::LogTrace(proto::LspLogTrace {
|
|
||||||
message: message.clone(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Self::Trace(trace_level) => {
|
||||||
|
use proto::trace_message;
|
||||||
|
let level = match trace_level {
|
||||||
|
TraceLevel::Off => trace_message::TraceLevel::Off,
|
||||||
|
TraceLevel::Messages => trace_message::TraceLevel::Messages,
|
||||||
|
TraceLevel::Verbose => trace_message::TraceLevel::Verbose,
|
||||||
|
};
|
||||||
|
proto::language_server_log::LogType::Trace(proto::TraceMessage {
|
||||||
|
level: level as i32,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Self::Rpc { received } => {
|
||||||
|
let kind = if *received {
|
||||||
|
proto::rpc_message::Kind::Received
|
||||||
|
} else {
|
||||||
|
proto::rpc_message::Kind::Sent
|
||||||
|
};
|
||||||
|
let kind = kind as i32;
|
||||||
|
proto::language_server_log::LogType::Rpc(proto::RpcMessage { kind })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
|
pub fn from_proto(log_type: proto::language_server_log::LogType) -> Self {
|
||||||
|
use proto::log_message::LogLevel;
|
||||||
|
use proto::rpc_message;
|
||||||
|
use proto::trace_message;
|
||||||
match log_type {
|
match log_type {
|
||||||
proto::language_server_log::LogType::LogMessageType(message_type) => {
|
proto::language_server_log::LogType::Log(message_type) => Self::Log(
|
||||||
Self::Log(match message_type {
|
match LogLevel::from_i32(message_type.level).unwrap_or(LogLevel::Log) {
|
||||||
1 => MessageType::ERROR,
|
LogLevel::Error => MessageType::ERROR,
|
||||||
2 => MessageType::WARNING,
|
LogLevel::Warning => MessageType::WARNING,
|
||||||
3 => MessageType::INFO,
|
LogLevel::Info => MessageType::INFO,
|
||||||
4 => MessageType::LOG,
|
LogLevel::Log => MessageType::LOG,
|
||||||
_ => MessageType::LOG,
|
},
|
||||||
})
|
),
|
||||||
}
|
proto::language_server_log::LogType::Trace(trace) => Self::Trace(
|
||||||
proto::language_server_log::LogType::LogTrace(trace) => Self::Trace(trace.message),
|
match trace_message::TraceLevel::from_i32(trace.level)
|
||||||
|
.unwrap_or(trace_message::TraceLevel::Messages)
|
||||||
|
{
|
||||||
|
trace_message::TraceLevel::Off => TraceLevel::Off,
|
||||||
|
trace_message::TraceLevel::Messages => TraceLevel::Messages,
|
||||||
|
trace_message::TraceLevel::Verbose => TraceLevel::Verbose,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
proto::language_server_log::LogType::Rpc(message) => Self::Rpc {
|
||||||
|
received: match rpc_message::Kind::from_i32(message.kind)
|
||||||
|
.unwrap_or(rpc_message::Kind::Received)
|
||||||
|
{
|
||||||
|
rpc_message::Kind::Received => true,
|
||||||
|
rpc_message::Kind::Sent => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -610,11 +610,42 @@ message ServerMetadataUpdated {
|
||||||
message LanguageServerLog {
|
message LanguageServerLog {
|
||||||
uint64 project_id = 1;
|
uint64 project_id = 1;
|
||||||
uint64 language_server_id = 2;
|
uint64 language_server_id = 2;
|
||||||
|
string message = 3;
|
||||||
oneof log_type {
|
oneof log_type {
|
||||||
uint32 log_message_type = 3;
|
LogMessage log = 4;
|
||||||
LspLogTrace log_trace = 4;
|
TraceMessage trace = 5;
|
||||||
|
RpcMessage rpc = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message LogMessage {
|
||||||
|
LogLevel level = 1;
|
||||||
|
|
||||||
|
enum LogLevel {
|
||||||
|
LOG = 0;
|
||||||
|
INFO = 1;
|
||||||
|
WARNING = 2;
|
||||||
|
ERROR = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message TraceMessage {
|
||||||
|
TraceLevel level = 1;
|
||||||
|
|
||||||
|
enum TraceLevel {
|
||||||
|
OFF = 0;
|
||||||
|
MESSAGES = 1;
|
||||||
|
VERBOSE = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message RpcMessage {
|
||||||
|
Kind kind = 1;
|
||||||
|
|
||||||
|
enum Kind {
|
||||||
|
RECEIVED = 0;
|
||||||
|
SENT = 1;
|
||||||
}
|
}
|
||||||
string message = 5;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message LspLogTrace {
|
message LspLogTrace {
|
||||||
|
|
|
@ -43,6 +43,7 @@ gpui_tokio.workspace = true
|
||||||
http_client.workspace = true
|
http_client.workspace = true
|
||||||
language.workspace = true
|
language.workspace = true
|
||||||
language_extension.workspace = true
|
language_extension.workspace = true
|
||||||
|
language_tools.workspace = true
|
||||||
languages.workspace = true
|
languages.workspace = true
|
||||||
log.workspace = true
|
log.workspace = true
|
||||||
lsp.workspace = true
|
lsp.workspace = true
|
||||||
|
|
|
@ -65,6 +65,13 @@ impl HeadlessProject {
|
||||||
settings::init(cx);
|
settings::init(cx);
|
||||||
language::init(cx);
|
language::init(cx);
|
||||||
project::Project::init_settings(cx);
|
project::Project::init_settings(cx);
|
||||||
|
// todo! what to do with the RPC log spam?
|
||||||
|
// if we have not enabled RPC logging on the remote client, we do not need these
|
||||||
|
//
|
||||||
|
// Maybe, add another RPC message, proto::ToggleRpcLogging(bool)
|
||||||
|
// and send it into the upstream client from the remotes, so that the local/headless counterpart
|
||||||
|
// can access this Global<LspLog> and toggle the spam send
|
||||||
|
language_tools::lsp_log::init(cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue