Cargo.lock 🔗
@@ -5008,6 +5008,7 @@ dependencies = [
"settings2",
"theme2",
"tree-sitter",
+ "ui2",
"unindent",
"util",
"workspace2",
Kirill Bulatov created
Cargo.lock | 1
crates/editor2/src/editor.rs | 13
crates/language_tools2/Cargo.toml | 1
crates/language_tools2/src/lsp_log.rs | 388 ++++++++-----------
crates/language_tools2/src/syntax_tree_view.rs | 361 ++++++++----------
5 files changed, 335 insertions(+), 429 deletions(-)
@@ -5008,6 +5008,7 @@ dependencies = [
"settings2",
"theme2",
"tree-sitter",
+ "ui2",
"unindent",
"util",
"workspace2",
@@ -1652,14 +1652,11 @@ impl Editor {
Self::new(EditorMode::SingleLine, buffer, None, cx)
}
- // pub fn multi_line(
- // field_editor_style: Option<Arc<GetFieldEditorTheme>>,
- // cx: &mut ViewContext<Self>,
- // ) -> Self {
- // let buffer = cx.build_model(|cx| Buffer::new(0, cx.model_id() as u64, String::new()));
- // let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx));
- // Self::new(EditorMode::Full, buffer, None, field_editor_style, cx)
- // }
+ pub fn multi_line(cx: &mut ViewContext<Self>) -> Self {
+ let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
+ let buffer = cx.build_model(|cx| MultiBuffer::singleton(buffer, cx));
+ Self::new(EditorMode::Full, buffer, None, cx)
+ }
pub fn auto_height(max_lines: usize, cx: &mut ViewContext<Self>) -> Self {
let buffer = cx.build_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), String::new()));
@@ -17,6 +17,7 @@ language = { package = "language2", path = "../language2" }
project = { package = "project2", path = "../project2" }
workspace = { package = "workspace2", path = "../workspace2" }
gpui = { package = "gpui2", path = "../gpui2" }
+ui = { package = "ui2", path = "../ui2" }
util = { path = "../util" }
lsp = { package = "lsp2", path = "../lsp2" }
futures.workspace = true
@@ -1,20 +1,22 @@
use collections::{HashMap, VecDeque};
-use editor::{Editor, MoveToEnd};
+use editor::{Editor, EditorElement, EditorEvent, MoveToEnd};
use futures::{channel::mpsc, StreamExt};
use gpui::{
- actions, AnchorCorner, AnyElement, AppContext, Context, CursorStyle, Element, Empty, Entity,
- Model, ModelContext, MouseButton, Overlay, OverlayFitMode, Subscription, View, ViewContext,
- VisualContext, WeakModel,
+ actions, div, overlay, red, AnchorCorner, AnyElement, AppContext, Context, CursorStyle, Div,
+ EventEmitter, FocusHandle, FocusableView, InteractiveElement, IntoElement, Model, ModelContext,
+ MouseButton, OverlayFitMode, 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 theme::Theme;
+use theme::{ActiveTheme, Theme};
+use ui::{h_stack, v_stack, Label};
use workspace::{
item::{Item, ItemHandle},
- searchable::{SearchableItem, SearchableItemHandle},
- ToolbarItemLocation, ToolbarItemView, Workspace,
+ searchable::{SearchEvent, SearchableItem, SearchableItemHandle},
+ ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
};
const SEND_LINE: &str = "// Send:";
@@ -50,6 +52,7 @@ pub struct LspLogView {
current_server_id: Option<LanguageServerId>,
is_showing_rpc_trace: bool,
project: Model<Project>,
+ focus_handle: FocusHandle,
_log_store_subscriptions: Vec<Subscription>,
}
@@ -110,9 +113,9 @@ impl LogStore {
projects: HashMap::default(),
io_tx,
};
- cx.spawn_weak(|this, mut cx| async move {
+ cx.spawn(|this, mut cx| async move {
while let Some((project, server_id, io_kind, message)) = io_rx.next().await {
- if let Some(this) = this.upgrade(&cx) {
+ if let Some(this) = this.upgrade() {
this.update(&mut cx, |this, cx| {
this.on_io(project, server_id, io_kind, &message, cx);
});
@@ -120,7 +123,7 @@ impl LogStore {
}
anyhow::Ok(())
})
- .detach();
+ .detach_and_log_err(cx);
this
}
@@ -131,7 +134,7 @@ impl LogStore {
ProjectState {
servers: HashMap::default(),
_subscriptions: [
- cx.observe_release(&project, move |this, _, _| {
+ cx.observe_release(project, move |this, _, _| {
this.projects.remove(&weak_project);
}),
cx.subscribe(project, |this, project, event, cx| match event {
@@ -185,14 +188,13 @@ impl LogStore {
.ok();
})
});
- let this = cx.weak_handle();
+ let this = cx.handle().downgrade();
let weak_project = project.downgrade();
server_state._lsp_logs_subscription = server.map(|server| {
let server_id = server.server_id();
server.on_notification::<lsp::notification::LogMessage, _>({
move |params, mut cx| {
- if let Some((project, this)) = weak_project.upgrade().zip(this.upgrade(&mut cx))
- {
+ if let Some((project, this)) = weak_project.upgrade().zip(this.upgrade()) {
this.update(&mut cx, |this, cx| {
this.add_language_server_log(&project, server_id, ¶ms.message, cx);
});
@@ -413,14 +415,25 @@ impl LspLogView {
}
});
let (editor, editor_subscription) = Self::editor_for_logs(String::new(), cx);
+
+ let focus_handle = cx.focus_handle();
+ let focus_subscription = cx.on_focus(&focus_handle, |log_view, cx| {
+ cx.focus_view(&log_view.editor);
+ });
+
let mut this = Self {
+ focus_handle,
editor,
editor_subscription,
project,
log_store,
current_server_id: None,
is_showing_rpc_trace: false,
- _log_store_subscriptions: vec![model_changes_subscription, events_subscriptions],
+ _log_store_subscriptions: vec![
+ model_changes_subscription,
+ events_subscriptions,
+ focus_subscription,
+ ],
};
if let Some(server_id) = server_id {
this.show_logs_for_server(server_id, cx);
@@ -433,13 +446,18 @@ impl LspLogView {
cx: &mut ViewContext<Self>,
) -> (View<Editor>, Subscription) {
let editor = cx.build_view(|cx| {
- let mut editor = Editor::multi_line(None, cx);
+ let mut editor = Editor::multi_line(cx);
editor.set_text(log_contents, cx);
editor.move_to_end(&MoveToEnd, cx);
editor.set_read_only(true);
editor
});
- let editor_subscription = cx.subscribe(&editor, |_, _, event, cx| cx.emit(event.clone()));
+ let editor_subscription = cx.subscribe(
+ &editor,
+ |_, _, event: &EditorEvent, cx: &mut ViewContext<'_, LspLogView>| {
+ cx.emit(event.clone())
+ },
+ );
(editor, editor_subscription)
}
@@ -526,7 +544,7 @@ impl LspLogView {
.as_singleton()
.expect("log buffer should be a singleton")
.update(cx, |_, cx| {
- cx.spawn_weak({
+ cx.spawn({
let buffer = cx.handle();
|_, mut cx| async move {
let language = language.await.ok();
@@ -574,30 +592,34 @@ fn log_contents(lines: &VecDeque<String>) -> String {
}
}
-impl View for LspLogView {
- fn ui_name() -> &'static str {
- "LspLogView"
- }
+impl Render for LspLogView {
+ // todo!()
+ // fn ui_name() -> &'static str {
+ // "LspLogView"
+ // }
- fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
- ChildView::new(&self.editor, cx).into_any()
+ type Element = EditorElement;
+
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+ self.editor.update(cx, |editor, cx| editor.render(cx))
}
+}
- fn focus_in(&mut self, _: gpui::AnyView, cx: &mut ViewContext<Self>) {
- if cx.is_self_focused() {
- cx.focus(&self.editor);
- }
+impl FocusableView for LspLogView {
+ fn focus_handle(&self, _: &AppContext) -> FocusHandle {
+ self.focus_handle.clone()
}
}
impl Item for LspLogView {
- fn tab_content<V: 'static>(
- &self,
- _: Option<usize>,
- style: &theme::Tab,
- _: &AppContext,
- ) -> AnyElement<V> {
- Label::new("LSP Logs", style.label.clone()).into_any()
+ type Event = EditorEvent;
+
+ fn to_item_events(event: &Self::Event, f: impl FnMut(workspace::item::ItemEvent)) {
+ Editor::to_item_events(event, f)
+ }
+
+ fn tab_content(&self, _: Option<usize>, _: bool, _: &WindowContext<'_>) -> AnyElement {
+ Label::new("LSP Logs").into_any_element()
}
fn as_searchable(&self, handle: &View<Self>) -> Option<Box<dyn SearchableItemHandle>> {
@@ -608,15 +630,6 @@ impl Item for LspLogView {
impl SearchableItem for LspLogView {
type Match = <Editor as SearchableItem>::Match;
- fn to_search_event(
- &mut self,
- event: &Self::Event,
- cx: &mut ViewContext<Self>,
- ) -> Option<workspace::searchable::SearchEvent> {
- self.editor
- .update(cx, |editor, cx| editor.to_search_event(event, cx))
- }
-
fn clear_matches(&mut self, cx: &mut ViewContext<Self>) {
self.editor.update(cx, |e, cx| e.clear_matches(cx))
}
@@ -675,6 +688,8 @@ impl SearchableItem for LspLogView {
}
}
+impl EventEmitter<ToolbarItemEvent> for LspLogToolbarItemView {}
+
impl ToolbarItemView for LspLogToolbarItemView {
fn set_active_pane_item(
&mut self,
@@ -688,9 +703,7 @@ impl ToolbarItemView for LspLogToolbarItemView {
self._log_view_subscription = Some(cx.observe(&log_view, |_, _, cx| {
cx.notify();
}));
- return ToolbarItemLocation::PrimaryLeft {
- flex: Some((1., false)),
- };
+ return ToolbarItemLocation::PrimaryLeft;
}
}
self.log_view = None;
@@ -699,15 +712,17 @@ impl ToolbarItemView for LspLogToolbarItemView {
}
}
-impl View for LspLogToolbarItemView {
- fn ui_name() -> &'static str {
- "LspLogView"
- }
+impl Render for LspLogToolbarItemView {
+ type Element = Div;
+ // todo!()
+ // fn ui_name() -> &'static str {
+ // "LspLogView"
+ // }
- fn render(&mut self, cx: &mut ViewContext<Self>) -> AnyElement<Self> {
- let theme = theme::current(cx).clone();
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> Div {
+ let theme = cx.theme().clone();
let Some(log_view) = self.log_view.as_ref() else {
- return Empty::new().into_any();
+ return div();
};
let (menu_rows, current_server_id) = log_view.update(cx, |log_view, cx| {
let menu_rows = log_view.menu_items(cx).unwrap_or_default();
@@ -726,19 +741,15 @@ impl View for LspLogToolbarItemView {
enum LspLogScroll {}
enum Menu {}
- let lsp_menu = Stack::new()
- .with_child(Self::render_language_server_menu_header(
- current_server,
- &theme,
- cx,
- ))
- .with_children(if self.menu_open {
+ let lsp_menu = h_stack()
+ .child(Self::render_language_server_menu_header(current_server, cx))
+ .children(if self.menu_open {
Some(
- Overlay::new(
- MouseEventHandler::new::<Menu, _>(0, cx, move |_, cx| {
- Flex::column()
+ overlay()
+ .child(
+ v_stack()
.scrollable::<LspLogScroll>(0, None, cx)
- .with_children(menu_rows.into_iter().map(|row| {
+ .children(menu_rows.into_iter().map(|row| {
Self::render_language_server_menu_item(
row.server_id,
row.server_name,
@@ -750,51 +761,27 @@ impl View for LspLogToolbarItemView {
cx,
)
}))
- .contained()
- .with_style(theme.toolbar_dropdown_menu.container)
- .constrained()
- .with_width(400.)
- .with_height(400.)
- })
- .on_down_out(MouseButton::Left, |_, this, cx| {
- this.menu_open = false;
- cx.notify()
- }),
- )
- .with_hoverable(true)
- .with_fit_mode(OverlayFitMode::SwitchAnchor)
- .with_anchor_corner(AnchorCorner::TopLeft)
- .with_z_index(999)
- .aligned()
- .bottom()
- .left(),
+ .on_down_out(MouseButton::Left, |_, this, cx| {
+ this.menu_open = false;
+ cx.notify()
+ }),
+ )
+ .with_hoverable(true)
+ .with_fit_mode(OverlayFitMode::SwitchAnchor)
+ .with_anchor_corner(AnchorCorner::TopLeft)
+ .with_z_index(999)
+ .bottom()
+ .left(),
)
} else {
None
- })
- .aligned()
- .left()
- .clipped();
+ });
enum LspCleanupButton {}
- let log_cleanup_button =
- MouseEventHandler::new::<LspCleanupButton, _>(1, cx, |state, cx| {
- let theme = theme::current(cx).clone();
- let style = theme
- .workspace
- .toolbar
- .toggleable_text_tool
- .in_state(server_selected)
- .style_for(state);
- Label::new("Clear", style.text.clone())
- .aligned()
- .contained()
- .with_style(style.container)
- .constrained()
- .with_height(theme.toolbar_dropdown_menu.row_height / 6.0 * 5.0)
- })
- .on_click(MouseButton::Left, move |_, this, cx| {
- if let Some(log_view) = this.log_view.as_ref() {
+ let log_cleanup_button = div()
+ .child(Label::new("Clear"))
+ .on_mouse_down(MouseButton::Left, move |_, cx| {
+ if let Some(log_view) = self.log_view.as_ref() {
log_view.update(cx, |log_view, cx| {
log_view.editor.update(cx, |editor, cx| {
editor.set_read_only(false);
@@ -804,17 +791,13 @@ impl View for LspLogToolbarItemView {
})
}
})
- .with_cursor_style(CursorStyle::PointingHand)
- .aligned()
- .right();
-
- Flex::row()
- .with_child(lsp_menu)
- .with_child(log_cleanup_button)
- .contained()
- .aligned()
- .left()
- .into_any_named("lsp log controls")
+ .cursor(CursorStyle::PointingHand);
+
+ h_stack()
+ .child(lsp_menu)
+ .child(log_cleanup_button)
+ .border_1()
+ .border_color(red())
}
}
@@ -871,37 +854,37 @@ impl LspLogToolbarItemView {
fn render_language_server_menu_header(
current_server: Option<LogMenuItem>,
- theme: &Arc<Theme>,
cx: &mut ViewContext<Self>,
- ) -> impl Element<Self> {
+ ) -> Div {
+ let view = cx.view().clone();
enum ToggleMenu {}
- MouseEventHandler::new::<ToggleMenu, _>(0, cx, move |state, _| {
- let label: Cow<str> = current_server
- .and_then(|row| {
- Some(
- format!(
- "{} ({}) - {}",
- row.server_name.0,
- row.worktree_root_name,
- if row.rpc_trace_selected {
- RPC_MESSAGES
- } else {
- SERVER_LOGS
- },
- )
- .into(),
+ let label: Cow<str> = current_server
+ .and_then(|row| {
+ Some(
+ format!(
+ "{} ({}) - {}",
+ row.server_name.0,
+ row.worktree_root_name,
+ if row.rpc_trace_selected {
+ RPC_MESSAGES
+ } else {
+ SERVER_LOGS
+ },
)
+ .into(),
+ )
+ })
+ .unwrap_or_else(|| "No server selected".into());
+ div()
+ .child(Label::new(label))
+ .cursor(CursorStyle::PointingHand)
+ .on_mouse_down(MouseButton::Left, move |_, cx| {
+ view.update(cx, |view, cx| {
+ view.toggle_menu(cx);
})
- .unwrap_or_else(|| "No server selected".into());
- let style = theme.toolbar_dropdown_menu.header.style_for(state);
- Label::new(label, style.text.clone())
- .contained()
- .with_style(style.container)
- })
- .with_cursor_style(CursorStyle::PointingHand)
- .on_click(MouseButton::Left, move |_, view, cx| {
- view.toggle_menu(cx);
- })
+ })
+ .border_1()
+ .border_color(red())
}
fn render_language_server_menu_item(
@@ -913,78 +896,52 @@ impl LspLogToolbarItemView {
rpc_trace_selected: bool,
theme: &Arc<Theme>,
cx: &mut ViewContext<Self>,
- ) -> impl Element<Self> {
+ ) -> Div {
enum ActivateLog {}
enum ActivateRpcTrace {}
enum LanguageServerCheckbox {}
- Flex::column()
- .with_child({
- let style = &theme.toolbar_dropdown_menu.section_header;
- Label::new(
- format!("{} ({})", name.0, worktree_root_name),
- style.text.clone(),
- )
- .contained()
- .with_style(style.container)
- .constrained()
- .with_height(theme.toolbar_dropdown_menu.row_height)
- })
- .with_child(
- MouseEventHandler::new::<ActivateLog, _>(id.0, cx, move |state, _| {
- let style = theme
- .toolbar_dropdown_menu
- .item
- .in_state(logs_selected)
- .style_for(state);
- Label::new(SERVER_LOGS, style.text.clone())
- .contained()
- .with_style(style.container)
- .constrained()
- .with_height(theme.toolbar_dropdown_menu.row_height)
- })
- .with_cursor_style(CursorStyle::PointingHand)
- .on_click(MouseButton::Left, move |_, view, cx| {
- view.show_logs_for_server(id, cx);
- }),
+ let view = cx.view().clone();
+
+ v_stack()
+ .child(Label::new(format!("{} ({})", name.0, worktree_root_name)))
+ .child(
+ div()
+ .child(Label::new(SERVER_LOGS))
+ .cursor(CursorStyle::PointingHand)
+ .on_mouse_down(MouseButton::Left, move |_, cx| {
+ view.update(cx, |view, cx| {
+ view.show_logs_for_server(id, cx);
+ })
+ }),
)
- .with_child(
- MouseEventHandler::new::<ActivateRpcTrace, _>(id.0, cx, move |state, cx| {
- let style = theme
- .toolbar_dropdown_menu
- .item
- .in_state(rpc_trace_selected)
- .style_for(state);
- Flex::row()
- .with_child(
- Label::new(RPC_MESSAGES, style.text.clone())
- .constrained()
- .with_height(theme.toolbar_dropdown_menu.row_height),
- )
- .with_child(
- ui::checkbox_with_label::<LanguageServerCheckbox, _, Self, _>(
- Empty::new(),
- &theme.welcome.checkbox,
- rpc_trace_enabled,
- id.0,
- cx,
- move |this, enabled, cx| {
- this.toggle_logging_for_server(id, enabled, cx);
- },
- )
- .flex_float(),
+ .child(
+ h_stack()
+ .child(Label::new(RPC_MESSAGES))
+ .child(
+ ui::checkbox_with_label::<LanguageServerCheckbox, _, Self, _>(
+ div(),
+ &theme.welcome.checkbox,
+ rpc_trace_enabled,
+ id.0,
+ cx,
+ move |this, enabled, cx| {
+ this.toggle_logging_for_server(id, enabled, cx);
+ },
)
- .align_children_center()
- .contained()
- .with_style(style.container)
- .constrained()
- .with_height(theme.toolbar_dropdown_menu.row_height)
- })
- .with_cursor_style(CursorStyle::PointingHand)
- .on_click(MouseButton::Left, move |_, view, cx| {
- view.show_rpc_trace_for_server(id, cx);
- }),
+ .flex_float(),
+ )
+ .border_1()
+ .border_color(red())
+ .cursor(CursorStyle::PointingHand)
+ .on_mouse_down(MouseButton::Left, move |_, cx| {
+ view.update(cx, |view, cx| {
+ view.show_rpc_trace_for_server(id, cx);
+ })
+ }),
)
+ .border_1()
+ .border_color(red())
}
}
@@ -996,14 +953,7 @@ pub enum Event {
},
}
-impl Entity for LogStore {
- type Event = Event;
-}
-
-impl Entity for LspLogView {
- type Event = editor::Event;
-}
-
-impl Entity for LspLogToolbarItemView {
- type Event = ();
-}
+impl EventEmitter<Event> for LogStore {}
+impl EventEmitter<Event> for LspLogView {}
+impl EventEmitter<EditorEvent> for LspLogView {}
+impl EventEmitter<SearchEvent> for LspLogView {}
@@ -1,17 +1,20 @@
use editor::{scroll::autoscroll::Autoscroll, Anchor, Editor, ExcerptId};
use gpui::{
- actions, AnchorCorner, AppContext, CursorStyle, Div, Element, Empty, Entity, Focusable, Model,
- MouseButton, Overlay, OverlayFitMode, ParentElement, Render, TextStyle, UniformList,
- UniformListState, View, ViewContext, VisualContext, WeakView,
+ actions, div, overlay, red, uniform_list, AnyElement, AppContext, CursorStyle, Div,
+ EventEmitter, FocusHandle, FocusableView, Hsla, InteractiveElement, IntoElement, Model,
+ MouseButton, ParentElement, Render, Styled, TextStyle, UniformListState, View, ViewContext,
+ VisualContext, WeakView, WindowContext,
};
use language::{Buffer, OwnedSyntaxLayerInfo, SyntaxLayerInfo};
-use std::{mem, ops::Range, sync::Arc};
-use theme::{ActiveTheme, Theme, ThemeSettings};
+use settings::Settings;
+use std::{mem, ops::Range};
+use theme::{ActiveTheme, ThemeSettings};
use tree_sitter::{Node, TreeCursor};
+use ui::{h_stack, Label};
use workspace::{
item::{Item, ItemHandle},
ui::v_stack,
- ToolbarItemLocation, ToolbarItemView, Workspace,
+ ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
};
actions!(debug, [OpenSyntaxTreeView]);
@@ -37,6 +40,7 @@ pub struct SyntaxTreeView {
list_state: UniformListState,
selected_descendant_ix: Option<usize>,
hovered_descendant_ix: Option<usize>,
+ focus_handle: FocusHandle,
}
pub struct SyntaxTreeToolbarItemView {
@@ -72,6 +76,7 @@ impl SyntaxTreeView {
line_height: None,
hovered_descendant_ix: None,
selected_descendant_ix: None,
+ focus_handle: cx.focus_handle(),
};
this.workspace_updated(active_item, cx);
@@ -229,7 +234,7 @@ impl SyntaxTreeView {
editor.clear_background_highlights::<Self>(cx);
editor.highlight_background::<Self>(
vec![range],
- |theme| theme.editor.document_highlight_write_background,
+ |theme| theme.editor_document_highlight_write_background,
cx,
);
});
@@ -281,10 +286,10 @@ impl SyntaxTreeView {
style: &TextStyle,
editor_theme: &theme::Editor,
cx: &AppContext,
- ) -> gpui::AnyElement<SyntaxTreeView> {
+ ) -> Div {
let node = cursor.node();
let mut range_style = style.clone();
- let em_width = style.em_width(cx.font_cache());
+ let em_width = style.em_width(cx.text_system());
let gutter_padding = (em_width * editor_theme.gutter_padding_factor).round();
range_style.color = editor_theme.line_number;
@@ -304,64 +309,54 @@ impl SyntaxTreeView {
anonymous_node_style.color = color;
}
- let mut row = Flex::row();
+ let mut row = h_stack();
if let Some(field_name) = cursor.field_name() {
let mut field_style = style.clone();
if let Some(color) = property_color {
field_style.color = color;
}
- row.add_children([
- Label::new(field_name, field_style),
- Label::new(": ", style.clone()),
- ]);
+ row = row.children([Label::new(field_name), Label::new(": ")]);
}
return row
- .with_child(
+ .child(
if node.is_named() {
- Label::new(node.kind(), style.clone())
+ Label::new(node.kind())
} else {
- Label::new(format!("\"{}\"", node.kind()), anonymous_node_style)
- }
- .contained()
- .with_margin_right(em_width),
+ Label::new(format!("\"{}\"", node.kind()))
+ }, // todo!()
+ // .margin(em_width),
)
- .with_child(Label::new(format_node_range(node), range_style))
- .contained()
- .with_background_color(if selected {
+ .child(Label::new(format_node_range(node)))
+ .text_bg(if selected {
editor_theme.selection.selection
} else if hovered && list_hovered {
editor_theme.active_line_background
} else {
- Default::default()
+ Hsla::default()
})
- .with_padding_left(gutter_padding + depth as f32 * 18.0)
- .into_any();
+ // todo!()
+ // .padding(gutter_padding + depth as f32 * 18.0)
+ .border_1()
+ .border_color(red());
}
}
-impl Entity for SyntaxTreeView {
- type Event = ();
-}
+impl Render for SyntaxTreeView {
+ // todo!()
+ // fn ui_name() -> &'static str {
+ // "SyntaxTreeView"
+ // }
-impl View for SyntaxTreeView {
- fn ui_name() -> &'static str {
- "SyntaxTreeView"
- }
+ type Element = Div;
- fn render(&mut self, cx: &mut gpui::ViewContext<'_, '_, Self>) -> gpui::AnyElement<Self> {
- let settings = settings::get::<ThemeSettings>(cx);
- let font_family_id = settings.buffer_font_family;
- let font_family_name = cx.font_cache().family_name(font_family_id).unwrap();
- let font_properties = Default::default();
- let font_id = cx
- .font_cache()
- .select_font(font_family_id, &font_properties)
- .unwrap();
+ fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> Div {
+ let settings = ThemeSettings::get_global(cx);
+ let font = settings.buffer_font;
let font_size = settings.buffer_font_size(cx);
- let editor_theme = settings.theme.editor.clone();
+ let editor_theme = settings.active_theme;
let style = TextStyle {
color: editor_theme.text_color,
font_family_name,
@@ -370,10 +365,16 @@ impl View for SyntaxTreeView {
font_size,
font_properties: Default::default(),
underline: Default::default(),
- soft_wrap: false,
+ font_family: todo!(),
+ font_features: todo!(),
+ line_height: todo!(),
+ font_weight: todo!(),
+ font_style: todo!(),
+ background_color: todo!(),
+ white_space: todo!(),
};
- let line_height = cx.font_cache().line_height(font_size);
+ let line_height = cx.text_system().line_height(font_size);
if Some(line_height) != self.line_height {
self.line_height = Some(line_height);
self.hover_state_changed(cx);
@@ -387,90 +388,95 @@ impl View for SyntaxTreeView {
{
let layer = layer.clone();
let theme = editor_theme.clone();
- return MouseEventHandler::new::<Self, _>(0, cx, move |state, cx| {
- let list_hovered = state.hovered();
- UniformList::new(
- self.list_state.clone(),
- layer.node().descendant_count(),
- cx,
- move |this, range, items, cx| {
- let mut cursor = layer.node().walk();
- let mut descendant_ix = range.start as usize;
- cursor.goto_descendant(descendant_ix);
- let mut depth = cursor.depth();
- let mut visited_children = false;
- while descendant_ix < range.end {
- if visited_children {
- if cursor.goto_next_sibling() {
- visited_children = false;
- } else if cursor.goto_parent() {
- depth -= 1;
- } else {
- break;
- }
+
+ let list_hovered = state.hovered();
+ uniform_list(
+ self.list_state.clone(),
+ layer.node().descendant_count(),
+ cx,
+ move |this, range, items, cx| {
+ let mut cursor = layer.node().walk();
+ let mut descendant_ix = range.start as usize;
+ cursor.goto_descendant(descendant_ix);
+ let mut depth = cursor.depth();
+ let mut visited_children = false;
+ while descendant_ix < range.end {
+ if visited_children {
+ if cursor.goto_next_sibling() {
+ visited_children = false;
+ } else if cursor.goto_parent() {
+ depth -= 1;
} else {
- items.push(Self::render_node(
- &cursor,
- depth,
- Some(descendant_ix) == this.selected_descendant_ix,
- Some(descendant_ix) == this.hovered_descendant_ix,
- list_hovered,
- &style,
- &theme,
- cx,
- ));
- descendant_ix += 1;
- if cursor.goto_first_child() {
- depth += 1;
- } else {
- visited_children = true;
- }
+ break;
+ }
+ } else {
+ items.push(Self::render_node(
+ &cursor,
+ depth,
+ Some(descendant_ix) == this.selected_descendant_ix,
+ Some(descendant_ix) == this.hovered_descendant_ix,
+ list_hovered,
+ &style,
+ &theme,
+ cx,
+ ));
+ descendant_ix += 1;
+ if cursor.goto_first_child() {
+ depth += 1;
+ } else {
+ visited_children = true;
}
}
- },
- )
- })
+ }
+ },
+ )
.on_move(move |event, this, cx| {
let y = event.position.y() - event.region.origin_y();
this.mouse_y = Some(y);
this.hover_state_changed(cx);
})
- .on_click(MouseButton::Left, move |event, this, cx| {
+ .on_mouse_down(MouseButton::Left, move |event, cx| {
let y = event.position.y() - event.region.origin_y();
- this.handle_click(y, cx);
- })
- .contained()
- .with_background_color(editor_theme.background)
- .into_any();
+ self.handle_click(y, cx);
+ });
}
- Empty::new().into_any()
+ div()
+ }
+}
+
+impl EventEmitter<()> for SyntaxTreeView {}
+
+impl FocusableView for SyntaxTreeView {
+ fn focus_handle(&self, _: &AppContext) -> gpui::FocusHandle {
+ self.focus_handle.clone()
}
}
impl Item for SyntaxTreeView {
- fn tab_content<V: 'static>(
- &self,
- _: Option<usize>,
- style: &theme::Tab,
- _: &AppContext,
- ) -> gpui::AnyElement<V> {
- Label::new("Syntax Tree", style.label.clone()).into_any()
+ type Event = ();
+
+ fn to_item_events(_: &Self::Event, _: impl FnMut(workspace::item::ItemEvent)) {}
+
+ fn tab_content(&self, _: Option<usize>, _: bool, _: &WindowContext<'_>) -> AnyElement {
+ Label::new("Syntax Tree").into_any_element()
}
fn clone_on_split(
&self,
- _workspace_id: workspace::WorkspaceId,
+ _: workspace::WorkspaceId,
cx: &mut ViewContext<Self>,
- ) -> Option<Self>
+ ) -> Option<View<Self>>
where
Self: Sized,
{
- let mut clone = Self::new(self.workspace_handle.clone(), None, cx);
- if let Some(editor) = &self.editor {
- clone.set_editor(editor.editor.clone(), cx)
- }
- Some(clone)
+ Some(cx.build_view(|cx| {
+ let mut clone = Self::new(self.workspace_handle.clone(), None, cx);
+ if let Some(editor) = &self.editor {
+ clone.set_editor(editor.editor.clone(), cx)
+ }
+ clone
+ }))
}
}
@@ -483,10 +489,7 @@ impl SyntaxTreeToolbarItemView {
}
}
- fn render_menu(
- &mut self,
- cx: &mut ViewContext<'_, '_, Self>,
- ) -> Option<gpui::AnyElement<Self>> {
+ fn render_menu(&mut self, cx: &mut ViewContext<'_, Self>) -> Option<Div> {
let theme = cx.theme().clone();
let tree_view = self.tree_view.as_ref()?;
let tree_view = tree_view.read(cx);
@@ -496,36 +499,23 @@ impl SyntaxTreeToolbarItemView {
let active_layer = buffer_state.active_layer.clone()?;
let active_buffer = buffer_state.buffer.read(cx).snapshot();
- enum Menu {}
-
Some(
v_stack()
- .child(Self::render_header(&theme, &active_layer, cx))
+ .child(Self::render_header(&active_layer, cx))
.children(self.menu_open.then(|| {
- overlay(
- mouse_event_handler::<Menu, _>(0, cx, move |_, cx| {
- v_stack()
- .with_children(active_buffer.syntax_layers().enumerate().map(
- |(ix, layer)| {
- Self::render_menu_item(&theme, &active_layer, layer, ix, cx)
- },
- ))
- .contained()
- .with_style(theme.toolbar_dropdown_menu.container)
- .constrained()
- .with_width(400.)
- .with_height(400.)
- })
- .on_down_out(MouseButton::Left, |_, this, cx| {
- this.menu_open = false;
- cx.notify()
- }),
+ overlay().child(
+ v_stack()
+ .children(active_buffer.syntax_layers().enumerate().map(
+ |(ix, layer)| Self::render_menu_item(&active_layer, layer, ix, cx),
+ ))
+ .on_mouse_down_out(|e, cx| {
+ if e.button == MouseButton::Left {
+ self.menu_open = false;
+ cx.notify()
+ }
+ }),
)
- .with_hoverable(true)
- .with_fit_content()
- .into_any()
- }))
- .into_any(),
+ })),
)
}
@@ -549,71 +539,39 @@ impl SyntaxTreeToolbarItemView {
})
}
- fn render_header(
- theme: &Arc<Theme>,
- active_layer: &OwnedSyntaxLayerInfo,
- cx: &mut ViewContext<Self>,
- ) -> impl Element<Self> {
- enum ToggleMenu {}
- MouseEventHandler::new::<ToggleMenu, _>(0, cx, move |state, _| {
- let style = theme.toolbar_dropdown_menu.header.style_for(state);
- Flex::row()
- .with_child(
- Label::new(active_layer.language.name().to_string(), style.text.clone())
- .contained()
- .with_margin_right(style.secondary_text_spacing),
- )
- .with_child(Label::new(
- format_node_range(active_layer.node()),
- style
- .secondary_text
- .clone()
- .unwrap_or_else(|| style.text.clone()),
- ))
- .contained()
- .with_style(style.container)
- })
- .with_cursor_style(CursorStyle::PointingHand)
- .on_click(MouseButton::Left, move |_, view, cx| {
- view.toggle_menu(cx);
- })
+ fn render_header(active_layer: &OwnedSyntaxLayerInfo, cx: &mut ViewContext<Self>) -> Div {
+ let view = cx.view().clone();
+ h_stack()
+ .child(Label::new(active_layer.language.name()))
+ .child(Label::new(format_node_range(active_layer.node())))
+ .on_mouse_down(MouseButton::Left, move |_, cx| {
+ view.update(cx, |view, cx| view.toggle_menu(cx));
+ })
+ .cursor(CursorStyle::PointingHand)
+ .border_1()
+ .border_color(red())
}
fn render_menu_item(
- theme: &Arc<Theme>,
active_layer: &OwnedSyntaxLayerInfo,
layer: SyntaxLayerInfo,
layer_ix: usize,
cx: &mut ViewContext<Self>,
- ) -> impl Element<Self> {
- enum ActivateLayer {}
- MouseEventHandler::new::<ActivateLayer, _>(layer_ix, cx, move |state, _| {
- let is_selected = layer.node() == active_layer.node();
- let style = theme
- .toolbar_dropdown_menu
- .item
- .in_state(is_selected)
- .style_for(state);
- Flex::row()
- .with_child(
- Label::new(layer.language.name().to_string(), style.text.clone())
- .contained()
- .with_margin_right(style.secondary_text_spacing),
- )
- .with_child(Label::new(
- format_node_range(layer.node()),
- style
- .secondary_text
- .clone()
- .unwrap_or_else(|| style.text.clone()),
- ))
- .contained()
- .with_style(style.container)
- })
- .with_cursor_style(CursorStyle::PointingHand)
- .on_click(MouseButton::Left, move |_, view, cx| {
- view.select_layer(layer_ix, cx);
- })
+ ) -> Div {
+ // todo!() styling
+ let _is_selected = layer.node() == active_layer.node();
+ let view = cx.view().clone();
+ h_stack()
+ .child(Label::new(layer.language.name().to_string()))
+ .child(Label::new(format_node_range(layer.node())))
+ .cursor(CursorStyle::PointingHand)
+ .on_mouse_down(MouseButton::Left, move |_, cx| {
+ view.update(cx, |view, cx| {
+ view.select_layer(layer_ix, cx);
+ })
+ })
+ .border_1()
+ .border_color(red())
}
}
@@ -630,33 +588,32 @@ fn format_node_range(node: Node) -> String {
}
impl Render for SyntaxTreeToolbarItemView {
- type Element = Focusable<Div>;
+ type Element = Div;
// todo!()
// fn ui_name() -> &'static str {
// "SyntaxTreeToolbarItemView"
// }
- fn render(&mut self, cx: &mut ViewContext<'_, '_, Self>) -> gpui::AnyElement<Self> {
- self.render_menu(cx)
- .unwrap_or_else(|| Empty::new().into_any())
+ fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> Div {
+ self.render_menu(cx).unwrap_or_else(|| div())
}
}
+impl EventEmitter<ToolbarItemEvent> for SyntaxTreeToolbarItemView {}
+
impl ToolbarItemView for SyntaxTreeToolbarItemView {
fn set_active_pane_item(
&mut self,
active_pane_item: Option<&dyn ItemHandle>,
cx: &mut ViewContext<Self>,
- ) -> workspace::ToolbarItemLocation {
+ ) -> ToolbarItemLocation {
self.menu_open = false;
if let Some(item) = active_pane_item {
if let Some(view) = item.downcast::<SyntaxTreeView>() {
self.tree_view = Some(view.clone());
self.subscription = Some(cx.observe(&view, |_, _, cx| cx.notify()));
- return ToolbarItemLocation::PrimaryLeft {
- flex: Some((1., false)),
- };
+ return ToolbarItemLocation::PrimaryLeft;
}
}
self.tree_view = None;