Highlight active lines
This commit is contained in:
committed by
Max Brunsfeld
parent
3abed88c76
commit
db9cfb0d2b
@@ -15,8 +15,9 @@ modal_match_text = 0xcccccc
|
|||||||
modal_match_text_highlight = 0x18a3ff
|
modal_match_text_highlight = 0x18a3ff
|
||||||
|
|
||||||
[editor]
|
[editor]
|
||||||
background = 0x1c1d1e
|
background = 0x131415
|
||||||
gutter_background = 0x1c1d1e
|
gutter_background = 0x131415
|
||||||
|
active_line_background = 0x1c1d1e
|
||||||
line_number = 0x5a5a5b
|
line_number = 0x5a5a5b
|
||||||
line_number_active = 0xffffff
|
line_number_active = 0xffffff
|
||||||
default_text = 0xd4d4d4
|
default_text = 0xd4d4d4
|
||||||
|
|||||||
+3
-3
@@ -27,7 +27,7 @@ use smallvec::SmallVec;
|
|||||||
use smol::Timer;
|
use smol::Timer;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{self, Ordering},
|
cmp::{self, Ordering},
|
||||||
collections::HashSet,
|
collections::BTreeMap,
|
||||||
fmt::Write,
|
fmt::Write,
|
||||||
iter::FromIterator,
|
iter::FromIterator,
|
||||||
mem,
|
mem,
|
||||||
@@ -2357,7 +2357,7 @@ impl Snapshot {
|
|||||||
pub fn layout_line_numbers(
|
pub fn layout_line_numbers(
|
||||||
&self,
|
&self,
|
||||||
rows: Range<u32>,
|
rows: Range<u32>,
|
||||||
active_rows: &HashSet<u32>,
|
active_rows: &BTreeMap<u32, bool>,
|
||||||
font_cache: &FontCache,
|
font_cache: &FontCache,
|
||||||
layout_cache: &TextLayoutCache,
|
layout_cache: &TextLayoutCache,
|
||||||
theme: &Theme,
|
theme: &Theme,
|
||||||
@@ -2373,7 +2373,7 @@ impl Snapshot {
|
|||||||
.enumerate()
|
.enumerate()
|
||||||
{
|
{
|
||||||
let display_row = rows.start + ix as u32;
|
let display_row = rows.start + ix as u32;
|
||||||
let color = if active_rows.contains(&display_row) {
|
let color = if active_rows.contains_key(&display_row) {
|
||||||
theme.editor.line_number_active.0
|
theme.editor.line_number_active.0
|
||||||
} else {
|
} else {
|
||||||
theme.editor.line_number.0
|
theme.editor.line_number.0
|
||||||
|
|||||||
+70
-22
@@ -14,10 +14,10 @@ use gpui::{
|
|||||||
};
|
};
|
||||||
use json::json;
|
use json::json;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{cmp::Ordering, collections::HashSet, ops::Range};
|
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{self},
|
cmp::{self, Ordering},
|
||||||
collections::HashMap,
|
collections::{BTreeMap, HashMap},
|
||||||
|
ops::Range,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct EditorElement {
|
pub struct EditorElement {
|
||||||
@@ -182,19 +182,64 @@ impl EditorElement {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, cx: &mut PaintContext) {
|
fn paint_background(
|
||||||
let settings = self.view(cx.app).settings.borrow();
|
&self,
|
||||||
let theme = &settings.theme;
|
gutter_bounds: RectF,
|
||||||
|
text_bounds: RectF,
|
||||||
|
layout: &LayoutState,
|
||||||
|
cx: &mut PaintContext,
|
||||||
|
) {
|
||||||
|
let bounds = gutter_bounds.union_rect(text_bounds);
|
||||||
let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
|
let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
|
||||||
|
let editor = self.view(cx.app);
|
||||||
cx.scene.push_layer(Some(rect));
|
let settings = editor.settings.borrow();
|
||||||
|
let theme = &settings.theme;
|
||||||
cx.scene.push_quad(Quad {
|
cx.scene.push_quad(Quad {
|
||||||
bounds: rect,
|
bounds: gutter_bounds,
|
||||||
background: Some(theme.editor.gutter_background.0),
|
background: Some(theme.editor.gutter_background.0),
|
||||||
border: Border::new(0., ColorU::transparent_black()),
|
border: Border::new(0., ColorU::transparent_black()),
|
||||||
corner_radius: 0.,
|
corner_radius: 0.,
|
||||||
});
|
});
|
||||||
|
cx.scene.push_quad(Quad {
|
||||||
|
bounds: text_bounds,
|
||||||
|
background: Some(theme.editor.background.0),
|
||||||
|
border: Border::new(0., ColorU::transparent_black()),
|
||||||
|
corner_radius: 0.,
|
||||||
|
});
|
||||||
|
|
||||||
|
if !editor.single_line {
|
||||||
|
let mut active_rows = layout.active_rows.iter().peekable();
|
||||||
|
while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
|
||||||
|
let mut end_row = *start_row;
|
||||||
|
while active_rows.peek().map_or(false, |r| {
|
||||||
|
*r.0 == end_row + 1 && r.1 == contains_non_empty_selection
|
||||||
|
}) {
|
||||||
|
active_rows.next().unwrap();
|
||||||
|
end_row += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !contains_non_empty_selection {
|
||||||
|
let origin = vec2f(
|
||||||
|
bounds.origin_x(),
|
||||||
|
bounds.origin_y() + (layout.line_height * *start_row as f32) - scroll_top,
|
||||||
|
);
|
||||||
|
let size = vec2f(
|
||||||
|
bounds.width(),
|
||||||
|
layout.line_height * (end_row - start_row + 1) as f32,
|
||||||
|
);
|
||||||
|
cx.scene.push_quad(Quad {
|
||||||
|
bounds: RectF::new(origin, size),
|
||||||
|
background: Some(theme.editor.active_line_background.0),
|
||||||
|
border: Border::default(),
|
||||||
|
corner_radius: 0.,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint_gutter(&mut self, rect: RectF, layout: &LayoutState, cx: &mut PaintContext) {
|
||||||
|
let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
|
||||||
for (ix, line) in layout.line_number_layouts.iter().enumerate() {
|
for (ix, line) in layout.line_number_layouts.iter().enumerate() {
|
||||||
if let Some(line) = line {
|
if let Some(line) = line {
|
||||||
let line_origin = rect.origin()
|
let line_origin = rect.origin()
|
||||||
@@ -209,8 +254,6 @@ impl EditorElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cx.scene.pop_layer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) {
|
fn paint_text(&mut self, bounds: RectF, layout: &LayoutState, cx: &mut PaintContext) {
|
||||||
@@ -225,12 +268,6 @@ impl EditorElement {
|
|||||||
let scroll_left = scroll_position.x() * max_glyph_width;
|
let scroll_left = scroll_position.x() * max_glyph_width;
|
||||||
|
|
||||||
cx.scene.push_layer(Some(bounds));
|
cx.scene.push_layer(Some(bounds));
|
||||||
cx.scene.push_quad(Quad {
|
|
||||||
bounds,
|
|
||||||
background: Some(theme.background.0),
|
|
||||||
border: Border::new(0., ColorU::transparent_black()),
|
|
||||||
corner_radius: 0.,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Draw selections
|
// Draw selections
|
||||||
let corner_radius = 2.5;
|
let corner_radius = 2.5;
|
||||||
@@ -393,7 +430,7 @@ impl Element for EditorElement {
|
|||||||
let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
|
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 selections = HashMap::new();
|
||||||
let mut active_rows = HashSet::new();
|
let mut active_rows = BTreeMap::new();
|
||||||
self.update_view(cx.app, |view, cx| {
|
self.update_view(cx.app, |view, cx| {
|
||||||
let replica_id = view.replica_id(cx);
|
let replica_id = view.replica_id(cx);
|
||||||
for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
|
for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
|
||||||
@@ -405,6 +442,7 @@ impl Element for EditorElement {
|
|||||||
) {
|
) {
|
||||||
set.push(selection.clone());
|
set.push(selection.clone());
|
||||||
if selection_set_id.replica_id == replica_id {
|
if selection_set_id.replica_id == replica_id {
|
||||||
|
let is_empty = selection.start == selection.end;
|
||||||
let mut selection_start;
|
let mut selection_start;
|
||||||
let mut selection_end;
|
let mut selection_end;
|
||||||
if selection.start < selection.end {
|
if selection.start < selection.end {
|
||||||
@@ -416,10 +454,13 @@ impl Element for EditorElement {
|
|||||||
};
|
};
|
||||||
selection_start = snapshot.prev_row_boundary(selection_start).0;
|
selection_start = snapshot.prev_row_boundary(selection_start).0;
|
||||||
selection_end = snapshot.next_row_boundary(selection_end).0;
|
selection_end = snapshot.next_row_boundary(selection_end).0;
|
||||||
active_rows.extend(
|
for row in cmp::max(selection_start.row(), start_row)
|
||||||
cmp::max(selection_start.row(), start_row)
|
..=cmp::min(selection_end.row(), end_row)
|
||||||
..=cmp::min(selection_end.row(), end_row),
|
{
|
||||||
);
|
let contains_non_empty_selection =
|
||||||
|
active_rows.entry(row).or_insert(!is_empty);
|
||||||
|
*contains_non_empty_selection |= !is_empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,6 +519,7 @@ impl Element for EditorElement {
|
|||||||
overscroll,
|
overscroll,
|
||||||
text_offset,
|
text_offset,
|
||||||
snapshot,
|
snapshot,
|
||||||
|
active_rows,
|
||||||
line_layouts,
|
line_layouts,
|
||||||
line_number_layouts,
|
line_number_layouts,
|
||||||
line_height,
|
line_height,
|
||||||
@@ -520,17 +562,22 @@ impl Element for EditorElement {
|
|||||||
cx: &mut PaintContext,
|
cx: &mut PaintContext,
|
||||||
) -> Self::PaintState {
|
) -> Self::PaintState {
|
||||||
if let Some(layout) = layout {
|
if let Some(layout) = layout {
|
||||||
|
cx.scene.push_layer(Some(bounds));
|
||||||
|
|
||||||
let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
|
let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
|
||||||
let text_bounds = RectF::new(
|
let text_bounds = RectF::new(
|
||||||
bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
|
bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
|
||||||
layout.text_size,
|
layout.text_size,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.paint_background(gutter_bounds, text_bounds, layout, cx);
|
||||||
if layout.gutter_size.x() > 0. {
|
if layout.gutter_size.x() > 0. {
|
||||||
self.paint_gutter(gutter_bounds, layout, cx);
|
self.paint_gutter(gutter_bounds, layout, cx);
|
||||||
}
|
}
|
||||||
self.paint_text(text_bounds, layout, cx);
|
self.paint_text(text_bounds, layout, cx);
|
||||||
|
|
||||||
|
cx.scene.pop_layer();
|
||||||
|
|
||||||
Some(PaintState {
|
Some(PaintState {
|
||||||
bounds,
|
bounds,
|
||||||
text_bounds,
|
text_bounds,
|
||||||
@@ -590,6 +637,7 @@ pub struct LayoutState {
|
|||||||
gutter_padding: f32,
|
gutter_padding: f32,
|
||||||
text_size: Vector2F,
|
text_size: Vector2F,
|
||||||
snapshot: Snapshot,
|
snapshot: Snapshot,
|
||||||
|
active_rows: BTreeMap<u32, bool>,
|
||||||
line_layouts: Vec<text_layout::Line>,
|
line_layouts: Vec<text_layout::Line>,
|
||||||
line_number_layouts: Vec<Option<text_layout::Line>>,
|
line_number_layouts: Vec<Option<text_layout::Line>>,
|
||||||
line_height: f32,
|
line_height: f32,
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ pub struct UiTheme {
|
|||||||
pub struct EditorTheme {
|
pub struct EditorTheme {
|
||||||
pub background: Color,
|
pub background: Color,
|
||||||
pub gutter_background: Color,
|
pub gutter_background: Color,
|
||||||
|
pub active_line_background: Color,
|
||||||
pub line_number: Color,
|
pub line_number: Color,
|
||||||
pub line_number_active: Color,
|
pub line_number_active: Color,
|
||||||
pub default_text: Color,
|
pub default_text: Color,
|
||||||
|
|||||||
Reference in New Issue
Block a user