From 208a45e923cfae4eccb6156bff29fccfaf4d70a0 Mon Sep 17 00:00:00 2001 From: Edgar Geier Date: Sun, 12 Mar 2023 10:37:10 +0100 Subject: [PATCH] Unify `Attrs` and `AttrsOwned` --- examples/editor-libcosmic/src/main.rs | 48 +++---- examples/editor-orbclient/src/main.rs | 5 +- examples/rich-text/src/main.rs | 112 ++++++++--------- src/attrs.rs | 175 +++++++++++++------------- src/buffer.rs | 28 +++-- src/buffer_line.rs | 2 +- src/edit/editor.rs | 5 +- src/edit/syntect.rs | 17 +-- src/edit/vi.rs | 2 +- src/font/system/no_std.rs | 9 +- src/font/system/std.rs | 66 +++++----- src/shape.rs | 2 +- 12 files changed, 247 insertions(+), 224 deletions(-) diff --git a/examples/editor-libcosmic/src/main.rs b/examples/editor-libcosmic/src/main.rs index 7c8c591aff..4d06c0ca5b 100644 --- a/examples/editor-libcosmic/src/main.rs +++ b/examples/editor-libcosmic/src/main.rs @@ -87,7 +87,7 @@ fn main() -> cosmic::iced::Result { pub struct Window { theme: Theme, path_opt: Option, - attrs: Attrs<'static>, + attrs: Attrs, font_size: FontSize, #[cfg(not(feature = "vi"))] editor: Mutex>, @@ -112,7 +112,7 @@ pub enum Message { impl Window { pub fn open(&mut self, path: PathBuf) { let mut editor = self.editor.lock().unwrap(); - match editor.load_text(&path, self.attrs) { + match editor.load_text(&path, &self.attrs) { Ok(()) => { log::info!("opened '{}'", path.display()); self.path_opt = Some(path); @@ -132,9 +132,10 @@ impl Application for Window { type Theme = Theme; fn new(_flags: ()) -> (Self, Command) { - let attrs = cosmic_text::Attrs::new() + let attrs = cosmic_text::Attrs::builder() .monospaced(true) - .family(cosmic_text::Family::Monospace); + .family(cosmic_text::Family::Monospace) + .build(); let mut editor = SyntaxEditor::new( Buffer::new(&FONT_SYSTEM, FontSize::Body.to_metrics()), @@ -146,7 +147,7 @@ impl Application for Window { #[cfg(feature = "vi")] let mut editor = cosmic_text::ViEditor::new(editor); - update_attrs(&mut editor, attrs); + update_attrs(&mut editor, &attrs); let mut window = Window { theme: Theme::Dark, @@ -203,37 +204,36 @@ impl Application for Window { } } Message::Bold(bold) => { - self.attrs = self.attrs.weight(if bold { + self.attrs.weight = if bold { cosmic_text::Weight::BOLD } else { cosmic_text::Weight::NORMAL - }); + }; let mut editor = self.editor.lock().unwrap(); - update_attrs(&mut *editor, self.attrs); + update_attrs(&mut *editor, &self.attrs); } Message::Italic(italic) => { - self.attrs = self.attrs.style(if italic { + self.attrs.style = if italic { cosmic_text::Style::Italic } else { cosmic_text::Style::Normal - }); + }; let mut editor = self.editor.lock().unwrap(); - update_attrs(&mut *editor, self.attrs); + update_attrs(&mut *editor, &self.attrs); } Message::Monospaced(monospaced) => { - self.attrs = self - .attrs - .family(if monospaced { - cosmic_text::Family::Monospace - } else { - cosmic_text::Family::SansSerif - }) - .monospaced(monospaced); + self.attrs.family_owned = if monospaced { + cosmic_text::Family::Monospace + } else { + cosmic_text::Family::SansSerif + } + .into(); + self.attrs.monospaced = monospaced; let mut editor = self.editor.lock().unwrap(); - update_attrs(&mut *editor, self.attrs); + update_attrs(&mut *editor, &self.attrs); } Message::FontSizeChanged(font_size) => { self.font_size = font_size; @@ -258,7 +258,7 @@ impl Application for Window { let Color { r, g, b, a } = self.theme.palette().text; let as_u8 = |component: f32| (component * 255.0) as u8; - self.attrs = self.attrs.color(cosmic_text::Color::rgba( + self.attrs.color_opt = Some(cosmic_text::Color::rgba( as_u8(r), as_u8(g), as_u8(b), @@ -266,7 +266,7 @@ impl Application for Window { )); let mut editor = self.editor.lock().unwrap(); - update_attrs(&mut *editor, self.attrs); + update_attrs(&mut *editor, &self.attrs); } } @@ -360,9 +360,9 @@ impl Application for Window { } } -fn update_attrs<'a, T: Edit<'a>>(editor: &mut T, attrs: Attrs<'a>) { +fn update_attrs<'a, T: Edit<'a>>(editor: &mut T, attrs: &Attrs) { editor.buffer_mut().lines.iter_mut().for_each(|line| { - line.set_attrs_list(AttrsList::new(attrs)); + line.set_attrs_list(AttrsList::new(attrs.clone())); }); } diff --git a/examples/editor-orbclient/src/main.rs b/examples/editor-orbclient/src/main.rs index 0ceed80344..76ce3b3b91 100644 --- a/examples/editor-orbclient/src/main.rs +++ b/examples/editor-orbclient/src/main.rs @@ -71,7 +71,10 @@ fn main() { .buffer_mut() .set_size(window.width() as f32 - line_x * 2.0, window.height() as f32); - let attrs = Attrs::new().monospaced(true).family(Family::Monospace); + let attrs = Attrs::builder() + .monospaced(true) + .family(Family::Monospace) + .build(); match editor.load_text(&path, attrs) { Ok(()) => (), Err(err) => { diff --git a/examples/rich-text/src/main.rs b/examples/rich-text/src/main.rs index fa5132cf31..26b734262a 100644 --- a/examples/rich-text/src/main.rs +++ b/examples/rich-text/src/main.rs @@ -1,8 +1,8 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use cosmic_text::{ - Action, Attrs, AttrsList, Buffer, BufferLine, Color, Edit, Editor, Family, FontSystem, Metrics, - Style, SwashCache, Weight, + Action, Attrs, AttrsBuilder, AttrsList, Buffer, BufferLine, Color, Edit, Editor, Family, + FontSystem, Metrics, Style, SwashCache, Weight, }; use orbclient::{EventOption, Renderer, Window, WindowFlag}; use std::{ @@ -45,98 +45,98 @@ fn main() { .buffer_mut() .set_size(window.width() as f32, window.height() as f32); - let attrs = Attrs::new(); - let serif_attrs = attrs.family(Family::Serif); - let mono_attrs = attrs.monospaced(true).family(Family::Monospace); - let comic_attrs = attrs.family(Family::Name("Comic Neue")); + let attrs = Attrs::builder(); + let serif_attrs = attrs.clone().family(Family::Serif); + let mono_attrs = attrs.clone().monospaced(true).family(Family::Monospace); + let comic_attrs = attrs.clone().family(Family::Name("Comic Neue")); editor.buffer_mut().lines.clear(); - let lines: &[&[(&str, Attrs)]] = &[ + let lines: &[&[(&str, AttrsBuilder)]] = &[ &[ - ("B", attrs.weight(Weight::BOLD)), - ("old ", attrs), - ("I", attrs.style(Style::Italic)), - ("talic ", attrs), - ("f", attrs), - ("i ", attrs), - ("f", attrs.weight(Weight::BOLD)), - ("i ", attrs), - ("f", attrs.style(Style::Italic)), - ("i ", attrs), + ("B", attrs.clone().weight(Weight::BOLD)), + ("old ", attrs.clone()), + ("I", attrs.clone().style(Style::Italic)), + ("talic ", attrs.clone()), + ("f", attrs.clone()), + ("i ", attrs.clone()), + ("f", attrs.clone().weight(Weight::BOLD)), + ("i ", attrs.clone()), + ("f", attrs.clone().style(Style::Italic)), + ("i ", attrs.clone()), ], &[ - ("Sans-Serif Normal ", attrs), - ("Sans-Serif Bold ", attrs.weight(Weight::BOLD)), - ("Sans-Serif Italic ", attrs.style(Style::Italic)), + ("Sans-Serif Normal ", attrs.clone()), + ("Sans-Serif Bold ", attrs.clone().weight(Weight::BOLD)), + ("Sans-Serif Italic ", attrs.clone().style(Style::Italic)), ( "Sans-Serif Bold Italic", - attrs.weight(Weight::BOLD).style(Style::Italic), + attrs.clone().weight(Weight::BOLD).style(Style::Italic), ), ], &[ - ("Serif Normal ", serif_attrs), - ("Serif Bold ", serif_attrs.weight(Weight::BOLD)), - ("Serif Italic ", serif_attrs.style(Style::Italic)), + ("Serif Normal ", serif_attrs.clone()), + ("Serif Bold ", serif_attrs.clone().weight(Weight::BOLD)), + ("Serif Italic ", serif_attrs.clone().style(Style::Italic)), ( "Serif Bold Italic", serif_attrs.weight(Weight::BOLD).style(Style::Italic), ), ], &[ - ("Mono Normal ", mono_attrs), - ("Mono Bold ", mono_attrs.weight(Weight::BOLD)), - ("Mono Italic ", mono_attrs.style(Style::Italic)), + ("Mono Normal ", mono_attrs.clone()), + ("Mono Bold ", mono_attrs.clone().weight(Weight::BOLD)), + ("Mono Italic ", mono_attrs.clone().style(Style::Italic)), ( "Mono Bold Italic", mono_attrs.weight(Weight::BOLD).style(Style::Italic), ), ], &[ - ("Comic Normal ", comic_attrs), - ("Comic Bold ", comic_attrs.weight(Weight::BOLD)), - ("Comic Italic ", comic_attrs.style(Style::Italic)), + ("Comic Normal ", comic_attrs.clone()), + ("Comic Bold ", comic_attrs.clone().weight(Weight::BOLD)), + ("Comic Italic ", comic_attrs.clone().style(Style::Italic)), ( "Comic Bold Italic", comic_attrs.weight(Weight::BOLD).style(Style::Italic), ), ], &[ - ("R", attrs.color(Color::rgb(0xFF, 0x00, 0x00))), - ("A", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))), - ("I", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))), - ("N", attrs.color(Color::rgb(0x00, 0xFF, 0x00))), - ("B", attrs.color(Color::rgb(0x00, 0x00, 0xFF))), - ("O", attrs.color(Color::rgb(0x4B, 0x00, 0x82))), - ("W ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))), - ("Red ", attrs.color(Color::rgb(0xFF, 0x00, 0x00))), - ("Orange ", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))), - ("Yellow ", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))), - ("Green ", attrs.color(Color::rgb(0x00, 0xFF, 0x00))), - ("Blue ", attrs.color(Color::rgb(0x00, 0x00, 0xFF))), - ("Indigo ", attrs.color(Color::rgb(0x4B, 0x00, 0x82))), - ("Violet ", attrs.color(Color::rgb(0x94, 0x00, 0xD3))), - ("U", attrs.color(Color::rgb(0x94, 0x00, 0xD3))), - ("N", attrs.color(Color::rgb(0x4B, 0x00, 0x82))), - ("I", attrs.color(Color::rgb(0x00, 0x00, 0xFF))), - ("C", attrs.color(Color::rgb(0x00, 0xFF, 0x00))), - ("O", attrs.color(Color::rgb(0xFF, 0xFF, 0x00))), - ("R", attrs.color(Color::rgb(0xFF, 0x7F, 0x00))), - ("N", attrs.color(Color::rgb(0xFF, 0x00, 0x00))), + ("R", attrs.clone().color(Color::rgb(0xFF, 0x00, 0x00))), + ("A", attrs.clone().color(Color::rgb(0xFF, 0x7F, 0x00))), + ("I", attrs.clone().color(Color::rgb(0xFF, 0xFF, 0x00))), + ("N", attrs.clone().color(Color::rgb(0x00, 0xFF, 0x00))), + ("B", attrs.clone().color(Color::rgb(0x00, 0x00, 0xFF))), + ("O", attrs.clone().color(Color::rgb(0x4B, 0x00, 0x82))), + ("W ", attrs.clone().color(Color::rgb(0x94, 0x00, 0xD3))), + ("Red ", attrs.clone().color(Color::rgb(0xFF, 0x00, 0x00))), + ("Orange ", attrs.clone().color(Color::rgb(0xFF, 0x7F, 0x00))), + ("Yellow ", attrs.clone().color(Color::rgb(0xFF, 0xFF, 0x00))), + ("Green ", attrs.clone().color(Color::rgb(0x00, 0xFF, 0x00))), + ("Blue ", attrs.clone().color(Color::rgb(0x00, 0x00, 0xFF))), + ("Indigo ", attrs.clone().color(Color::rgb(0x4B, 0x00, 0x82))), + ("Violet ", attrs.clone().color(Color::rgb(0x94, 0x00, 0xD3))), + ("U", attrs.clone().color(Color::rgb(0x94, 0x00, 0xD3))), + ("N", attrs.clone().color(Color::rgb(0x4B, 0x00, 0x82))), + ("I", attrs.clone().color(Color::rgb(0x00, 0x00, 0xFF))), + ("C", attrs.clone().color(Color::rgb(0x00, 0xFF, 0x00))), + ("O", attrs.clone().color(Color::rgb(0xFF, 0xFF, 0x00))), + ("R", attrs.clone().color(Color::rgb(0xFF, 0x7F, 0x00))), + ("N", attrs.clone().color(Color::rgb(0xFF, 0x00, 0x00))), ], &[( "生活,삶,जिंदगी 😀 FPS", - attrs.color(Color::rgb(0xFF, 0x00, 0x00)), + attrs.clone().color(Color::rgb(0xFF, 0x00, 0x00)), )], ]; - for &line in lines { + for line in lines { let mut line_text = String::new(); - let mut attrs_list = AttrsList::new(attrs); - for &(text, attrs) in line { + let mut attrs_list = AttrsList::new(attrs.clone().build()); + for (text, attrs) in line.iter() { let start = line_text.len(); line_text.push_str(text); let end = line_text.len(); - attrs_list.add_span(start..end, attrs); + attrs_list.add_span(start..end, attrs.clone().build()); } editor .buffer_mut() diff --git a/src/attrs.rs b/src/attrs.rs index aae14048dc..2c3794758e 100644 --- a/src/attrs.rs +++ b/src/attrs.rs @@ -1,10 +1,8 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 +use alloc::borrow::Cow; #[cfg(not(feature = "std"))] -use alloc::{ - string::{String, ToString}, - vec::Vec, -}; +use alloc::{string::ToString, vec::Vec}; use core::ops::Range; pub use fontdb::{Family, Stretch, Style, Weight}; @@ -55,7 +53,7 @@ impl Color { /// An owned version of [`Family`] #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum FamilyOwned { - Name(String), + Name(Cow<'static, str>), Serif, SansSerif, Cursive, @@ -66,7 +64,7 @@ pub enum FamilyOwned { impl FamilyOwned { pub fn new(family: Family) -> Self { match family { - Family::Name(name) => FamilyOwned::Name(name.to_string()), + Family::Name(name) => FamilyOwned::Name(Cow::Owned(name.to_string())), Family::Serif => FamilyOwned::Serif, Family::SansSerif => FamilyOwned::SansSerif, Family::Cursive => FamilyOwned::Cursive, @@ -87,76 +85,107 @@ impl FamilyOwned { } } -/// Text attributes -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub struct Attrs<'a> { - //TODO: should this be an option? - pub color_opt: Option, - pub family: Family<'a>, - pub monospaced: bool, - pub stretch: Stretch, - pub style: Style, - pub weight: Weight, - pub metadata: usize, +impl From> for FamilyOwned { + fn from(value: Family<'static>) -> Self { + match value { + Family::Name(name) => FamilyOwned::Name(Cow::Borrowed(name)), + Family::Serif => FamilyOwned::Serif, + Family::SansSerif => FamilyOwned::SansSerif, + Family::Cursive => FamilyOwned::Cursive, + Family::Fantasy => FamilyOwned::Fantasy, + Family::Monospace => FamilyOwned::Monospace, + } + } } -impl<'a> Attrs<'a> { - /// Create a new set of attributes with sane defaults - /// - /// This defaults to a regular Sans-Serif font. - pub fn new() -> Self { - Self { - color_opt: None, - family: Family::SansSerif, - monospaced: false, - stretch: Stretch::Normal, - style: Style::Normal, - weight: Weight::NORMAL, - metadata: 0, - } +#[derive(Clone)] +#[repr(transparent)] +pub struct AttrsBuilder(Attrs); + +impl AttrsBuilder { + pub fn new(attrs: Attrs) -> Self { + Self(attrs) + } + + pub fn build(self) -> Attrs { + self.0 } /// Set [Color] pub fn color(mut self, color: Color) -> Self { - self.color_opt = Some(color); + self.0.color_opt = Some(color); self } /// Set [Family] - pub fn family(mut self, family: Family<'a>) -> Self { - self.family = family; + pub fn family(mut self, family: impl Into) -> Self { + self.0.family_owned = family.into(); self } /// Set monospaced pub fn monospaced(mut self, monospaced: bool) -> Self { - self.monospaced = monospaced; + self.0.monospaced = monospaced; self } /// Set [Stretch] pub fn stretch(mut self, stretch: Stretch) -> Self { - self.stretch = stretch; + self.0.stretch = stretch; self } /// Set [Style] pub fn style(mut self, style: Style) -> Self { - self.style = style; + self.0.style = style; self } /// Set [Weight] pub fn weight(mut self, weight: Weight) -> Self { - self.weight = weight; + self.0.weight = weight; self } /// Set metadata pub fn metadata(mut self, metadata: usize) -> Self { - self.metadata = metadata; + self.0.metadata = metadata; self } +} + +/// Text attributes +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Attrs { + //TODO: should this be an option? + pub color_opt: Option, + pub family_owned: FamilyOwned, + pub monospaced: bool, + pub stretch: Stretch, + pub style: Style, + pub weight: Weight, + pub metadata: usize, +} + +impl Attrs { + /// Create a new set of attributes with sane defaults + /// + /// This defaults to a regular Sans-Serif font. + pub fn new() -> Self { + Self { + color_opt: None, + family_owned: FamilyOwned::SansSerif, + monospaced: false, + stretch: Stretch::Normal, + style: Style::Normal, + weight: Weight::NORMAL, + metadata: 0, + } + } + + pub fn builder() -> AttrsBuilder { + AttrsBuilder::new(Self::new()) + } /// Check if font matches pub fn matches(&self, face: &fontdb::FaceInfo) -> bool { @@ -170,7 +199,7 @@ impl<'a> Attrs<'a> { /// Check if this set of attributes can be shaped with another pub fn compatible(&self, other: &Self) -> bool { - self.family == other.family + self.family_owned == other.family_owned && self.monospaced == other.monospaced && self.stretch == other.stretch && self.style == other.style @@ -178,42 +207,15 @@ impl<'a> Attrs<'a> { } } -/// An owned version of [`Attrs`] -#[derive(Clone, Debug, Eq, Hash, PartialEq)] -pub struct AttrsOwned { - //TODO: should this be an option? - pub color_opt: Option, - pub family_owned: FamilyOwned, - pub monospaced: bool, - pub stretch: Stretch, - pub style: Style, - pub weight: Weight, - pub metadata: usize, -} - -impl AttrsOwned { - pub fn new(attrs: Attrs) -> Self { - Self { - color_opt: attrs.color_opt, - family_owned: FamilyOwned::new(attrs.family), - monospaced: attrs.monospaced, - stretch: attrs.stretch, - style: attrs.style, - weight: attrs.weight, - metadata: attrs.metadata, - } +impl AsRef for Attrs { + fn as_ref(&self) -> &Attrs { + self } +} - pub fn as_attrs(&self) -> Attrs { - Attrs { - color_opt: self.color_opt, - family: self.family_owned.as_family(), - monospaced: self.monospaced, - stretch: self.stretch, - style: self.style, - weight: self.weight, - metadata: self.metadata, - } +impl From<&Attrs> for Attrs { + fn from(value: &Attrs) -> Self { + value.clone() } } @@ -221,26 +223,26 @@ impl AttrsOwned { //TODO: have this clean up the spans when changes are made #[derive(Eq, PartialEq)] pub struct AttrsList { - defaults: AttrsOwned, - spans: RangeMap, + defaults: Attrs, + spans: RangeMap, } impl AttrsList { /// Create a new attributes list with a set of default [Attrs] pub fn new(defaults: Attrs) -> Self { Self { - defaults: AttrsOwned::new(defaults), + defaults, spans: RangeMap::new(), } } /// Get the default [Attrs] - pub fn defaults(&self) -> Attrs { - self.defaults.as_attrs() + pub fn defaults(&self) -> &Attrs { + &self.defaults } /// Get the current attribute spans - pub fn spans(&self) -> Vec<(&Range, &AttrsOwned)> { + pub fn spans(&self) -> Vec<(&Range, &Attrs)> { self.spans.iter().collect() } @@ -250,28 +252,25 @@ impl AttrsList { } /// Add an attribute span, removes any previous matching parts of spans - pub fn add_span(&mut self, range: Range, attrs: Attrs) { + pub fn add_span(&mut self, range: Range, attrs: impl Into) { //do not support 1..1 even if by accident. if range.start == range.end { return; } - self.spans.insert(range, AttrsOwned::new(attrs)); + self.spans.insert(range, attrs.into()); } /// Get the attribute span for an index /// /// This returns a span that contains the index - pub fn get_span(&self, index: usize) -> Attrs { - self.spans - .get(&index) - .map(|v| v.as_attrs()) - .unwrap_or(self.defaults.as_attrs()) + pub fn get_span(&self, index: usize) -> &Attrs { + self.spans.get(&index).unwrap_or(&self.defaults) } /// Split attributes list at an offset pub fn split_off(&mut self, index: usize) -> Self { - let mut new = Self::new(self.defaults.as_attrs()); + let mut new = Self::new(self.defaults.clone()); let mut removes = Vec::new(); //get the keys we need to remove or fix. diff --git a/src/buffer.rs b/src/buffer.rs index 144fcd58b8..213f99e407 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -565,16 +565,28 @@ impl<'a> Buffer<'a> { } /// Set text of buffer, using provided attributes for each line by default - pub fn set_text(&mut self, text: &str, attrs: Attrs<'a>) { + pub fn set_text(&mut self, text: &str, attrs: impl AsRef + Into) { self.lines.clear(); - for line in text.lines() { - self.lines - .push(BufferLine::new(line.to_string(), AttrsList::new(attrs))); - } - // Make sure there is always one line - if self.lines.is_empty() { + let mut lines = text.lines().peekable(); + if lines.peek().is_some() { + while let Some(line) = lines.next() { + if lines.peek().is_some() { + self.lines.push(BufferLine::new( + line.to_string(), + AttrsList::new(attrs.as_ref().clone()), + )); + } else { + self.lines.push(BufferLine::new( + line.to_string(), + AttrsList::new(attrs.into()), + )); + break; + } + } + } else { + // Make sure there is always one line self.lines - .push(BufferLine::new(String::new(), AttrsList::new(attrs))); + .push(BufferLine::new(String::new(), AttrsList::new(attrs.into()))); } self.scroll = 0; diff --git a/src/buffer_line.rs b/src/buffer_line.rs index e9b7e0b3e5..51df0cc960 100644 --- a/src/buffer_line.rs +++ b/src/buffer_line.rs @@ -132,7 +132,7 @@ impl BufferLine { for (other_range, attrs) in other.attrs_list.spans() { // Add previous attrs spans let range = other_range.start + len..other_range.end + len; - self.attrs_list.add_span(range, attrs.as_attrs()); + self.attrs_list.add_span(range, attrs); } self.reset(); diff --git a/src/edit/editor.rs b/src/edit/editor.rs index 5d0325f65b..93f6c2bba5 100644 --- a/src/edit/editor.rs +++ b/src/edit/editor.rs @@ -227,8 +227,9 @@ impl<'a> Edit<'a> for Editor<'a> { let after_len = after.text().len(); // Collect attributes - let mut final_attrs = attrs_list - .unwrap_or_else(|| AttrsList::new(line.attrs_list().get_span(line.text().len()))); + let mut final_attrs = attrs_list.unwrap_or_else(|| { + AttrsList::new(line.attrs_list().get_span(line.text().len()).clone()) + }); // Append the inserted text, line by line // we want to see a blank entry if the string ends with a newline diff --git a/src/edit/syntect.rs b/src/edit/syntect.rs index 14a41ee9e3..19dfa41464 100644 --- a/src/edit/syntect.rs +++ b/src/edit/syntect.rs @@ -7,7 +7,9 @@ use syntect::highlighting::{ }; use syntect::parsing::{ParseState, ScopeStack, SyntaxReference, SyntaxSet}; -use crate::{Action, AttrsList, Buffer, Color, Cursor, Edit, Editor, Style, Weight, Wrap}; +use crate::{ + Action, AttrsBuilder, AttrsList, Buffer, Color, Cursor, Edit, Editor, Style, Weight, Wrap, +}; pub struct SyntaxSystem { pub syntax_set: SyntaxSet, @@ -67,10 +69,10 @@ impl<'a> SyntaxEditor<'a> { /// /// Returns an [`io::Error`] if reading the file fails #[cfg(feature = "std")] - pub fn load_text>( + pub fn load_text( &mut self, - path: P, - attrs: crate::Attrs<'a>, + path: impl AsRef, + attrs: impl AsRef + Into, ) -> io::Result<()> { let path = path.as_ref(); @@ -171,11 +173,11 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> { ); let attrs = line.attrs_list().defaults(); - let mut attrs_list = AttrsList::new(attrs); + let mut attrs_list = AttrsList::new(attrs.clone()); for (style, _, range) in ranges { attrs_list.add_span( range, - attrs + AttrsBuilder::new(attrs.clone()) .color(Color::rgba( style.foreground.r, style.foreground.g, @@ -192,7 +194,8 @@ impl<'a> Edit<'a> for SyntaxEditor<'a> { Weight::BOLD } else { Weight::NORMAL - }), //TODO: underline + }) + .build(), //TODO: underline ); } diff --git a/src/edit/vi.rs b/src/edit/vi.rs index 22bbc7845c..a7794e49b0 100644 --- a/src/edit/vi.rs +++ b/src/edit/vi.rs @@ -31,7 +31,7 @@ impl<'a> ViEditor<'a> { pub fn load_text>( &mut self, path: P, - attrs: crate::Attrs<'a>, + attrs: impl AsRef + Into, ) -> std::io::Result<()> { self.editor.load_text(path, attrs) } diff --git a/src/font/system/no_std.rs b/src/font/system/no_std.rs index 6542310b97..a0a2654f1a 100644 --- a/src/font/system/no_std.rs +++ b/src/font/system/no_std.rs @@ -56,10 +56,10 @@ impl FontSystem { } } - pub fn get_font_matches<'a>(&'a self, attrs: Attrs) -> Arc> { + pub fn get_font_matches(&self, attrs: impl AsRef + Into) -> Arc { let mut fonts = Vec::new(); for face in self.db.faces() { - if !attrs.matches(face) { + if !attrs.as_ref().matches(face) { continue; } @@ -70,7 +70,10 @@ impl FontSystem { Arc::new(FontMatches { locale: &self.locale, - default_family: self.db.family_name(&attrs.family).to_string(), + default_family: self + .db + .family_name(&attrs.as_ref().family_owned.as_family()) + .to_string(), fonts, }) } diff --git a/src/font/system/std.rs b/src/font/system/std.rs index 071fcb9123..a7849316eb 100644 --- a/src/font/system/std.rs +++ b/src/font/system/std.rs @@ -5,7 +5,7 @@ use std::{ sync::{Arc, Mutex}, }; -use crate::{Attrs, AttrsOwned, Font, FontMatches}; +use crate::{Attrs, Font, FontMatches}; #[ouroboros::self_referencing] struct FontSystemInner { @@ -16,7 +16,7 @@ struct FontSystemInner { font_cache: Mutex>>>>, #[borrows(locale, db)] #[not_covariant] - font_matches_cache: Mutex>>>, + font_matches_cache: Mutex>>>, } /// Access system fonts @@ -122,45 +122,47 @@ impl FontSystem { self.0.with(|fields| get_font(&fields, id)) } - pub fn get_font_matches<'a>(&'a self, attrs: Attrs) -> Arc> { + pub fn get_font_matches(&self, attrs: impl AsRef + Into) -> Arc { self.0.with(|fields| { let mut font_matches_cache = fields .font_matches_cache .lock() .expect("failed to lock font matches cache"); - //TODO: do not create AttrsOwned unless entry does not already exist - font_matches_cache - .entry(AttrsOwned::new(attrs)) - .or_insert_with(|| { - #[cfg(not(target_arch = "wasm32"))] - let now = std::time::Instant::now(); - - let mut fonts = Vec::new(); - for face in fields.db.faces() { - if !attrs.matches(face) { - continue; - } - - if let Some(font) = get_font(&fields, face.id) { - fonts.push(font); - } + if let Some(matches) = font_matches_cache.get(attrs.as_ref()) { + matches.clone() + } else { + #[cfg(not(target_arch = "wasm32"))] + let now = std::time::Instant::now(); + + let mut fonts = Vec::new(); + for face in fields.db.faces() { + if !attrs.as_ref().matches(face) { + continue; } - let font_matches = Arc::new(FontMatches { - locale: fields.locale, - default_family: fields.db.family_name(&attrs.family).to_string(), - fonts, - }); - - #[cfg(not(target_arch = "wasm32"))] - { - let elapsed = now.elapsed(); - log::debug!("font matches for {:?} in {:?}", attrs, elapsed); + if let Some(font) = get_font(&fields, face.id) { + fonts.push(font); } + } - font_matches - }) - .clone() + let font_matches = Arc::new(FontMatches { + locale: fields.locale, + default_family: fields + .db + .family_name(&attrs.as_ref().family_owned.as_family()) + .to_string(), + fonts, + }); + + #[cfg(not(target_arch = "wasm32"))] + { + let elapsed = now.elapsed(); + log::debug!("font matches for {:?} in {:?}", attrs.as_ref(), elapsed); + } + + font_matches_cache.insert(attrs.into(), font_matches.clone()); + font_matches + } }) } } diff --git a/src/shape.rs b/src/shape.rs index 5904483aa6..99e3f0fb9c 100644 --- a/src/shape.rs +++ b/src/shape.rs @@ -302,7 +302,7 @@ impl ShapeWord { for (egc_i, _egc) in word.grapheme_indices(true) { let start_egc = word_range.start + egc_i; let attrs_egc = attrs_list.get_span(start_egc); - if !attrs.compatible(&attrs_egc) { + if !attrs.compatible(attrs_egc) { //TODO: more efficient glyphs.append(&mut shape_run( font_system,