mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-10 20:29:05 +00:00
lsp_log: Add server capabilities view (#19448)
Hello, this PR adds a new view to the LSP servers menu for displaying an LSP server capabilities. When I work on LSP stuff, quite often I need to check what capabilities an LSP server has. Currently there is no built-in way for checking that in Zed, and I have to use [`LSP DevTools`](https://lsp-devtools.readthedocs.io) project. LSP DevTools works OK but it works as a proxy between the client and the server, so setting it up is not that easy in Zed. Zed already has many goodies for LSP like tracing and RPC messages, so I thought that a simple view with server capabilities could be useful too. Thanks! ## Some screenshots: ### Ruby LSP ![CleanShot 2024-10-19 at 07 44 38@2x](https://github.com/user-attachments/assets/22c97b49-c539-4e39-a5f1-1c926347abca) ### New menu entry: ![CleanShot 2024-10-19 at 07 45 08@2x](https://github.com/user-attachments/assets/d3903d6e-c09a-40e2-b042-1abde490987d) Release Notes: - N/A
This commit is contained in:
parent
d53a86b01d
commit
375bc88f95
1 changed files with 79 additions and 2 deletions
|
@ -9,7 +9,8 @@ use gpui::{
|
|||
};
|
||||
use language::{LanguageServerId, LanguageServerName};
|
||||
use lsp::{
|
||||
notification::SetTrace, IoKind, LanguageServer, MessageType, SetTraceParams, TraceValue,
|
||||
notification::SetTrace, IoKind, LanguageServer, MessageType, ServerCapabilities,
|
||||
SetTraceParams, TraceValue,
|
||||
};
|
||||
use project::{search::SearchQuery, Project, WorktreeId};
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
@ -107,6 +108,7 @@ struct LanguageServerState {
|
|||
rpc_state: Option<LanguageServerRpcState>,
|
||||
trace_level: TraceValue,
|
||||
log_level: MessageType,
|
||||
capabilities: ServerCapabilities,
|
||||
io_logs_subscription: Option<lsp::Subscription>,
|
||||
}
|
||||
|
||||
|
@ -176,6 +178,7 @@ pub enum LogKind {
|
|||
Trace,
|
||||
#[default]
|
||||
Logs,
|
||||
Capabilities,
|
||||
}
|
||||
|
||||
impl LogKind {
|
||||
|
@ -184,6 +187,7 @@ impl LogKind {
|
|||
LogKind::Rpc => RPC_MESSAGES,
|
||||
LogKind::Trace => SERVER_TRACE,
|
||||
LogKind::Logs => SERVER_LOGS,
|
||||
LogKind::Capabilities => SERVER_CAPABILITIES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -374,6 +378,7 @@ impl LogStore {
|
|||
trace_level: TraceValue::Off,
|
||||
log_level: MessageType::LOG,
|
||||
io_logs_subscription: None,
|
||||
capabilities: ServerCapabilities::default(),
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -384,7 +389,10 @@ impl LogStore {
|
|||
server_state.worktree_id = Some(worktree_id);
|
||||
}
|
||||
|
||||
if let Some(server) = server.filter(|_| server_state.io_logs_subscription.is_none()) {
|
||||
if let Some(server) = server
|
||||
.clone()
|
||||
.filter(|_| server_state.io_logs_subscription.is_none())
|
||||
{
|
||||
let io_tx = self.io_tx.clone();
|
||||
let server_id = server.server_id();
|
||||
server_state.io_logs_subscription = Some(server.on_io(move |io_kind, message| {
|
||||
|
@ -393,6 +401,11 @@ impl LogStore {
|
|||
.ok();
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(server) = server {
|
||||
server_state.capabilities = server.capabilities();
|
||||
}
|
||||
|
||||
Some(server_state)
|
||||
}
|
||||
|
||||
|
@ -477,6 +490,10 @@ impl LogStore {
|
|||
Some(&self.language_servers.get(&server_id)?.trace_messages)
|
||||
}
|
||||
|
||||
fn server_capabilities(&self, server_id: LanguageServerId) -> Option<&ServerCapabilities> {
|
||||
Some(&self.language_servers.get(&server_id)?.capabilities)
|
||||
}
|
||||
|
||||
fn server_ids_for_project<'a>(
|
||||
&'a self,
|
||||
lookup_project: &'a WeakModel<Project>,
|
||||
|
@ -602,6 +619,9 @@ impl LspLogView {
|
|||
LogKind::Rpc => this.show_rpc_trace_for_server(server_id, cx),
|
||||
LogKind::Trace => this.show_trace_for_server(server_id, cx),
|
||||
LogKind::Logs => this.show_logs_for_server(server_id, cx),
|
||||
LogKind::Capabilities => {
|
||||
this.show_capabilities_for_server(server_id, cx)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.current_server_id = None;
|
||||
|
@ -618,6 +638,7 @@ impl LspLogView {
|
|||
LogKind::Rpc => this.show_rpc_trace_for_server(server_id, cx),
|
||||
LogKind::Trace => this.show_trace_for_server(server_id, cx),
|
||||
LogKind::Logs => this.show_logs_for_server(server_id, cx),
|
||||
LogKind::Capabilities => this.show_capabilities_for_server(server_id, cx),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -695,6 +716,33 @@ impl LspLogView {
|
|||
(editor, vec![editor_subscription, search_subscription])
|
||||
}
|
||||
|
||||
fn editor_for_capabilities(
|
||||
capabilities: ServerCapabilities,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> (View<Editor>, Vec<Subscription>) {
|
||||
let editor = cx.new_view(|cx| {
|
||||
let mut editor = Editor::multi_line(cx);
|
||||
editor.set_text(serde_json::to_string_pretty(&capabilities).unwrap(), cx);
|
||||
editor.move_to_end(&MoveToEnd, cx);
|
||||
editor.set_read_only(true);
|
||||
editor.set_show_inline_completions(Some(false), cx);
|
||||
editor
|
||||
});
|
||||
let editor_subscription = cx.subscribe(
|
||||
&editor,
|
||||
|_, _, event: &EditorEvent, cx: &mut ViewContext<'_, LspLogView>| {
|
||||
cx.emit(event.clone())
|
||||
},
|
||||
);
|
||||
let search_subscription = cx.subscribe(
|
||||
&editor,
|
||||
|_, _, event: &SearchEvent, cx: &mut ViewContext<'_, LspLogView>| {
|
||||
cx.emit(event.clone())
|
||||
},
|
||||
);
|
||||
(editor, vec![editor_subscription, search_subscription])
|
||||
}
|
||||
|
||||
pub(crate) fn menu_items<'a>(&'a self, cx: &'a AppContext) -> Option<Vec<LogMenuItem>> {
|
||||
let log_store = self.log_store.read(cx);
|
||||
|
||||
|
@ -881,6 +929,7 @@ impl LspLogView {
|
|||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn update_trace_level(
|
||||
&self,
|
||||
server_id: LanguageServerId,
|
||||
|
@ -899,6 +948,25 @@ impl LspLogView {
|
|||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
fn show_capabilities_for_server(
|
||||
&mut self,
|
||||
server_id: LanguageServerId,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let capabilities = self.log_store.read(cx).server_capabilities(server_id);
|
||||
|
||||
if let Some(capabilities) = capabilities {
|
||||
self.current_server_id = Some(server_id);
|
||||
self.active_entry_kind = LogKind::Capabilities;
|
||||
let (editor, editor_subscriptions) =
|
||||
Self::editor_for_capabilities(capabilities.clone(), cx);
|
||||
self.editor = editor;
|
||||
self.editor_subscriptions = editor_subscriptions;
|
||||
cx.notify();
|
||||
}
|
||||
cx.focus(&self.focus_handle);
|
||||
}
|
||||
}
|
||||
|
||||
fn log_filter<T: Message>(line: &T, cmp: <T as Message>::Level) -> Option<&str> {
|
||||
|
@ -967,6 +1035,7 @@ impl Item for LspLogView {
|
|||
LogKind::Rpc => new_view.show_rpc_trace_for_server(server_id, cx),
|
||||
LogKind::Trace => new_view.show_trace_for_server(server_id, cx),
|
||||
LogKind::Logs => new_view.show_logs_for_server(server_id, cx),
|
||||
LogKind::Capabilities => new_view.show_capabilities_for_server(server_id, cx),
|
||||
}
|
||||
}
|
||||
new_view
|
||||
|
@ -1168,6 +1237,13 @@ impl Render for LspLogToolbarItemView {
|
|||
view.show_rpc_trace_for_server(row.server_id, cx);
|
||||
}),
|
||||
);
|
||||
menu = menu.entry(
|
||||
SERVER_CAPABILITIES,
|
||||
None,
|
||||
cx.handler_for(&log_view, move |view, cx| {
|
||||
view.show_capabilities_for_server(row.server_id, cx);
|
||||
}),
|
||||
);
|
||||
if server_selected && row.selected_entry == LogKind::Rpc {
|
||||
let selected_ix = menu.select_last();
|
||||
debug_assert_eq!(
|
||||
|
@ -1317,6 +1393,7 @@ impl Render for LspLogToolbarItemView {
|
|||
const RPC_MESSAGES: &str = "RPC Messages";
|
||||
const SERVER_LOGS: &str = "Server Logs";
|
||||
const SERVER_TRACE: &str = "Server Trace";
|
||||
const SERVER_CAPABILITIES: &str = "Server Capabilities";
|
||||
|
||||
impl Default for LspLogToolbarItemView {
|
||||
fn default() -> Self {
|
||||
|
|
Loading…
Reference in a new issue