@@ -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<Workspace>,
- // ) {
- // let editor = workspace.open_path(path, None, true, cx);
- // cx.spawn(|_, mut cx| async move {
- // let editor = editor
- // .await?
- // .downcast::<Editor>()
- // .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<Self>,
+ ) {
+ 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::<Editor>()
+ .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<Vec<Range<OffsetUtf16>>> {
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::<BlockContext, _>(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::<BlockContextToolip>(
- // 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()
})
}
@@ -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<Pixels>,
- // visible_bounds: Bounds<Pixels>,
- // layout: &mut LayoutState,
- // editor: &mut Editor,
- // cx: &mut ViewContext<Editor>,
- // ) {
- // 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);
- // }
- // }
+ fn paint_blocks(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ layout: &mut LayoutState,
+ editor: &mut Editor,
+ cx: &mut ViewContext<Editor>,
+ ) {
+ 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(
+ 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<Editor>) -> 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<AvailableSpace>,
+ block_id: usize,
+ editor: &mut Editor,
+ cx: &mut ViewContext<Editor>| {
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::<Pixels>::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<Editor> 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<Range<u32>>,
line_number_layouts: Vec<Option<gpui::Line>>,
display_hunks: Vec<DisplayDiffHunk>,
- // blocks: Vec<BlockLayout>,
+ blocks: Vec<BlockLayout>,
highlighted_ranges: Vec<(Range<DisplayPoint>, Hsla)>,
fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Hsla)>,
selections: Vec<(PlayerColor, Vec<SelectionLayout>)>,
@@ -3358,6 +3357,7 @@ impl PositionMap {
struct BlockLayout {
row: u32,
element: AnyElement<Editor>,
+ available_space: Size<AvailableSpace>,
style: BlockStyle,
}