@@ -36,11 +36,13 @@
// Whether to show tabs and spaces in the editor.
// This setting can take two values:
//
- // 1. Do not draw any tabs or spaces (default):
+ // 1. Draw tabs and spaces only for the selected text (default):
+ // "selection"
+ // 2. Do not draw any tabs or spaces:
// "none"
- // 2. Draw all invisible symbols:
+ // 3. Draw all invisible symbols:
// "all"
- "show_invisibles": "none",
+ "show_invisibles": "selection",
// Whether the screen sharing icon is shown in the os status bar.
"show_call_status_icon": true,
// Whether to use language servers to provide code intelligence.
@@ -784,11 +784,15 @@ impl EditorElement {
let mut cursors = SmallVec::<[Cursor; 32]>::new();
let corner_radius = 0.15 * layout.position_map.line_height;
+ let mut selection_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
for (replica_id, selections) in &layout.selections {
let selection_style = style.replica_selection_style(*replica_id);
for selection in selections {
+ if !selection.range.is_empty() {
+ selection_ranges.push(selection.range.clone());
+ }
self.paint_highlighted_range(
scene,
selection.range.clone(),
@@ -880,33 +884,42 @@ impl EditorElement {
);
let settings = cx.global::<Settings>();
- match settings
+ let regions_to_hit = match settings
.editor_overrides
.show_invisibles
.or(settings.editor_defaults.show_invisibles)
.unwrap_or_default()
{
- ShowInvisibles::None => {}
- ShowInvisibles::All => {
- for invisible in &line_with_invisibles.invisibles {
- let (token_offset, invisible_symbol) = match invisible {
- Invisible::Tab { line_start_offset } => {
- (*line_start_offset, &layout.tab_invisible)
- }
- Invisible::Whitespace { line_offset } => {
- (*line_offset, &layout.space_invisible)
- }
- };
-
- let x_offset = line_with_invisibles.line.x_for_index(token_offset);
- let invisible_offset =
- (layout.position_map.em_width - invisible_symbol.width()).max(0.0)
- / 2.0;
- let origin = content_origin
- + vec2f(-scroll_left + x_offset + invisible_offset, line_y);
- invisible_symbol.paint(scene, origin, visible_bounds, line_height, cx);
+ ShowInvisibles::None => continue,
+ ShowInvisibles::Selection => Some(&selection_ranges),
+ ShowInvisibles::All => None,
+ };
+
+ for invisible in &line_with_invisibles.invisibles {
+ let (&token_offset, invisible_symbol) = match invisible {
+ Invisible::Tab { line_start_offset } => {
+ (line_start_offset, &layout.tab_invisible)
+ }
+ Invisible::Whitespace { line_offset } => {
+ (line_offset, &layout.space_invisible)
+ }
+ };
+
+ let x_offset = line_with_invisibles.line.x_for_index(token_offset);
+ let invisible_offset =
+ (layout.position_map.em_width - invisible_symbol.width()).max(0.0) / 2.0;
+ let origin =
+ content_origin + vec2f(-scroll_left + x_offset + invisible_offset, line_y);
+
+ if let Some(regions_to_hit) = regions_to_hit {
+ let invisible_point = DisplayPoint::new(row, token_offset as u32);
+ if !regions_to_hit.iter().any(|region| {
+ region.start <= invisible_point && invisible_point < region.end
+ }) {
+ continue;
}
}
+ invisible_symbol.paint(scene, origin, visible_bounds, line_height, cx);
}
}
}
@@ -451,6 +451,7 @@ pub struct FeaturesContent {
#[serde(rename_all = "snake_case")]
pub enum ShowInvisibles {
#[default]
+ Selection,
None,
All,
}