mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-06 18:46:49 +00:00
Draft invisibles' tabs display
This commit is contained in:
parent
4f8607039c
commit
ad731ea6d2
3 changed files with 75 additions and 11 deletions
|
@ -1359,7 +1359,11 @@ impl EditorElement {
|
||||||
highlight_style = Some(diagnostic_highlight);
|
highlight_style = Some(diagnostic_highlight);
|
||||||
}
|
}
|
||||||
|
|
||||||
(chunk.text, highlight_style)
|
HighlightedChunk {
|
||||||
|
chunk: chunk.text,
|
||||||
|
style: highlight_style,
|
||||||
|
is_tab: chunk.is_tab,
|
||||||
|
}
|
||||||
});
|
});
|
||||||
layout_highlighted_chunks(
|
layout_highlighted_chunks(
|
||||||
chunks,
|
chunks,
|
||||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{ToJson, Value},
|
json::{ToJson, Value},
|
||||||
text_layout::{Line, RunStyle, ShapedBoundary},
|
text_layout::{Invisible, Line, RunStyle, ShapedBoundary},
|
||||||
AppContext, Element, FontCache, LayoutContext, SceneBuilder, SizeConstraint, TextLayoutCache,
|
AppContext, Element, FontCache, LayoutContext, SceneBuilder, SizeConstraint, TextLayoutCache,
|
||||||
View, ViewContext,
|
View, ViewContext,
|
||||||
};
|
};
|
||||||
|
@ -114,7 +114,11 @@ impl<V: View> Element<V> for Text {
|
||||||
} else {
|
} else {
|
||||||
result = None;
|
result = None;
|
||||||
}
|
}
|
||||||
result
|
result.map(|(chunk, style)| HighlightedChunk {
|
||||||
|
chunk,
|
||||||
|
style,
|
||||||
|
is_tab: false,
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
// Perform shaping on these highlighted chunks
|
// Perform shaping on these highlighted chunks
|
||||||
|
@ -337,9 +341,25 @@ impl<V: View> Element<V> for Text {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct HighlightedChunk<'a> {
|
||||||
|
pub chunk: &'a str,
|
||||||
|
pub style: Option<HighlightStyle>,
|
||||||
|
pub is_tab: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> HighlightedChunk<'a> {
|
||||||
|
fn plain_str(str_symbols: &'a str) -> Self {
|
||||||
|
Self {
|
||||||
|
chunk: str_symbols,
|
||||||
|
style: None,
|
||||||
|
is_tab: str_symbols == "\t",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Perform text layout on a series of highlighted chunks of text.
|
/// Perform text layout on a series of highlighted chunks of text.
|
||||||
pub fn layout_highlighted_chunks<'a>(
|
pub fn layout_highlighted_chunks<'a>(
|
||||||
chunks: impl Iterator<Item = (&'a str, Option<HighlightStyle>)>,
|
chunks: impl Iterator<Item = HighlightedChunk<'a>>,
|
||||||
text_style: &TextStyle,
|
text_style: &TextStyle,
|
||||||
text_layout_cache: &TextLayoutCache,
|
text_layout_cache: &TextLayoutCache,
|
||||||
font_cache: &Arc<FontCache>,
|
font_cache: &Arc<FontCache>,
|
||||||
|
@ -348,13 +368,17 @@ pub fn layout_highlighted_chunks<'a>(
|
||||||
) -> Vec<Line> {
|
) -> Vec<Line> {
|
||||||
let mut layouts = Vec::with_capacity(max_line_count);
|
let mut layouts = Vec::with_capacity(max_line_count);
|
||||||
let mut line = String::new();
|
let mut line = String::new();
|
||||||
|
let mut invisibles = Vec::new();
|
||||||
let mut styles = Vec::new();
|
let mut styles = Vec::new();
|
||||||
let mut row = 0;
|
let mut row = 0;
|
||||||
let mut line_exceeded_max_len = false;
|
let mut line_exceeded_max_len = false;
|
||||||
for (chunk, highlight_style) in chunks.chain([("\n", Default::default())]) {
|
for highlighted_chunk in chunks.chain(std::iter::once(HighlightedChunk::plain_str("\n"))) {
|
||||||
for (ix, mut line_chunk) in chunk.split('\n').enumerate() {
|
for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
|
||||||
if ix > 0 {
|
if ix > 0 {
|
||||||
layouts.push(text_layout_cache.layout_str(&line, text_style.font_size, &styles));
|
let mut laid_out_line =
|
||||||
|
text_layout_cache.layout_str(&line, text_style.font_size, &styles);
|
||||||
|
laid_out_line.invisibles.extend(invisibles.drain(..));
|
||||||
|
layouts.push(laid_out_line);
|
||||||
line.clear();
|
line.clear();
|
||||||
styles.clear();
|
styles.clear();
|
||||||
row += 1;
|
row += 1;
|
||||||
|
@ -365,7 +389,7 @@ pub fn layout_highlighted_chunks<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
if !line_chunk.is_empty() && !line_exceeded_max_len {
|
if !line_chunk.is_empty() && !line_exceeded_max_len {
|
||||||
let text_style = if let Some(style) = highlight_style {
|
let text_style = if let Some(style) = highlighted_chunk.style {
|
||||||
text_style
|
text_style
|
||||||
.clone()
|
.clone()
|
||||||
.highlight(style, font_cache)
|
.highlight(style, font_cache)
|
||||||
|
@ -384,7 +408,6 @@ pub fn layout_highlighted_chunks<'a>(
|
||||||
line_exceeded_max_len = true;
|
line_exceeded_max_len = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
line.push_str(line_chunk);
|
|
||||||
styles.push((
|
styles.push((
|
||||||
line_chunk.len(),
|
line_chunk.len(),
|
||||||
RunStyle {
|
RunStyle {
|
||||||
|
@ -393,6 +416,12 @@ pub fn layout_highlighted_chunks<'a>(
|
||||||
underline: text_style.underline,
|
underline: text_style.underline,
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
if highlighted_chunk.is_tab {
|
||||||
|
invisibles.push(Invisible::Tab {
|
||||||
|
range: line.len()..line.len() + line_chunk.len(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
line.push_str(line_chunk);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
window::WindowContext,
|
window::WindowContext,
|
||||||
SceneBuilder,
|
SceneBuilder,
|
||||||
};
|
};
|
||||||
|
use itertools::Itertools;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -178,6 +179,7 @@ impl<'a> Hash for CacheKeyRef<'a> {
|
||||||
pub struct Line {
|
pub struct Line {
|
||||||
layout: Arc<LineLayout>,
|
layout: Arc<LineLayout>,
|
||||||
style_runs: SmallVec<[StyleRun; 32]>,
|
style_runs: SmallVec<[StyleRun; 32]>,
|
||||||
|
pub invisibles: SmallVec<[Invisible; 32]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
@ -211,6 +213,12 @@ pub struct Glyph {
|
||||||
pub is_emoji: bool,
|
pub is_emoji: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Invisible {
|
||||||
|
Tab { range: std::ops::Range<usize> },
|
||||||
|
Whitespace { range: std::ops::Range<usize> },
|
||||||
|
}
|
||||||
|
|
||||||
impl Line {
|
impl Line {
|
||||||
fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
|
fn new(layout: Arc<LineLayout>, runs: &[(usize, RunStyle)]) -> Self {
|
||||||
let mut style_runs = SmallVec::new();
|
let mut style_runs = SmallVec::new();
|
||||||
|
@ -221,7 +229,11 @@ impl Line {
|
||||||
underline: style.underline,
|
underline: style.underline,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Self { layout, style_runs }
|
Self {
|
||||||
|
layout,
|
||||||
|
style_runs,
|
||||||
|
invisibles: SmallVec::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn runs(&self) -> &[Run] {
|
pub fn runs(&self) -> &[Run] {
|
||||||
|
@ -298,6 +310,16 @@ impl Line {
|
||||||
let mut color = Color::black();
|
let mut color = Color::black();
|
||||||
let mut underline = None;
|
let mut underline = None;
|
||||||
|
|
||||||
|
let tab_ranges = self
|
||||||
|
.invisibles
|
||||||
|
.iter()
|
||||||
|
.filter_map(|invisible| match invisible {
|
||||||
|
Invisible::Tab { range } => Some(range),
|
||||||
|
Invisible::Whitespace { .. } => None,
|
||||||
|
})
|
||||||
|
.sorted_by(|tab_range_1, tab_range_2| tab_range_1.start.cmp(&tab_range_2.start))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for run in &self.layout.runs {
|
for run in &self.layout.runs {
|
||||||
let max_glyph_width = cx
|
let max_glyph_width = cx
|
||||||
.font_cache
|
.font_cache
|
||||||
|
@ -364,10 +386,19 @@ impl Line {
|
||||||
origin: glyph_origin,
|
origin: glyph_origin,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
let id = if tab_ranges.iter().any(|tab_range| {
|
||||||
|
tab_range.start <= glyph.index && glyph.index < tab_range.end
|
||||||
|
}) {
|
||||||
|
// TODO kb get a proper (cached) glyph
|
||||||
|
glyph.id + 100
|
||||||
|
} else {
|
||||||
|
glyph.id
|
||||||
|
};
|
||||||
|
|
||||||
scene.push_glyph(scene::Glyph {
|
scene.push_glyph(scene::Glyph {
|
||||||
font_id: run.font_id,
|
font_id: run.font_id,
|
||||||
font_size: self.layout.font_size,
|
font_size: self.layout.font_size,
|
||||||
id: glyph.id,
|
id,
|
||||||
origin: glyph_origin,
|
origin: glyph_origin,
|
||||||
color,
|
color,
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue