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