Remove AttrsList lifetime bound
This commit is contained in:
parent
06cb0c2637
commit
ac354c3a2a
6 changed files with 114 additions and 44 deletions
|
|
@ -45,7 +45,7 @@ impl StyleSheet for Theme {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Text {
|
pub struct Text {
|
||||||
line: BufferLine<'static>,
|
line: BufferLine,
|
||||||
metrics: Metrics,
|
metrics: Metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
105
src/attrs.rs
105
src/attrs.rs
|
|
@ -51,6 +51,40 @@ impl Color {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
|
pub enum FamilyOwned {
|
||||||
|
Name(String),
|
||||||
|
Serif,
|
||||||
|
SansSerif,
|
||||||
|
Cursive,
|
||||||
|
Fantasy,
|
||||||
|
Monospace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FamilyOwned {
|
||||||
|
pub fn new(family: Family) -> Self {
|
||||||
|
match family {
|
||||||
|
Family::Name(name) => FamilyOwned::Name(name.to_string()),
|
||||||
|
Family::Serif => FamilyOwned::Serif,
|
||||||
|
Family::SansSerif => FamilyOwned::SansSerif,
|
||||||
|
Family::Cursive => FamilyOwned::Cursive,
|
||||||
|
Family::Fantasy => FamilyOwned::Fantasy,
|
||||||
|
Family::Monospace => FamilyOwned::Monospace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_family(&self) -> Family {
|
||||||
|
match self {
|
||||||
|
FamilyOwned::Name(name) => Family::Name(&name),
|
||||||
|
FamilyOwned::Serif => Family::Serif,
|
||||||
|
FamilyOwned::SansSerif => Family::SansSerif,
|
||||||
|
FamilyOwned::Cursive => Family::Cursive,
|
||||||
|
FamilyOwned::Fantasy => Family::Fantasy,
|
||||||
|
FamilyOwned::Monospace => Family::Monospace,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Text attributes
|
/// Text attributes
|
||||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||||
pub struct Attrs<'a> {
|
pub struct Attrs<'a> {
|
||||||
|
|
@ -136,30 +170,65 @@ impl<'a> Attrs<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
|
pub struct AttrsOwned {
|
||||||
|
//TODO: should this be an option?
|
||||||
|
pub color_opt: Option<Color>,
|
||||||
|
pub family_owned: FamilyOwned,
|
||||||
|
pub monospaced: bool,
|
||||||
|
pub stretch: Stretch,
|
||||||
|
pub style: Style,
|
||||||
|
pub weight: Weight,
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// List of text attributes to apply to a line
|
/// List of text attributes to apply to a line
|
||||||
//TODO: have this clean up the spans when changes are made
|
//TODO: have this clean up the spans when changes are made
|
||||||
#[derive(Eq, PartialEq)]
|
#[derive(Eq, PartialEq)]
|
||||||
pub struct AttrsList<'a> {
|
pub struct AttrsList {
|
||||||
defaults: Attrs<'a>,
|
defaults: AttrsOwned,
|
||||||
spans: Vec<(Range<usize>, Attrs<'a>)>,
|
spans: Vec<(Range<usize>, AttrsOwned)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AttrsList<'a> {
|
impl AttrsList {
|
||||||
/// Create a new attributes list with a set of default [Attrs]
|
/// Create a new attributes list with a set of default [Attrs]
|
||||||
pub fn new(defaults: Attrs<'a>) -> Self {
|
pub fn new(defaults: Attrs) -> Self {
|
||||||
Self {
|
Self {
|
||||||
defaults,
|
defaults: AttrsOwned::new(defaults),
|
||||||
spans: Vec::new(),
|
spans: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the default [Attrs]
|
/// Get the default [Attrs]
|
||||||
pub fn defaults(&self) -> Attrs<'a> {
|
pub fn defaults(&self) -> Attrs {
|
||||||
self.defaults
|
self.defaults.as_attrs()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current attribute spans
|
/// Get the current attribute spans
|
||||||
pub fn spans(&self) -> &Vec<(Range<usize>, Attrs<'a>)> {
|
pub fn spans(&self) -> &Vec<(Range<usize>, AttrsOwned)> {
|
||||||
&self.spans
|
&self.spans
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,7 +238,7 @@ impl<'a> AttrsList<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an attribute span, removes any previous matching parts of spans
|
/// Add an attribute span, removes any previous matching parts of spans
|
||||||
pub fn add_span(&mut self, range: Range<usize>, attrs: Attrs<'a>) {
|
pub fn add_span(&mut self, range: Range<usize>, attrs: Attrs) {
|
||||||
//do not support 1..1 even if by accident.
|
//do not support 1..1 even if by accident.
|
||||||
if range.start == range.end {
|
if range.start == range.end {
|
||||||
return;
|
return;
|
||||||
|
|
@ -191,7 +260,7 @@ impl<'a> AttrsList<'a> {
|
||||||
rework_spans.push((rework.0.start..range.start, rework.1))
|
rework_spans.push((rework.0.start..range.start, rework.1))
|
||||||
} else if self.spans[i].0.end > range.end && self.spans[i].0.start < range.start {
|
} else if self.spans[i].0.end > range.end && self.spans[i].0.start < range.start {
|
||||||
let rework = self.spans.remove(i);
|
let rework = self.spans.remove(i);
|
||||||
rework_spans.push((rework.0.start..range.start, rework.1));
|
rework_spans.push((rework.0.start..range.start, rework.1.clone()));
|
||||||
rework_spans.push((range.end..rework.0.end, rework.1));
|
rework_spans.push((range.end..rework.0.end, rework.1));
|
||||||
} else if self.spans[i].0.start > range.end {
|
} else if self.spans[i].0.start > range.end {
|
||||||
break;
|
break;
|
||||||
|
|
@ -208,7 +277,7 @@ impl<'a> AttrsList<'a> {
|
||||||
// Combine span if possible
|
// Combine span if possible
|
||||||
let mut combined = false;
|
let mut combined = false;
|
||||||
for span in self.spans.iter_mut() {
|
for span in self.spans.iter_mut() {
|
||||||
if span.1 != attrs {
|
if span.1.as_attrs() != attrs {
|
||||||
// Ignore not matching attrs
|
// Ignore not matching attrs
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -230,7 +299,7 @@ impl<'a> AttrsList<'a> {
|
||||||
|
|
||||||
if ! combined {
|
if ! combined {
|
||||||
//Finally lets add the new span. it should fit now.
|
//Finally lets add the new span. it should fit now.
|
||||||
self.spans.push((range, attrs));
|
self.spans.push((range, AttrsOwned::new(attrs)));
|
||||||
}
|
}
|
||||||
|
|
||||||
//sort by start to speed up further additions
|
//sort by start to speed up further additions
|
||||||
|
|
@ -240,18 +309,18 @@ impl<'a> AttrsList<'a> {
|
||||||
/// Get the highest priority attribute span for a range
|
/// Get the highest priority attribute span for a range
|
||||||
///
|
///
|
||||||
/// This returns the first span that contains the range
|
/// This returns the first span that contains the range
|
||||||
pub fn get_span(&self, range: Range<usize>) -> Attrs<'a> {
|
pub fn get_span(&self, range: Range<usize>) -> Attrs {
|
||||||
for span in self.spans.iter() {
|
for span in self.spans.iter() {
|
||||||
if range.start >= span.0.start && range.end <= span.0.end {
|
if range.start >= span.0.start && range.end <= span.0.end {
|
||||||
return span.1;
|
return span.1.as_attrs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.defaults
|
self.defaults.as_attrs()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Split attributes list at an offset
|
/// Split attributes list at an offset
|
||||||
pub fn split_off(&mut self, index: usize) -> Self {
|
pub fn split_off(&mut self, index: usize) -> Self {
|
||||||
let mut new = Self::new(self.defaults);
|
let mut new = Self::new(self.defaults.as_attrs());
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < self.spans.len() {
|
while i < self.spans.len() {
|
||||||
if self.spans[i].0.end <= index {
|
if self.spans[i].0.end <= index {
|
||||||
|
|
@ -268,7 +337,7 @@ impl<'a> AttrsList<'a> {
|
||||||
// New span has index..end
|
// New span has index..end
|
||||||
new.spans.push((
|
new.spans.push((
|
||||||
0..self.spans[i].0.end - index,
|
0..self.spans[i].0.end - index,
|
||||||
self.spans[i].1
|
self.spans[i].1.clone()
|
||||||
));
|
));
|
||||||
// Old span has start..index
|
// Old span has start..index
|
||||||
self.spans[i].0.end = index;
|
self.spans[i].0.end = index;
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ impl fmt::Display for Metrics {
|
||||||
pub struct Buffer<'a> {
|
pub struct Buffer<'a> {
|
||||||
font_system: &'a FontSystem<'a>,
|
font_system: &'a FontSystem<'a>,
|
||||||
/// Lines (or paragraphs) of text in the buffer
|
/// Lines (or paragraphs) of text in the buffer
|
||||||
pub lines: Vec<BufferLine<'a>>,
|
pub lines: Vec<BufferLine>,
|
||||||
metrics: Metrics,
|
metrics: Metrics,
|
||||||
width: i32,
|
width: i32,
|
||||||
height: i32,
|
height: i32,
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,20 @@
|
||||||
use crate::{AttrsList, FontSystem, LayoutLine, ShapeLine};
|
use crate::{AttrsList, FontSystem, LayoutLine, ShapeLine};
|
||||||
|
|
||||||
/// A line (or paragraph) of text that is shaped and laid out
|
/// A line (or paragraph) of text that is shaped and laid out
|
||||||
pub struct BufferLine<'a> {
|
pub struct BufferLine {
|
||||||
//TODO: make this not pub(crate)
|
//TODO: make this not pub(crate)
|
||||||
text: String,
|
text: String,
|
||||||
attrs_list: AttrsList<'a>,
|
attrs_list: AttrsList,
|
||||||
wrap_simple: bool,
|
wrap_simple: bool,
|
||||||
shape_opt: Option<ShapeLine>,
|
shape_opt: Option<ShapeLine>,
|
||||||
layout_opt: Option<Vec<LayoutLine>>,
|
layout_opt: Option<Vec<LayoutLine>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BufferLine<'a> {
|
impl BufferLine {
|
||||||
/// Create a new line with the given text and attributes list
|
/// Create a new line with the given text and attributes list
|
||||||
/// Cached shaping and layout can be done using the [Self::shape] and
|
/// Cached shaping and layout can be done using the [Self::shape] and
|
||||||
/// [Self::layout] functions
|
/// [Self::layout] functions
|
||||||
pub fn new<T: Into<String>>(text: T, attrs_list: AttrsList<'a>) -> Self {
|
pub fn new<T: Into<String>>(text: T, attrs_list: AttrsList) -> Self {
|
||||||
Self {
|
Self {
|
||||||
text: text.into(),
|
text: text.into(),
|
||||||
attrs_list,
|
attrs_list,
|
||||||
|
|
@ -33,7 +33,7 @@ impl<'a> BufferLine<'a> {
|
||||||
///
|
///
|
||||||
/// Will reset shape and layout if it differs from current text and attributes list.
|
/// Will reset shape and layout if it differs from current text and attributes list.
|
||||||
/// Returns true if the line was reset
|
/// Returns true if the line was reset
|
||||||
pub fn set_text<T: AsRef<str> + Into<String>>(&mut self, text: T, attrs_list: AttrsList<'a>) -> bool {
|
pub fn set_text<T: AsRef<str> + Into<String>>(&mut self, text: T, attrs_list: AttrsList) -> bool {
|
||||||
if text.as_ref() != &self.text || attrs_list != self.attrs_list {
|
if text.as_ref() != &self.text || attrs_list != self.attrs_list {
|
||||||
self.text = text.into();
|
self.text = text.into();
|
||||||
self.attrs_list = attrs_list;
|
self.attrs_list = attrs_list;
|
||||||
|
|
@ -45,7 +45,7 @@ impl<'a> BufferLine<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get attributes list
|
/// Get attributes list
|
||||||
pub fn attrs_list(&self) -> &AttrsList<'a> {
|
pub fn attrs_list(&self) -> &AttrsList {
|
||||||
&self.attrs_list
|
&self.attrs_list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ impl<'a> BufferLine<'a> {
|
||||||
///
|
///
|
||||||
/// Will reset shape and layout if it differs from current attributes list.
|
/// Will reset shape and layout if it differs from current attributes list.
|
||||||
/// Returns true if the line was reset
|
/// Returns true if the line was reset
|
||||||
pub fn set_attrs_list(&mut self, attrs_list: AttrsList<'a>) -> bool {
|
pub fn set_attrs_list(&mut self, attrs_list: AttrsList) -> bool {
|
||||||
if attrs_list != self.attrs_list {
|
if attrs_list != self.attrs_list {
|
||||||
self.attrs_list = attrs_list;
|
self.attrs_list = attrs_list;
|
||||||
self.reset();
|
self.reset();
|
||||||
|
|
@ -97,7 +97,7 @@ impl<'a> BufferLine<'a> {
|
||||||
for (other_range, attrs) in other.attrs_list.spans() {
|
for (other_range, attrs) in other.attrs_list.spans() {
|
||||||
// Add previous attrs spans
|
// Add previous attrs spans
|
||||||
let range = other_range.start + len..other_range.end + len;
|
let range = other_range.start + len..other_range.end + len;
|
||||||
self.attrs_list.add_span(range, *attrs);
|
self.attrs_list.add_span(range, attrs.as_attrs());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.reset();
|
self.reset();
|
||||||
|
|
@ -132,7 +132,7 @@ impl<'a> BufferLine<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shape line, will cache results
|
/// Shape line, will cache results
|
||||||
pub fn shape(&mut self, font_system: &'a FontSystem<'a>) -> &ShapeLine {
|
pub fn shape<'a>(&mut self, font_system: &'a FontSystem<'a>) -> &ShapeLine {
|
||||||
if self.shape_opt.is_none() {
|
if self.shape_opt.is_none() {
|
||||||
self.shape_opt = Some(ShapeLine::new(font_system, &self.text, &self.attrs_list));
|
self.shape_opt = Some(ShapeLine::new(font_system, &self.text, &self.attrs_list));
|
||||||
self.layout_opt = None;
|
self.layout_opt = None;
|
||||||
|
|
@ -146,7 +146,7 @@ impl<'a> BufferLine<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Layout line, will cache results
|
/// Layout line, will cache results
|
||||||
pub fn layout(&mut self, font_system: &'a FontSystem<'a>, font_size: i32, width: i32) -> &[LayoutLine] {
|
pub fn layout<'a>(&mut self, font_system: &'a FontSystem<'a>, font_size: i32, width: i32) -> &[LayoutLine] {
|
||||||
if self.layout_opt.is_none() {
|
if self.layout_opt.is_none() {
|
||||||
let wrap_simple = self.wrap_simple;
|
let wrap_simple = self.wrap_simple;
|
||||||
let shape = self.shape(font_system);
|
let shape = self.shape(font_system);
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{Attrs, Font, FontMatches};
|
use crate::{Attrs, AttrsOwned, Font, FontMatches};
|
||||||
|
|
||||||
/// Access system fonts
|
/// Access system fonts
|
||||||
pub struct FontSystem<'a> {
|
pub struct FontSystem<'a> {
|
||||||
pub locale: String,
|
pub locale: String,
|
||||||
pub db: fontdb::Database,
|
pub db: fontdb::Database,
|
||||||
pub font_cache: Mutex<HashMap<fontdb::ID, Option<Arc<Font<'a>>>>>,
|
pub font_cache: Mutex<HashMap<fontdb::ID, Option<Arc<Font<'a>>>>>,
|
||||||
pub font_matches_cache: Mutex<HashMap<Attrs<'a>, Arc<FontMatches<'a>>>>,
|
pub font_matches_cache: Mutex<HashMap<AttrsOwned, Arc<FontMatches<'a>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FontSystem<'a> {
|
impl<'a> FontSystem<'a> {
|
||||||
|
|
@ -79,9 +79,10 @@ impl<'a> FontSystem<'a> {
|
||||||
}).clone()
|
}).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_font_matches(&'a self, attrs: Attrs<'a>) -> Arc<FontMatches<'a>> {
|
pub fn get_font_matches(&'a self, attrs: Attrs) -> Arc<FontMatches<'a>> {
|
||||||
let mut font_matches_cache = self.font_matches_cache.lock().unwrap();
|
let mut font_matches_cache = self.font_matches_cache.lock().unwrap();
|
||||||
font_matches_cache.entry(attrs).or_insert_with(|| {
|
//TODO: do not create AttrsOwned unless entry does not already exist
|
||||||
|
font_matches_cache.entry(AttrsOwned::new(attrs)).or_insert_with(|| {
|
||||||
let now = std::time::Instant::now();
|
let now = std::time::Instant::now();
|
||||||
|
|
||||||
let mut fonts = Vec::new();
|
let mut fonts = Vec::new();
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,7 @@ fn shape_fallback(
|
||||||
fn shape_run<'a>(
|
fn shape_run<'a>(
|
||||||
font_system: &'a FontSystem<'a>,
|
font_system: &'a FontSystem<'a>,
|
||||||
line: &str,
|
line: &str,
|
||||||
attrs_list: &AttrsList<'a>,
|
attrs_list: &AttrsList,
|
||||||
start_run: usize,
|
start_run: usize,
|
||||||
end_run: usize,
|
end_run: usize,
|
||||||
span_rtl: bool,
|
span_rtl: bool,
|
||||||
|
|
@ -283,7 +283,7 @@ impl ShapeWord {
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(
|
||||||
font_system: &'a FontSystem<'a>,
|
font_system: &'a FontSystem<'a>,
|
||||||
line: &str,
|
line: &str,
|
||||||
attrs_list: &AttrsList<'a>,
|
attrs_list: &AttrsList,
|
||||||
start_word: usize,
|
start_word: usize,
|
||||||
end_word: usize,
|
end_word: usize,
|
||||||
span_rtl: bool,
|
span_rtl: bool,
|
||||||
|
|
@ -346,7 +346,7 @@ impl ShapeSpan {
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(
|
||||||
font_system: &'a FontSystem<'a>,
|
font_system: &'a FontSystem<'a>,
|
||||||
line: &str,
|
line: &str,
|
||||||
attrs_list: &AttrsList<'a>,
|
attrs_list: &AttrsList,
|
||||||
start_span: usize,
|
start_span: usize,
|
||||||
end_span: usize,
|
end_span: usize,
|
||||||
line_rtl: bool,
|
line_rtl: bool,
|
||||||
|
|
@ -426,7 +426,7 @@ impl ShapeLine {
|
||||||
pub fn new<'a>(
|
pub fn new<'a>(
|
||||||
font_system: &'a FontSystem<'a>,
|
font_system: &'a FontSystem<'a>,
|
||||||
line: &str,
|
line: &str,
|
||||||
attrs_list: &AttrsList<'a>
|
attrs_list: &AttrsList
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut spans = Vec::new();
|
let mut spans = Vec::new();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue