From 3abed88c7692fb728db9214d83fc6174fd50a007 Mon Sep 17 00:00:00 2001 From: Antonio Scandurra Date: Fri, 30 Jul 2021 12:07:14 +0200 Subject: [PATCH] Highlight active row(s) in the gutter --- zed/assets/themes/dark.toml | 1 - zed/src/editor.rs | 49 ++++++++++++++++++++-------- zed/src/editor/element.rs | 65 ++++++++++++++++++++++++------------- 3 files changed, 78 insertions(+), 37 deletions(-) diff --git a/zed/assets/themes/dark.toml b/zed/assets/themes/dark.toml index c386289d07..96ba65bd63 100644 --- a/zed/assets/themes/dark.toml +++ b/zed/assets/themes/dark.toml @@ -14,7 +14,6 @@ modal_match_border = 0x000000 modal_match_text = 0xcccccc modal_match_text_highlight = 0x18a3ff - [editor] background = 0x1c1d1e gutter_background = 0x1c1d1e diff --git a/zed/src/editor.rs b/zed/src/editor.rs index d5ca0bf1f3..bd4fb7baed 100644 --- a/zed/src/editor.rs +++ b/zed/src/editor.rs @@ -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 { &self.buffer } @@ -2350,27 +2356,28 @@ impl Snapshot { pub fn layout_line_numbers( &self, - viewport_height: f32, + rows: Range, + active_rows: &HashSet, font_cache: &FontCache, layout_cache: &TextLayoutCache, theme: &Theme, ) -> Result>> { 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); diff --git a/zed/src/editor/element.rs b/zed/src/editor/element.rs index 8dd75f867a..ad9aac701a 100644 --- a/zed/src/editor/element.rs +++ b/zed/src/editor/element.rs @@ -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::>() { + 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::>() { - 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,