@@ -790,7 +790,7 @@ impl EditorElement {
let selection_style = style.replica_selection_style(*replica_id);
for selection in selections {
- if !selection.range.is_empty() {
+ if !selection.range.is_empty() && *replica_id == local_replica_id {
selection_ranges.push(selection.range.clone());
}
self.paint_highlighted_range(
@@ -868,18 +868,21 @@ impl EditorElement {
}
if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
- draw_line_glyphs(
- layout,
- start_row,
- scroll_top,
- scene,
- content_origin,
- scroll_left,
- visible_text_bounds,
- cx,
- selection_ranges,
- visible_bounds,
- );
+ for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
+ let row = start_row + ix as u32;
+ line_with_invisibles.draw(
+ layout,
+ row,
+ scroll_top,
+ scene,
+ content_origin,
+ scroll_left,
+ visible_text_bounds,
+ cx,
+ &selection_ranges,
+ visible_bounds,
+ )
+ }
}
scene.paint_layer(Some(bounds), |scene| {
@@ -1374,7 +1377,7 @@ impl EditorElement {
}
});
- layout_highlighted_chunks(
+ LineWithInvisibles::from_chunks(
chunks,
&style.text,
cx.text_layout_cache(),
@@ -1602,25 +1605,143 @@ impl EditorElement {
}
}
-fn draw_line_glyphs(
- layout: &mut LayoutState,
- start_row: u32,
- scroll_top: f32,
- scene: &mut SceneBuilder,
- content_origin: Vector2F,
- scroll_left: f32,
- visible_text_bounds: RectF,
- cx: &mut ViewContext<Editor>,
- selection_ranges: SmallVec<[Range<DisplayPoint>; 32]>,
- visible_bounds: RectF,
-) {
- let line_height = layout.position_map.line_height;
-
- for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
- let row = start_row + ix as u32;
+struct HighlightedChunk<'a> {
+ chunk: &'a str,
+ style: Option<HighlightStyle>,
+ is_tab: bool,
+}
+
+#[derive(Debug)]
+pub struct LineWithInvisibles {
+ pub line: Line,
+ invisibles: Vec<Invisible>,
+}
+
+impl LineWithInvisibles {
+ fn from_chunks<'a>(
+ chunks: impl Iterator<Item = HighlightedChunk<'a>>,
+ text_style: &TextStyle,
+ text_layout_cache: &TextLayoutCache,
+ font_cache: &Arc<FontCache>,
+ max_line_len: usize,
+ max_line_count: usize,
+ line_number_layouts: &[Option<Line>],
+ editor_mode: EditorMode,
+ ) -> Vec<Self> {
+ let mut layouts = Vec::with_capacity(max_line_count);
+ let mut line = String::new();
+ let mut invisibles = Vec::new();
+ let mut styles = Vec::new();
+ let mut non_whitespace_added = false;
+ let mut row = 0;
+ let mut line_exceeded_max_len = false;
+ for highlighted_chunk in chunks.chain([HighlightedChunk {
+ chunk: "\n",
+ style: None,
+ is_tab: false,
+ }]) {
+ for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
+ if ix > 0 {
+ layouts.push(Self {
+ line: text_layout_cache.layout_str(&line, text_style.font_size, &styles),
+ invisibles: invisibles.drain(..).collect(),
+ });
+
+ line.clear();
+ styles.clear();
+ row += 1;
+ line_exceeded_max_len = false;
+ non_whitespace_added = false;
+ if row == max_line_count {
+ return layouts;
+ }
+ }
+
+ if !line_chunk.is_empty() && !line_exceeded_max_len {
+ let text_style = if let Some(style) = highlighted_chunk.style {
+ text_style
+ .clone()
+ .highlight(style, font_cache)
+ .map(Cow::Owned)
+ .unwrap_or_else(|_| Cow::Borrowed(text_style))
+ } else {
+ Cow::Borrowed(text_style)
+ };
+
+ if line.len() + line_chunk.len() > max_line_len {
+ let mut chunk_len = max_line_len - line.len();
+ while !line_chunk.is_char_boundary(chunk_len) {
+ chunk_len -= 1;
+ }
+ line_chunk = &line_chunk[..chunk_len];
+ line_exceeded_max_len = true;
+ }
+
+ styles.push((
+ line_chunk.len(),
+ RunStyle {
+ font_id: text_style.font_id,
+ color: text_style.color,
+ underline: text_style.underline,
+ },
+ ));
+
+ if editor_mode == EditorMode::Full {
+ // Line wrap pads its contents with fake whitespaces,
+ // avoid printing them
+ let inside_wrapped_string = line_number_layouts
+ .get(row)
+ .and_then(|layout| layout.as_ref())
+ .is_none();
+ if highlighted_chunk.is_tab {
+ if non_whitespace_added || !inside_wrapped_string {
+ invisibles.push(Invisible::Tab {
+ line_start_offset: line.len(),
+ });
+ }
+ } else {
+ invisibles.extend(
+ line_chunk
+ .chars()
+ .enumerate()
+ .filter(|(_, line_char)| {
+ let is_whitespace = line_char.is_whitespace();
+ non_whitespace_added |= !is_whitespace;
+ is_whitespace
+ && (non_whitespace_added || !inside_wrapped_string)
+ })
+ .map(|(whitespace_index, _)| Invisible::Whitespace {
+ line_offset: line.len() + whitespace_index,
+ }),
+ )
+ }
+ }
+
+ line.push_str(line_chunk);
+ }
+ }
+ }
+
+ layouts
+ }
+
+ fn draw(
+ &self,
+ layout: &LayoutState,
+ row: u32,
+ scroll_top: f32,
+ scene: &mut SceneBuilder,
+ content_origin: Vector2F,
+ scroll_left: f32,
+ visible_text_bounds: RectF,
+ cx: &mut ViewContext<Editor>,
+ selection_ranges: &[Range<DisplayPoint>],
+ visible_bounds: RectF,
+ ) {
+ let line_height = layout.position_map.line_height;
let line_y = row as f32 * line_height - scroll_top;
- line_with_invisibles.line.paint(
+ self.line.paint(
scene,
content_origin + vec2f(-scroll_left, line_y),
visible_text_bounds,
@@ -1628,10 +1749,9 @@ fn draw_line_glyphs(
cx,
);
- draw_invisibles(
+ self.draw_invisibles(
cx,
&selection_ranges,
- line_with_invisibles,
layout,
content_origin,
scroll_left,
@@ -1642,182 +1762,63 @@ fn draw_line_glyphs(
line_height,
);
}
-}
-
-fn draw_invisibles(
- cx: &mut ViewContext<Editor>,
- selection_ranges: &SmallVec<[Range<DisplayPoint>; 32]>,
- line_with_invisibles: &LineWithInvisibles,
- layout: &LayoutState,
- content_origin: Vector2F,
- scroll_left: f32,
- line_y: f32,
- row: u32,
- scene: &mut SceneBuilder,
- visible_bounds: RectF,
- line_height: f32,
-) {
- let settings = cx.global::<Settings>();
- let regions_to_hit = match settings
- .editor_overrides
- .show_whitespaces
- .or(settings.editor_defaults.show_whitespaces)
- .unwrap_or_default()
- {
- ShowWhitespaces::None => return,
- ShowWhitespaces::Selection => Some(selection_ranges),
- ShowWhitespaces::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),
+ fn draw_invisibles(
+ &self,
+ cx: &mut ViewContext<Editor>,
+ selection_ranges: &[Range<DisplayPoint>],
+ layout: &LayoutState,
+ content_origin: Vector2F,
+ scroll_left: f32,
+ line_y: f32,
+ row: u32,
+ scene: &mut SceneBuilder,
+ visible_bounds: RectF,
+ line_height: f32,
+ ) {
+ let settings = cx.global::<Settings>();
+ let regions_to_hit = match settings
+ .editor_overrides
+ .show_whitespaces
+ .or(settings.editor_defaults.show_whitespaces)
+ .unwrap_or_default()
+ {
+ ShowWhitespaces::None => return,
+ ShowWhitespaces::Selection => Some(selection_ranges),
+ ShowWhitespaces::All => None,
};
- 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);
+ for invisible in &self.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),
+ };
- 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;
+ let x_offset = self.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);
}
- invisible_symbol.paint(scene, origin, visible_bounds, line_height, cx);
}
}
-struct HighlightedChunk<'a> {
- chunk: &'a str,
- style: Option<HighlightStyle>,
- is_tab: bool,
-}
-
-#[derive(Debug)]
-pub struct LineWithInvisibles {
- pub line: Line,
- invisibles: Vec<Invisible>,
-}
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Invisible {
Tab { line_start_offset: usize },
Whitespace { line_offset: usize },
}
-fn layout_highlighted_chunks<'a>(
- chunks: impl Iterator<Item = HighlightedChunk<'a>>,
- text_style: &TextStyle,
- text_layout_cache: &TextLayoutCache,
- font_cache: &Arc<FontCache>,
- max_line_len: usize,
- max_line_count: usize,
- line_number_layouts: &[Option<Line>],
- editor_mode: EditorMode,
-) -> Vec<LineWithInvisibles> {
- let mut layouts = Vec::with_capacity(max_line_count);
- let mut line = String::new();
- let mut invisibles = Vec::new();
- let mut styles = Vec::new();
- let mut non_whitespace_added = false;
- let mut row = 0;
- let mut line_exceeded_max_len = false;
- for highlighted_chunk in chunks.chain([HighlightedChunk {
- chunk: "\n",
- style: None,
- is_tab: false,
- }]) {
- for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
- if ix > 0 {
- layouts.push(LineWithInvisibles {
- line: text_layout_cache.layout_str(&line, text_style.font_size, &styles),
- invisibles: invisibles.drain(..).collect(),
- });
-
- line.clear();
- styles.clear();
- row += 1;
- line_exceeded_max_len = false;
- non_whitespace_added = false;
- if row == max_line_count {
- return layouts;
- }
- }
-
- if !line_chunk.is_empty() && !line_exceeded_max_len {
- let text_style = if let Some(style) = highlighted_chunk.style {
- text_style
- .clone()
- .highlight(style, font_cache)
- .map(Cow::Owned)
- .unwrap_or_else(|_| Cow::Borrowed(text_style))
- } else {
- Cow::Borrowed(text_style)
- };
-
- if line.len() + line_chunk.len() > max_line_len {
- let mut chunk_len = max_line_len - line.len();
- while !line_chunk.is_char_boundary(chunk_len) {
- chunk_len -= 1;
- }
- line_chunk = &line_chunk[..chunk_len];
- line_exceeded_max_len = true;
- }
-
- styles.push((
- line_chunk.len(),
- RunStyle {
- font_id: text_style.font_id,
- color: text_style.color,
- underline: text_style.underline,
- },
- ));
-
- if editor_mode == EditorMode::Full {
- // Line wrap pads its contents with fake whitespaces,
- // avoid printing them
- let inside_wrapped_string = line_number_layouts
- .get(row)
- .and_then(|layout| layout.as_ref())
- .is_none();
- if highlighted_chunk.is_tab {
- if non_whitespace_added || !inside_wrapped_string {
- invisibles.push(Invisible::Tab {
- line_start_offset: line.len(),
- });
- }
- } else {
- invisibles.extend(
- line_chunk
- .chars()
- .enumerate()
- .filter(|(_, line_char)| {
- let is_whitespace = line_char.is_whitespace();
- non_whitespace_added |= !is_whitespace;
- is_whitespace
- && (non_whitespace_added || !inside_wrapped_string)
- })
- .map(|(whitespace_index, _)| Invisible::Whitespace {
- line_offset: line.len() + whitespace_index,
- }),
- )
- }
- }
-
- line.push_str(line_chunk);
- }
- }
- }
-
- layouts
-}
-
impl Element<Editor> for EditorElement {
type LayoutState = LayoutState;
type PaintState = ();