Make all HighlightStyle properties optional

Previously, some of those properties such the font weight, style and color
would be mandatory: when the theme didn't specify them, Zed would use a default
value during deserialization. This meant that those default properties would
unconditionally override the base text style, causing a rendering bug when
combining syntax highlights with diagnostic styles.

This commit fixes that by making `HighlightStyle`s more additive: each property
can be set independently and only the properties that theme specifies get
overridden in the base text style.
This commit is contained in:
Antonio Scandurra 2022-03-15 10:39:43 +01:00
parent 72692f1700
commit fbf7cdf4f2
10 changed files with 149 additions and 146 deletions

View file

@ -1174,7 +1174,7 @@ mod tests {
for chunk in snapshot.chunks(rows, true) { for chunk in snapshot.chunks(rows, true) {
let color = chunk let color = chunk
.syntax_highlight_id .syntax_highlight_id
.and_then(|id| id.style(theme).map(|s| s.color)); .and_then(|id| id.style(theme)?.color);
if let Some((last_chunk, last_color)) = chunks.last_mut() { if let Some((last_chunk, last_color)) = chunks.last_mut() {
if color == *last_color { if color == *last_color {
last_chunk.push_str(chunk.text); last_chunk.push_str(chunk.text);

View file

@ -615,11 +615,7 @@ impl CompletionsMenu {
.with_highlights(combine_syntax_and_fuzzy_match_highlights( .with_highlights(combine_syntax_and_fuzzy_match_highlights(
&completion.label.text, &completion.label.text,
style.text.color.into(), style.text.color.into(),
styled_runs_for_code_label( styled_runs_for_code_label(&completion.label, &style.syntax),
&completion.label,
style.text.color,
&style.syntax,
),
&mat.positions, &mat.positions,
)) ))
.contained() .contained()
@ -5716,7 +5712,7 @@ fn build_style(
font_id, font_id,
font_size, font_size,
font_properties, font_properties,
underline: None, underline: Default::default(),
}, },
placeholder_text: None, placeholder_text: None,
theme, theme,
@ -5938,7 +5934,7 @@ pub fn combine_syntax_and_fuzzy_match_highlights(
for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())]) for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
{ {
syntax_highlight.font_properties.weight(Default::default()); syntax_highlight.weight = None;
// Add highlights for any fuzzy match characters before the next // Add highlights for any fuzzy match characters before the next
// syntax highlight range. // syntax highlight range.
@ -5949,7 +5945,7 @@ pub fn combine_syntax_and_fuzzy_match_highlights(
match_indices.next(); match_indices.next();
let end_index = char_ix_after(match_index, text); let end_index = char_ix_after(match_index, text);
let mut match_style = default_style; let mut match_style = default_style;
match_style.font_properties.weight(fonts::Weight::BOLD); match_style.weight = Some(fonts::Weight::BOLD);
result.push((match_index..end_index, match_style)); result.push((match_index..end_index, match_style));
} }
@ -5981,7 +5977,7 @@ pub fn combine_syntax_and_fuzzy_match_highlights(
} }
let mut match_style = syntax_highlight; let mut match_style = syntax_highlight;
match_style.font_properties.weight(fonts::Weight::BOLD); match_style.weight = Some(fonts::Weight::BOLD);
result.push((match_index..end_index, match_style)); result.push((match_index..end_index, match_style));
offset = end_index; offset = end_index;
} }
@ -6000,16 +5996,12 @@ pub fn combine_syntax_and_fuzzy_match_highlights(
pub fn styled_runs_for_code_label<'a>( pub fn styled_runs_for_code_label<'a>(
label: &'a CodeLabel, label: &'a CodeLabel,
default_color: Color,
syntax_theme: &'a theme::SyntaxTheme, syntax_theme: &'a theme::SyntaxTheme,
) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> { ) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
const MUTED_OPACITY: usize = 165; let fade_out = HighlightStyle {
fade_out: Some(0.35),
let mut muted_default_style = HighlightStyle {
color: default_color,
..Default::default() ..Default::default()
}; };
muted_default_style.color.a = ((default_color.a as usize * MUTED_OPACITY) / 255) as u8;
let mut prev_end = label.filter_range.end; let mut prev_end = label.filter_range.end;
label label
@ -6023,12 +6015,12 @@ pub fn styled_runs_for_code_label<'a>(
return Default::default(); return Default::default();
}; };
let mut muted_style = style.clone(); let mut muted_style = style.clone();
muted_style.color.a = ((style.color.a as usize * MUTED_OPACITY) / 255) as u8; muted_style.highlight(fade_out);
let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new(); let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
if range.start >= label.filter_range.end { if range.start >= label.filter_range.end {
if range.start > prev_end { if range.start > prev_end {
runs.push((prev_end..range.start, muted_default_style)); runs.push((prev_end..range.start, fade_out));
} }
runs.push((range.clone(), muted_style)); runs.push((range.clone(), muted_style));
} else if range.end <= label.filter_range.end { } else if range.end <= label.filter_range.end {
@ -6040,7 +6032,7 @@ pub fn styled_runs_for_code_label<'a>(
prev_end = cmp::max(prev_end, range.end); prev_end = cmp::max(prev_end, range.end);
if ix + 1 == label.runs.len() && label.text.len() > prev_end { if ix + 1 == label.runs.len() && label.text.len() > prev_end {
runs.push((prev_end..label.text.len(), muted_default_style)); runs.push((prev_end..label.text.len(), fade_out));
} }
runs runs
@ -8995,20 +8987,19 @@ mod tests {
#[test] #[test]
fn test_combine_syntax_and_fuzzy_match_highlights() { fn test_combine_syntax_and_fuzzy_match_highlights() {
let string = "abcdefghijklmnop"; let string = "abcdefghijklmnop";
let default = HighlightStyle::default();
let syntax_ranges = [ let syntax_ranges = [
( (
0..3, 0..3,
HighlightStyle { HighlightStyle {
color: Color::red(), color: Some(Color::red()),
..default ..Default::default()
}, },
), ),
( (
4..8, 4..8,
HighlightStyle { HighlightStyle {
color: Color::green(), color: Some(Color::green()),
..default ..Default::default()
}, },
), ),
]; ];
@ -9016,7 +9007,7 @@ mod tests {
assert_eq!( assert_eq!(
combine_syntax_and_fuzzy_match_highlights( combine_syntax_and_fuzzy_match_highlights(
&string, &string,
default, Default::default(),
syntax_ranges.into_iter(), syntax_ranges.into_iter(),
&match_indices, &match_indices,
), ),
@ -9024,38 +9015,38 @@ mod tests {
( (
0..3, 0..3,
HighlightStyle { HighlightStyle {
color: Color::red(), color: Some(Color::red()),
..default ..Default::default()
}, },
), ),
( (
4..5, 4..5,
HighlightStyle { HighlightStyle {
color: Color::green(), color: Some(Color::green()),
font_properties: *fonts::Properties::default().weight(fonts::Weight::BOLD), weight: Some(fonts::Weight::BOLD),
..default ..Default::default()
}, },
), ),
( (
5..6, 5..6,
HighlightStyle { HighlightStyle {
color: Color::green(), color: Some(Color::green()),
..default ..Default::default()
}, },
), ),
( (
6..8, 6..8,
HighlightStyle { HighlightStyle {
color: Color::green(), color: Some(Color::green()),
font_properties: *fonts::Properties::default().weight(fonts::Weight::BOLD), weight: Some(fonts::Weight::BOLD),
..default ..Default::default()
}, },
), ),
( (
8..9, 8..9,
HighlightStyle { HighlightStyle {
font_properties: *fonts::Properties::default().weight(fonts::Weight::BOLD), weight: Some(fonts::Weight::BOLD),
..default ..Default::default()
}, },
), ),
] ]

View file

@ -397,7 +397,7 @@ impl EditorElement {
RunStyle { RunStyle {
font_id, font_id,
color: style.background, color: style.background,
underline: None, underline: Default::default(),
}, },
)], )],
)) ))
@ -555,7 +555,7 @@ impl EditorElement {
RunStyle { RunStyle {
font_id: style.text.font_id, font_id: style.text.font_id,
color: Color::black(), color: Color::black(),
underline: None, underline: Default::default(),
}, },
)], )],
) )
@ -596,7 +596,7 @@ impl EditorElement {
RunStyle { RunStyle {
font_id: style.text.font_id, font_id: style.text.font_id,
color, color,
underline: None, underline: Default::default(),
}, },
)], )],
))); )));
@ -644,7 +644,7 @@ impl EditorElement {
RunStyle { RunStyle {
font_id: placeholder_style.font_id, font_id: placeholder_style.font_id,
color: placeholder_style.color, color: placeholder_style.color,
underline: None, underline: Default::default(),
}, },
)], )],
) )
@ -669,7 +669,7 @@ impl EditorElement {
let diagnostic_style = super::diagnostic_style(severity, true, style); let diagnostic_style = super::diagnostic_style(severity, true, style);
let diagnostic_highlight = HighlightStyle { let diagnostic_highlight = HighlightStyle {
underline: Some(Underline { underline: Some(Underline {
color: diagnostic_style.message.text.color, color: Some(diagnostic_style.message.text.color),
thickness: 1.0.into(), thickness: 1.0.into(),
squiggly: true, squiggly: true,
}), }),
@ -1237,7 +1237,7 @@ fn layout_line(
RunStyle { RunStyle {
font_id: style.text.font_id, font_id: style.text.font_id,
color: Color::black(), color: Color::black(),
underline: None, underline: Default::default(),
}, },
)], )],
) )

View file

@ -62,7 +62,7 @@ impl gpui::Element for TextElement {
.select_font(family, &Default::default()) .select_font(family, &Default::default())
.unwrap(), .unwrap(),
color: Color::default(), color: Color::default(),
underline: None, underline: Default::default(),
}; };
let bold = RunStyle { let bold = RunStyle {
font_id: cx font_id: cx
@ -76,7 +76,7 @@ impl gpui::Element for TextElement {
) )
.unwrap(), .unwrap(),
color: Color::default(), color: Color::default(),
underline: None, underline: Default::default(),
}; };
let text = "Hello world!"; let text = "Hello world!";

View file

@ -214,7 +214,7 @@ mod tests {
"Menlo", "Menlo",
12., 12.,
Default::default(), Default::default(),
None, Default::default(),
Color::black(), Color::black(),
cx.font_cache(), cx.font_cache(),
) )
@ -223,7 +223,7 @@ mod tests {
"Menlo", "Menlo",
12., 12.,
*FontProperties::new().weight(Weight::BOLD), *FontProperties::new().weight(Weight::BOLD),
None, Default::default(),
Color::new(255, 0, 0, 255), Color::new(255, 0, 0, 255),
cx.font_cache(), cx.font_cache(),
) )

View file

@ -1,4 +1,4 @@
use std::{ops::Range, sync::Arc}; use std::{borrow::Cow, ops::Range, sync::Arc};
use crate::{ use crate::{
color::Color, color::Color,
@ -205,8 +205,6 @@ pub fn layout_highlighted_chunks<'a>(
max_line_count: usize, max_line_count: usize,
) -> Vec<Line> { ) -> Vec<Line> {
let mut layouts = Vec::with_capacity(max_line_count); let mut layouts = Vec::with_capacity(max_line_count);
let mut prev_font_properties = text_style.font_properties.clone();
let mut prev_font_id = text_style.font_id;
let mut line = String::new(); let mut line = String::new();
let mut styles = Vec::new(); let mut styles = Vec::new();
let mut row = 0; let mut row = 0;
@ -225,30 +223,14 @@ 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 font_properties; let text_style = if let Some(style) = highlight_style {
let mut color; text_style
let underline; .clone()
.highlight(style, font_cache)
if let Some(highlight_style) = highlight_style { .map(Cow::Owned)
font_properties = highlight_style.font_properties; .unwrap_or_else(|_| Cow::Borrowed(text_style))
color = Color::blend(highlight_style.color, text_style.color);
if let Some(fade) = highlight_style.fade_out {
color.fade_out(fade);
}
underline = highlight_style.underline;
} else { } else {
font_properties = text_style.font_properties; Cow::Borrowed(text_style)
color = text_style.color;
underline = None;
}
// Avoid a lookup if the font properties match the previous ones.
let font_id = if font_properties == prev_font_properties {
prev_font_id
} else {
font_cache
.select_font(text_style.font_family_id, &font_properties)
.unwrap_or(text_style.font_id)
}; };
if line.len() + line_chunk.len() > max_line_len { if line.len() + line_chunk.len() > max_line_len {
@ -264,13 +246,11 @@ pub fn layout_highlighted_chunks<'a>(
styles.push(( styles.push((
line_chunk.len(), line_chunk.len(),
RunStyle { RunStyle {
font_id, font_id: text_style.font_id,
color, color: text_style.color,
underline, underline: text_style.underline,
}, },
)); ));
prev_font_id = font_id;
prev_font_properties = font_properties;
} }
} }
} }

View file

@ -28,13 +28,14 @@ pub struct TextStyle {
pub font_id: FontId, pub font_id: FontId,
pub font_size: f32, pub font_size: f32,
pub font_properties: Properties, pub font_properties: Properties,
pub underline: Option<Underline>, pub underline: Underline,
} }
#[derive(Copy, Clone, Debug, Default, PartialEq)] #[derive(Copy, Clone, Debug, Default, PartialEq)]
pub struct HighlightStyle { pub struct HighlightStyle {
pub color: Color, pub color: Option<Color>,
pub font_properties: Properties, pub weight: Option<Weight>,
pub italic: Option<bool>,
pub underline: Option<Underline>, pub underline: Option<Underline>,
pub fade_out: Option<f32>, pub fade_out: Option<f32>,
} }
@ -43,7 +44,7 @@ impl Eq for HighlightStyle {}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Underline { pub struct Underline {
pub color: Color, pub color: Option<Color>,
pub thickness: OrderedFloat<f32>, pub thickness: OrderedFloat<f32>,
pub squiggly: bool, pub squiggly: bool,
} }
@ -80,13 +81,10 @@ struct TextStyleJson {
#[derive(Deserialize)] #[derive(Deserialize)]
struct HighlightStyleJson { struct HighlightStyleJson {
color: Color, color: Option<Color>,
weight: Option<WeightJson>, weight: Option<WeightJson>,
#[serde(default)] italic: Option<bool>,
italic: bool, underline: Option<UnderlineStyleJson>,
#[serde(default)]
underline: UnderlineStyleJson,
#[serde(default)]
fade_out: Option<f32>, fade_out: Option<f32>,
} }
@ -109,7 +107,7 @@ impl TextStyle {
font_family_name: impl Into<Arc<str>>, font_family_name: impl Into<Arc<str>>,
font_size: f32, font_size: f32,
font_properties: Properties, font_properties: Properties,
underline: Option<Underline>, underline: Underline,
color: Color, color: Color,
font_cache: &FontCache, font_cache: &FontCache,
) -> Result<Self> { ) -> Result<Self> {
@ -133,14 +131,31 @@ impl TextStyle {
} }
pub fn highlight(mut self, style: HighlightStyle, font_cache: &FontCache) -> Result<Self> { pub fn highlight(mut self, style: HighlightStyle, font_cache: &FontCache) -> Result<Self> {
if self.font_properties != style.font_properties { let mut font_properties = self.font_properties;
self.font_id = font_cache.select_font(self.font_family_id, &style.font_properties)?; if let Some(weight) = style.weight {
font_properties.weight(weight);
}
if let Some(italic) = style.italic {
if italic {
font_properties.style(Style::Italic);
} else {
font_properties.style(Style::Normal);
}
}
if self.font_properties != font_properties {
self.font_id = font_cache.select_font(self.font_family_id, &font_properties)?;
}
if let Some(color) = style.color {
self.color = Color::blend(color, self.color);
} }
self.color = Color::blend(style.color, self.color);
if let Some(factor) = style.fade_out { if let Some(factor) = style.fade_out {
self.color.fade_out(factor); self.color.fade_out(factor);
} }
self.underline = style.underline; if let Some(underline) = style.underline {
self.underline = underline;
}
Ok(self) Ok(self)
} }
@ -160,7 +175,7 @@ impl TextStyle {
json.family, json.family,
json.size, json.size,
font_properties, font_properties,
underline_from_json(json.underline, json.color), underline_from_json(json.underline),
json.color, json.color,
font_cache, font_cache,
) )
@ -214,9 +229,10 @@ impl From<TextStyle> for HighlightStyle {
impl From<&TextStyle> for HighlightStyle { impl From<&TextStyle> for HighlightStyle {
fn from(other: &TextStyle) -> Self { fn from(other: &TextStyle) -> Self {
Self { Self {
color: other.color, color: Some(other.color),
font_properties: other.font_properties, weight: Some(other.font_properties.weight),
underline: other.underline, italic: Some(other.font_properties.style == Style::Italic),
underline: Some(other.underline),
fade_out: None, fade_out: None,
} }
} }
@ -256,17 +272,38 @@ impl Default for TextStyle {
impl HighlightStyle { impl HighlightStyle {
fn from_json(json: HighlightStyleJson) -> Self { fn from_json(json: HighlightStyleJson) -> Self {
let font_properties = properties_from_json(json.weight, json.italic);
Self { Self {
color: json.color, color: json.color,
font_properties, weight: json.weight.map(weight_from_json),
underline: underline_from_json(json.underline, json.color), italic: json.italic,
underline: json.underline.map(underline_from_json),
fade_out: json.fade_out, fade_out: json.fade_out,
} }
} }
pub fn highlight(&mut self, other: HighlightStyle) { pub fn highlight(&mut self, other: HighlightStyle) {
self.color = Color::blend(other.color, self.color); match (self.color, other.color) {
(Some(self_color), Some(other_color)) => {
self.color = Some(Color::blend(other_color, self_color));
}
(None, Some(other_color)) => {
self.color = Some(other_color);
}
_ => {}
}
if other.weight.is_some() {
self.weight = other.weight;
}
if other.italic.is_some() {
self.italic = other.italic;
}
if other.underline.is_some() {
self.underline = other.underline;
}
match (other.fade_out, self.fade_out) { match (other.fade_out, self.fade_out) {
(Some(source_fade), None) => self.fade_out = Some(source_fade), (Some(source_fade), None) => self.fade_out = Some(source_fade),
(Some(source_fade), Some(dest_fade)) => { (Some(source_fade), Some(dest_fade)) => {
@ -278,20 +315,14 @@ impl HighlightStyle {
} }
_ => {} _ => {}
} }
self.font_properties = other.font_properties;
if other.underline.is_some() {
self.underline = other.underline;
}
} }
} }
impl From<Color> for HighlightStyle { impl From<Color> for HighlightStyle {
fn from(color: Color) -> Self { fn from(color: Color) -> Self {
Self { Self {
color, color: Some(color),
font_properties: Default::default(), ..Default::default()
underline: None,
fade_out: None,
} }
} }
} }
@ -329,36 +360,40 @@ impl<'de> Deserialize<'de> for HighlightStyle {
} else { } else {
Ok(Self { Ok(Self {
color: serde_json::from_value(json).map_err(de::Error::custom)?, color: serde_json::from_value(json).map_err(de::Error::custom)?,
font_properties: Properties::new(), ..Default::default()
underline: None,
fade_out: None,
}) })
} }
} }
} }
fn underline_from_json(json: UnderlineStyleJson, text_color: Color) -> Option<Underline> { fn underline_from_json(json: UnderlineStyleJson) -> Underline {
match json { match json {
UnderlineStyleJson::Underlined(false) => None, UnderlineStyleJson::Underlined(false) => Underline::default(),
UnderlineStyleJson::Underlined(true) => Some(Underline { UnderlineStyleJson::Underlined(true) => Underline {
color: text_color, color: None,
thickness: 1.0.into(), thickness: 1.0.into(),
squiggly: false, squiggly: false,
}), },
UnderlineStyleJson::UnderlinedWithProperties { UnderlineStyleJson::UnderlinedWithProperties {
color, color,
thickness, thickness,
squiggly, squiggly,
} => Some(Underline { } => Underline {
color: color.unwrap_or(text_color), color,
thickness: thickness.unwrap_or(1.).into(), thickness: thickness.unwrap_or(1.).into(),
squiggly, squiggly,
}), },
} }
} }
fn properties_from_json(weight: Option<WeightJson>, italic: bool) -> Properties { fn properties_from_json(weight: Option<WeightJson>, italic: bool) -> Properties {
let weight = match weight.unwrap_or(WeightJson::normal) { let weight = weight.map(weight_from_json).unwrap_or_default();
let style = if italic { Style::Italic } else { Style::Normal };
*Properties::new().weight(weight).style(style)
}
fn weight_from_json(weight: WeightJson) -> Weight {
match weight {
WeightJson::thin => Weight::THIN, WeightJson::thin => Weight::THIN,
WeightJson::extra_light => Weight::EXTRA_LIGHT, WeightJson::extra_light => Weight::EXTRA_LIGHT,
WeightJson::light => Weight::LIGHT, WeightJson::light => Weight::LIGHT,
@ -368,9 +403,7 @@ fn properties_from_json(weight: Option<WeightJson>, italic: bool) -> Properties
WeightJson::bold => Weight::BOLD, WeightJson::bold => Weight::BOLD,
WeightJson::extra_bold => Weight::EXTRA_BOLD, WeightJson::extra_bold => Weight::EXTRA_BOLD,
WeightJson::black => Weight::BLACK, WeightJson::black => Weight::BLACK,
}; }
let style = if italic { Style::Italic } else { Style::Normal };
*Properties::new().weight(weight).style(style)
} }
impl ToJson for Properties { impl ToJson for Properties {

View file

@ -425,21 +425,21 @@ mod tests {
let menlo_regular = RunStyle { let menlo_regular = RunStyle {
font_id: fonts.select_font(&menlo, &Properties::new()).unwrap(), font_id: fonts.select_font(&menlo, &Properties::new()).unwrap(),
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
let menlo_italic = RunStyle { let menlo_italic = RunStyle {
font_id: fonts font_id: fonts
.select_font(&menlo, &Properties::new().style(Style::Italic)) .select_font(&menlo, &Properties::new().style(Style::Italic))
.unwrap(), .unwrap(),
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
let menlo_bold = RunStyle { let menlo_bold = RunStyle {
font_id: fonts font_id: fonts
.select_font(&menlo, &Properties::new().weight(Weight::BOLD)) .select_font(&menlo, &Properties::new().weight(Weight::BOLD))
.unwrap(), .unwrap(),
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
assert_ne!(menlo_regular, menlo_italic); assert_ne!(menlo_regular, menlo_italic);
assert_ne!(menlo_regular, menlo_bold); assert_ne!(menlo_regular, menlo_bold);
@ -466,13 +466,13 @@ mod tests {
let zapfino_regular = RunStyle { let zapfino_regular = RunStyle {
font_id: fonts.select_font(&zapfino, &Properties::new())?, font_id: fonts.select_font(&zapfino, &Properties::new())?,
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
let menlo = fonts.load_family("Menlo")?; let menlo = fonts.load_family("Menlo")?;
let menlo_regular = RunStyle { let menlo_regular = RunStyle {
font_id: fonts.select_font(&menlo, &Properties::new())?, font_id: fonts.select_font(&menlo, &Properties::new())?,
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
let text = "This is, m𐍈re 𐍈r less, Zapfino!𐍈"; let text = "This is, m𐍈re 𐍈r less, Zapfino!𐍈";
@ -551,7 +551,7 @@ mod tests {
let style = RunStyle { let style = RunStyle {
font_id: fonts.select_font(&font_ids, &Default::default()).unwrap(), font_id: fonts.select_font(&font_ids, &Default::default()).unwrap(),
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
let line = "\u{feff}"; let line = "\u{feff}";

View file

@ -28,7 +28,7 @@ pub struct TextLayoutCache {
pub struct RunStyle { pub struct RunStyle {
pub color: Color, pub color: Color,
pub font_id: FontId, pub font_id: FontId,
pub underline: Option<Underline>, pub underline: Underline,
} }
impl TextLayoutCache { impl TextLayoutCache {
@ -167,7 +167,7 @@ impl<'a> Hash for CacheKeyRef<'a> {
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Line { pub struct Line {
layout: Arc<LineLayout>, layout: Arc<LineLayout>,
style_runs: SmallVec<[(u32, Color, Option<Underline>); 32]>, style_runs: SmallVec<[(u32, Color, Underline); 32]>,
} }
#[derive(Default, Debug)] #[derive(Default, Debug)]
@ -283,17 +283,21 @@ impl Line {
if glyph.index >= run_end { if glyph.index >= run_end {
if let Some((run_len, run_color, run_underline)) = style_runs.next() { if let Some((run_len, run_color, run_underline)) = style_runs.next() {
if let Some((_, underline_style)) = underline { if let Some((_, underline_style)) = underline {
if *run_underline != Some(underline_style) { if *run_underline != underline_style {
finished_underline = underline.take(); finished_underline = underline.take();
} }
} }
if let Some(run_underline) = run_underline { if run_underline.thickness.into_inner() > 0. {
underline.get_or_insert(( underline.get_or_insert((
vec2f( vec2f(
glyph_origin.x(), glyph_origin.x(),
origin.y() + baseline_offset.y() + 0.618 * self.layout.descent, origin.y() + baseline_offset.y() + 0.618 * self.layout.descent,
), ),
*run_underline, Underline {
color: Some(run_underline.color.unwrap_or(*run_color)),
thickness: run_underline.thickness.into(),
squiggly: run_underline.squiggly,
},
)); ));
} }
@ -301,7 +305,6 @@ impl Line {
color = *run_color; color = *run_color;
} else { } else {
run_end = self.layout.len; run_end = self.layout.len;
color = Color::black();
finished_underline = underline.take(); finished_underline = underline.take();
} }
} }
@ -315,7 +318,7 @@ impl Line {
origin: underline_origin, origin: underline_origin,
width: glyph_origin.x() - underline_origin.x(), width: glyph_origin.x() - underline_origin.x(),
thickness: underline_style.thickness.into(), thickness: underline_style.thickness.into(),
color: underline_style.color, color: underline_style.color.unwrap(),
squiggly: underline_style.squiggly, squiggly: underline_style.squiggly,
}); });
} }
@ -335,7 +338,7 @@ impl Line {
cx.scene.push_underline(scene::Underline { cx.scene.push_underline(scene::Underline {
origin: underline_start, origin: underline_start,
width: line_end_x - underline_start.x(), width: line_end_x - underline_start.x(),
color: underline_style.color, color: underline_style.color.unwrap(),
thickness: underline_style.thickness.into(), thickness: underline_style.thickness.into(),
squiggly: underline_style.squiggly, squiggly: underline_style.squiggly,
}); });
@ -610,7 +613,7 @@ impl LineWrapper {
RunStyle { RunStyle {
font_id: self.font_id, font_id: self.font_id,
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}, },
)], )],
) )
@ -694,7 +697,7 @@ mod tests {
let normal = RunStyle { let normal = RunStyle {
font_id, font_id,
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
let bold = RunStyle { let bold = RunStyle {
font_id: font_cache font_id: font_cache
@ -707,7 +710,7 @@ mod tests {
) )
.unwrap(), .unwrap(),
color: Default::default(), color: Default::default(),
underline: None, underline: Default::default(),
}; };
let text = "aa bbb cccc ddddd eeee"; let text = "aa bbb cccc ddddd eeee";

View file

@ -284,11 +284,7 @@ impl ProjectSymbolsView {
&settings.theme.selector.item &settings.theme.selector.item
}; };
let symbol = &self.symbols[string_match.candidate_id]; let symbol = &self.symbols[string_match.candidate_id];
let syntax_runs = styled_runs_for_code_label( let syntax_runs = styled_runs_for_code_label(&symbol.label, &settings.theme.editor.syntax);
&symbol.label,
style.label.text.color,
&settings.theme.editor.syntax,
);
let mut path = symbol.path.to_string_lossy(); let mut path = symbol.path.to_string_lossy();
if show_worktree_root_name { if show_worktree_root_name {