Added DisplayRow abstraction to make folding code more readable
This commit is contained in:
parent
637e8ada42
commit
da78abd99f
3 changed files with 95 additions and 38 deletions
|
@ -576,10 +576,10 @@ impl DisplaySnapshot {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn line_indent(&self, display_row: u32) -> (u32, bool) {
|
pub fn line_indent(&self, display_row: DisplayRow) -> (u32, bool) {
|
||||||
let mut indent = 0;
|
let mut indent = 0;
|
||||||
let mut is_blank = true;
|
let mut is_blank = true;
|
||||||
for (c, _) in self.chars_at(DisplayPoint::new(display_row, 0)) {
|
for (c, _) in self.chars_at(display_row.start(self)) {
|
||||||
if c == ' ' {
|
if c == ' ' {
|
||||||
indent += 1;
|
indent += 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -599,7 +599,8 @@ impl DisplaySnapshot {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fold_for_line(self: &Self, display_row: u32) -> Option<FoldStatus> {
|
pub fn fold_for_line(self: &Self, display_row: u32) -> Option<FoldStatus> {
|
||||||
if self.is_line_foldable(display_row) {
|
let display_row_typed = DisplayRow::new(display_row);
|
||||||
|
if self.is_foldable(display_row_typed) {
|
||||||
Some(FoldStatus::Foldable)
|
Some(FoldStatus::Foldable)
|
||||||
} else if self.is_line_folded(display_row) {
|
} else if self.is_line_folded(display_row) {
|
||||||
Some(FoldStatus::Folded)
|
Some(FoldStatus::Folded)
|
||||||
|
@ -608,44 +609,43 @@ impl DisplaySnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_line_foldable(self: &Self, display_row: u32) -> bool {
|
pub fn is_foldable(self: &Self, row: DisplayRow) -> bool {
|
||||||
let max_point = self.max_point();
|
if let Some(next_lines) = row.next_rows(self) {
|
||||||
if display_row >= max_point.row() {
|
let (start_indent, is_blank) = self.line_indent(row);
|
||||||
false
|
|
||||||
} else {
|
|
||||||
let (start_indent, is_blank) = self.line_indent(display_row);
|
|
||||||
if is_blank {
|
if is_blank {
|
||||||
false
|
return false;
|
||||||
} else {
|
}
|
||||||
for display_row in display_row + 1..=max_point.row() {
|
|
||||||
let (indent, is_blank) = self.line_indent(display_row);
|
for display_row in next_lines {
|
||||||
if !is_blank {
|
let (indent, is_blank) = self.line_indent(display_row);
|
||||||
return indent > start_indent;
|
if !is_blank {
|
||||||
}
|
return indent > start_indent;
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn foldable_range_for_line(self: &Self, start_row: u32) -> Option<Range<Point>> {
|
pub fn foldable_range(self: &Self, row: DisplayRow) -> Option<Range<Point>> {
|
||||||
if self.is_line_foldable(start_row) && !self.is_line_folded(start_row) {
|
let start = row.end(&self);
|
||||||
|
|
||||||
|
if self.is_foldable(row) && !self.is_line_folded(start.row()) {
|
||||||
|
let (start_indent, _) = self.line_indent(row);
|
||||||
let max_point = self.max_point();
|
let max_point = self.max_point();
|
||||||
let (start_indent, _) = self.line_indent(start_row);
|
|
||||||
let start = DisplayPoint::new(start_row, self.line_len(start_row));
|
|
||||||
let mut end = None;
|
let mut end = None;
|
||||||
for row in start_row + 1..=max_point.row() {
|
|
||||||
|
for row in row.next_rows(self).unwrap() {
|
||||||
let (indent, is_blank) = self.line_indent(row);
|
let (indent, is_blank) = self.line_indent(row);
|
||||||
if !is_blank && indent <= start_indent {
|
if !is_blank && indent <= start_indent {
|
||||||
end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1)));
|
end = row.previous_row(self);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let end = end.unwrap_or(max_point);
|
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.to_point(self)..end.to_point(self))
|
||||||
} else {
|
} else {
|
||||||
return None;
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,19 +665,74 @@ pub struct DisplayPoint(BlockPoint);
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct DisplayRow(pub u32);
|
pub struct DisplayRow(pub u32);
|
||||||
|
|
||||||
|
// TODO: Move display_map check into new, and then remove it from everywhere else
|
||||||
impl DisplayRow {
|
impl DisplayRow {
|
||||||
pub fn new(display_row: u32) -> Self {
|
pub fn new(display_row: u32) -> Self {
|
||||||
DisplayRow(display_row)
|
DisplayRow(display_row)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_span(self, display_map: &DisplaySnapshot) -> Range<DisplayPoint> {
|
pub fn to_line_span(&self, display_map: &DisplaySnapshot) -> Range<DisplayPoint> {
|
||||||
let row_start = DisplayPoint::new(self.0, 0);
|
self.start(display_map)..self.end(&display_map)
|
||||||
let row_end = DisplayPoint::new(
|
}
|
||||||
self.0,
|
|
||||||
display_map.buffer_snapshot.line_len(row_start.row()),
|
|
||||||
);
|
|
||||||
|
|
||||||
row_start..row_end
|
pub fn previous_row(&self, _display_map: &DisplaySnapshot) -> Option<DisplayRow> {
|
||||||
|
self.0.checked_sub(1).map(|prev_row| DisplayRow(prev_row))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_row(&self, display_map: &DisplaySnapshot) -> Option<DisplayRow> {
|
||||||
|
if self.0 + 1 > display_map.max_point().row() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(DisplayRow(self.0 + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Remove and use next_row
|
||||||
|
fn next_unchecked(&self) -> Option<DisplayRow> {
|
||||||
|
Some(DisplayRow(self.0 + 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_rows(
|
||||||
|
&self,
|
||||||
|
display_map: &DisplaySnapshot,
|
||||||
|
) -> Option<impl Iterator<Item = DisplayRow>> {
|
||||||
|
self.next_row(display_map)
|
||||||
|
.and_then(|next_row| next_row.span_to(display_map.max_point()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn span_to<I: Into<DisplayRow>>(
|
||||||
|
&self,
|
||||||
|
end_row: I,
|
||||||
|
) -> Option<impl Iterator<Item = DisplayRow>> {
|
||||||
|
let end_row = end_row.into();
|
||||||
|
if self.0 <= end_row.0 {
|
||||||
|
let start = *self;
|
||||||
|
let mut current = None;
|
||||||
|
|
||||||
|
Some(std::iter::from_fn(move || {
|
||||||
|
if current == None {
|
||||||
|
current = Some(start);
|
||||||
|
} else {
|
||||||
|
current = current.unwrap().next_unchecked();
|
||||||
|
}
|
||||||
|
if current.unwrap().0 > end_row.0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
current
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force users to think about the display map when using this type
|
||||||
|
pub fn start(&self, _display_map: &DisplaySnapshot) -> DisplayPoint {
|
||||||
|
DisplayPoint::new(self.0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end(&self, display_map: &DisplaySnapshot) -> DisplayPoint {
|
||||||
|
DisplayPoint::new(self.0, display_map.line_len(self.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5715,7 +5715,7 @@ impl Editor {
|
||||||
let buffer_start_row = range.start.to_point(&display_map).row;
|
let buffer_start_row = range.start.to_point(&display_map).row;
|
||||||
|
|
||||||
for row in (0..=range.end.row()).rev() {
|
for row in (0..=range.end.row()).rev() {
|
||||||
if let Some(fold_range) = display_map.foldable_range_for_line(row) {
|
if let Some(fold_range) = display_map.foldable_range(DisplayRow::new(row)) {
|
||||||
if fold_range.end.row >= buffer_start_row {
|
if fold_range.end.row >= buffer_start_row {
|
||||||
fold_ranges.push(fold_range);
|
fold_ranges.push(fold_range);
|
||||||
if row <= range.start.row() {
|
if row <= range.start.row() {
|
||||||
|
@ -5734,7 +5734,7 @@ impl Editor {
|
||||||
|
|
||||||
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
|
|
||||||
if let Some(fold_range) = display_map.foldable_range_for_line(display_row.0) {
|
if let Some(fold_range) = display_map.foldable_range(display_row) {
|
||||||
self.fold_ranges(std::iter::once(fold_range), true, cx);
|
self.fold_ranges(std::iter::once(fold_range), true, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5762,7 +5762,7 @@ impl Editor {
|
||||||
|
|
||||||
let display_range = fold_at
|
let display_range = fold_at
|
||||||
.display_row
|
.display_row
|
||||||
.to_span(&display_map)
|
.to_line_span(&display_map)
|
||||||
.map_endpoints(|endpoint| endpoint.to_point(&display_map));
|
.map_endpoints(|endpoint| endpoint.to_point(&display_map));
|
||||||
|
|
||||||
self.unfold_ranges(std::iter::once(display_range), true, true, cx)
|
self.unfold_ranges(std::iter::once(display_range), true, true, cx)
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
use collections::{HashMap, HashSet};
|
use collections::{HashMap, HashSet};
|
||||||
use editor::{
|
use editor::{
|
||||||
display_map::ToDisplayPoint,
|
display_map::{DisplayRow, ToDisplayPoint},
|
||||||
scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount},
|
scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount},
|
||||||
Anchor, Bias, ClipboardSelection, DisplayPoint, Editor,
|
Anchor, Bias, ClipboardSelection, DisplayPoint, Editor,
|
||||||
};
|
};
|
||||||
|
@ -195,7 +195,7 @@ fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContex
|
||||||
.map(|selection| selection.start.row())
|
.map(|selection| selection.start.row())
|
||||||
.collect();
|
.collect();
|
||||||
let edits = selection_start_rows.into_iter().map(|row| {
|
let edits = selection_start_rows.into_iter().map(|row| {
|
||||||
let (indent, _) = map.line_indent(row);
|
let (indent, _) = map.line_indent(DisplayRow::new(row));
|
||||||
let start_of_line = map
|
let start_of_line = map
|
||||||
.clip_point(DisplayPoint::new(row, 0), Bias::Left)
|
.clip_point(DisplayPoint::new(row, 0), Bias::Left)
|
||||||
.to_point(&map);
|
.to_point(&map);
|
||||||
|
@ -216,6 +216,8 @@ fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContex
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: FIGURE OUT WHY PANIC WHEN CLICKING ON FOLDS
|
||||||
|
|
||||||
fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContext<Workspace>) {
|
fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContext<Workspace>) {
|
||||||
Vim::update(cx, |vim, cx| {
|
Vim::update(cx, |vim, cx| {
|
||||||
vim.switch_mode(Mode::Insert, false, cx);
|
vim.switch_mode(Mode::Insert, false, cx);
|
||||||
|
@ -227,7 +229,7 @@ fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContex
|
||||||
.map(|selection| selection.end.row())
|
.map(|selection| selection.end.row())
|
||||||
.collect();
|
.collect();
|
||||||
let edits = selection_end_rows.into_iter().map(|row| {
|
let edits = selection_end_rows.into_iter().map(|row| {
|
||||||
let (indent, _) = map.line_indent(row);
|
let (indent, _) = map.line_indent(DisplayRow::new(row));
|
||||||
let end_of_line = map
|
let end_of_line = map
|
||||||
.clip_point(DisplayPoint::new(row, map.line_len(row)), Bias::Left)
|
.clip_point(DisplayPoint::new(row, map.line_len(row)), Bias::Left)
|
||||||
.to_point(&map);
|
.to_point(&map);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue