diff --git a/crates/language_tools2/src/lsp_log.rs b/crates/language_tools2/src/lsp_log.rs index 06cdaf3bf93d5f9070dcbc600d6c78d18dca5640..3cff408280f0c345121822f0521424c4b5ece1cc 100644 --- a/crates/language_tools2/src/lsp_log.rs +++ b/crates/language_tools2/src/lsp_log.rs @@ -2,16 +2,18 @@ use collections::{HashMap, VecDeque}; use editor::{Editor, EditorElement, EditorEvent, MoveToEnd}; use futures::{channel::mpsc, StreamExt}; use gpui::{ - actions, div, overlay, red, AnyElement, AppContext, Context, CursorStyle, Div, EventEmitter, - FocusHandle, FocusableView, InteractiveElement, IntoElement, Model, ModelContext, MouseButton, - MouseDownEvent, ParentElement, Render, Styled, Subscription, View, ViewContext, VisualContext, + actions, div, red, AnchorCorner, AnyElement, AppContext, Context, CursorStyle, Div, + EventEmitter, FocusHandle, FocusableView, InteractiveElement, IntoElement, Model, ModelContext, + MouseButton, ParentElement, Render, Styled, Subscription, View, ViewContext, VisualContext, WeakModel, WindowContext, }; use language::{LanguageServerId, LanguageServerName}; use lsp::IoKind; use project::{search::SearchQuery, Project}; use std::{borrow::Cow, sync::Arc}; -use ui::{h_stack, v_stack, Checkbox, Label}; +use ui::{ + h_stack, popover_menu, v_stack, Button, Checkbox, Clickable, ContextMenu, Divider, Label, +}; use workspace::{ item::{Item, ItemHandle}, searchable::{SearchEvent, SearchableItem, SearchableItemHandle}, @@ -58,7 +60,6 @@ pub struct LspLogView { pub struct LspLogToolbarItemView { log_view: Option>, _log_view_subscription: Option, - menu_open: bool, } #[derive(Copy, Clone, PartialEq, Eq)] @@ -594,11 +595,6 @@ fn log_contents(lines: &VecDeque) -> String { } impl Render for LspLogView { - // todo!() - // fn ui_name() -> &'static str { - // "LspLogView" - // } - type Element = EditorElement; fn render(&mut self, cx: &mut ViewContext) -> Self::Element { @@ -697,7 +693,6 @@ impl ToolbarItemView for LspLogToolbarItemView { active_pane_item: Option<&dyn ItemHandle>, cx: &mut ViewContext, ) -> workspace::ToolbarItemLocation { - self.menu_open = false; if let Some(item) = active_pane_item { if let Some(log_view) = item.downcast::() { self.log_view = Some(log_view.clone()); @@ -715,13 +710,9 @@ impl ToolbarItemView for LspLogToolbarItemView { impl Render for LspLogToolbarItemView { type Element = Div; - // todo!() - // fn ui_name() -> &'static str { - // "LspLogView" - // } - fn render(&mut self, cx: &mut ViewContext) -> Div { - let Some(log_view) = self.log_view.as_ref() else { + fn render(&mut self, cx: &mut ViewContext) -> Self::Element { + let Some(log_view) = self.log_view.clone() else { return div(); }; let (menu_rows, current_server_id) = log_view.update(cx, |log_view, cx| { @@ -737,70 +728,63 @@ impl Render for LspLogToolbarItemView { None } }); - // todo!() styling - let _server_selected = current_server.is_some(); - let lsp_menu = h_stack() - .size_full() - .child(Self::render_language_server_menu_header(current_server, cx)) - .children(if self.menu_open { - Some( - overlay().child( - v_stack() - .size_full() - // todo!() - // .scrollable::(0, None, cx) - .children(menu_rows.into_iter().map(|row| { - Self::render_language_server_menu_item( - row.server_id, - row.server_name, - &row.worktree_root_name, - row.rpc_trace_enabled, - row.logs_selected, - row.rpc_trace_selected, - cx, - ) - })) - .on_mouse_down_out(cx.listener(|this, event: &MouseDownEvent, cx| { - if event.button == MouseButton::Left { - this.menu_open = false; - cx.notify() - } - })), - ), // todo!() - // .with_hoverable(true) - // .with_fit_mode(OverlayFitMode::SwitchAnchor) - // .with_anchor_corner(AnchorCorner::TopLeft) - ) - } else { - None - }) - .z_index(99); - - let log_cleanup_button = div() - .child(Label::new("Clear")) - .on_mouse_down( - MouseButton::Left, - cx.listener(move |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); - }); - }) + let lsp_menu = popover_menu("LspLogView") + .anchor(AnchorCorner::TopLeft) + .trigger(Self::render_language_server_menu_header(current_server)) + .menu(move |cx| { + let menu_rows = menu_rows.clone(); + let log_view = log_view.clone(); + ContextMenu::build(cx, move |mut menu, cx| { + for row in menu_rows { + menu = menu + .header(format!( + "{} ({})", + row.server_name.0, row.worktree_root_name + )) + .entry( + format!("{SERVER_LOGS} ({})", row.server_name.0), + |cx| { + dbg!("????????????????????"); + }, // cx.handler_for(&log_view, move |view, cx| { + // // todo!() why does not it work??? + // dbg!("~~~~~~~~~~~~~~~~~~~~~~~~~~??@@@#", row.server_id); + // view.show_logs_for_server(row.server_id, cx) + // }), + ) + // TODO kb custom element with checkbox & toggle logging for server + .entry( + format!("{RPC_MESSAGES} ({})", row.server_name.0), + |cx| { + dbg!("?????????????@@@@@@@@@@@@@@@"); + }, // cx.handler_for(&log_view, move |view, cx| { + // view.show_rpc_trace_for_server(row.server_id, cx) + // }), + ) } - }), - ) - .cursor(CursorStyle::PointingHand); + menu + }) + }); - h_stack() - .size_full() - .child(lsp_menu) - .child(log_cleanup_button) - .border_1() - .border_color(red()) + h_stack().size_full().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(), + ) } } @@ -810,17 +794,11 @@ const SERVER_LOGS: &str = "Server Logs"; impl LspLogToolbarItemView { pub fn new() -> Self { Self { - menu_open: false, log_view: None, _log_view_subscription: None, } } - fn toggle_menu(&mut self, cx: &mut ViewContext) { - self.menu_open = !self.menu_open; - cx.notify(); - } - fn toggle_logging_for_server( &mut self, id: LanguageServerId, @@ -842,7 +820,6 @@ impl LspLogToolbarItemView { fn show_logs_for_server(&mut self, id: LanguageServerId, cx: &mut ViewContext) { if let Some(log_view) = &self.log_view { log_view.update(cx, |view, cx| view.show_logs_for_server(id, cx)); - self.menu_open = false; cx.notify(); } } @@ -850,19 +827,16 @@ impl LspLogToolbarItemView { fn show_rpc_trace_for_server(&mut self, id: LanguageServerId, cx: &mut ViewContext) { if let Some(log_view) = &self.log_view { log_view.update(cx, |view, cx| view.show_rpc_trace_for_server(id, cx)); - self.menu_open = false; cx.notify(); } } - fn render_language_server_menu_header( - current_server: Option, - cx: &mut ViewContext, - ) -> Div { - let label: Cow = current_server - .and_then(|row| { - Some( - format!( + fn render_language_server_menu_header(current_server: Option) -> Button { + Button::new( + "language_server_menu_header", + current_server + .and_then(|row| { + Some(Cow::Owned(format!( "{} ({}) - {}", row.server_name.0, row.worktree_root_name, @@ -871,22 +845,10 @@ impl LspLogToolbarItemView { } else { SERVER_LOGS }, - ) - .into(), - ) - }) - .unwrap_or_else(|| "No server selected".into()); - div() - .child(Label::new(label)) - .cursor(CursorStyle::PointingHand) - .on_mouse_down( - MouseButton::Left, - cx.listener(move |view, _, cx| { - view.toggle_menu(cx); - }), - ) - .border_1() - .border_color(red()) + ))) + }) + .unwrap_or_else(|| "No server selected".into()), + ) } fn render_language_server_menu_item( @@ -894,7 +856,6 @@ impl LspLogToolbarItemView { name: LanguageServerName, worktree_root_name: &str, rpc_trace_enabled: bool, - // todo!() styling _logs_selected: bool, _rpc_trace_selected: bool, cx: &mut ViewContext, diff --git a/crates/language_tools2/src/syntax_tree_view.rs b/crates/language_tools2/src/syntax_tree_view.rs index 4c9e7529c5cde073d369aeb5716fa65e9933b117..9b205cb28bddeaf2af016329fea045e206f0c65d 100644 --- a/crates/language_tools2/src/syntax_tree_view.rs +++ b/crates/language_tools2/src/syntax_tree_view.rs @@ -1,20 +1,19 @@ use editor::{scroll::autoscroll::Autoscroll, Anchor, Editor, ExcerptId}; use gpui::{ - actions, div, overlay, red, uniform_list, AnyElement, AppContext, CursorStyle, Div, - EventEmitter, FocusHandle, FocusableView, Hsla, InteractiveElement, IntoElement, Model, - MouseButton, MouseDownEvent, MouseMoveEvent, ParentElement, Pixels, Render, Styled, TextStyle, - UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WindowContext, + actions, div, rems, uniform_list, AnyElement, AppContext, Div, EventEmitter, FocusHandle, + FocusableView, Hsla, InteractiveElement, IntoElement, Model, MouseButton, MouseDownEvent, + MouseMoveEvent, ParentElement, Pixels, Render, Styled, TextStyle, UniformListScrollHandle, + View, ViewContext, VisualContext, WeakView, WindowContext, }; -use language::{Buffer, OwnedSyntaxLayerInfo, SyntaxLayerInfo}; +use language::{Buffer, OwnedSyntaxLayerInfo}; use settings::Settings; use std::{mem, ops::Range}; use theme::{Theme, ThemeSettings}; use tree_sitter::{Node, TreeCursor}; -use ui::{h_stack, Label}; +use ui::{h_stack, popover_menu, ButtonLike, ContextMenu, Label, PopoverMenu}; use workspace::{ item::{Item, ItemHandle}, - ui::v_stack, - ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, + SplitDirection, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace, }; actions!(debug, [OpenSyntaxTreeView]); @@ -26,7 +25,7 @@ pub fn init(cx: &mut AppContext) { let workspace_handle = workspace.weak_handle(); let syntax_tree_view = cx.build_view(|cx| SyntaxTreeView::new(workspace_handle, active_item, cx)); - workspace.add_item(Box::new(syntax_tree_view), cx); + workspace.split_item(SplitDirection::Right, Box::new(syntax_tree_view), cx) }); }) .detach(); @@ -46,7 +45,6 @@ pub struct SyntaxTreeView { pub struct SyntaxTreeToolbarItemView { tree_view: Option>, subscription: Option, - menu_open: bool, } struct EditorState { @@ -279,7 +277,7 @@ impl SyntaxTreeView { fn render_node( cursor: &TreeCursor, - _depth: u32, + depth: u32, selected: bool, hovered: bool, list_hovered: bool, @@ -290,18 +288,6 @@ impl SyntaxTreeView { let editor_colors = editor_theme.colors(); let node = cursor.node(); let mut range_style = style.clone(); - // todo!() styling - // let font_id = cx.text_system().font_id(&style.text.font()).unwrap(); - // let font_size = style.text.font_size.to_pixels(cx.rem_size()); - // let line_height = style.text.line_height_in_pixels(cx.rem_size()); - // let em_width = cx - // .text_system() - // .typographic_bounds(font_id, font_size, 'm') - // .unwrap() - // .size - // .width; - // let gutter_padding = (em_width * editor_theme.gutter_padding_factor).round(); - range_style.color = editor_colors.editor_line_number; let mut anonymous_node_style = style.clone(); @@ -335,8 +321,7 @@ impl SyntaxTreeView { Label::new(node.kind()) } else { Label::new(format!("\"{}\"", node.kind())) - }, // todo!() - // .margin(em_width), + }, ) .child(Label::new(format_node_range(node))) .text_bg(if selected { @@ -346,10 +331,10 @@ impl SyntaxTreeView { } else { Hsla::default() }) - // todo!() + // todo!() does not work + .ml(rems(depth as f32 * 180.0)) // .padding(gutter_padding + depth as f32 * 18.0) - .border_1() - .border_color(red()); + ; } } @@ -389,8 +374,6 @@ impl Render for SyntaxTreeView { let layer = layer.clone(); let theme = editor_theme.clone(); - // todo!() - // let list_hovered = state.hovered(); let list_hovered = false; let list = uniform_list( cx.view().clone(), @@ -434,6 +417,7 @@ impl Render for SyntaxTreeView { items }, ) + // todo!() does scroll either editor or the tree .track_scroll(self.list_scroll_handle.clone()) .on_mouse_move(cx.listener(move |tree_view, event: &MouseMoveEvent, cx| { tree_view.mouse_y = Some(event.position.y); @@ -492,13 +476,12 @@ impl Item for SyntaxTreeView { impl SyntaxTreeToolbarItemView { pub fn new() -> Self { Self { - menu_open: false, tree_view: None, subscription: None, } } - fn render_menu(&mut self, cx: &mut ViewContext<'_, Self>) -> Option
{ + fn render_menu(&mut self, cx: &mut ViewContext<'_, Self>) -> Option> { let tree_view = self.tree_view.as_ref()?; let tree_view = tree_view.read(cx); @@ -507,34 +490,30 @@ impl SyntaxTreeToolbarItemView { let active_layer = buffer_state.active_layer.clone()?; let active_buffer = buffer_state.buffer.read(cx).snapshot(); + let view = cx.view().clone(); Some( - v_stack() - .size_full() - .child(Self::render_header(&active_layer, cx)) - .children(self.menu_open.then(|| { - overlay().child( - v_stack() - .size_full() - .children(active_buffer.syntax_layers().enumerate().map( - |(ix, layer)| Self::render_menu_item(&active_layer, layer, ix, cx), - )) - .on_mouse_down_out(cx.listener(|this, e: &MouseDownEvent, cx| { - if e.button == MouseButton::Left { - this.menu_open = false; - cx.notify() - } - })), - ) - })) - .z_index(99), + popover_menu("Syntax Tree") + .trigger(Self::render_header(&active_layer)) + .menu(move |cx| { + ContextMenu::build(cx, |mut menu, cx| { + for (layer_ix, layer) in active_buffer.syntax_layers().enumerate() { + menu = menu.entry( + format!( + "{} {}", + layer.language.name(), + format_node_range(layer.node()) + ), + cx.handler_for(&view, move |view, cx| { + view.select_layer(layer_ix, cx); + }), + ); + } + menu + }) + }), ) } - fn toggle_menu(&mut self, cx: &mut ViewContext) { - self.menu_open = !self.menu_open; - cx.notify(); - } - fn select_layer(&mut self, layer_ix: usize, cx: &mut ViewContext) -> Option<()> { let tree_view = self.tree_view.as_ref()?; tree_view.update(cx, |view, cx| { @@ -544,50 +523,15 @@ impl SyntaxTreeToolbarItemView { let layer = snapshot.syntax_layers().nth(layer_ix)?; buffer_state.active_layer = Some(layer.to_owned()); view.selected_descendant_ix = None; - self.menu_open = false; cx.notify(); Some(()) }) } - fn render_header(active_layer: &OwnedSyntaxLayerInfo, cx: &mut ViewContext) -> Div { - h_stack() - .size_full() + fn render_header(active_layer: &OwnedSyntaxLayerInfo) -> ButtonLike { + ButtonLike::new("syntax tree header") .child(Label::new(active_layer.language.name())) .child(Label::new(format_node_range(active_layer.node()))) - .on_mouse_down( - MouseButton::Left, - cx.listener(move |view, _, cx| { - view.toggle_menu(cx); - }), - ) - .cursor(CursorStyle::PointingHand) - .border_1() - .border_color(red()) - } - - fn render_menu_item( - active_layer: &OwnedSyntaxLayerInfo, - layer: SyntaxLayerInfo, - layer_ix: usize, - cx: &mut ViewContext, - ) -> Div { - // todo!() styling - let _is_selected = layer.node() == active_layer.node(); - h_stack() - .size_full() - .child(Label::new(layer.language.name().to_string())) - .child(Label::new(format_node_range(layer.node()))) - .cursor(CursorStyle::PointingHand) - .on_mouse_down( - MouseButton::Left, - cx.listener(move |view, _, cx| { - view.select_layer(layer_ix, cx); - }), - ) - .border_1() - .border_color(red()) - .bg(red()) } } @@ -604,15 +548,11 @@ fn format_node_range(node: Node) -> String { } impl Render for SyntaxTreeToolbarItemView { - type Element = Div; - - // todo!() - // fn ui_name() -> &'static str { - // "SyntaxTreeToolbarItemView" - // } + type Element = PopoverMenu; - fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> Div { - self.render_menu(cx).unwrap_or_else(|| div()) + fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> PopoverMenu { + self.render_menu(cx) + .unwrap_or_else(|| popover_menu("Empty Syntax Tree")) } } @@ -624,7 +564,6 @@ impl ToolbarItemView for SyntaxTreeToolbarItemView { active_pane_item: Option<&dyn ItemHandle>, cx: &mut ViewContext, ) -> ToolbarItemLocation { - self.menu_open = false; if let Some(item) = active_pane_item { if let Some(view) = item.downcast::() { self.tree_view = Some(view.clone()); diff --git a/crates/ui2/src/components/context_menu.rs b/crates/ui2/src/components/context_menu.rs index 8fce15d1c69d0fcf97f8ac1757874be4884950b6..4e3c03ad80a1ab1f66b84d69685a0d5260401fda 100644 --- a/crates/ui2/src/components/context_menu.rs +++ b/crates/ui2/src/components/context_menu.rs @@ -9,7 +9,7 @@ use gpui::{ use menu::{SelectFirst, SelectLast, SelectNext, SelectPrev}; use std::{rc::Rc, time::Duration}; -pub enum ContextMenuItem { +enum ContextMenuItem { Separator, Header(SharedString), Entry {