Accept colors in styling runs passed to layout_str
Also move from the runs being expressed as ranges to the runs being expressed as a sequence of contiguous scalar lengths.
This commit is contained in:
+6
-11
@@ -82,11 +82,11 @@ impl gpui::Element for TextElement {
|
||||
text,
|
||||
font_size,
|
||||
&[
|
||||
(0..1, normal),
|
||||
(1..2, bold),
|
||||
(2..3, normal),
|
||||
(3..4, bold),
|
||||
(4..text.len(), normal),
|
||||
(1, normal, ColorU::default()),
|
||||
(1, bold, ColorU::default()),
|
||||
(1, normal, ColorU::default()),
|
||||
(1, bold, ColorU::default()),
|
||||
(text.len() - 4, normal, ColorU::default()),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -95,12 +95,7 @@ impl gpui::Element for TextElement {
|
||||
background: Some(ColorU::white()),
|
||||
..Default::default()
|
||||
});
|
||||
line.paint(
|
||||
bounds.origin(),
|
||||
bounds,
|
||||
&[(0..text.len(), ColorU::black())],
|
||||
ctx,
|
||||
);
|
||||
line.paint(bounds.origin(), bounds, ctx);
|
||||
}
|
||||
|
||||
fn dispatch_event(
|
||||
|
||||
+58
-75
@@ -1,4 +1,5 @@
|
||||
use serde_json::json;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::{
|
||||
color::ColorU,
|
||||
@@ -13,7 +14,6 @@ use crate::{
|
||||
AfterLayoutContext, DebugContext, Element, Event, EventContext, FontCache, LayoutContext,
|
||||
PaintContext, SizeConstraint,
|
||||
};
|
||||
use std::{ops::Range, sync::Arc};
|
||||
|
||||
pub struct Label {
|
||||
text: String,
|
||||
@@ -23,11 +23,6 @@ pub struct Label {
|
||||
highlights: Option<Highlights>,
|
||||
}
|
||||
|
||||
pub struct LayoutState {
|
||||
line: Arc<Line>,
|
||||
colors: Vec<(Range<usize>, ColorU)>,
|
||||
}
|
||||
|
||||
pub struct Highlights {
|
||||
color: ColorU,
|
||||
indices: Vec<usize>,
|
||||
@@ -59,60 +54,56 @@ impl Label {
|
||||
self
|
||||
}
|
||||
|
||||
fn layout_text(
|
||||
fn compute_runs(
|
||||
&self,
|
||||
font_cache: &FontCache,
|
||||
font_id: FontId,
|
||||
) -> (Vec<(Range<usize>, FontId)>, Vec<(Range<usize>, ColorU)>) {
|
||||
let text_len = self.text.len();
|
||||
let mut styles;
|
||||
let mut colors;
|
||||
) -> SmallVec<[(usize, FontId, ColorU); 8]> {
|
||||
if let Some(highlights) = self.highlights.as_ref() {
|
||||
styles = Vec::new();
|
||||
colors = Vec::new();
|
||||
let highlight_font_id = font_cache
|
||||
.select_font(self.family_id, &highlights.font_properties)
|
||||
.unwrap_or(font_id);
|
||||
let mut pending_highlight: Option<Range<usize>> = None;
|
||||
for ix in &highlights.indices {
|
||||
if let Some(pending_highlight) = pending_highlight.as_mut() {
|
||||
if *ix == pending_highlight.end {
|
||||
pending_highlight.end += 1;
|
||||
} else {
|
||||
styles.push((pending_highlight.clone(), highlight_font_id));
|
||||
colors.push((pending_highlight.clone(), highlights.color));
|
||||
styles.push((pending_highlight.end..*ix, font_id));
|
||||
colors.push((pending_highlight.end..*ix, ColorU::black()));
|
||||
*pending_highlight = *ix..*ix + 1;
|
||||
}
|
||||
} else {
|
||||
styles.push((0..*ix, font_id));
|
||||
colors.push((0..*ix, ColorU::black()));
|
||||
pending_highlight = Some(*ix..*ix + 1);
|
||||
}
|
||||
}
|
||||
if let Some(pending_highlight) = pending_highlight.as_mut() {
|
||||
styles.push((pending_highlight.clone(), highlight_font_id));
|
||||
colors.push((pending_highlight.clone(), highlights.color));
|
||||
if text_len > pending_highlight.end {
|
||||
styles.push((pending_highlight.end..text_len, font_id));
|
||||
colors.push((pending_highlight.end..text_len, ColorU::black()));
|
||||
}
|
||||
} else {
|
||||
styles.push((0..text_len, font_id));
|
||||
colors.push((0..text_len, ColorU::black()));
|
||||
}
|
||||
} else {
|
||||
styles = vec![(0..text_len, font_id)];
|
||||
colors = vec![(0..text_len, ColorU::black())];
|
||||
}
|
||||
|
||||
(styles, colors)
|
||||
let mut highlight_indices = highlights.indices.iter().copied().peekable();
|
||||
let mut runs = SmallVec::new();
|
||||
|
||||
for (char_ix, c) in self.text.char_indices() {
|
||||
let mut font_id = font_id;
|
||||
let mut color = ColorU::black();
|
||||
if let Some(highlight_ix) = highlight_indices.peek() {
|
||||
if char_ix == *highlight_ix {
|
||||
font_id = highlight_font_id;
|
||||
color = highlights.color;
|
||||
highlight_indices.next();
|
||||
}
|
||||
}
|
||||
|
||||
let push_new_run =
|
||||
if let Some((last_len, last_font_id, last_color)) = runs.last_mut() {
|
||||
if font_id == *last_font_id && color == *last_color {
|
||||
*last_len += c.len_utf8();
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if push_new_run {
|
||||
runs.push((c.len_utf8(), font_id, color));
|
||||
}
|
||||
}
|
||||
|
||||
runs
|
||||
} else {
|
||||
smallvec![(self.text.len(), font_id, ColorU::black())]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Element for Label {
|
||||
type LayoutState = LayoutState;
|
||||
type LayoutState = Line;
|
||||
type PaintState = ();
|
||||
|
||||
fn layout(
|
||||
@@ -124,17 +115,17 @@ impl Element for Label {
|
||||
.font_cache
|
||||
.select_font(self.family_id, &self.font_properties)
|
||||
.unwrap();
|
||||
let (styles, colors) = self.layout_text(&ctx.font_cache, font_id);
|
||||
let runs = self.compute_runs(&ctx.font_cache, font_id);
|
||||
let line =
|
||||
ctx.text_layout_cache
|
||||
.layout_str(self.text.as_str(), self.font_size, styles.as_slice());
|
||||
.layout_str(self.text.as_str(), self.font_size, runs.as_slice());
|
||||
|
||||
let size = vec2f(
|
||||
line.width.max(constraint.min.x()).min(constraint.max.x()),
|
||||
line.width().max(constraint.min.x()).min(constraint.max.x()),
|
||||
ctx.font_cache.line_height(font_id, self.font_size).ceil(),
|
||||
);
|
||||
|
||||
(size, LayoutState { line, colors })
|
||||
(size, line)
|
||||
}
|
||||
|
||||
fn after_layout(&mut self, _: Vector2F, _: &mut Self::LayoutState, _: &mut AfterLayoutContext) {
|
||||
@@ -143,13 +134,12 @@ impl Element for Label {
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: RectF,
|
||||
layout: &mut Self::LayoutState,
|
||||
line: &mut Self::LayoutState,
|
||||
ctx: &mut PaintContext,
|
||||
) -> Self::PaintState {
|
||||
layout.line.paint(
|
||||
line.paint(
|
||||
bounds.origin(),
|
||||
RectF::new(vec2f(0., 0.), bounds.size()),
|
||||
layout.colors.as_slice(),
|
||||
ctx,
|
||||
)
|
||||
}
|
||||
@@ -226,28 +216,21 @@ mod tests {
|
||||
],
|
||||
);
|
||||
|
||||
let (styles, colors) = label.layout_text(app.font_cache().as_ref(), menlo_regular);
|
||||
assert_eq!(styles.len(), colors.len());
|
||||
|
||||
let mut spans = Vec::new();
|
||||
for ((style_range, font_id), (color_range, color)) in styles.into_iter().zip(colors) {
|
||||
assert_eq!(style_range, color_range);
|
||||
spans.push((style_range, font_id, color));
|
||||
}
|
||||
let runs = label.compute_runs(app.font_cache().as_ref(), menlo_regular);
|
||||
assert_eq!(
|
||||
spans,
|
||||
runs.as_slice(),
|
||||
&[
|
||||
(0..3, menlo_regular, black),
|
||||
(3..4, menlo_bold, red),
|
||||
(4..5, menlo_regular, black),
|
||||
(5..6, menlo_bold, red),
|
||||
(6..9, menlo_regular, black),
|
||||
(9..10, menlo_bold, red),
|
||||
(10..15, menlo_regular, black),
|
||||
(15..16, menlo_bold, red),
|
||||
(16..18, menlo_regular, black),
|
||||
(18..19, menlo_bold, red),
|
||||
(19..34, menlo_regular, black)
|
||||
(3, menlo_regular, black),
|
||||
(1, menlo_bold, red),
|
||||
(1, menlo_regular, black),
|
||||
(1, menlo_bold, red),
|
||||
(3, menlo_regular, black),
|
||||
(1, menlo_bold, red),
|
||||
(5, menlo_regular, black),
|
||||
(1, menlo_bold, red),
|
||||
(2, menlo_regular, black),
|
||||
(1, menlo_bold, red),
|
||||
(15, menlo_regular, black),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
color::ColorU,
|
||||
fonts::{FontId, GlyphId, Metrics, Properties},
|
||||
geometry::{
|
||||
rect::{RectF, RectI},
|
||||
@@ -6,7 +7,7 @@ use crate::{
|
||||
vector::{vec2f, vec2i, Vector2F},
|
||||
},
|
||||
platform,
|
||||
text_layout::{Glyph, Line, Run},
|
||||
text_layout::{Glyph, LineLayout, Run},
|
||||
};
|
||||
use cocoa::appkit::{CGFloat, CGPoint};
|
||||
use core_foundation::{
|
||||
@@ -21,7 +22,7 @@ use core_graphics::{
|
||||
use core_text::{line::CTLine, string_attributes::kCTFontAttributeName};
|
||||
use font_kit::{canvas::RasterizationOptions, hinting::HintingOptions, source::SystemSource};
|
||||
use parking_lot::RwLock;
|
||||
use std::{char, convert::TryFrom};
|
||||
use std::{cell::RefCell, char, convert::TryFrom};
|
||||
|
||||
#[allow(non_upper_case_globals)]
|
||||
const kCGImageAlphaOnly: u32 = 7;
|
||||
@@ -80,8 +81,8 @@ impl platform::FontSystem for FontSystem {
|
||||
&self,
|
||||
text: &str,
|
||||
font_size: f32,
|
||||
runs: &[(std::ops::Range<usize>, FontId)],
|
||||
) -> Line {
|
||||
runs: &[(usize, FontId, ColorU)],
|
||||
) -> LineLayout {
|
||||
self.0.read().layout_str(text, font_size, runs)
|
||||
}
|
||||
}
|
||||
@@ -185,8 +186,8 @@ impl FontSystemState {
|
||||
&self,
|
||||
text: &str,
|
||||
font_size: f32,
|
||||
runs: &[(std::ops::Range<usize>, FontId)],
|
||||
) -> Line {
|
||||
runs: &[(usize, FontId, ColorU)],
|
||||
) -> LineLayout {
|
||||
let font_id_attr_name = CFString::from_static_string("zed_font_id");
|
||||
|
||||
let len = text.len();
|
||||
@@ -205,16 +206,34 @@ impl FontSystemState {
|
||||
let mut utf8_and_utf16_ixs = utf8_and_utf16_ixs.clone();
|
||||
string.replace_str(&CFString::new(text), CFRange::init(0, 0));
|
||||
|
||||
let last_run: RefCell<Option<(usize, FontId)>> = Default::default();
|
||||
let font_runs = runs
|
||||
.iter()
|
||||
.filter_map(|(len, font_id, _)| {
|
||||
let mut last_run = last_run.borrow_mut();
|
||||
if let Some((last_len, last_font_id)) = last_run.as_mut() {
|
||||
if font_id == last_font_id {
|
||||
*last_len += *len;
|
||||
None
|
||||
} else {
|
||||
let result = (*last_len, *last_font_id);
|
||||
*last_len = *len;
|
||||
*last_font_id = *font_id;
|
||||
Some(result)
|
||||
}
|
||||
} else {
|
||||
*last_run = Some((*len, *font_id));
|
||||
None
|
||||
}
|
||||
})
|
||||
.chain(std::iter::from_fn(|| last_run.borrow_mut().take()));
|
||||
|
||||
let mut utf8_ix = 0;
|
||||
let mut utf16_ix = 0;
|
||||
for (range, font_id) in runs {
|
||||
while utf8_ix < range.start {
|
||||
let (next_utf8_ix, next_utf16_ix) = utf8_and_utf16_ixs.next().unwrap();
|
||||
utf8_ix = next_utf8_ix;
|
||||
utf16_ix = next_utf16_ix;
|
||||
}
|
||||
for (run_len, font_id) in font_runs {
|
||||
let utf8_end = utf16_ix + run_len;
|
||||
let utf16_start = utf16_ix;
|
||||
while utf8_ix < range.end {
|
||||
while utf8_ix < utf8_end {
|
||||
let (next_utf8_ix, next_utf16_ix) = utf8_and_utf16_ixs.next().unwrap();
|
||||
utf8_ix = next_utf8_ix;
|
||||
utf16_ix = next_utf16_ix;
|
||||
@@ -279,7 +298,7 @@ impl FontSystemState {
|
||||
}
|
||||
|
||||
let typographic_bounds = line.get_typographic_bounds();
|
||||
Line {
|
||||
LineLayout {
|
||||
width: typographic_bounds.width as f32,
|
||||
ascent: typographic_bounds.ascent as f32,
|
||||
descent: typographic_bounds.descent as f32,
|
||||
@@ -308,9 +327,9 @@ mod tests {
|
||||
"hello world",
|
||||
16.0,
|
||||
&[
|
||||
(0..2, menlo_bold),
|
||||
(2..6, menlo_italic),
|
||||
(6..11, menlo_regular),
|
||||
(2, menlo_bold, Default::default()),
|
||||
(4, menlo_italic, Default::default()),
|
||||
(5, menlo_regular, Default::default()),
|
||||
],
|
||||
);
|
||||
assert_eq!(line.runs.len(), 3);
|
||||
@@ -336,9 +355,9 @@ mod tests {
|
||||
text,
|
||||
16.0,
|
||||
&[
|
||||
(0..9, zapfino_regular),
|
||||
(9..22, menlo_regular),
|
||||
(22..text.len(), zapfino_regular),
|
||||
(9, zapfino_regular, ColorU::default()),
|
||||
(13, menlo_regular, ColorU::default()),
|
||||
(text.len() - 22, zapfino_regular, ColorU::default()),
|
||||
],
|
||||
);
|
||||
assert_eq!(
|
||||
|
||||
@@ -8,20 +8,20 @@ pub mod current {
|
||||
}
|
||||
|
||||
use crate::{
|
||||
color::ColorU,
|
||||
executor,
|
||||
fonts::{FontId, GlyphId, Metrics as FontMetrics, Properties as FontProperties},
|
||||
geometry::{
|
||||
rect::{RectF, RectI},
|
||||
vector::Vector2F,
|
||||
},
|
||||
text_layout::Line,
|
||||
text_layout::LineLayout,
|
||||
ClipboardItem, Menu, Scene,
|
||||
};
|
||||
use async_task::Runnable;
|
||||
pub use event::Event;
|
||||
use std::{
|
||||
any::Any,
|
||||
ops::Range,
|
||||
path::{Path, PathBuf},
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
@@ -122,5 +122,10 @@ pub trait FontSystem: Send + Sync {
|
||||
subpixel_shift: Vector2F,
|
||||
scale_factor: f32,
|
||||
) -> Option<(RectI, Vec<u8>)>;
|
||||
fn layout_str(&self, text: &str, font_size: f32, runs: &[(Range<usize>, FontId)]) -> Line;
|
||||
fn layout_str(
|
||||
&self,
|
||||
text: &str,
|
||||
font_size: f32,
|
||||
runs: &[(usize, FontId, ColorU)],
|
||||
) -> LineLayout;
|
||||
}
|
||||
|
||||
+54
-38
@@ -14,13 +14,12 @@ use std::{
|
||||
borrow::Borrow,
|
||||
collections::HashMap,
|
||||
hash::{Hash, Hasher},
|
||||
ops::Range,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
pub struct TextLayoutCache {
|
||||
prev_frame: Mutex<HashMap<CacheKeyValue, Arc<Line>>>,
|
||||
curr_frame: RwLock<HashMap<CacheKeyValue, Arc<Line>>>,
|
||||
prev_frame: Mutex<HashMap<CacheKeyValue, Arc<LineLayout>>>,
|
||||
curr_frame: RwLock<HashMap<CacheKeyValue, Arc<LineLayout>>>,
|
||||
fonts: Arc<dyn platform::FontSystem>,
|
||||
}
|
||||
|
||||
@@ -44,31 +43,31 @@ impl TextLayoutCache {
|
||||
&'a self,
|
||||
text: &'a str,
|
||||
font_size: f32,
|
||||
runs: &'a [(Range<usize>, FontId)],
|
||||
) -> Arc<Line> {
|
||||
runs: &'a [(usize, FontId, ColorU)],
|
||||
) -> Line {
|
||||
let key = &CacheKeyRef {
|
||||
text,
|
||||
font_size: OrderedFloat(font_size),
|
||||
runs,
|
||||
} as &dyn CacheKey;
|
||||
let curr_frame = self.curr_frame.upgradable_read();
|
||||
if let Some(line) = curr_frame.get(key) {
|
||||
return line.clone();
|
||||
if let Some(layout) = curr_frame.get(key) {
|
||||
return Line::new(layout.clone(), runs);
|
||||
}
|
||||
|
||||
let mut curr_frame = RwLockUpgradableReadGuard::upgrade(curr_frame);
|
||||
if let Some((key, line)) = self.prev_frame.lock().remove_entry(key) {
|
||||
curr_frame.insert(key, line.clone());
|
||||
line.clone()
|
||||
if let Some((key, layout)) = self.prev_frame.lock().remove_entry(key) {
|
||||
curr_frame.insert(key, layout.clone());
|
||||
Line::new(layout.clone(), runs)
|
||||
} else {
|
||||
let line = Arc::new(self.fonts.layout_str(text, font_size, runs));
|
||||
let layout = Arc::new(self.fonts.layout_str(text, font_size, runs));
|
||||
let key = CacheKeyValue {
|
||||
text: text.into(),
|
||||
font_size: OrderedFloat(font_size),
|
||||
runs: SmallVec::from(runs),
|
||||
};
|
||||
curr_frame.insert(key, line.clone());
|
||||
line
|
||||
curr_frame.insert(key, layout.clone());
|
||||
Line::new(layout, runs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,7 +94,7 @@ impl<'a> Hash for (dyn CacheKey + 'a) {
|
||||
struct CacheKeyValue {
|
||||
text: String,
|
||||
font_size: OrderedFloat<f32>,
|
||||
runs: SmallVec<[(Range<usize>, FontId); 1]>,
|
||||
runs: SmallVec<[(usize, FontId, ColorU); 1]>,
|
||||
}
|
||||
|
||||
impl CacheKey for CacheKeyValue {
|
||||
@@ -124,7 +123,7 @@ impl<'a> Borrow<dyn CacheKey + 'a> for CacheKeyValue {
|
||||
struct CacheKeyRef<'a> {
|
||||
text: &'a str,
|
||||
font_size: OrderedFloat<f32>,
|
||||
runs: &'a [(Range<usize>, FontId)],
|
||||
runs: &'a [(usize, FontId, ColorU)],
|
||||
}
|
||||
|
||||
impl<'a> CacheKey for CacheKeyRef<'a> {
|
||||
@@ -135,6 +134,12 @@ impl<'a> CacheKey for CacheKeyRef<'a> {
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct Line {
|
||||
layout: Arc<LineLayout>,
|
||||
color_runs: SmallVec<[(u32, ColorU); 32]>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct LineLayout {
|
||||
pub width: f32,
|
||||
pub ascent: f32,
|
||||
pub descent: f32,
|
||||
@@ -157,22 +162,34 @@ pub struct Glyph {
|
||||
}
|
||||
|
||||
impl Line {
|
||||
fn new(layout: Arc<LineLayout>, runs: &[(usize, FontId, ColorU)]) -> Self {
|
||||
let mut color_runs = SmallVec::new();
|
||||
for (len, _, color) in runs {
|
||||
color_runs.push((*len as u32, *color));
|
||||
}
|
||||
Self { layout, color_runs }
|
||||
}
|
||||
|
||||
pub fn width(&self) -> f32 {
|
||||
self.layout.width
|
||||
}
|
||||
|
||||
pub fn x_for_index(&self, index: usize) -> f32 {
|
||||
for run in &self.runs {
|
||||
for run in &self.layout.runs {
|
||||
for glyph in &run.glyphs {
|
||||
if glyph.index == index {
|
||||
return glyph.position.x();
|
||||
}
|
||||
}
|
||||
}
|
||||
self.width
|
||||
self.layout.width
|
||||
}
|
||||
|
||||
pub fn index_for_x(&self, x: f32) -> Option<usize> {
|
||||
if x >= self.width {
|
||||
if x >= self.layout.width {
|
||||
None
|
||||
} else {
|
||||
for run in self.runs.iter().rev() {
|
||||
for run in self.layout.runs.iter().rev() {
|
||||
for glyph in run.glyphs.iter().rev() {
|
||||
if glyph.position.x() <= x {
|
||||
return Some(glyph.index);
|
||||
@@ -183,21 +200,19 @@ impl Line {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint(
|
||||
&self,
|
||||
origin: Vector2F,
|
||||
bounds: RectF,
|
||||
colors: &[(Range<usize>, ColorU)],
|
||||
ctx: &mut PaintContext,
|
||||
) {
|
||||
let mut colors = colors.iter().peekable();
|
||||
pub fn paint(&self, origin: Vector2F, bounds: RectF, ctx: &mut PaintContext) {
|
||||
let padding_top = (bounds.height() - self.layout.ascent - self.layout.descent) / 2.;
|
||||
let baseline_origin = vec2f(0., padding_top + self.layout.ascent);
|
||||
|
||||
let mut color_runs = self.color_runs.iter();
|
||||
let mut color_end = 0;
|
||||
let mut color = ColorU::black();
|
||||
|
||||
let padding_top = (bounds.height() - self.ascent - self.descent) / 2.;
|
||||
let baseline_origin = vec2f(0., padding_top + self.ascent);
|
||||
|
||||
for run in &self.runs {
|
||||
let max_glyph_width = ctx.font_cache.bounding_box(run.font_id, self.font_size).x();
|
||||
for run in &self.layout.runs {
|
||||
let max_glyph_width = ctx
|
||||
.font_cache
|
||||
.bounding_box(run.font_id, self.layout.font_size)
|
||||
.x();
|
||||
|
||||
for glyph in &run.glyphs {
|
||||
let glyph_origin = baseline_origin + glyph.position;
|
||||
@@ -209,18 +224,19 @@ impl Line {
|
||||
break;
|
||||
}
|
||||
|
||||
while let Some((range, next_color)) = colors.peek() {
|
||||
if glyph.index >= range.end {
|
||||
colors.next();
|
||||
if glyph.index >= color_end {
|
||||
if let Some(next_run) = color_runs.next() {
|
||||
color_end += next_run.0 as usize;
|
||||
color = next_run.1;
|
||||
} else {
|
||||
color = *next_color;
|
||||
break;
|
||||
color_end = self.layout.len;
|
||||
color = ColorU::black();
|
||||
}
|
||||
}
|
||||
|
||||
ctx.scene.push_glyph(scene::Glyph {
|
||||
font_id: run.font_id,
|
||||
font_size: self.font_size,
|
||||
font_size: self.layout.font_size,
|
||||
id: glyph.id,
|
||||
origin: origin + glyph_origin,
|
||||
color,
|
||||
|
||||
@@ -14,10 +14,7 @@ use gpui::{
|
||||
use json::json;
|
||||
use smallvec::SmallVec;
|
||||
use std::cmp::Ordering;
|
||||
use std::{
|
||||
cmp::{self},
|
||||
sync::Arc,
|
||||
};
|
||||
use std::cmp::{self};
|
||||
|
||||
pub struct BufferElement {
|
||||
view: WeakViewHandle<BufferView>,
|
||||
@@ -188,13 +185,12 @@ impl BufferElement {
|
||||
for (ix, line) in layout.line_number_layouts.iter().enumerate() {
|
||||
let line_origin = rect.origin()
|
||||
+ vec2f(
|
||||
rect.width() - line.width - layout.gutter_padding,
|
||||
rect.width() - line.width() - layout.gutter_padding,
|
||||
ix as f32 * line_height - (scroll_top % line_height),
|
||||
);
|
||||
line.paint(
|
||||
line_origin,
|
||||
RectF::new(vec2f(0., 0.), vec2f(line.width, line_height)),
|
||||
&[(0..line.len, ColorU::black())],
|
||||
RectF::new(vec2f(0., 0.), vec2f(line.width(), line_height)),
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
@@ -259,7 +255,7 @@ impl BufferElement {
|
||||
+ line_layout.x_for_index(range_end.column() as usize)
|
||||
- scroll_left
|
||||
} else {
|
||||
content_origin.x() + line_layout.width + corner_radius * 2.0
|
||||
content_origin.x() + line_layout.width() + corner_radius * 2.0
|
||||
- scroll_left
|
||||
},
|
||||
}
|
||||
@@ -292,7 +288,6 @@ impl BufferElement {
|
||||
line.paint(
|
||||
content_origin + vec2f(-scroll_left, row as f32 * line_height - scroll_top),
|
||||
RectF::new(vec2f(scroll_left, 0.), vec2f(bounds.width(), line_height)),
|
||||
&[(0..line.len, ColorU::black())],
|
||||
ctx,
|
||||
);
|
||||
}
|
||||
@@ -377,8 +372,8 @@ impl Element for BufferElement {
|
||||
}
|
||||
Ok(layouts) => {
|
||||
for line in &layouts {
|
||||
if line.width > max_visible_line_width {
|
||||
max_visible_line_width = line.width;
|
||||
if line.width() > max_visible_line_width {
|
||||
max_visible_line_width = line.width();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -506,8 +501,8 @@ pub struct LayoutState {
|
||||
gutter_size: Vector2F,
|
||||
gutter_padding: f32,
|
||||
text_size: Vector2F,
|
||||
line_layouts: Vec<Arc<text_layout::Line>>,
|
||||
line_number_layouts: Vec<Arc<text_layout::Line>>,
|
||||
line_layouts: Vec<text_layout::Line>,
|
||||
line_number_layouts: Vec<text_layout::Line>,
|
||||
max_visible_line_width: f32,
|
||||
autoscroll_horizontally: bool,
|
||||
}
|
||||
@@ -524,7 +519,7 @@ impl LayoutState {
|
||||
let longest_line_width = view
|
||||
.layout_line(row, font_cache, layout_cache, app)
|
||||
.unwrap()
|
||||
.width;
|
||||
.width();
|
||||
longest_line_width.max(self.max_visible_line_width) + view.em_width(font_cache)
|
||||
}
|
||||
|
||||
|
||||
@@ -5,9 +5,10 @@ use super::{
|
||||
use crate::{settings::Settings, util::post_inc, workspace, worktree::FileHandle};
|
||||
use anyhow::Result;
|
||||
use gpui::{
|
||||
fonts::Properties as FontProperties, geometry::vector::Vector2F, keymap::Binding, text_layout,
|
||||
AppContext, ClipboardItem, Element, ElementBox, Entity, FontCache, ModelHandle,
|
||||
MutableAppContext, Task, TextLayoutCache, View, ViewContext, WeakViewHandle,
|
||||
color::ColorU, fonts::Properties as FontProperties, geometry::vector::Vector2F,
|
||||
keymap::Binding, text_layout, AppContext, ClipboardItem, Element, ElementBox, Entity,
|
||||
FontCache, ModelHandle, MutableAppContext, Task, TextLayoutCache, View, ViewContext,
|
||||
WeakViewHandle,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use postage::watch;
|
||||
@@ -448,7 +449,7 @@ impl BufferView {
|
||||
viewport_width: f32,
|
||||
scroll_width: f32,
|
||||
max_glyph_width: f32,
|
||||
layouts: &[Arc<text_layout::Line>],
|
||||
layouts: &[text_layout::Line],
|
||||
ctx: &AppContext,
|
||||
) {
|
||||
let mut target_left = std::f32::INFINITY;
|
||||
@@ -2077,9 +2078,9 @@ impl BufferView {
|
||||
.layout_str(
|
||||
"1".repeat(digit_count).as_str(),
|
||||
font_size,
|
||||
&[(0..digit_count, font_id)],
|
||||
&[(digit_count, font_id, ColorU::black())],
|
||||
)
|
||||
.width)
|
||||
.width())
|
||||
}
|
||||
|
||||
pub fn layout_line_numbers(
|
||||
@@ -2088,7 +2089,7 @@ impl BufferView {
|
||||
font_cache: &FontCache,
|
||||
layout_cache: &TextLayoutCache,
|
||||
ctx: &AppContext,
|
||||
) -> Result<Vec<Arc<text_layout::Line>>> {
|
||||
) -> Result<Vec<text_layout::Line>> {
|
||||
let settings = self.settings.borrow();
|
||||
let font_size = settings.buffer_font_size;
|
||||
let font_id =
|
||||
@@ -2114,7 +2115,7 @@ impl BufferView {
|
||||
layouts.push(layout_cache.layout_str(
|
||||
&line_number,
|
||||
font_size,
|
||||
&[(0..line_number.len(), font_id)],
|
||||
&[(line_number.len(), font_id, ColorU::black())],
|
||||
));
|
||||
}
|
||||
|
||||
@@ -2127,7 +2128,7 @@ impl BufferView {
|
||||
font_cache: &FontCache,
|
||||
layout_cache: &TextLayoutCache,
|
||||
ctx: &AppContext,
|
||||
) -> Result<Vec<Arc<text_layout::Line>>> {
|
||||
) -> Result<Vec<text_layout::Line>> {
|
||||
rows.end = cmp::min(rows.end, self.display_map.max_point(ctx).row() + 1);
|
||||
if rows.start >= rows.end {
|
||||
return Ok(Vec::new());
|
||||
@@ -2151,7 +2152,7 @@ impl BufferView {
|
||||
layouts.push(layout_cache.layout_str(
|
||||
&line,
|
||||
font_size,
|
||||
&[(0..line.len(), font_id)],
|
||||
&[(line.len(), font_id, ColorU::black())],
|
||||
));
|
||||
line.clear();
|
||||
row += 1;
|
||||
@@ -2171,7 +2172,7 @@ impl BufferView {
|
||||
font_cache: &FontCache,
|
||||
layout_cache: &TextLayoutCache,
|
||||
app: &AppContext,
|
||||
) -> Result<Arc<text_layout::Line>> {
|
||||
) -> Result<text_layout::Line> {
|
||||
let settings = self.settings.borrow();
|
||||
let font_id =
|
||||
font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
|
||||
@@ -2181,7 +2182,7 @@ impl BufferView {
|
||||
Ok(layout_cache.layout_str(
|
||||
&line,
|
||||
settings.buffer_font_size,
|
||||
&[(0..self.line_len(row, app) as usize, font_id)],
|
||||
&[(self.line_len(row, app) as usize, font_id, ColorU::black())],
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user