@@ -9,12 +9,13 @@ use anyhow::Result;
use collections::{BTreeMap, HashMap};
use gpui::{
black, hsla, point, px, relative, size, transparent_black, AnyElement, BorrowWindow, Bounds,
- ContentMask, Corners, Edges, Element, Hsla, Line, Pixels, Size, Style, TextRun, TextStyle,
- TextSystem, ViewContext, WindowContext,
+ ContentMask, Corners, Edges, Element, Hsla, Line, Pixels, ShapedGlyph, Size, Style, TextRun,
+ TextStyle, TextSystem, ViewContext, WindowContext,
};
use itertools::Itertools;
use language::language_settings::ShowWhitespaceSetting;
use multi_buffer::Anchor;
+use project::project_settings::{GitGutterSetting, ProjectSettings};
use settings::Settings;
use smallvec::SmallVec;
use std::{
@@ -373,29 +374,29 @@ impl EditorElement {
// );
// if editor.has_pending_selection() {
- // let mut scroll_delta = gpui::Point<Pixels>::zero();
+ // let mut scroll_delta = gpui::Point::<Pixels>::zero();
// let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);
// let top = text_bounds.origin.y + vertical_margin;
- // let bottom = text_bounds.lower_left().y() - vertical_margin;
- // if position.y() < top {
- // scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))
+ // let bottom = text_bounds.lower_left().y - vertical_margin;
+ // if position.y < top {
+ // scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y))
// }
- // if position.y() > bottom {
- // scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
+ // if position.y > bottom {
+ // scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y - bottom))
// }
// let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);
// let left = text_bounds.origin.x + horizontal_margin;
- // let right = text_bounds.upper_right().x() - horizontal_margin;
- // if position.x() < left {
+ // let right = text_bounds.upper_right().x - horizontal_margin;
+ // if position.x < left {
// scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
- // left - position.x(),
+ // left - position.x,
// ))
// }
- // if position.x() > right {
+ // if position.x > right {
// scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
- // position.x() - right,
+ // position.x - right,
// ))
// }
@@ -406,7 +407,7 @@ impl EditorElement {
// position: point_for_position.previous_valid,
// goal_column: point_for_position.exact_unclipped.column(),
// scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
- // .clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max),
+ // .clamp(gpui::Point::<Pixels>::zero(), position_map.scroll_max),
// },
// cx,
// );
@@ -489,9 +490,9 @@ impl EditorElement {
// };
// let scroll_position = position_map.snapshot.scroll_position();
- // let x = (scroll_position.x() * max_glyph_width - delta.x()) / max_glyph_width;
- // let y = (scroll_position.y() * line_height - delta.y()) / line_height;
- // let scroll_position = point(x, y).clamp(gpui::Point<Pixels>::zero(), position_map.scroll_max);
+ // let x = (scroll_position.x * max_glyph_width - delta.x) / max_glyph_width;
+ // let y = (scroll_position.y * line_height - delta.y) / line_height;
+ // let scroll_position = point(x, y).clamp(gpui::Point::<Pixels>::zero(), position_map.scroll_max);
// editor.scroll(scroll_position, axis, cx);
// true
@@ -608,452 +609,476 @@ impl EditorElement {
}
}
- // fn paint_gutter(
- // &mut self,
- // bounds: Bounds<Pixels>,
- // visible_bounds: Bounds<Pixels>,
- // layout: &mut LayoutState,
- // editor: &mut Editor,
- // cx: &mut ViewContext<Editor>,
- // ) {
- // let line_height = layout.position_map.line_height;
-
- // let scroll_position = layout.position_map.snapshot.scroll_position();
- // let scroll_top = scroll_position.y() * line_height;
-
- // let show_gutter = matches!(
- // settings::get::<ProjectSettings>(cx).git.git_gutter,
- // Some(GitGutterSetting::TrackedFiles)
- // );
-
- // if show_gutter {
- // Self::paint_diff_hunks(bounds, layout, cx);
- // }
-
- // for (ix, line) in layout.line_number_layouts.iter().enumerate() {
- // if let Some(line) = line {
- // let line_origin = bounds.origin()
- // + point(
- // bounds.width() - line.width() - layout.gutter_padding,
- // ix as f32 * line_height - (scroll_top % line_height),
- // );
-
- // line.paint(line_origin, visible_bounds, line_height, cx);
- // }
- // }
-
- // for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
- // if let Some(indicator) = fold_indicator.as_mut() {
- // let position = point(
- // bounds.width() - layout.gutter_padding,
- // ix as f32 * line_height - (scroll_top % line_height),
- // );
- // let centering_offset = point(
- // (layout.gutter_padding + layout.gutter_margin - indicator.size().x()) / 2.,
- // (line_height - indicator.size().y()) / 2.,
- // );
-
- // let indicator_origin = bounds.origin() + position + centering_offset;
-
- // indicator.paint(indicator_origin, visible_bounds, editor, cx);
- // }
- // }
-
- // if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
- // let mut x = 0.;
- // let mut y = *row as f32 * line_height - scroll_top;
- // x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
- // y += (line_height - indicator.size().y()) / 2.;
- // indicator.paint(bounds.origin() + point(x, y), visible_bounds, editor, cx);
- // }
- // }
-
- // fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &mut LayoutState, cx: &mut ViewContext<Editor>) {
- // let diff_style = &theme::current(cx).editor.diff.clone();
- // let line_height = layout.position_map.line_height;
-
- // let scroll_position = layout.position_map.snapshot.scroll_position();
- // let scroll_top = scroll_position.y() * line_height;
-
- // for hunk in &layout.display_hunks {
- // let (display_row_range, status) = match hunk {
- // //TODO: This rendering is entirely a horrible hack
- // &DisplayDiffHunk::Folded { display_row: row } => {
- // let start_y = row as f32 * line_height - scroll_top;
- // let end_y = start_y + line_height;
-
- // let width = diff_style.removed_width_em * line_height;
- // let highlight_origin = bounds.origin() + point(-width, start_y);
- // let highlight_size = point(width * 2., end_y - start_y);
- // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
-
- // cx.paint_quad(Quad {
- // bounds: highlight_bounds,
- // background: Some(diff_style.modified),
- // border: Border::new(0., Color::transparent_black()).into(),
- // corner_radii: (1. * line_height).into(),
- // });
-
- // continue;
- // }
-
- // DisplayDiffHunk::Unfolded {
- // display_row_range,
- // status,
- // } => (display_row_range, status),
- // };
-
- // let color = match status {
- // DiffHunkStatus::Added => diff_style.inserted,
- // DiffHunkStatus::Modified => diff_style.modified,
-
- // //TODO: This rendering is entirely a horrible hack
- // DiffHunkStatus::Removed => {
- // let row = display_row_range.start;
+ fn paint_gutter(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ layout: &mut LayoutState,
+ editor: &mut Editor,
+ cx: &mut ViewContext<Editor>,
+ ) {
+ let line_height = layout.position_map.line_height;
- // let offset = line_height / 2.;
- // let start_y = row as f32 * line_height - offset - scroll_top;
- // let end_y = start_y + line_height;
+ let scroll_position = layout.position_map.snapshot.scroll_position();
+ let scroll_top = scroll_position.y * line_height;
- // let width = diff_style.removed_width_em * line_height;
- // let highlight_origin = bounds.origin() + point(-width, start_y);
- // let highlight_size = point(width * 2., end_y - start_y);
- // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
+ let show_gutter = matches!(
+ ProjectSettings::get_global(cx).git.git_gutter,
+ Some(GitGutterSetting::TrackedFiles)
+ );
- // cx.paint_quad(Quad {
- // bounds: highlight_bounds,
- // background: Some(diff_style.deleted),
- // border: Border::new(0., Color::transparent_black()).into(),
- // corner_radii: (1. * line_height).into(),
- // });
+ if show_gutter {
+ Self::paint_diff_hunks(bounds, layout, cx);
+ }
- // continue;
- // }
- // };
+ for (ix, line) in layout.line_number_layouts.iter().enumerate() {
+ if let Some(line) = line {
+ let line_origin = bounds.origin
+ + point(
+ bounds.size.width - line.width - layout.gutter_padding,
+ ix as f32 * line_height - (scroll_top % line_height),
+ );
- // let start_row = display_row_range.start;
- // let end_row = display_row_range.end;
+ line.paint(line_origin, line_height, cx);
+ }
+ }
- // let start_y = start_row as f32 * line_height - scroll_top;
- // let end_y = end_row as f32 * line_height - scroll_top;
+ // todo!("fold indicators")
+ // for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
+ // if let Some(indicator) = fold_indicator.as_mut() {
+ // let position = point(
+ // bounds.width() - layout.gutter_padding,
+ // ix as f32 * line_height - (scroll_top % line_height),
+ // );
+ // let centering_offset = point(
+ // (layout.gutter_padding + layout.gutter_margin - indicator.size().x) / 2.,
+ // (line_height - indicator.size().y) / 2.,
+ // );
- // let width = diff_style.width_em * line_height;
- // let highlight_origin = bounds.origin() + point(-width, start_y);
- // let highlight_size = point(width * 2., end_y - start_y);
- // let highlight_bounds = Bounds<Pixels>::new(highlight_origin, highlight_size);
+ // let indicator_origin = bounds.origin + position + centering_offset;
- // cx.paint_quad(Quad {
- // bounds: highlight_bounds,
- // background: Some(color),
- // border: Border::new(0., Color::transparent_black()).into(),
- // corner_radii: (diff_style.corner_radius * line_height).into(),
- // });
- // }
- // }
+ // indicator.paint(indicator_origin, visible_bounds, editor, cx);
+ // }
+ // }
- // fn paint_text(
- // &mut self,
- // bounds: Bounds<Pixels>,
- // visible_bounds: Bounds<Pixels>,
- // layout: &mut LayoutState,
- // editor: &mut Editor,
- // cx: &mut ViewContext<Editor>,
- // ) {
- // let style = &self.style;
- // let scroll_position = layout.position_map.snapshot.scroll_position();
- // let start_row = layout.visible_display_row_range.start;
- // let scroll_top = scroll_position.y() * layout.position_map.line_height;
- // let max_glyph_width = layout.position_map.em_width;
- // let scroll_left = scroll_position.x() * max_glyph_width;
- // let content_origin = bounds.origin() + point(layout.gutter_margin, 0.);
- // let line_end_overshoot = 0.15 * layout.position_map.line_height;
- // let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
+ // todo!("code actions indicator")
+ // if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
+ // let mut x = 0.;
+ // let mut y = *row as f32 * line_height - scroll_top;
+ // x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x) / 2.;
+ // y += (line_height - indicator.size().y) / 2.;
+ // indicator.paint(bounds.origin + point(x, y), visible_bounds, editor, cx);
+ // }
+ }
- // cx.scene().push_layer(Some(bounds));
+ fn paint_diff_hunks(
+ bounds: Bounds<Pixels>,
+ layout: &mut LayoutState,
+ cx: &mut ViewContext<Editor>,
+ ) {
+ // todo!()
+ // let diff_style = &theme::current(cx).editor.diff.clone();
+ // let line_height = layout.position_map.line_height;
+
+ // let scroll_position = layout.position_map.snapshot.scroll_position();
+ // let scroll_top = scroll_position.y * line_height;
+
+ // for hunk in &layout.display_hunks {
+ // let (display_row_range, status) = match hunk {
+ // //TODO: This rendering is entirely a horrible hack
+ // &DisplayDiffHunk::Folded { display_row: row } => {
+ // let start_y = row as f32 * line_height - scroll_top;
+ // let end_y = start_y + line_height;
+
+ // let width = diff_style.removed_width_em * line_height;
+ // let highlight_origin = bounds.origin + point(-width, start_y);
+ // let highlight_size = point(width * 2., end_y - start_y);
+ // let highlight_bounds = Bounds::<Pixels>::new(highlight_origin, highlight_size);
+
+ // cx.paint_quad(Quad {
+ // bounds: highlight_bounds,
+ // background: Some(diff_style.modified),
+ // border: Border::new(0., Color::transparent_black()).into(),
+ // corner_radii: (1. * line_height).into(),
+ // });
+
+ // continue;
+ // }
- // cx.scene().push_cursor_region(CursorRegion {
- // bounds,
- // style: if !editor.link_go_to_definition_state.definitions.is_empty() {
- // CursorStyle::PointingHand
- // } else {
- // CursorStyle::IBeam
- // },
- // });
+ // DisplayDiffHunk::Unfolded {
+ // display_row_range,
+ // status,
+ // } => (display_row_range, status),
+ // };
+
+ // let color = match status {
+ // DiffHunkStatus::Added => diff_style.inserted,
+ // DiffHunkStatus::Modified => diff_style.modified,
+
+ // //TODO: This rendering is entirely a horrible hack
+ // DiffHunkStatus::Removed => {
+ // let row = display_row_range.start;
+
+ // let offset = line_height / 2.;
+ // let start_y = row as f32 * line_height - offset - scroll_top;
+ // let end_y = start_y + line_height;
+
+ // let width = diff_style.removed_width_em * line_height;
+ // let highlight_origin = bounds.origin + point(-width, start_y);
+ // let highlight_size = point(width * 2., end_y - start_y);
+ // let highlight_bounds = Bounds::<Pixels>::new(highlight_origin, highlight_size);
+
+ // cx.paint_quad(Quad {
+ // bounds: highlight_bounds,
+ // background: Some(diff_style.deleted),
+ // border: Border::new(0., Color::transparent_black()).into(),
+ // corner_radii: (1. * line_height).into(),
+ // });
+
+ // continue;
+ // }
+ // };
- // let fold_corner_radius =
- // self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
- // for (id, range, color) in layout.fold_ranges.iter() {
- // self.paint_highlighted_range(
- // range.clone(),
- // *color,
- // fold_corner_radius,
- // fold_corner_radius * 2.,
- // layout,
- // content_origin,
- // scroll_top,
- // scroll_left,
- // bounds,
- // cx,
- // );
+ // let start_row = display_row_range.start;
+ // let end_row = display_row_range.end;
- // for bound in range_to_bounds(
- // &range,
- // content_origin,
- // scroll_left,
- // scroll_top,
- // &layout.visible_display_row_range,
- // line_end_overshoot,
- // &layout.position_map,
- // ) {
- // cx.scene().push_cursor_region(CursorRegion {
- // bounds: bound,
- // style: CursorStyle::PointingHand,
- // });
-
- // let display_row = range.start.row();
-
- // let buffer_row = DisplayPoint::new(display_row, 0)
- // .to_point(&layout.position_map.snapshot.display_snapshot)
- // .row;
-
- // let view_id = cx.view_id();
- // cx.scene().push_mouse_region(
- // MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
- // .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
- // editor.unfold_at(&UnfoldAt { buffer_row }, cx)
- // })
- // .with_notify_on_hover(true)
- // .with_notify_on_click(true),
- // )
- // }
- // }
+ // let start_y = start_row as f32 * line_height - scroll_top;
+ // let end_y = end_row as f32 * line_height - scroll_top;
- // for (range, color) in &layout.highlighted_ranges {
- // self.paint_highlighted_range(
- // range.clone(),
- // *color,
- // 0.,
- // line_end_overshoot,
- // layout,
- // content_origin,
- // scroll_top,
- // scroll_left,
- // bounds,
- // cx,
- // );
- // }
+ // let width = diff_style.width_em * line_height;
+ // let highlight_origin = bounds.origin + point(-width, start_y);
+ // let highlight_size = point(width * 2., end_y - start_y);
+ // let highlight_bounds = Bounds::<Pixels>::new(highlight_origin, highlight_size);
- // let mut cursors = SmallVec::<[Cursor; 32]>::new();
- // let corner_radius = 0.15 * layout.position_map.line_height;
- // let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
-
- // for (selection_style, selections) in &layout.selections {
- // for selection in selections {
- // self.paint_highlighted_range(
- // selection.range.clone(),
- // selection_style.selection,
- // corner_radius,
- // corner_radius * 2.,
- // layout,
- // content_origin,
- // scroll_top,
- // scroll_left,
- // bounds,
- // cx,
- // );
-
- // if selection.is_local && !selection.range.is_empty() {
- // invisible_display_ranges.push(selection.range.clone());
- // }
- // if !selection.is_local || editor.show_local_cursors(cx) {
- // let cursor_position = selection.head;
- // if layout
- // .visible_display_row_range
- // .contains(&cursor_position.row())
- // {
- // let cursor_row_layout = &layout.position_map.line_layouts
- // [(cursor_position.row() - start_row) as usize]
- // .line;
- // let cursor_column = cursor_position.column() as usize;
-
- // let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
- // let mut block_width =
- // cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
- // if block_width == 0.0 {
- // block_width = layout.position_map.em_width;
- // }
- // let block_text = if let CursorShape::Block = selection.cursor_shape {
- // layout
- // .position_map
- // .snapshot
- // .chars_at(cursor_position)
- // .next()
- // .and_then(|(character, _)| {
- // let font_id =
- // cursor_row_layout.font_for_index(cursor_column)?;
- // let text = character.to_string();
-
- // Some(cx.text_layout_cache().layout_str(
- // &text,
- // cursor_row_layout.font_size(),
- // &[(
- // text.chars().count(),
- // RunStyle {
- // font_id,
- // color: style.background,
- // underline: Default::default(),
- // },
- // )],
- // ))
- // })
- // } else {
- // None
- // };
+ // cx.paint_quad(Quad {
+ // bounds: highlight_bounds,
+ // background: Some(color),
+ // border: Border::new(0., Color::transparent_black()).into(),
+ // corner_radii: (diff_style.corner_radius * line_height).into(),
+ // });
+ // }
+ }
- // let x = cursor_character_x - scroll_left;
- // let y = cursor_position.row() as f32 * layout.position_map.line_height
- // - scroll_top;
- // if selection.is_newest {
- // editor.pixel_position_of_newest_cursor = Some(point(
- // bounds.origin.x + x + block_width / 2.,
- // bounds.origin.y + y + layout.position_map.line_height / 2.,
- // ));
- // }
- // cursors.push(Cursor {
- // color: selection_style.cursor,
- // block_width,
- // origin: point(x, y),
- // line_height: layout.position_map.line_height,
- // shape: selection.cursor_shape,
- // block_text,
- // });
- // }
- // }
- // }
- // }
+ fn paint_text(
+ &mut self,
+ bounds: Bounds<Pixels>,
+ layout: &mut LayoutState,
+ editor: &mut Editor,
+ cx: &mut ViewContext<Editor>,
+ ) {
+ let style = &self.style;
+ let scroll_position = layout.position_map.snapshot.scroll_position();
+ let start_row = layout.visible_display_row_range.start;
+ let scroll_top = scroll_position.y * layout.position_map.line_height;
+ let max_glyph_width = layout.position_map.em_width;
+ let scroll_left = scroll_position.x * max_glyph_width;
+ let content_origin = bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
+ let line_end_overshoot = 0.15 * layout.position_map.line_height;
+ let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
- // if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
- // for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
- // let row = start_row + ix as u32;
- // line_with_invisibles.draw(
- // layout,
- // row,
- // scroll_top,
- // content_origin,
- // scroll_left,
- // visible_text_bounds,
- // whitespace_setting,
- // &invisible_display_ranges,
- // visible_bounds,
- // cx,
- // )
- // }
- // }
+ cx.with_content_mask(ContentMask { bounds }, |cx| {
+ // todo!("cursor region")
+ // cx.scene().push_cursor_region(CursorRegion {
+ // bounds,
+ // style: if !editor.link_go_to_definition_state.definitions.is_empty {
+ // CursorStyle::PointingHand
+ // } else {
+ // CursorStyle::IBeam
+ // },
+ // });
+
+ // todo!("fold ranges")
+ // let fold_corner_radius =
+ // self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
+ // for (id, range, color) in layout.fold_ranges.iter() {
+ // self.paint_highlighted_range(
+ // range.clone(),
+ // *color,
+ // fold_corner_radius,
+ // fold_corner_radius * 2.,
+ // layout,
+ // content_origin,
+ // scroll_top,
+ // scroll_left,
+ // bounds,
+ // cx,
+ // );
+
+ // for bound in range_to_bounds(
+ // &range,
+ // content_origin,
+ // scroll_left,
+ // scroll_top,
+ // &layout.visible_display_row_range,
+ // line_end_overshoot,
+ // &layout.position_map,
+ // ) {
+ // cx.scene().push_cursor_region(CursorRegion {
+ // bounds: bound,
+ // style: CursorStyle::PointingHand,
+ // });
+
+ // let display_row = range.start.row();
+
+ // let buffer_row = DisplayPoint::new(display_row, 0)
+ // .to_point(&layout.position_map.snapshot.display_snapshot)
+ // .row;
+
+ // let view_id = cx.view_id();
+ // cx.scene().push_mouse_region(
+ // MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
+ // .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
+ // editor.unfold_at(&UnfoldAt { buffer_row }, cx)
+ // })
+ // .with_notify_on_hover(true)
+ // .with_notify_on_click(true),
+ // )
+ // }
+ // }
+
+ for (range, color) in &layout.highlighted_ranges {
+ self.paint_highlighted_range(
+ range.clone(),
+ *color,
+ Pixels::ZERO,
+ line_end_overshoot,
+ layout,
+ content_origin,
+ scroll_top,
+ scroll_left,
+ bounds,
+ cx,
+ );
+ }
- // cx.scene().push_layer(Some(bounds));
- // for cursor in cursors {
- // cursor.paint(content_origin, cx);
- // }
- // cx.scene().pop_layer();
-
- // if let Some((position, context_menu)) = layout.context_menu.as_mut() {
- // cx.scene().push_stacking_context(None, None);
- // let cursor_row_layout =
- // &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
- // let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
- // let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
- // let mut list_origin = content_origin + point(x, y);
- // let list_width = context_menu.size().x();
- // let list_height = context_menu.size().y();
-
- // // Snap the right edge of the list to the right edge of the window if
- // // its horizontal bounds overflow.
- // if list_origin.x() + list_width > cx.window_size().x() {
- // list_origin.set_x((cx.window_size().x() - list_width).max(0.));
- // }
+ let mut cursors = SmallVec::<[Cursor; 32]>::new();
+ let corner_radius = 0.15 * layout.position_map.line_height;
+ let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
+
+ for (selection_style, selections) in &layout.selections {
+ for selection in selections {
+ self.paint_highlighted_range(
+ selection.range.clone(),
+ selection_style.selection,
+ corner_radius,
+ corner_radius * 2.,
+ layout,
+ content_origin,
+ scroll_top,
+ scroll_left,
+ bounds,
+ cx,
+ );
- // if list_origin.y() + list_height > bounds.max_y() {
- // list_origin.set_y(list_origin.y() - layout.position_map.line_height - list_height);
- // }
+ if selection.is_local && !selection.range.is_empty() {
+ invisible_display_ranges.push(selection.range.clone());
+ }
+ if !selection.is_local || editor.show_local_cursors(cx) {
+ let cursor_position = selection.head;
+ if layout
+ .visible_display_row_range
+ .contains(&cursor_position.row())
+ {
+ let cursor_row_layout = &layout.position_map.line_layouts
+ [(cursor_position.row() - start_row) as usize]
+ .line;
+ let cursor_column = cursor_position.column() as usize;
+
+ let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
+ let mut block_width = cursor_row_layout.x_for_index(cursor_column + 1)
+ - cursor_character_x;
+ if block_width == Pixels::ZERO {
+ block_width = layout.position_map.em_width;
+ }
+ let block_text = if let CursorShape::Block = selection.cursor_shape {
+ layout
+ .position_map
+ .snapshot
+ .chars_at(cursor_position)
+ .next()
+ .and_then(|(character, _)| {
+ let font_id =
+ cursor_row_layout.font_for_index(cursor_column)?;
+ let text = character.to_string();
+
+ cx.text_system().layout_text(
+ &text,
+ cursor_row_layout.font_size,
+ &[TextRun {
+ len: text.len(),
+ font: todo!(),
+ color: todo!(),
+ underline: todo!(),
+ }],
+ None,
+ );
+ Some(cx.text_layout_cache().layout_str(
+ &text,
+ cursor_row_layout.font_size,
+ &[(
+ text.chars().count(),
+ RunStyle {
+ font_id,
+ color: style.background,
+ underline: Default::default(),
+ },
+ )],
+ ))
+ })
+ } else {
+ None
+ };
+
+ let x = cursor_character_x - scroll_left;
+ let y = cursor_position.row() as f32 * layout.position_map.line_height
+ - scroll_top;
+ if selection.is_newest {
+ editor.pixel_position_of_newest_cursor = Some(point(
+ bounds.origin.x + x + block_width / 2.,
+ bounds.origin.y + y + layout.position_map.line_height / 2.,
+ ));
+ }
+ cursors.push(Cursor {
+ color: selection_style.cursor,
+ block_width,
+ origin: point(x, y),
+ line_height: layout.position_map.line_height,
+ shape: selection.cursor_shape,
+ block_text,
+ });
+ }
+ }
+ }
+ }
- // context_menu.paint(
- // list_origin,
- // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), point(f32::MAX, f32::MAX)), // Let content bleed outside of editor
- // editor,
- // cx,
- // );
+ for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
+ let row = start_row + ix as u32;
+ line_with_invisibles.draw(
+ layout,
+ row,
+ scroll_top,
+ content_origin,
+ scroll_left,
+ visible_text_bounds,
+ whitespace_setting,
+ &invisible_display_ranges,
+ visible_bounds,
+ cx,
+ )
+ }
- // cx.scene().pop_stacking_context();
- // }
+ cx.scene().push_layer(Some(bounds));
+ for cursor in cursors {
+ cursor.paint(content_origin, cx);
+ }
+ cx.scene().pop_layer();
+
+ if let Some((position, context_menu)) = layout.context_menu.as_mut() {
+ cx.scene().push_stacking_context(None, None);
+ let cursor_row_layout =
+ &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
+ let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
+ let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
+ let mut list_origin = content_origin + point(x, y);
+ let list_width = context_menu.size().x;
+ let list_height = context_menu.size().y;
+
+ // Snap the right edge of the list to the right edge of the window if
+ // its horizontal bounds overflow.
+ if list_origin.x + list_width > cx.window_size().x {
+ list_origin.set_x((cx.window_size().x - list_width).max(0.));
+ }
- // if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
- // cx.scene().push_stacking_context(None, None);
-
- // // This is safe because we check on layout whether the required row is available
- // let hovered_row_layout =
- // &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
-
- // // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
- // // height. This is the size we will use to decide whether to render popovers above or below
- // // the hovered line.
- // let first_size = hover_popovers[0].size();
- // let height_to_reserve = first_size.y()
- // + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
-
- // // Compute Hovered Point
- // let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
- // let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
- // let hovered_point = content_origin + point(x, y);
-
- // if hovered_point.y() - height_to_reserve > 0.0 {
- // // There is enough space above. Render popovers above the hovered point
- // let mut current_y = hovered_point.y();
- // for hover_popover in hover_popovers {
- // let size = hover_popover.size();
- // let mut popover_origin = point(hovered_point.x(), current_y - size.y());
-
- // let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
- // if x_out_of_bounds < 0.0 {
- // popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
- // }
+ if list_origin.y + list_height > bounds.max_y {
+ list_origin
+ .set_y(list_origin.y - layout.position_map.line_height - list_height);
+ }
- // hover_popover.paint(
- // popover_origin,
- // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), point(f32::MAX, f32::MAX)), // Let content bleed outside of editor
- // editor,
- // cx,
- // );
+ context_menu.paint(
+ list_origin,
+ Bounds::<Pixels>::from_points(
+ gpui::Point::<Pixels>::zero(),
+ point(f32::MAX, f32::MAX),
+ ), // Let content bleed outside of editor
+ editor,
+ cx,
+ );
- // current_y = popover_origin.y() - HOVER_POPOVER_GAP;
- // }
- // } else {
- // // There is not enough space above. Render popovers below the hovered point
- // let mut current_y = hovered_point.y() + layout.position_map.line_height;
- // for hover_popover in hover_popovers {
- // let size = hover_popover.size();
- // let mut popover_origin = point(hovered_point.x(), current_y);
-
- // let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
- // if x_out_of_bounds < 0.0 {
- // popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
- // }
+ cx.scene().pop_stacking_context();
+ }
- // hover_popover.paint(
- // popover_origin,
- // Bounds<Pixels>::from_points(gpui::Point<Pixels>::zero(), point(f32::MAX, f32::MAX)), // Let content bleed outside of editor
- // editor,
- // cx,
- // );
+ if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
+ cx.scene().push_stacking_context(None, None);
+
+ // This is safe because we check on layout whether the required row is available
+ let hovered_row_layout =
+ &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
+
+ // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
+ // height. This is the size we will use to decide whether to render popovers above or below
+ // the hovered line.
+ let first_size = hover_popovers[0].size();
+ let height_to_reserve = first_size.y
+ + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
+
+ // Compute Hovered Point
+ let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
+ let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
+ let hovered_point = content_origin + point(x, y);
+
+ if hovered_point.y - height_to_reserve > 0.0 {
+ // There is enough space above. Render popovers above the hovered point
+ let mut current_y = hovered_point.y;
+ for hover_popover in hover_popovers {
+ let size = hover_popover.size();
+ let mut popover_origin = point(hovered_point.x, current_y - size.y);
+
+ let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
+ if x_out_of_bounds < 0.0 {
+ popover_origin.set_x(popover_origin.x + x_out_of_bounds);
+ }
- // current_y = popover_origin.y() + size.y() + HOVER_POPOVER_GAP;
- // }
- // }
+ hover_popover.paint(
+ popover_origin,
+ Bounds::<Pixels>::from_points(
+ gpui::Point::<Pixels>::zero(),
+ point(f32::MAX, f32::MAX),
+ ), // Let content bleed outside of editor
+ editor,
+ cx,
+ );
+
+ current_y = popover_origin.y - HOVER_POPOVER_GAP;
+ }
+ } else {
+ // There is not enough space above. Render popovers below the hovered point
+ let mut current_y = hovered_point.y + layout.position_map.line_height;
+ for hover_popover in hover_popovers {
+ let size = hover_popover.size();
+ let mut popover_origin = point(hovered_point.x, current_y);
+
+ let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
+ if x_out_of_bounds < 0.0 {
+ popover_origin.set_x(popover_origin.x + x_out_of_bounds);
+ }
- // cx.scene().pop_stacking_context();
- // }
+ hover_popover.paint(
+ popover_origin,
+ Bounds::<Pixels>::from_points(
+ gpui::Point::<Pixels>::zero(),
+ point(f32::MAX, f32::MAX),
+ ), // Let content bleed outside of editor
+ editor,
+ cx,
+ );
+
+ current_y = popover_origin.y + size.y + HOVER_POPOVER_GAP;
+ }
+ }
- // cx.scene().pop_layer();
- // }
+ cx.scene().pop_stacking_context();
+ }
+ })
+ }
fn scrollbar_left(&self, bounds: &Bounds<Pixels>) -> Pixels {
bounds.upper_right().x - self.style.scrollbar_width
@@ -1073,9 +1098,9 @@ impl EditorElement {
// let style = &self.style.theme.scrollbar;
- // let top = bounds.min_y();
- // let bottom = bounds.max_y();
- // let right = bounds.max_x();
+ // let top = bounds.min_y;
+ // let bottom = bounds.max_y;
+ // let right = bounds.max_x;
// let left = self.scrollbar_left(&bounds);
// let row_range = &layout.scrollbar_row_range;
// let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
@@ -1097,8 +1122,8 @@ impl EditorElement {
// let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
// let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
- // let track_bounds = Bounds<Pixels>::from_points(point(left, top), point(right, bottom));
- // let thumb_bounds = Bounds<Pixels>::from_points(point(left, thumb_top), point(right, thumb_bottom));
+ // let track_bounds = Bounds::<Pixels>::from_points(point(left, top), point(right, bottom));
+ // let thumb_bounds = Bounds::<Pixels>::from_points(point(left, thumb_top), point(right, thumb_bottom));
// if layout.show_scrollbars {
// cx.paint_quad(Quad {
@@ -1112,7 +1137,7 @@ impl EditorElement {
// let scrollbar_theme = &theme.editor.scrollbar;
// if layout.is_singleton && scrollbar_settings.selections {
// let start_anchor = Anchor::min();
- // let end_anchor = Anchor::max();
+ // let end_anchor = Anchor::max;
// let color = scrollbar_theme.selections;
// let border = Border {
// width: 1.,