Detailed changes
@@ -579,7 +579,7 @@ impl DisplaySnapshot {
pub fn line_indent(&self, display_row: DisplayRow) -> (u32, bool) {
let mut indent = 0;
let mut is_blank = true;
- for (c, _) in self.chars_at(display_row.start(self)) {
+ for (c, _) in self.chars_at(display_row.start()) {
if c == ' ' {
indent += 1;
} else {
@@ -626,7 +626,7 @@ impl DisplaySnapshot {
return false;
}
- pub fn foldable_range(self: &Self, row: DisplayRow) -> Option<Range<Point>> {
+ pub fn foldable_range(self: &Self, row: DisplayRow) -> Option<Range<DisplayPoint>> {
let start = row.end(&self);
if self.is_foldable(row) && !self.is_line_folded(start.row()) {
@@ -637,13 +637,13 @@ impl DisplaySnapshot {
for row in row.next_rows(self).unwrap() {
let (indent, is_blank) = self.line_indent(row);
if !is_blank && indent <= start_indent {
- end = row.previous_row(self);
+ end = row.previous_row();
break;
}
}
let end = end.map(|end_row| end_row.end(self)).unwrap_or(max_point);
- Some(start.to_point(self)..end.to_point(self))
+ Some(start..end)
} else {
None
}
@@ -661,6 +661,81 @@ impl DisplaySnapshot {
#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq)]
pub struct DisplayPoint(BlockPoint);
+impl Debug for DisplayPoint {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ f.write_fmt(format_args!(
+ "DisplayPoint({}, {})",
+ self.row(),
+ self.column()
+ ))
+ }
+}
+
+impl DisplayPoint {
+ pub fn new(row: u32, column: u32) -> Self {
+ Self(BlockPoint(Point::new(row, column)))
+ }
+
+ pub fn zero() -> Self {
+ Self::new(0, 0)
+ }
+
+ pub fn is_zero(&self) -> bool {
+ self.0.is_zero()
+ }
+
+ pub fn row(self) -> u32 {
+ self.0.row
+ }
+
+ pub fn column(self) -> u32 {
+ self.0.column
+ }
+
+ pub fn row_mut(&mut self) -> &mut u32 {
+ &mut self.0.row
+ }
+
+ pub fn column_mut(&mut self) -> &mut u32 {
+ &mut self.0.column
+ }
+
+ pub fn to_point(self, map: &DisplaySnapshot) -> Point {
+ map.display_point_to_point(self, Bias::Left)
+ }
+
+ pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize {
+ let unblocked_point = map.blocks_snapshot.to_wrap_point(self.0);
+ let unwrapped_point = map.wraps_snapshot.to_tab_point(unblocked_point);
+ let unexpanded_point = map.tabs_snapshot.to_fold_point(unwrapped_point, bias).0;
+ unexpanded_point.to_buffer_offset(&map.folds_snapshot)
+ }
+}
+
+impl ToDisplayPoint for usize {
+ fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
+ map.point_to_display_point(self.to_point(&map.buffer_snapshot), Bias::Left)
+ }
+}
+
+impl ToDisplayPoint for OffsetUtf16 {
+ fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
+ self.to_offset(&map.buffer_snapshot).to_display_point(map)
+ }
+}
+
+impl ToDisplayPoint for Point {
+ fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
+ map.point_to_display_point(*self, Bias::Left)
+ }
+}
+
+impl ToDisplayPoint for Anchor {
+ fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
+ self.to_point(&map.buffer_snapshot).to_display_point(map)
+ }
+}
+
#[derive(Copy, Clone, Default, Eq, Ord, PartialOrd, PartialEq, Deserialize, Serialize)]
#[repr(transparent)]
pub struct DisplayRow(pub u32);
@@ -672,10 +747,10 @@ impl DisplayRow {
}
pub fn to_line_span(&self, display_map: &DisplaySnapshot) -> Range<DisplayPoint> {
- self.start(display_map)..self.end(&display_map)
+ self.start()..self.end(&display_map)
}
- pub fn previous_row(&self, _display_map: &DisplaySnapshot) -> Option<DisplayRow> {
+ pub fn previous_row(&self) -> Option<DisplayRow> {
self.0.checked_sub(1).map(|prev_row| DisplayRow(prev_row))
}
@@ -727,7 +802,7 @@ impl DisplayRow {
}
// Force users to think about the display map when using this type
- pub fn start(&self, _display_map: &DisplaySnapshot) -> DisplayPoint {
+ pub fn start(&self) -> DisplayPoint {
DisplayPoint::new(self.0, 0)
}
@@ -742,81 +817,6 @@ impl From<DisplayPoint> for DisplayRow {
}
}
-impl Debug for DisplayPoint {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_fmt(format_args!(
- "DisplayPoint({}, {})",
- self.row(),
- self.column()
- ))
- }
-}
-
-impl DisplayPoint {
- pub fn new(row: u32, column: u32) -> Self {
- Self(BlockPoint(Point::new(row, column)))
- }
-
- pub fn zero() -> Self {
- Self::new(0, 0)
- }
-
- pub fn is_zero(&self) -> bool {
- self.0.is_zero()
- }
-
- pub fn row(self) -> u32 {
- self.0.row
- }
-
- pub fn column(self) -> u32 {
- self.0.column
- }
-
- pub fn row_mut(&mut self) -> &mut u32 {
- &mut self.0.row
- }
-
- pub fn column_mut(&mut self) -> &mut u32 {
- &mut self.0.column
- }
-
- pub fn to_point(self, map: &DisplaySnapshot) -> Point {
- map.display_point_to_point(self, Bias::Left)
- }
-
- pub fn to_offset(self, map: &DisplaySnapshot, bias: Bias) -> usize {
- let unblocked_point = map.blocks_snapshot.to_wrap_point(self.0);
- let unwrapped_point = map.wraps_snapshot.to_tab_point(unblocked_point);
- let unexpanded_point = map.tabs_snapshot.to_fold_point(unwrapped_point, bias).0;
- unexpanded_point.to_buffer_offset(&map.folds_snapshot)
- }
-}
-
-impl ToDisplayPoint for usize {
- fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
- map.point_to_display_point(self.to_point(&map.buffer_snapshot), Bias::Left)
- }
-}
-
-impl ToDisplayPoint for OffsetUtf16 {
- fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
- self.to_offset(&map.buffer_snapshot).to_display_point(map)
- }
-}
-
-impl ToDisplayPoint for Point {
- fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
- map.point_to_display_point(*self, Bias::Left)
- }
-}
-
-impl ToDisplayPoint for Anchor {
- fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
- self.to_point(&map.buffer_snapshot).to_display_point(map)
- }
-}
-
#[cfg(test)]
pub mod tests {
use super::*;
@@ -2686,47 +2686,51 @@ impl Editor {
pub fn render_fold_indicators(
&self,
- fold_data: Vec<(u32, FoldStatus)>,
- fold_indicators: &mut Vec<(u32, ElementBox)>,
+ fold_data: Option<Vec<(u32, FoldStatus)>>,
style: &EditorStyle,
cx: &mut RenderContext<Self>,
- ) {
+ ) -> Option<Vec<(u32, ElementBox)>> {
enum FoldIndicators {}
- for (fold_location, fold_status) in fold_data.iter() {
- fold_indicators.push((
- *fold_location,
- MouseEventHandler::<FoldIndicators>::new(
- *fold_location as usize,
- cx,
- |_, _| -> ElementBox {
- Svg::new(match *fold_status {
- FoldStatus::Folded => "icons/chevron_right_8.svg",
- FoldStatus::Foldable => "icons/chevron_down_8.svg",
+ fold_data.map(|fold_data| {
+ fold_data
+ .iter()
+ .map(|(fold_location, fold_status)| {
+ (
+ *fold_location,
+ MouseEventHandler::<FoldIndicators>::new(
+ *fold_location as usize,
+ cx,
+ |_, _| -> ElementBox {
+ Svg::new(match *fold_status {
+ FoldStatus::Folded => "icons/chevron_right_8.svg",
+ FoldStatus::Foldable => "icons/chevron_down_8.svg",
+ })
+ .with_color(style.folds.indicator)
+ .boxed()
+ },
+ )
+ .with_cursor_style(CursorStyle::PointingHand)
+ .with_padding(Padding::uniform(3.))
+ .on_down(MouseButton::Left, {
+ let fold_location = *fold_location;
+ let fold_status = *fold_status;
+ move |_, cx| {
+ cx.dispatch_any_action(match fold_status {
+ FoldStatus::Folded => Box::new(UnfoldAt {
+ display_row: DisplayRow::new(fold_location),
+ }),
+ FoldStatus::Foldable => Box::new(FoldAt {
+ display_row: DisplayRow::new(fold_location),
+ }),
+ });
+ }
})
- .with_color(style.folds.indicator)
- .boxed()
- },
- )
- .with_cursor_style(CursorStyle::PointingHand)
- .with_padding(Padding::uniform(3.))
- .on_down(MouseButton::Left, {
- let fold_location = *fold_location;
- let fold_status = *fold_status;
- move |_, cx| {
- cx.dispatch_any_action(match fold_status {
- FoldStatus::Folded => Box::new(UnfoldAt {
- display_row: DisplayRow::new(fold_location),
- }),
- FoldStatus::Foldable => Box::new(FoldAt {
- display_row: DisplayRow::new(fold_location),
- }),
- });
- }
+ .boxed(),
+ )
})
- .boxed(),
- ))
- }
+ .collect()
+ })
}
pub fn context_menu_visible(&self) -> bool {
@@ -5715,7 +5719,13 @@ impl Editor {
let buffer_start_row = range.start.to_point(&display_map).row;
for row in (0..=range.end.row()).rev() {
- if let Some(fold_range) = display_map.foldable_range(DisplayRow::new(row)) {
+ let fold_range = display_map
+ .foldable_range(DisplayRow::new(row))
+ .map(|range| {
+ range.map_range(|display_point| display_point.to_point(&display_map))
+ });
+
+ if let Some(fold_range) = fold_range {
if fold_range.end.row >= buffer_start_row {
fold_ranges.push(fold_range);
if row <= range.start.row() {
@@ -5735,10 +5745,29 @@ impl Editor {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
if let Some(fold_range) = display_map.foldable_range(display_row) {
- self.fold_ranges(std::iter::once(fold_range), true, cx);
+ let autoscroll = self.selections_intersect(&fold_range, &display_map, cx);
+
+ let point_range =
+ fold_range.map_range(|display_point| display_point.to_point(&display_map));
+
+ self.fold_ranges(std::iter::once(point_range), autoscroll, cx);
}
}
+ fn selections_intersect(
+ &mut self,
+ range: &Range<DisplayPoint>,
+ display_map: &DisplaySnapshot,
+ cx: &mut ViewContext<Editor>,
+ ) -> bool {
+ let selections = self.selections.all::<Point>(cx);
+
+ selections.iter().any(|selection| {
+ let display_range = selection.display_range(display_map);
+ range.contains(&display_range.start) || range.contains(&display_range.end)
+ })
+ }
+
pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
let buffer = &display_map.buffer_snapshot;
@@ -5760,12 +5789,13 @@ impl Editor {
pub fn unfold_at(&mut self, fold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
- let display_range = fold_at
- .display_row
- .to_line_span(&display_map)
- .map_endpoints(|endpoint| endpoint.to_point(&display_map));
+ let unfold_range = fold_at.display_row.to_line_span(&display_map);
+
+ let autoscroll = self.selections_intersect(&unfold_range, &display_map, cx);
+
+ let unfold_range = unfold_range.map_range(|endpoint| endpoint.to_point(&display_map));
- self.unfold_ranges(std::iter::once(display_range), true, true, cx)
+ self.unfold_ranges(std::iter::once(unfold_range), true, autoscroll, cx)
}
pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
@@ -48,6 +48,7 @@ use std::{
ops::{DerefMut, Range},
sync::Arc,
};
+use workspace::item::Item;
struct SelectionLayout {
head: DisplayPoint,
@@ -576,15 +577,18 @@ impl EditorElement {
indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, cx);
}
- for (line, fold_indicator) in layout.fold_indicators.iter_mut() {
- let mut x = bounds.width() - layout.gutter_padding;
- let mut y = *line as f32 * line_height - scroll_top;
+ layout.fold_indicators.as_mut().map(|fold_indicators| {
+ for (line, fold_indicator) in fold_indicators.iter_mut() {
+ let mut x = bounds.width() - layout.gutter_padding;
+ let mut y = *line as f32 * line_height - scroll_top;
- x += ((layout.gutter_padding + layout.gutter_margin) - fold_indicator.size().x()) / 2.;
- y += (line_height - fold_indicator.size().y()) / 2.;
+ x += ((layout.gutter_padding + layout.gutter_margin) - fold_indicator.size().x())
+ / 2.;
+ y += (line_height - fold_indicator.size().y()) / 2.;
- fold_indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, cx);
- }
+ fold_indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, cx);
+ }
+ });
}
fn paint_diff_hunks(bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) {
@@ -1130,17 +1134,20 @@ impl EditorElement {
fn get_fold_indicators(
&self,
+ is_singleton: bool,
display_rows: Range<u32>,
snapshot: &EditorSnapshot,
- ) -> Vec<(u32, FoldStatus)> {
- display_rows
- .into_iter()
- .filter_map(|display_row| {
- snapshot
- .fold_for_line(display_row)
- .map(|fold_status| (display_row, fold_status))
- })
- .collect()
+ ) -> Option<Vec<(u32, FoldStatus)>> {
+ is_singleton.then(|| {
+ display_rows
+ .into_iter()
+ .filter_map(|display_row| {
+ snapshot
+ .fold_for_line(display_row)
+ .map(|fold_status| (display_row, fold_status))
+ })
+ .collect()
+ })
}
//Folds contained in a hunk are ignored apart from shrinking visual size
@@ -1633,7 +1640,10 @@ impl Element for EditorElement {
let mut highlighted_ranges = Vec::new();
let mut show_scrollbars = false;
let mut include_root = false;
+ let mut is_singleton = false;
self.update_view(cx.app, |view, cx| {
+ is_singleton = view.is_singleton(cx);
+
let display_map = view.display_map.update(cx, |map, cx| map.snapshot(cx));
highlighted_rows = view.highlighted_rows();
@@ -1714,7 +1724,7 @@ impl Element for EditorElement {
let display_hunks = self.layout_git_gutters(start_row..end_row, &snapshot);
- let folds = self.get_fold_indicators(start_row..end_row, &snapshot);
+ let folds = self.get_fold_indicators(is_singleton, start_row..end_row, &snapshot);
let scrollbar_row_range = scroll_position.y()..(scroll_position.y() + height_in_lines);
@@ -1778,12 +1788,11 @@ impl Element for EditorElement {
}
});
- let mut fold_indicators = Vec::with_capacity(folds.len());
let mut context_menu = None;
let mut code_actions_indicator = None;
let mut hover = None;
let mut mode = EditorMode::Full;
- cx.render(&self.view.upgrade(cx).unwrap(), |view, cx| {
+ let mut fold_indicators = cx.render(&self.view.upgrade(cx).unwrap(), |view, cx| {
let newest_selection_head = view
.selections
.newest::<usize>(cx)
@@ -1802,11 +1811,11 @@ impl Element for EditorElement {
.map(|indicator| (newest_selection_head.row(), indicator));
}
- view.render_fold_indicators(folds, &mut fold_indicators, &style, cx);
-
let visible_rows = start_row..start_row + line_layouts.len() as u32;
hover = view.hover_state.render(&snapshot, &style, visible_rows, cx);
mode = view.mode;
+
+ view.render_fold_indicators(folds, &style, cx)
});
if let Some((_, context_menu)) = context_menu.as_mut() {
@@ -1832,15 +1841,17 @@ impl Element for EditorElement {
);
}
- for (_, indicator) in fold_indicators.iter_mut() {
- indicator.layout(
- SizeConstraint::strict_along(
- Axis::Vertical,
- line_height * style.code_actions.vertical_scale,
- ),
- cx,
- );
- }
+ fold_indicators.as_mut().map(|fold_indicators| {
+ for (_, indicator) in fold_indicators.iter_mut() {
+ indicator.layout(
+ SizeConstraint::strict_along(
+ Axis::Vertical,
+ line_height * style.code_actions.vertical_scale,
+ ),
+ cx,
+ );
+ }
+ });
if let Some((_, hover_popovers)) = hover.as_mut() {
for hover_popover in hover_popovers.iter_mut() {
@@ -2020,7 +2031,7 @@ pub struct LayoutState {
context_menu: Option<(DisplayPoint, ElementBox)>,
code_actions_indicator: Option<(u32, ElementBox)>,
hover_popovers: Option<(DisplayPoint, Vec<ElementBox>)>,
- fold_indicators: Vec<(u32, ElementBox)>,
+ fold_indicators: Option<Vec<(u32, ElementBox)>>,
}
pub struct PositionMap {
@@ -146,14 +146,14 @@ where
}
pub trait MapRangeEndsExt<R> {
- fn map_endpoints<T, F>(self, f: F) -> Range<T>
+ fn map_range<T, F>(self, f: F) -> Range<T>
where
Self: Sized,
F: Fn(R) -> T;
}
impl<R> MapRangeEndsExt<R> for Range<R> {
- fn map_endpoints<T, F>(self, f: F) -> Range<T>
+ fn map_range<T, F>(self, f: F) -> Range<T>
where
Self: Sized,
F: Fn(R) -> T,