Highlight active row(s) in the gutter

This commit is contained in:
Antonio Scandurra 2021-07-30 12:07:14 +02:00 committed by Max Brunsfeld
parent 372d2ccb6d
commit 3abed88c76
3 changed files with 78 additions and 37 deletions

View File

@ -14,7 +14,6 @@ modal_match_border = 0x000000
modal_match_text = 0xcccccc
modal_match_text_highlight = 0x18a3ff
[editor]
background = 0x1c1d1e
gutter_background = 0x1c1d1e

View File

@ -5,6 +5,7 @@ pub mod movement;
use crate::{
settings::{Settings, StyleId, Theme},
time::ReplicaId,
util::{post_inc, Bias},
workspace,
worktree::{File, Worktree},
@ -26,6 +27,7 @@ use smallvec::SmallVec;
use smol::Timer;
use std::{
cmp::{self, Ordering},
collections::HashSet,
fmt::Write,
iter::FromIterator,
mem,
@ -461,6 +463,10 @@ impl Editor {
}
}
pub fn replica_id(&self, cx: &AppContext) -> ReplicaId {
self.buffer.read(cx).replica_id()
}
pub fn buffer(&self) -> &ModelHandle<Buffer> {
&self.buffer
}
@ -2350,27 +2356,28 @@ impl Snapshot {
pub fn layout_line_numbers(
&self,
viewport_height: f32,
rows: Range<u32>,
active_rows: &HashSet<u32>,
font_cache: &FontCache,
layout_cache: &TextLayoutCache,
theme: &Theme,
) -> Result<Vec<Option<text_layout::Line>>> {
let font_id = font_cache.select_font(self.font_family, &FontProperties::new())?;
let start_row = self.scroll_position().y() as usize;
let end_row = cmp::min(
self.display_snapshot.max_point().row() as usize,
start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
);
let line_count = end_row - start_row + 1;
let mut layouts = Vec::with_capacity(line_count);
let mut layouts = Vec::with_capacity(rows.len());
let mut line_number = String::new();
for (buffer_row, soft_wrapped) in self
for (ix, (buffer_row, soft_wrapped)) in self
.display_snapshot
.buffer_rows(start_row as u32)
.take(line_count)
.buffer_rows(rows.start)
.take((rows.end - rows.start) as usize)
.enumerate()
{
let display_row = rows.start + ix as u32;
let color = if active_rows.contains(&display_row) {
theme.editor.line_number_active.0
} else {
theme.editor.line_number.0
};
if soft_wrapped {
layouts.push(None);
} else {
@ -2379,7 +2386,7 @@ impl Snapshot {
layouts.push(Some(layout_cache.layout_str(
&line_number,
self.font_size,
&[(line_number.len(), font_id, theme.editor.line_number.0)],
&[(line_number.len(), font_id, color)],
)));
}
}
@ -2482,6 +2489,14 @@ impl Snapshot {
)],
))
}
pub fn prev_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) {
self.display_snapshot.prev_row_boundary(point)
}
pub fn next_row_boundary(&self, point: DisplayPoint) -> (DisplayPoint, Point) {
self.display_snapshot.next_row_boundary(point)
}
}
fn compute_scroll_position(
@ -2792,7 +2807,13 @@ mod tests {
let layouts = editor.update(cx, |editor, cx| {
editor
.snapshot(cx)
.layout_line_numbers(1000.0, &font_cache, &layout_cache, &settings.borrow().theme)
.layout_line_numbers(
0..6,
&Default::default(),
&font_cache,
&layout_cache,
&settings.borrow().theme,
)
.unwrap()
});
assert_eq!(layouts.len(), 6);

View File

@ -14,7 +14,7 @@ use gpui::{
};
use json::json;
use smallvec::SmallVec;
use std::{cmp::Ordering, ops::Range};
use std::{cmp::Ordering, collections::HashSet, ops::Range};
use std::{
cmp::{self},
collections::HashMap,
@ -387,6 +387,46 @@ impl Element for EditorElement {
(autoscroll_horizontally, snapshot)
});
let scroll_position = snapshot.scroll_position();
let start_row = scroll_position.y() as u32;
let scroll_top = scroll_position.y() * line_height;
let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
let mut selections = HashMap::new();
let mut active_rows = HashSet::new();
self.update_view(cx.app, |view, cx| {
let replica_id = view.replica_id(cx);
for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
let mut set = Vec::new();
for selection in view.selections_in_range(
selection_set_id,
DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
cx,
) {
set.push(selection.clone());
if selection_set_id.replica_id == replica_id {
let mut selection_start;
let mut selection_end;
if selection.start < selection.end {
selection_start = selection.start;
selection_end = selection.end;
} else {
selection_start = selection.end;
selection_end = selection.start;
};
selection_start = snapshot.prev_row_boundary(selection_start).0;
selection_end = snapshot.next_row_boundary(selection_end).0;
active_rows.extend(
cmp::max(selection_start.row(), start_row)
..=cmp::min(selection_end.row(), end_row),
);
}
}
selections.insert(selection_set_id.replica_id, set);
}
});
let line_number_layouts = if snapshot.gutter_visible {
let settings = self
.view
@ -396,7 +436,8 @@ impl Element for EditorElement {
.settings
.borrow();
match snapshot.layout_line_numbers(
size.y(),
start_row..end_row,
&active_rows,
cx.font_cache,
cx.text_layout_cache,
&settings.theme,
@ -411,11 +452,6 @@ impl Element for EditorElement {
Vec::new()
};
let scroll_position = snapshot.scroll_position();
let start_row = scroll_position.y() as u32;
let scroll_top = scroll_position.y() * line_height;
let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
let mut max_visible_line_width = 0.0;
let line_layouts = match snapshot.layout_lines(start_row..end_row, font_cache, layout_cache)
{
@ -434,21 +470,6 @@ impl Element for EditorElement {
}
};
let mut selections = HashMap::new();
self.update_view(cx.app, |view, cx| {
for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
selections.insert(
selection_set_id.replica_id,
view.selections_in_range(
selection_set_id,
DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
cx,
)
.collect(),
);
}
});
let mut layout = LayoutState {
size,
gutter_size,