Add code folding indicators into the gutter.
This commit is contained in:
parent
514da604d7
commit
e3061066c9
7 changed files with 239 additions and 85 deletions
|
@ -23,6 +23,12 @@ pub use block_map::{
|
||||||
BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock,
|
BlockDisposition, BlockId, BlockProperties, BlockStyle, RenderBlock, TransformBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum FoldStatus {
|
||||||
|
Folded,
|
||||||
|
Foldable,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait ToDisplayPoint {
|
pub trait ToDisplayPoint {
|
||||||
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint;
|
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint;
|
||||||
}
|
}
|
||||||
|
@ -591,6 +597,57 @@ impl DisplaySnapshot {
|
||||||
self.blocks_snapshot.longest_row()
|
self.blocks_snapshot.longest_row()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fold_for_line(self: &Self, display_row: u32) -> Option<FoldStatus> {
|
||||||
|
if self.is_line_foldable(display_row) {
|
||||||
|
Some(FoldStatus::Foldable)
|
||||||
|
} else if self.is_line_folded(display_row) {
|
||||||
|
Some(FoldStatus::Folded)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_line_foldable(self: &Self, display_row: u32) -> bool {
|
||||||
|
let max_point = self.max_point();
|
||||||
|
if display_row >= max_point.row() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
let (start_indent, is_blank) = self.line_indent(display_row);
|
||||||
|
if is_blank {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
for display_row in display_row + 1..=max_point.row() {
|
||||||
|
let (indent, is_blank) = self.line_indent(display_row);
|
||||||
|
if !is_blank {
|
||||||
|
return indent > start_indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn foldable_range_for_line(self: &Self, start_row: u32) -> Option<Range<Point>> {
|
||||||
|
if self.is_line_foldable(start_row) && !self.is_line_folded(start_row) {
|
||||||
|
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;
|
||||||
|
for row in start_row + 1..=max_point.row() {
|
||||||
|
let (indent, is_blank) = self.line_indent(row);
|
||||||
|
if !is_blank && indent <= start_indent {
|
||||||
|
end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let end = end.unwrap_or(max_point);
|
||||||
|
Some(start.to_point(self)..end.to_point(self))
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
pub fn highlight_ranges<Tag: ?Sized + 'static>(
|
pub fn highlight_ranges<Tag: ?Sized + 'static>(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
mod blink_manager;
|
mod blink_manager;
|
||||||
pub mod display_map;
|
pub mod display_map;
|
||||||
mod element;
|
mod element;
|
||||||
|
|
||||||
mod git;
|
mod git;
|
||||||
mod highlight_matching_bracket;
|
mod highlight_matching_bracket;
|
||||||
mod hover_popover;
|
mod hover_popover;
|
||||||
|
@ -160,6 +161,16 @@ pub struct ToggleComments {
|
||||||
pub advance_downwards: bool,
|
pub advance_downwards: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default, Deserialize, PartialEq)]
|
||||||
|
pub struct FoldAt {
|
||||||
|
pub display_row: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Default, Deserialize, PartialEq)]
|
||||||
|
pub struct UnfoldAt {
|
||||||
|
pub display_row: u32,
|
||||||
|
}
|
||||||
|
|
||||||
actions!(
|
actions!(
|
||||||
editor,
|
editor,
|
||||||
[
|
[
|
||||||
|
@ -258,6 +269,8 @@ impl_actions!(
|
||||||
ConfirmCompletion,
|
ConfirmCompletion,
|
||||||
ConfirmCodeAction,
|
ConfirmCodeAction,
|
||||||
ToggleComments,
|
ToggleComments,
|
||||||
|
FoldAt,
|
||||||
|
UnfoldAt
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -348,7 +361,9 @@ pub fn init(cx: &mut MutableAppContext) {
|
||||||
cx.add_action(Editor::go_to_definition);
|
cx.add_action(Editor::go_to_definition);
|
||||||
cx.add_action(Editor::go_to_type_definition);
|
cx.add_action(Editor::go_to_type_definition);
|
||||||
cx.add_action(Editor::fold);
|
cx.add_action(Editor::fold);
|
||||||
|
cx.add_action(Editor::fold_at);
|
||||||
cx.add_action(Editor::unfold_lines);
|
cx.add_action(Editor::unfold_lines);
|
||||||
|
cx.add_action(Editor::unfold_at);
|
||||||
cx.add_action(Editor::fold_selected_ranges);
|
cx.add_action(Editor::fold_selected_ranges);
|
||||||
cx.add_action(Editor::show_completions);
|
cx.add_action(Editor::show_completions);
|
||||||
cx.add_action(Editor::toggle_code_actions);
|
cx.add_action(Editor::toggle_code_actions);
|
||||||
|
@ -2648,9 +2663,9 @@ impl Editor {
|
||||||
cx: &mut RenderContext<Self>,
|
cx: &mut RenderContext<Self>,
|
||||||
) -> Option<ElementBox> {
|
) -> Option<ElementBox> {
|
||||||
if self.available_code_actions.is_some() {
|
if self.available_code_actions.is_some() {
|
||||||
enum Tag {}
|
enum CodeActions {}
|
||||||
Some(
|
Some(
|
||||||
MouseEventHandler::<Tag>::new(0, cx, |_, _| {
|
MouseEventHandler::<CodeActions>::new(0, cx, |_, _| {
|
||||||
Svg::new("icons/bolt_8.svg")
|
Svg::new("icons/bolt_8.svg")
|
||||||
.with_color(style.code_actions.indicator)
|
.with_color(style.code_actions.indicator)
|
||||||
.boxed()
|
.boxed()
|
||||||
|
@ -2669,6 +2684,51 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn render_fold_indicators(
|
||||||
|
&self,
|
||||||
|
fold_data: Vec<(u32, FoldStatus)>,
|
||||||
|
fold_indicators: &mut Vec<(u32, ElementBox)>,
|
||||||
|
style: &EditorStyle,
|
||||||
|
cx: &mut RenderContext<Self>,
|
||||||
|
) {
|
||||||
|
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",
|
||||||
|
})
|
||||||
|
.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: fold_location,
|
||||||
|
}),
|
||||||
|
FoldStatus::Foldable => Box::new(FoldAt {
|
||||||
|
display_row: fold_location,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.boxed(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn context_menu_visible(&self) -> bool {
|
pub fn context_menu_visible(&self) -> bool {
|
||||||
self.context_menu
|
self.context_menu
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -3251,26 +3311,12 @@ impl Editor {
|
||||||
|
|
||||||
while let Some(selection) = selections.next() {
|
while let Some(selection) = selections.next() {
|
||||||
// Find all the selections that span a contiguous row range
|
// Find all the selections that span a contiguous row range
|
||||||
contiguous_row_selections.push(selection.clone());
|
let (start_row, end_row) = consume_contiguous_rows(
|
||||||
let start_row = selection.start.row;
|
&mut contiguous_row_selections,
|
||||||
let mut end_row = if selection.end.column > 0 || selection.is_empty() {
|
selection,
|
||||||
display_map.next_line_boundary(selection.end).0.row + 1
|
&display_map,
|
||||||
} else {
|
&mut selections,
|
||||||
selection.end.row
|
);
|
||||||
};
|
|
||||||
|
|
||||||
while let Some(next_selection) = selections.peek() {
|
|
||||||
if next_selection.start.row <= end_row {
|
|
||||||
end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
|
|
||||||
display_map.next_line_boundary(next_selection.end).0.row + 1
|
|
||||||
} else {
|
|
||||||
next_selection.end.row
|
|
||||||
};
|
|
||||||
contiguous_row_selections.push(selections.next().unwrap().clone());
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the text spanned by the row range to be before the line preceding the row range
|
// Move the text spanned by the row range to be before the line preceding the row range
|
||||||
if start_row > 0 {
|
if start_row > 0 {
|
||||||
|
@ -3363,26 +3409,12 @@ impl Editor {
|
||||||
|
|
||||||
while let Some(selection) = selections.next() {
|
while let Some(selection) = selections.next() {
|
||||||
// Find all the selections that span a contiguous row range
|
// Find all the selections that span a contiguous row range
|
||||||
contiguous_row_selections.push(selection.clone());
|
let (start_row, end_row) = consume_contiguous_rows(
|
||||||
let start_row = selection.start.row;
|
&mut contiguous_row_selections,
|
||||||
let mut end_row = if selection.end.column > 0 || selection.is_empty() {
|
selection,
|
||||||
display_map.next_line_boundary(selection.end).0.row + 1
|
&display_map,
|
||||||
} else {
|
&mut selections,
|
||||||
selection.end.row
|
);
|
||||||
};
|
|
||||||
|
|
||||||
while let Some(next_selection) = selections.peek() {
|
|
||||||
if next_selection.start.row <= end_row {
|
|
||||||
end_row = if next_selection.end.column > 0 || next_selection.is_empty() {
|
|
||||||
display_map.next_line_boundary(next_selection.end).0.row + 1
|
|
||||||
} else {
|
|
||||||
next_selection.end.row
|
|
||||||
};
|
|
||||||
contiguous_row_selections.push(selections.next().unwrap().clone());
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move the text spanned by the row range to be after the last line of the row range
|
// Move the text spanned by the row range to be after the last line of the row range
|
||||||
if end_row <= buffer.max_point().row {
|
if end_row <= buffer.max_point().row {
|
||||||
|
@ -5676,14 +5708,14 @@ impl Editor {
|
||||||
let mut fold_ranges = Vec::new();
|
let mut fold_ranges = Vec::new();
|
||||||
|
|
||||||
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));
|
||||||
|
|
||||||
let selections = self.selections.all::<Point>(cx);
|
let selections = self.selections.all::<Point>(cx);
|
||||||
for selection in selections {
|
for selection in selections {
|
||||||
let range = selection.display_range(&display_map).sorted();
|
let range = selection.display_range(&display_map).sorted();
|
||||||
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 self.is_line_foldable(&display_map, row) && !display_map.is_line_folded(row) {
|
if let Some(fold_range) = display_map.foldable_range_for_line(row) {
|
||||||
let fold_range = self.foldable_range_for_line(&display_map, 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() {
|
||||||
|
@ -5697,6 +5729,16 @@ impl Editor {
|
||||||
self.fold_ranges(fold_ranges, cx);
|
self.fold_ranges(fold_ranges, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fold_at(&mut self, fold_at: &FoldAt, cx: &mut ViewContext<Self>) {
|
||||||
|
let display_row = fold_at.display_row;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
self.fold_ranges(std::iter::once(fold_range), cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn unfold_lines(&mut self, _: &UnfoldLines, cx: &mut ViewContext<Self>) {
|
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 display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
let buffer = &display_map.buffer_snapshot;
|
let buffer = &display_map.buffer_snapshot;
|
||||||
|
@ -5715,46 +5757,11 @@ impl Editor {
|
||||||
self.unfold_ranges(ranges, true, cx);
|
self.unfold_ranges(ranges, true, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_line_foldable(&self, display_map: &DisplaySnapshot, display_row: u32) -> bool {
|
pub fn unfold_at(&mut self, fold_at: &UnfoldAt, cx: &mut ViewContext<Self>) {
|
||||||
let max_point = display_map.max_point();
|
let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
|
||||||
if display_row >= max_point.row() {
|
let unfold_range = display_map.buffer_snapshot.row_span(fold_at.display_row);
|
||||||
false
|
|
||||||
} else {
|
|
||||||
let (start_indent, is_blank) = display_map.line_indent(display_row);
|
|
||||||
if is_blank {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
for display_row in display_row + 1..=max_point.row() {
|
|
||||||
let (indent, is_blank) = display_map.line_indent(display_row);
|
|
||||||
if !is_blank {
|
|
||||||
return indent > start_indent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn foldable_range_for_line(
|
self.unfold_ranges(std::iter::once(unfold_range), true, cx)
|
||||||
&self,
|
|
||||||
display_map: &DisplaySnapshot,
|
|
||||||
start_row: u32,
|
|
||||||
) -> Range<Point> {
|
|
||||||
let max_point = display_map.max_point();
|
|
||||||
|
|
||||||
let (start_indent, _) = display_map.line_indent(start_row);
|
|
||||||
let start = DisplayPoint::new(start_row, display_map.line_len(start_row));
|
|
||||||
let mut end = None;
|
|
||||||
for row in start_row + 1..=max_point.row() {
|
|
||||||
let (indent, is_blank) = display_map.line_indent(row);
|
|
||||||
if !is_blank && indent <= start_indent {
|
|
||||||
end = Some(DisplayPoint::new(row - 1, display_map.line_len(row - 1)));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let end = end.unwrap_or(max_point);
|
|
||||||
start.to_point(display_map)..end.to_point(display_map)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
|
pub fn fold_selected_ranges(&mut self, _: &FoldSelectedRanges, cx: &mut ViewContext<Self>) {
|
||||||
|
@ -6252,6 +6259,35 @@ impl Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn consume_contiguous_rows(
|
||||||
|
contiguous_row_selections: &mut Vec<Selection<Point>>,
|
||||||
|
selection: &Selection<Point>,
|
||||||
|
display_map: &DisplaySnapshot,
|
||||||
|
selections: &mut std::iter::Peekable<std::slice::Iter<Selection<Point>>>,
|
||||||
|
) -> (u32, u32) {
|
||||||
|
contiguous_row_selections.push(selection.clone());
|
||||||
|
let start_row = selection.start.row;
|
||||||
|
let mut end_row = ending_row(selection, display_map);
|
||||||
|
|
||||||
|
while let Some(next_selection) = selections.peek() {
|
||||||
|
if next_selection.start.row <= end_row {
|
||||||
|
end_row = ending_row(next_selection, display_map);
|
||||||
|
contiguous_row_selections.push(selections.next().unwrap().clone());
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(start_row, end_row)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> u32 {
|
||||||
|
if next_selection.end.column > 0 || next_selection.is_empty() {
|
||||||
|
display_map.next_line_boundary(next_selection.end).0.row + 1
|
||||||
|
} else {
|
||||||
|
next_selection.end.row
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl EditorSnapshot {
|
impl EditorSnapshot {
|
||||||
pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
|
pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
|
||||||
self.display_snapshot.buffer_snapshot.language_at(position)
|
self.display_snapshot.buffer_snapshot.language_at(position)
|
||||||
|
|
|
@ -4,7 +4,7 @@ use super::{
|
||||||
ToPoint, MAX_LINE_LEN,
|
ToPoint, MAX_LINE_LEN,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
display_map::{BlockStyle, DisplaySnapshot, TransformBlock},
|
display_map::{BlockStyle, DisplaySnapshot, FoldStatus, TransformBlock},
|
||||||
git::{diff_hunk_to_display, DisplayDiffHunk},
|
git::{diff_hunk_to_display, DisplayDiffHunk},
|
||||||
hover_popover::{
|
hover_popover::{
|
||||||
HideHover, HoverAt, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT,
|
HideHover, HoverAt, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT,
|
||||||
|
@ -575,6 +575,16 @@ impl EditorElement {
|
||||||
y += (line_height - indicator.size().y()) / 2.;
|
y += (line_height - indicator.size().y()) / 2.;
|
||||||
indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, cx);
|
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;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_diff_hunks(bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) {
|
fn paint_diff_hunks(bounds: RectF, layout: &mut LayoutState, cx: &mut PaintContext) {
|
||||||
|
@ -1118,6 +1128,21 @@ impl EditorElement {
|
||||||
.width()
|
.width()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_fold_indicators(
|
||||||
|
&self,
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
//Folds contained in a hunk are ignored apart from shrinking visual size
|
//Folds contained in a hunk are ignored apart from shrinking visual size
|
||||||
//If a fold contains any hunks then that fold line is marked as modified
|
//If a fold contains any hunks then that fold line is marked as modified
|
||||||
fn layout_git_gutters(
|
fn layout_git_gutters(
|
||||||
|
@ -1689,6 +1714,8 @@ impl Element for EditorElement {
|
||||||
|
|
||||||
let display_hunks = self.layout_git_gutters(start_row..end_row, &snapshot);
|
let display_hunks = self.layout_git_gutters(start_row..end_row, &snapshot);
|
||||||
|
|
||||||
|
let folds = self.get_fold_indicators(start_row..end_row, &snapshot);
|
||||||
|
|
||||||
let scrollbar_row_range = scroll_position.y()..(scroll_position.y() + height_in_lines);
|
let scrollbar_row_range = scroll_position.y()..(scroll_position.y() + height_in_lines);
|
||||||
|
|
||||||
let mut max_visible_line_width = 0.0;
|
let mut max_visible_line_width = 0.0;
|
||||||
|
@ -1751,6 +1778,7 @@ impl Element for EditorElement {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let mut fold_indicators = Vec::with_capacity(folds.len());
|
||||||
let mut context_menu = None;
|
let mut context_menu = None;
|
||||||
let mut code_actions_indicator = None;
|
let mut code_actions_indicator = None;
|
||||||
let mut hover = None;
|
let mut hover = None;
|
||||||
|
@ -1774,6 +1802,8 @@ impl Element for EditorElement {
|
||||||
.map(|indicator| (newest_selection_head.row(), indicator));
|
.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;
|
let visible_rows = start_row..start_row + line_layouts.len() as u32;
|
||||||
hover = view.hover_state.render(&snapshot, &style, visible_rows, cx);
|
hover = view.hover_state.render(&snapshot, &style, visible_rows, cx);
|
||||||
mode = view.mode;
|
mode = view.mode;
|
||||||
|
@ -1802,6 +1832,16 @@ 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,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some((_, hover_popovers)) = hover.as_mut() {
|
if let Some((_, hover_popovers)) = hover.as_mut() {
|
||||||
for hover_popover in hover_popovers.iter_mut() {
|
for hover_popover in hover_popovers.iter_mut() {
|
||||||
hover_popover.layout(
|
hover_popover.layout(
|
||||||
|
@ -1851,6 +1891,7 @@ impl Element for EditorElement {
|
||||||
selections,
|
selections,
|
||||||
context_menu,
|
context_menu,
|
||||||
code_actions_indicator,
|
code_actions_indicator,
|
||||||
|
fold_indicators,
|
||||||
hover_popovers: hover,
|
hover_popovers: hover,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
@ -1979,6 +2020,7 @@ pub struct LayoutState {
|
||||||
context_menu: Option<(DisplayPoint, ElementBox)>,
|
context_menu: Option<(DisplayPoint, ElementBox)>,
|
||||||
code_actions_indicator: Option<(u32, ElementBox)>,
|
code_actions_indicator: Option<(u32, ElementBox)>,
|
||||||
hover_popovers: Option<(DisplayPoint, Vec<ElementBox>)>,
|
hover_popovers: Option<(DisplayPoint, Vec<ElementBox>)>,
|
||||||
|
fold_indicators: Vec<(u32, ElementBox)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PositionMap {
|
pub struct PositionMap {
|
||||||
|
|
|
@ -1916,6 +1916,10 @@ impl MultiBufferSnapshot {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn row_span(&self, display_row: u32) -> Range<Point> {
|
||||||
|
Point::new(display_row, 0)..Point::new(display_row, self.line_len(display_row))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows {
|
pub fn buffer_rows(&self, start_row: u32) -> MultiBufferRows {
|
||||||
let mut result = MultiBufferRows {
|
let mut result = MultiBufferRows {
|
||||||
buffer_row_range: 0..0,
|
buffer_row_range: 0..0,
|
||||||
|
|
|
@ -296,7 +296,10 @@ impl<T: Element> AnyElement for Lifecycle<T> {
|
||||||
paint,
|
paint,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => panic!("invalid element lifecycle state"),
|
Lifecycle::Empty => panic!("invalid element lifecycle state"),
|
||||||
|
Lifecycle::Init { .. } => {
|
||||||
|
panic!("invalid element lifecycle state, paint called before layout")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -562,6 +562,7 @@ pub struct Editor {
|
||||||
pub invalid_hint_diagnostic: DiagnosticStyle,
|
pub invalid_hint_diagnostic: DiagnosticStyle,
|
||||||
pub autocomplete: AutocompleteStyle,
|
pub autocomplete: AutocompleteStyle,
|
||||||
pub code_actions: CodeActions,
|
pub code_actions: CodeActions,
|
||||||
|
pub folds: Folds,
|
||||||
pub unnecessary_code_fade: f32,
|
pub unnecessary_code_fade: f32,
|
||||||
pub hover_popover: HoverPopover,
|
pub hover_popover: HoverPopover,
|
||||||
pub link_definition: HighlightStyle,
|
pub link_definition: HighlightStyle,
|
||||||
|
@ -638,6 +639,13 @@ pub struct CodeActions {
|
||||||
pub vertical_scale: f32,
|
pub vertical_scale: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Deserialize, Default)]
|
||||||
|
pub struct Folds {
|
||||||
|
#[serde(default)]
|
||||||
|
pub indicator: Color,
|
||||||
|
pub fold_background: Color,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Default)]
|
#[derive(Clone, Deserialize, Default)]
|
||||||
pub struct DiffStyle {
|
pub struct DiffStyle {
|
||||||
pub inserted: Color,
|
pub inserted: Color,
|
||||||
|
|
|
@ -47,6 +47,10 @@ export default function editor(colorScheme: ColorScheme) {
|
||||||
indicator: foreground(layer, "variant"),
|
indicator: foreground(layer, "variant"),
|
||||||
verticalScale: 0.55,
|
verticalScale: 0.55,
|
||||||
},
|
},
|
||||||
|
folds: {
|
||||||
|
indicator: foreground(layer, "variant"),
|
||||||
|
fold_background: foreground(layer, "variant"),
|
||||||
|
},
|
||||||
diff: {
|
diff: {
|
||||||
deleted: foreground(layer, "negative"),
|
deleted: foreground(layer, "negative"),
|
||||||
modified: foreground(layer, "warning"),
|
modified: foreground(layer, "warning"),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue