diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index fe98dd8679..22ceea51a3 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -22,7 +22,7 @@ mod editor_tests; pub mod test; use ::git::diff::DiffHunk; use aho_corasick::AhoCorasick; -use anyhow::{Context as _, Result}; +use anyhow::{anyhow, Context as _, Result}; use blink_manager::BlinkManager; use client::{ClickhouseEvent, Client, Collaborator, ParticipantIndex, TelemetrySettings}; use clock::ReplicaId; @@ -43,8 +43,8 @@ use gpui::{ AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context, EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, - StatelessInteractive, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View, - ViewContext, VisualContext, WeakView, WindowContext, + StatefulInteractive, StatelessInteractive, Styled, Subscription, Task, TextStyle, + UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WindowContext, }; use highlight_matching_bracket::refresh_matching_bracket_highlights; use hover_popover::{hide_hover, HoverState}; @@ -69,7 +69,7 @@ pub use multi_buffer::{ }; use ordered_float::OrderedFloat; use parking_lot::{Mutex, RwLock}; -use project::{FormatTrigger, Location, Project, ProjectTransaction}; +use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction}; use rand::prelude::*; use rpc::proto::*; use scroll::{ @@ -97,7 +97,7 @@ use text::{OffsetUtf16, Rope}; use theme::{ ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings, }; -use ui::{IconButton, StyledExt}; +use ui::{v_stack, HighlightedLabel, IconButton, StyledExt, TextTooltip}; use util::{post_inc, RangeExt, ResultExt, TryFutureExt}; use workspace::{ item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, @@ -8869,46 +8869,50 @@ impl Editor { // }); // } - // fn jump( - // workspace: &mut Workspace, - // path: ProjectPath, - // position: Point, - // anchor: language::Anchor, - // cx: &mut ViewContext, - // ) { - // let editor = workspace.open_path(path, None, true, cx); - // cx.spawn(|_, mut cx| async move { - // let editor = editor - // .await? - // .downcast::() - // .ok_or_else(|| anyhow!("opened item was not an editor"))? - // .downgrade(); - // editor.update(&mut cx, |editor, cx| { - // let buffer = editor - // .buffer() - // .read(cx) - // .as_singleton() - // .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?; - // let buffer = buffer.read(cx); - // let cursor = if buffer.can_resolve(&anchor) { - // language::ToPoint::to_point(&anchor, buffer) - // } else { - // buffer.clip_point(position, Bias::Left) - // }; + fn jump( + &mut self, + path: ProjectPath, + position: Point, + anchor: language::Anchor, + cx: &mut ViewContext, + ) { + let workspace = self.workspace(); + cx.spawn(|_, mut cx| async move { + let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?; + let editor = workspace.update(&mut cx, |workspace, cx| { + workspace.open_path(path, None, true, cx) + })?; + let editor = editor + .await? + .downcast::() + .ok_or_else(|| anyhow!("opened item was not an editor"))? + .downgrade(); + editor.update(&mut cx, |editor, cx| { + let buffer = editor + .buffer() + .read(cx) + .as_singleton() + .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?; + let buffer = buffer.read(cx); + let cursor = if buffer.can_resolve(&anchor) { + language::ToPoint::to_point(&anchor, buffer) + } else { + buffer.clip_point(position, Bias::Left) + }; - // let nav_history = editor.nav_history.take(); - // editor.change_selections(Some(Autoscroll::newest()), cx, |s| { - // s.select_ranges([cursor..cursor]); - // }); - // editor.nav_history = nav_history; + let nav_history = editor.nav_history.take(); + editor.change_selections(Some(Autoscroll::newest()), cx, |s| { + s.select_ranges([cursor..cursor]); + }); + editor.nav_history = nav_history; - // anyhow::Ok(()) - // })??; + anyhow::Ok(()) + })??; - // anyhow::Ok(()) - // }) - // .detach_and_log_err(cx); - // } + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + } fn marked_text_ranges(&self, cx: &AppContext) -> Option>> { let snapshot = self.buffer.read(cx).read(cx); @@ -9973,43 +9977,20 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend } let message = diagnostic.message; Arc::new(move |cx: &mut BlockContext| { - todo!() - // let message = message.clone(); - // let settings = ThemeSettings::get_global(cx); - // let tooltip_style = settings.theme.tooltip.clone(); - // let theme = &settings.theme.editor; - // let style = diagnostic_style(diagnostic.severity, is_valid, theme); - // let font_size = (style.text_scale_factor * settings.buffer_font_size(cx)).round(); - // let anchor_x = cx.anchor_x; - // enum BlockContextToolip {} - // MouseEventHandler::new::(cx.block_id, cx, |_, _| { - // Flex::column() - // .with_children(highlighted_lines.iter().map(|(line, highlights)| { - // Label::new( - // line.clone(), - // style.message.clone().with_font_size(font_size), - // ) - // .with_highlights(highlights.clone()) - // .contained() - // .with_margin_left(anchor_x) - // })) - // .aligned() - // .left() - // .into_any() - // }) - // .with_cursor_style(CursorStyle::PointingHand) - // .on_click(MouseButton::Left, move |_, _, cx| { - // cx.write_to_clipboard(ClipboardItem::new(message.clone())); - // }) - // // We really need to rethink this ID system... - // .with_tooltip::( - // cx.block_id, - // "Copy diagnostic message", - // None, - // tooltip_style, - // cx, - // ) - // .into_any() + let message = message.clone(); + v_stack() + .id(cx.block_id) + .children(highlighted_lines.iter().map(|(line, highlights)| { + div() + .child(HighlightedLabel::new(line.clone(), highlights.clone())) + .ml(cx.anchor_x) + })) + .cursor_pointer() + .on_click(move |_, _, cx| { + cx.write_to_clipboard(ClipboardItem::new(message.clone())); + }) + .tooltip(|_, cx| cx.build_view(|cx| TextTooltip::new("Copy diagnostic message"))) + .render() }) } diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index 8a1385cf93..64a281d9e2 100644 --- a/crates/editor2/src/element.rs +++ b/crates/editor2/src/element.rs @@ -19,9 +19,10 @@ use anyhow::Result; use collections::{BTreeMap, HashMap}; use gpui::{ point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace, BorrowWindow, - Bounds, ContentMask, Corners, DispatchPhase, Edges, Element, ElementId, ElementInputHandler, - Entity, Hsla, Line, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, - Pixels, ScrollWheelEvent, Size, Style, TextRun, TextStyle, ViewContext, WindowContext, + Bounds, Component, ContentMask, Corners, DispatchPhase, Edges, Element, ElementId, + ElementInputHandler, Entity, Hsla, Line, MouseButton, MouseDownEvent, MouseMoveEvent, + MouseUpEvent, ParentElement, Pixels, ScrollWheelEvent, Size, Style, TextRun, TextStyle, + ViewContext, WindowContext, }; use itertools::Itertools; use language::language_settings::ShowWhitespaceSetting; @@ -1176,30 +1177,31 @@ impl EditorElement { } } - // fn paint_blocks( - // &mut self, - // bounds: Bounds, - // visible_bounds: Bounds, - // layout: &mut LayoutState, - // editor: &mut Editor, - // cx: &mut ViewContext, - // ) { - // let scroll_position = layout.position_map.snapshot.scroll_position(); - // let scroll_left = scroll_position.x * layout.position_map.em_width; - // let scroll_top = scroll_position.y * layout.position_map.line_height; + fn paint_blocks( + &mut self, + bounds: Bounds, + layout: &mut LayoutState, + editor: &mut Editor, + cx: &mut ViewContext, + ) { + let scroll_position = layout.position_map.snapshot.scroll_position(); + let scroll_left = scroll_position.x * layout.position_map.em_width; + let scroll_top = scroll_position.y * layout.position_map.line_height; - // for block in &mut layout.blocks { - // let mut origin = bounds.origin - // + point( - // 0., - // block.row as f32 * layout.position_map.line_height - scroll_top, - // ); - // if !matches!(block.style, BlockStyle::Sticky) { - // origin += point(-scroll_left, 0.); - // } - // block.element.paint(origin, visible_bounds, editor, cx); - // } - // } + for block in &mut layout.blocks { + let mut origin = bounds.origin + + point( + Pixels::ZERO, + block.row as f32 * layout.position_map.line_height - scroll_top, + ); + if !matches!(block.style, BlockStyle::Sticky) { + origin += point(-scroll_left, Pixels::ZERO); + } + block + .element + .draw(origin, block.available_space, editor, cx); + } + } fn column_pixels(&self, column: usize, cx: &ViewContext) -> Pixels { let style = &self.style; @@ -1942,7 +1944,7 @@ impl EditorElement { fold_ranges, line_number_layouts, display_hunks, - // blocks, + blocks, selections, context_menu, code_actions_indicator, @@ -1978,7 +1980,11 @@ impl EditorElement { TransformBlock::ExcerptHeader { .. } => false, TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed, }); - let mut render_block = |block: &TransformBlock, width: Pixels, block_id: usize| { + let mut render_block = |block: &TransformBlock, + available_space: Size, + block_id: usize, + editor: &mut Editor, + cx: &mut ViewContext| { let mut element = match block { TransformBlock::Custom(block) => { let align_to = block @@ -2031,28 +2037,15 @@ impl EditorElement { let jump_position = language::ToPoint::to_point(&jump_anchor, buffer); // todo!("avoid ElementId collision risk here") - IconButton::new(usize::from(*id), ui::Icon::ArrowUpRight) - .on_click(move |editor, cx| { - if let Some(workspace) = editor - .workspace - .as_ref() - .and_then(|(workspace, _)| workspace.upgrade(cx)) - { - workspace.update(cx, |workspace, cx| { - Editor::jump( - workspace, - jump_path.clone(), - jump_position, - jump_anchor, - cx, - ); - }); - } + let icon_button_id: usize = id.clone().into(); + IconButton::new(icon_button_id, ui::Icon::ArrowUpRight) + .on_click(move |editor: &mut Editor, cx| { + editor.jump(jump_path.clone(), jump_position, jump_anchor, cx); }) .tooltip("Jump to Buffer") // todo!(pass an action as well to show key binding) }); - if *starts_new_buffer { + let element = if *starts_new_buffer { let path = buffer.resolve_file_path(cx, include_root); let mut filename = None; let mut parent_path = None; @@ -2066,40 +2059,34 @@ impl EditorElement { h_stack() .child(filename.unwrap_or_else(|| "untitled".to_string())) .children(parent_path) - .children(jump_icon) - .p_x(gutter_padding) + .children(jump_icon) // .p_x(gutter_padding) } else { let text_style = style.text.clone(); - h_stack() - .child("⋯") - .children(jump_icon) - .p_x(gutter_padding) - .expanded() - .into_any_named("collapsed context") - } + h_stack().child("⋯").children(jump_icon) // .p_x(gutter_padding) + }; + element.render() } }; - // element.layout( - // SizeConstraint { - // min: gpui::Point::::zero(), - // max: point(width, block.height() as f32 * line_height), - // }, - // editor, - // cx, - // ); - element + let size = element.measure(available_space, editor, cx); + (element, size) }; let mut fixed_block_max_width = Pixels::ZERO; let mut blocks = Vec::new(); for (row, block) in fixed_blocks { - let element = render_block(block, f32::INFINITY, block_id); + let available_space = size( + AvailableSpace::MinContent, + AvailableSpace::Definite(block.height() as f32 * line_height), + ); + let (element, element_size) = + render_block(block, available_space, block_id, editor, cx); block_id += 1; - fixed_block_max_width = fixed_block_max_width.max(element.size().x + em_width); + fixed_block_max_width = fixed_block_max_width.max(element_size.width + em_width); blocks.push(BlockLayout { row, element, + available_space, style: BlockStyle::Fixed, }); } @@ -2115,11 +2102,16 @@ impl EditorElement { .max(gutter_width + scroll_width), BlockStyle::Fixed => unreachable!(), }; - let element = render_block(block, width, block_id); + let available_space = size( + AvailableSpace::Definite(width), + AvailableSpace::Definite(block.height() as f32 * line_height), + ); + let (element, _) = render_block(block, available_space, block_id, editor, cx); block_id += 1; blocks.push(BlockLayout { row, element, + available_space, style, }); } @@ -2630,11 +2622,18 @@ impl Element for EditorElement { &layout.position_map, cx, ); + self.paint_background(gutter_bounds, text_bounds, &layout, cx); if layout.gutter_size.width > Pixels::ZERO { self.paint_gutter(gutter_bounds, &mut layout, editor, cx); } + self.paint_text(text_bounds, &mut layout, editor, cx); + + if !layout.blocks.is_empty() { + self.paint_blocks(bounds, &mut layout, editor, cx); + } + let input_handler = ElementInputHandler::new(bounds, cx); cx.handle_input(&editor.focus_handle, input_handler); }); @@ -3255,7 +3254,7 @@ pub struct LayoutState { highlighted_rows: Option>, line_number_layouts: Vec>, display_hunks: Vec, - // blocks: Vec, + blocks: Vec, highlighted_ranges: Vec<(Range, Hsla)>, fold_ranges: Vec<(BufferRow, Range, Hsla)>, selections: Vec<(PlayerColor, Vec)>, @@ -3358,6 +3357,7 @@ impl PositionMap { struct BlockLayout { row: u32, element: AnyElement, + available_space: Size, style: BlockStyle, } diff --git a/crates/ui2/src/components/tooltip.rs b/crates/ui2/src/components/tooltip.rs index e6c0e3f44d..ee3e9708c0 100644 --- a/crates/ui2/src/components/tooltip.rs +++ b/crates/ui2/src/components/tooltip.rs @@ -9,8 +9,10 @@ pub struct TextTooltip { } impl TextTooltip { - pub fn new(str: SharedString) -> Self { - Self { title: str } + pub fn new(title: impl Into) -> Self { + Self { + title: title.into(), + } } }