language_tools: Split LSP log view selector into two (#21742)

This should make it easier to interact with LSP log view when there are
multiple language servers. I often find the current UI clunky when I
have over 5 servers running (which isn't uncommon with multiple projects
open)


https://github.com/user-attachments/assets/2ecaf17f-4b40-4c8f-aa6f-03b437a3d979


Closes #ISSUE

Release Notes:

- N/A
This commit is contained in:
Piotr Osiewicz 2024-12-09 14:10:11 +01:00 committed by GitHub
parent a7d12eea39
commit 39e8944dcc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1145,19 +1145,28 @@ impl Render for LspLogToolbarItemView {
None
}
});
let available_language_servers: Vec<_> = menu_rows
.iter()
.map(|row| {
(
row.server_id,
row.server_name.clone(),
row.worktree_root_name.clone(),
row.selected_entry,
)
})
.collect();
let log_toolbar_view = cx.view().clone();
let lsp_menu = PopoverMenu::new("LspLogView")
.anchor(AnchorCorner::TopLeft)
.trigger(Button::new(
"language_server_menu_header",
current_server
.as_ref()
.map(|row| {
Cow::Owned(format!(
"{} ({}) - {}",
row.server_name.0,
row.worktree_root_name,
row.selected_entry.label()
"{} ({})",
row.server_name.0, row.worktree_root_name,
))
})
.unwrap_or_else(|| "No server selected".into()),
@ -1165,36 +1174,71 @@ impl Render for LspLogToolbarItemView {
.menu({
let log_view = log_view.clone();
move |cx| {
let menu_rows = menu_rows.clone();
let log_view = log_view.clone();
let log_toolbar_view = log_toolbar_view.clone();
ContextMenu::build(cx, move |mut menu, cx| {
for (ix, row) in menu_rows.into_iter().enumerate() {
let server_selected = Some(row.server_id) == current_server_id;
menu = menu
.header(format!(
"{} ({})",
row.server_name.0, row.worktree_root_name
ContextMenu::build(cx, |mut menu, cx| {
for (server_id, name, worktree_root, active_entry_kind) in
available_language_servers.iter()
{
let label = format!("{} ({})", name, worktree_root);
let server_id = *server_id;
let active_entry_kind = *active_entry_kind;
menu = menu.entry(
label,
None,
cx.handler_for(&log_view, move |view, cx| {
view.current_server_id = Some(server_id);
view.active_entry_kind = active_entry_kind;
match view.active_entry_kind {
LogKind::Rpc => {
view.toggle_rpc_trace_for_server(server_id, true, cx);
view.show_rpc_trace_for_server(server_id, cx);
}
LogKind::Trace => view.show_trace_for_server(server_id, cx),
LogKind::Logs => view.show_logs_for_server(server_id, cx),
LogKind::Capabilities => {
view.show_capabilities_for_server(server_id, cx)
}
}
cx.notify();
}),
);
}
menu
})
.into()
}
});
let view_selector = current_server.map(|server| {
let server_id = server.server_id;
let is_remote = server.server_kind.is_remote();
let rpc_trace_enabled = server.rpc_trace_enabled;
let log_view = log_view.clone();
PopoverMenu::new("LspViewSelector")
.anchor(AnchorCorner::TopLeft)
.trigger(Button::new(
"language_server_menu_header",
server.selected_entry.label(),
))
.entry(
.menu(move |cx| {
let log_toolbar_view = log_toolbar_view.clone();
let log_view = log_view.clone();
Some(ContextMenu::build(cx, move |this, cx| {
this.entry(
SERVER_LOGS,
None,
cx.handler_for(&log_view, move |view, cx| {
view.show_logs_for_server(row.server_id, cx);
view.show_logs_for_server(server_id, cx);
}),
);
// We do not support tracing for remote language servers right now
if row.server_kind.is_remote() {
continue;
}
menu = menu.entry(
)
.when(!is_remote, |this| {
this.entry(
SERVER_TRACE,
None,
cx.handler_for(&log_view, move |view, cx| {
view.show_trace_for_server(row.server_id, cx);
view.show_trace_for_server(server_id, cx);
}),
);
menu = menu.custom_entry(
)
.custom_entry(
{
let log_toolbar_view = log_toolbar_view.clone();
move |cx| {
@ -1205,8 +1249,8 @@ impl Render for LspLogToolbarItemView {
.child(
div().child(
Checkbox::new(
ix,
if row.rpc_trace_enabled {
"LspLogEnableRpcTrace",
if rpc_trace_enabled {
Selection::Selected
} else {
Selection::Unselected
@ -1220,9 +1264,7 @@ impl Render for LspLogToolbarItemView {
Selection::Selected
);
view.toggle_rpc_logging_for_server(
row.server_id,
enabled,
cx,
server_id, enabled, cx,
);
cx.stop_propagation();
},
@ -1233,61 +1275,27 @@ impl Render for LspLogToolbarItemView {
}
},
cx.handler_for(&log_view, move |view, cx| {
view.show_rpc_trace_for_server(row.server_id, cx);
view.show_rpc_trace_for_server(server_id, cx);
}),
);
if server_selected && row.selected_entry == LogKind::Rpc {
let selected_ix = menu.select_last();
// Each language server has:
// 1. A title.
// 2. Server logs.
// 3. Server trace.
// 4. RPC messages.
// 5. Server capabilities
// Thus, if nth server's RPC is selected, the index of selected entry should match this formula
let _expected_index = ix * 5 + 3;
debug_assert_eq!(
Some(_expected_index),
selected_ix,
"Could not scroll to a just added LSP menu item"
);
}
menu = menu.entry(
)
})
.entry(
SERVER_CAPABILITIES,
None,
cx.handler_for(&log_view, move |view, cx| {
view.show_capabilities_for_server(row.server_id, cx);
view.show_capabilities_for_server(server_id, cx);
}),
);
}
menu
)
}))
})
.into()
}
});
h_flex()
.size_full()
.justify_between()
.child(
h_flex()
.child(lsp_menu)
.child(
div()
.child(
Button::new("clear_log_button", "Clear").on_click(cx.listener(
|this, _, cx| {
if let Some(log_view) = this.log_view.as_ref() {
log_view.update(cx, |log_view, cx| {
log_view.editor.update(cx, |editor, cx| {
editor.set_read_only(false);
editor.clear(cx);
editor.set_read_only(true);
});
})
}
},
)),
)
.ml_2(),
)
.children(view_selector)
.child(log_view.update(cx, |this, _| match this.active_entry_kind {
LogKind::Trace => {
let log_view = log_view.clone();
@ -1306,7 +1314,10 @@ impl Render for LspLogToolbarItemView {
let trace_level = log_view.update(cx, |this, cx| {
this.log_store.update(cx, |this, _| {
Some(this.get_language_server_state(id)?.trace_level)
Some(
this.get_language_server_state(id)?
.trace_level,
)
})
})?;
@ -1322,8 +1333,12 @@ impl Render for LspLogToolbarItemView {
let log_view = log_view.clone();
move |cx| {
log_view.update(cx, |this, cx| {
if let Some(id) = this.current_server_id {
this.update_trace_level(id, option, cx);
if let Some(id) =
this.current_server_id
{
this.update_trace_level(
id, option, cx,
);
}
});
}
@ -1357,7 +1372,10 @@ impl Render for LspLogToolbarItemView {
let log_level = log_view.update(cx, |this, cx| {
this.log_store.update(cx, |this, _| {
Some(this.get_language_server_state(id)?.log_level)
Some(
this.get_language_server_state(id)?
.log_level,
)
})
})?;
@ -1374,8 +1392,12 @@ impl Render for LspLogToolbarItemView {
let log_view = log_view.clone();
move |cx| {
log_view.update(cx, |this, cx| {
if let Some(id) = this.current_server_id {
this.update_log_level(id, option, cx);
if let Some(id) =
this.current_server_id
{
this.update_log_level(
id, option, cx,
);
}
});
}
@ -1393,7 +1415,27 @@ impl Render for LspLogToolbarItemView {
)
}
_ => div(),
}))
})),
)
.child(
div()
.child(
Button::new("clear_log_button", "Clear").on_click(cx.listener(
|this, _, cx| {
if let Some(log_view) = this.log_view.as_ref() {
log_view.update(cx, |log_view, cx| {
log_view.editor.update(cx, |editor, cx| {
editor.set_read_only(false);
editor.clear(cx);
editor.set_read_only(true);
});
})
}
},
)),
)
.ml_2(),
)
}
}