Add width field to Span and IndexedSpan

This commit is contained in:
Alexandre Bury 2019-03-20 16:48:48 -07:00
parent 57f9b05d64
commit c9dc371223
5 changed files with 34 additions and 22 deletions

View File

@ -102,7 +102,7 @@ impl<'a, 'b> Printer<'a, 'b> {
for span in text.spans() { for span in text.spans() {
self.with_style(*span.attr, |printer| { self.with_style(*span.attr, |printer| {
printer.print((x, y), span.content); printer.print((x, y), span.content);
x += span.content.width(); x += span.width;
}); });
} }
} }
@ -135,10 +135,10 @@ impl<'a, 'b> Printer<'a, 'b> {
if hidden_part.x > text_width { if hidden_part.x > text_width {
return; return;
} }
let mut text = text; let mut text = text;
let mut start = start; let mut start = start;
if hidden_part.x > 0 { if hidden_part.x > 0 {
// We have to drop hidden_part.x width from the start of the string. // We have to drop hidden_part.x width from the start of the string.
// prefix() may be too short if there's a double-width character. // prefix() may be too short if there's a double-width character.
@ -161,7 +161,7 @@ impl<'a, 'b> Printer<'a, 'b> {
start = start + (skipped_width, 0); start = start + (skipped_width, 0);
text_width -= skipped_width; text_width -= skipped_width;
} }
assert!(start.fits(self.content_offset)); assert!(start.fits(self.content_offset));
// What we did before should guarantee that this won't overflow. // What we did before should guarantee that this won't overflow.

View File

@ -20,7 +20,7 @@ struct DummySpannedText<'a> {
impl<'a> DummySpannedText<'a> { impl<'a> DummySpannedText<'a> {
fn new(content: &'a str) -> Self { fn new(content: &'a str) -> Self {
let attrs = vec![IndexedSpan::simple(content, ())]; let attrs = vec![IndexedSpan::simple_borrowed(content, ())];
DummySpannedText { content, attrs } DummySpannedText { content, attrs }
} }
} }

View File

@ -26,6 +26,7 @@ impl Segment {
Span { Span {
content, content,
attr: &span.attr, attr: &span.attr,
width: self.width,
} }
} }

View File

@ -2,13 +2,13 @@
//! //!
//! Needs the `markdown` feature to be enabled. //! Needs the `markdown` feature to be enabled.
use pulldown_cmark;
use self::pulldown_cmark::{Event, Tag};
use crate::theme::{Effect, Style}; use crate::theme::{Effect, Style};
use crate::utils::markup::{StyledIndexedSpan, StyledString}; use crate::utils::markup::{StyledIndexedSpan, StyledString};
use crate::utils::span::IndexedCow; use crate::utils::span::IndexedCow;
use pulldown_cmark::{self, Event, Tag};
use unicode_width::UnicodeWidthStr;
/// Parses the given string as markdown text. /// Parses the given string as markdown text.
pub fn parse<S>(input: S) -> StyledString pub fn parse<S>(input: S) -> StyledString
where where
@ -45,10 +45,7 @@ impl<'a> Parser<'a> {
where where
S: Into<String>, S: Into<String>,
{ {
StyledIndexedSpan { StyledIndexedSpan::simple_owned(text.into(), Style::merge(&self.stack))
content: IndexedCow::Owned(text.into()),
attr: Style::merge(&self.stack),
}
} }
} }
@ -110,10 +107,12 @@ impl<'a> Iterator for Parser<'a> {
| Event::InlineHtml(text) | Event::InlineHtml(text)
| Event::Html(text) | Event::Html(text)
| Event::Text(text) => { | Event::Text(text) => {
let width = text.width();
// Return something! // Return something!
return Some(StyledIndexedSpan { return Some(StyledIndexedSpan {
content: IndexedCow::from_cow(text, self.input), content: IndexedCow::from_cow(text, self.input),
attr: Style::merge(&self.stack), attr: Style::merge(&self.stack),
width,
}); });
} }
} }

View File

@ -193,13 +193,7 @@ impl<T> SpannedString<T> {
{ {
let source = source.into(); let source = source.into();
let spans = vec![IndexedSpan { let spans = vec![IndexedSpan::simple_borrowed(&source, attr)];
content: IndexedCow::Borrowed {
start: 0,
end: source.len(),
},
attr,
}];
Self::with_spans(source, spans) Self::with_spans(source, spans)
} }
@ -256,7 +250,7 @@ impl<T> SpannedString<T> {
/// ///
/// This is the sum of the width of each span. /// This is the sum of the width of each span.
pub fn width(&self) -> usize { pub fn width(&self) -> usize {
self.spans().map(|s| s.content.width()).sum() self.spans().map(|s| s.width).sum()
} }
} }
@ -274,6 +268,9 @@ pub struct IndexedSpan<T> {
/// Attribute applied to the span. /// Attribute applied to the span.
pub attr: T, pub attr: T,
/// Width of the text for this span.
pub width: usize,
} }
impl<T> AsRef<IndexedCow> for IndexedSpan<T> { impl<T> AsRef<IndexedCow> for IndexedSpan<T> {
@ -290,6 +287,9 @@ pub struct Span<'a, T> {
/// Attribute associated to this span. /// Attribute associated to this span.
pub attr: &'a T, pub attr: &'a T,
/// Width of the text for this span.
pub width: usize,
} }
impl<T> IndexedSpan<T> { impl<T> IndexedSpan<T> {
@ -301,6 +301,7 @@ impl<T> IndexedSpan<T> {
Span { Span {
content: self.content.resolve(source), content: self.content.resolve(source),
attr: &self.attr, attr: &self.attr,
width: self.width,
} }
} }
@ -309,14 +310,25 @@ impl<T> IndexedSpan<T> {
self.content.is_empty() self.content.is_empty()
} }
/// Returns a single span around the entire text. /// Returns a single indexed span around the entire text.
pub fn simple(content: &str, attr: T) -> Self { pub fn simple_borrowed(content: &str, attr: T) -> Self {
IndexedSpan { IndexedSpan {
content: IndexedCow::Borrowed { content: IndexedCow::Borrowed {
start: 0, start: 0,
end: content.len(), end: content.len(),
}, },
attr, attr,
width: content.width(),
}
}
/// Returns a single owned indexed span around the entire text.
pub fn simple_owned(content: String, attr: T) -> Self {
let width = content.width();
IndexedSpan {
content: IndexedCow::Owned(content),
attr,
width,
} }
} }
} }