Render block elements

Co-Authored-By: Julia <julia@zed.dev>
This commit is contained in:
Antonio Scandurra 2023-11-14 16:03:06 +01:00
parent fc5ec47cc8
commit f9b9b7549f
3 changed files with 132 additions and 149 deletions

View file

@ -22,7 +22,7 @@ mod editor_tests;
pub mod test; pub mod test;
use ::git::diff::DiffHunk; use ::git::diff::DiffHunk;
use aho_corasick::AhoCorasick; use aho_corasick::AhoCorasick;
use anyhow::{Context as _, Result}; use anyhow::{anyhow, Context as _, Result};
use blink_manager::BlinkManager; use blink_manager::BlinkManager;
use client::{ClickhouseEvent, Client, Collaborator, ParticipantIndex, TelemetrySettings}; use client::{ClickhouseEvent, Client, Collaborator, ParticipantIndex, TelemetrySettings};
use clock::ReplicaId; use clock::ReplicaId;
@ -43,8 +43,8 @@ use gpui::{
AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla, EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla,
InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render,
StatelessInteractive, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View, StatefulInteractive, StatelessInteractive, Styled, Subscription, Task, TextStyle,
ViewContext, VisualContext, WeakView, WindowContext, UniformListScrollHandle, View, ViewContext, VisualContext, WeakView, WindowContext,
}; };
use highlight_matching_bracket::refresh_matching_bracket_highlights; use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState}; use hover_popover::{hide_hover, HoverState};
@ -69,7 +69,7 @@ pub use multi_buffer::{
}; };
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use project::{FormatTrigger, Location, Project, ProjectTransaction}; use project::{FormatTrigger, Location, Project, ProjectPath, ProjectTransaction};
use rand::prelude::*; use rand::prelude::*;
use rpc::proto::*; use rpc::proto::*;
use scroll::{ use scroll::{
@ -97,7 +97,7 @@ use text::{OffsetUtf16, Rope};
use theme::{ use theme::{
ActiveTheme, DiagnosticStyle, PlayerColor, SyntaxTheme, Theme, ThemeColors, ThemeSettings, 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 util::{post_inc, RangeExt, ResultExt, TryFutureExt};
use workspace::{ use workspace::{
item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, item::ItemEvent, searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace,
@ -8869,46 +8869,50 @@ impl Editor {
// }); // });
// } // }
// fn jump( fn jump(
// workspace: &mut Workspace, &mut self,
// path: ProjectPath, path: ProjectPath,
// position: Point, position: Point,
// anchor: language::Anchor, anchor: language::Anchor,
// cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Self>,
// ) { ) {
// let editor = workspace.open_path(path, None, true, cx); let workspace = self.workspace();
// cx.spawn(|_, mut cx| async move { cx.spawn(|_, mut cx| async move {
// let editor = editor let workspace = workspace.ok_or_else(|| anyhow!("cannot jump without workspace"))?;
// .await? let editor = workspace.update(&mut cx, |workspace, cx| {
// .downcast::<Editor>() workspace.open_path(path, None, true, cx)
// .ok_or_else(|| anyhow!("opened item was not an editor"))? })?;
// .downgrade(); let editor = editor
// editor.update(&mut cx, |editor, cx| { .await?
// let buffer = editor .downcast::<Editor>()
// .buffer() .ok_or_else(|| anyhow!("opened item was not an editor"))?
// .read(cx) .downgrade();
// .as_singleton() editor.update(&mut cx, |editor, cx| {
// .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?; let buffer = editor
// let buffer = buffer.read(cx); .buffer()
// let cursor = if buffer.can_resolve(&anchor) { .read(cx)
// language::ToPoint::to_point(&anchor, buffer) .as_singleton()
// } else { .ok_or_else(|| anyhow!("cannot jump in a multi-buffer"))?;
// buffer.clip_point(position, Bias::Left) 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(); let nav_history = editor.nav_history.take();
// editor.change_selections(Some(Autoscroll::newest()), cx, |s| { editor.change_selections(Some(Autoscroll::newest()), cx, |s| {
// s.select_ranges([cursor..cursor]); s.select_ranges([cursor..cursor]);
// }); });
// editor.nav_history = nav_history; editor.nav_history = nav_history;
// anyhow::Ok(()) anyhow::Ok(())
// })??; })??;
// anyhow::Ok(()) anyhow::Ok(())
// }) })
// .detach_and_log_err(cx); .detach_and_log_err(cx);
// } }
fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> { fn marked_text_ranges(&self, cx: &AppContext) -> Option<Vec<Range<OffsetUtf16>>> {
let snapshot = self.buffer.read(cx).read(cx); 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; let message = diagnostic.message;
Arc::new(move |cx: &mut BlockContext| { Arc::new(move |cx: &mut BlockContext| {
todo!() let message = message.clone();
// let message = message.clone(); v_stack()
// let settings = ThemeSettings::get_global(cx); .id(cx.block_id)
// let tooltip_style = settings.theme.tooltip.clone(); .children(highlighted_lines.iter().map(|(line, highlights)| {
// let theme = &settings.theme.editor; div()
// let style = diagnostic_style(diagnostic.severity, is_valid, theme); .child(HighlightedLabel::new(line.clone(), highlights.clone()))
// let font_size = (style.text_scale_factor * settings.buffer_font_size(cx)).round(); .ml(cx.anchor_x)
// let anchor_x = cx.anchor_x; }))
// enum BlockContextToolip {} .cursor_pointer()
// MouseEventHandler::new::<BlockContext, _>(cx.block_id, cx, |_, _| { .on_click(move |_, _, cx| {
// Flex::column() cx.write_to_clipboard(ClipboardItem::new(message.clone()));
// .with_children(highlighted_lines.iter().map(|(line, highlights)| { })
// Label::new( .tooltip(|_, cx| cx.build_view(|cx| TextTooltip::new("Copy diagnostic message")))
// line.clone(), .render()
// 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::<BlockContextToolip>(
// cx.block_id,
// "Copy diagnostic message",
// None,
// tooltip_style,
// cx,
// )
// .into_any()
}) })
} }

View file

@ -19,9 +19,10 @@ use anyhow::Result;
use collections::{BTreeMap, HashMap}; use collections::{BTreeMap, HashMap};
use gpui::{ use gpui::{
point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace, BorrowWindow, point, px, relative, size, transparent_black, Action, AnyElement, AvailableSpace, BorrowWindow,
Bounds, ContentMask, Corners, DispatchPhase, Edges, Element, ElementId, ElementInputHandler, Bounds, Component, ContentMask, Corners, DispatchPhase, Edges, Element, ElementId,
Entity, Hsla, Line, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, ElementInputHandler, Entity, Hsla, Line, MouseButton, MouseDownEvent, MouseMoveEvent,
Pixels, ScrollWheelEvent, Size, Style, TextRun, TextStyle, ViewContext, WindowContext, MouseUpEvent, ParentElement, Pixels, ScrollWheelEvent, Size, Style, TextRun, TextStyle,
ViewContext, WindowContext,
}; };
use itertools::Itertools; use itertools::Itertools;
use language::language_settings::ShowWhitespaceSetting; use language::language_settings::ShowWhitespaceSetting;
@ -1176,30 +1177,31 @@ impl EditorElement {
} }
} }
// fn paint_blocks( fn paint_blocks(
// &mut self, &mut self,
// bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
// visible_bounds: Bounds<Pixels>, layout: &mut LayoutState,
// layout: &mut LayoutState, editor: &mut Editor,
// editor: &mut Editor, cx: &mut ViewContext<Editor>,
// cx: &mut ViewContext<Editor>, ) {
// ) { let scroll_position = layout.position_map.snapshot.scroll_position();
// let scroll_position = layout.position_map.snapshot.scroll_position(); let scroll_left = scroll_position.x * layout.position_map.em_width;
// let scroll_left = scroll_position.x * layout.position_map.em_width; let scroll_top = scroll_position.y * layout.position_map.line_height;
// let scroll_top = scroll_position.y * layout.position_map.line_height;
// for block in &mut layout.blocks { for block in &mut layout.blocks {
// let mut origin = bounds.origin let mut origin = bounds.origin
// + point( + point(
// 0., Pixels::ZERO,
// block.row as f32 * layout.position_map.line_height - scroll_top, block.row as f32 * layout.position_map.line_height - scroll_top,
// ); );
// if !matches!(block.style, BlockStyle::Sticky) { if !matches!(block.style, BlockStyle::Sticky) {
// origin += point(-scroll_left, 0.); origin += point(-scroll_left, Pixels::ZERO);
// } }
// block.element.paint(origin, visible_bounds, editor, cx); block
// } .element
// } .draw(origin, block.available_space, editor, cx);
}
}
fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> Pixels { fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> Pixels {
let style = &self.style; let style = &self.style;
@ -1942,7 +1944,7 @@ impl EditorElement {
fold_ranges, fold_ranges,
line_number_layouts, line_number_layouts,
display_hunks, display_hunks,
// blocks, blocks,
selections, selections,
context_menu, context_menu,
code_actions_indicator, code_actions_indicator,
@ -1978,7 +1980,11 @@ impl EditorElement {
TransformBlock::ExcerptHeader { .. } => false, TransformBlock::ExcerptHeader { .. } => false,
TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed, 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<AvailableSpace>,
block_id: usize,
editor: &mut Editor,
cx: &mut ViewContext<Editor>| {
let mut element = match block { let mut element = match block {
TransformBlock::Custom(block) => { TransformBlock::Custom(block) => {
let align_to = block let align_to = block
@ -2031,28 +2037,15 @@ impl EditorElement {
let jump_position = language::ToPoint::to_point(&jump_anchor, buffer); let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
// todo!("avoid ElementId collision risk here") // todo!("avoid ElementId collision risk here")
IconButton::new(usize::from(*id), ui::Icon::ArrowUpRight) let icon_button_id: usize = id.clone().into();
.on_click(move |editor, cx| { IconButton::new(icon_button_id, ui::Icon::ArrowUpRight)
if let Some(workspace) = editor .on_click(move |editor: &mut Editor, cx| {
.workspace editor.jump(jump_path.clone(), jump_position, jump_anchor, cx);
.as_ref()
.and_then(|(workspace, _)| workspace.upgrade(cx))
{
workspace.update(cx, |workspace, cx| {
Editor::jump(
workspace,
jump_path.clone(),
jump_position,
jump_anchor,
cx,
);
});
}
}) })
.tooltip("Jump to Buffer") // todo!(pass an action as well to show key binding) .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 path = buffer.resolve_file_path(cx, include_root);
let mut filename = None; let mut filename = None;
let mut parent_path = None; let mut parent_path = None;
@ -2066,40 +2059,34 @@ impl EditorElement {
h_stack() h_stack()
.child(filename.unwrap_or_else(|| "untitled".to_string())) .child(filename.unwrap_or_else(|| "untitled".to_string()))
.children(parent_path) .children(parent_path)
.children(jump_icon) .children(jump_icon) // .p_x(gutter_padding)
.p_x(gutter_padding)
} else { } else {
let text_style = style.text.clone(); let text_style = style.text.clone();
h_stack() h_stack().child("").children(jump_icon) // .p_x(gutter_padding)
.child("") };
.children(jump_icon) element.render()
.p_x(gutter_padding)
.expanded()
.into_any_named("collapsed context")
}
} }
}; };
// element.layout( let size = element.measure(available_space, editor, cx);
// SizeConstraint { (element, size)
// min: gpui::Point::<Pixels>::zero(),
// max: point(width, block.height() as f32 * line_height),
// },
// editor,
// cx,
// );
element
}; };
let mut fixed_block_max_width = Pixels::ZERO; let mut fixed_block_max_width = Pixels::ZERO;
let mut blocks = Vec::new(); let mut blocks = Vec::new();
for (row, block) in fixed_blocks { 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; 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 { blocks.push(BlockLayout {
row, row,
element, element,
available_space,
style: BlockStyle::Fixed, style: BlockStyle::Fixed,
}); });
} }
@ -2115,11 +2102,16 @@ impl EditorElement {
.max(gutter_width + scroll_width), .max(gutter_width + scroll_width),
BlockStyle::Fixed => unreachable!(), 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; block_id += 1;
blocks.push(BlockLayout { blocks.push(BlockLayout {
row, row,
element, element,
available_space,
style, style,
}); });
} }
@ -2630,11 +2622,18 @@ impl Element<Editor> for EditorElement {
&layout.position_map, &layout.position_map,
cx, cx,
); );
self.paint_background(gutter_bounds, text_bounds, &layout, cx); self.paint_background(gutter_bounds, text_bounds, &layout, cx);
if layout.gutter_size.width > Pixels::ZERO { if layout.gutter_size.width > Pixels::ZERO {
self.paint_gutter(gutter_bounds, &mut layout, editor, cx); self.paint_gutter(gutter_bounds, &mut layout, editor, cx);
} }
self.paint_text(text_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); let input_handler = ElementInputHandler::new(bounds, cx);
cx.handle_input(&editor.focus_handle, input_handler); cx.handle_input(&editor.focus_handle, input_handler);
}); });
@ -3255,7 +3254,7 @@ pub struct LayoutState {
highlighted_rows: Option<Range<u32>>, highlighted_rows: Option<Range<u32>>,
line_number_layouts: Vec<Option<gpui::Line>>, line_number_layouts: Vec<Option<gpui::Line>>,
display_hunks: Vec<DisplayDiffHunk>, display_hunks: Vec<DisplayDiffHunk>,
// blocks: Vec<BlockLayout>, blocks: Vec<BlockLayout>,
highlighted_ranges: Vec<(Range<DisplayPoint>, Hsla)>, highlighted_ranges: Vec<(Range<DisplayPoint>, Hsla)>,
fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Hsla)>, fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Hsla)>,
selections: Vec<(PlayerColor, Vec<SelectionLayout>)>, selections: Vec<(PlayerColor, Vec<SelectionLayout>)>,
@ -3358,6 +3357,7 @@ impl PositionMap {
struct BlockLayout { struct BlockLayout {
row: u32, row: u32,
element: AnyElement<Editor>, element: AnyElement<Editor>,
available_space: Size<AvailableSpace>,
style: BlockStyle, style: BlockStyle,
} }

View file

@ -9,8 +9,10 @@ pub struct TextTooltip {
} }
impl TextTooltip { impl TextTooltip {
pub fn new(str: SharedString) -> Self { pub fn new(title: impl Into<SharedString>) -> Self {
Self { title: str } Self {
title: title.into(),
}
} }
} }