mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Implement From<Effect> and From<ColorStyle> for Style
This commit is contained in:
parent
67e230e246
commit
1acde148be
44
src/theme.rs
44
src/theme.rs
@ -120,6 +120,50 @@ use std::io::Read;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use toml;
|
use toml;
|
||||||
|
|
||||||
|
/// Combine a color and an effect.
|
||||||
|
///
|
||||||
|
/// Represents any transformation that can be applied to text.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Style {
|
||||||
|
/// Effect to apply.
|
||||||
|
///
|
||||||
|
/// `None` to keep using previous effects.
|
||||||
|
pub effect: Option<Effect>,
|
||||||
|
|
||||||
|
/// Color style to apply.
|
||||||
|
///
|
||||||
|
/// `None` to keep using the previous colors.
|
||||||
|
pub color: Option<ColorStyle>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Style {
|
||||||
|
/// Returns a new `Style` that doesn't apply anything.
|
||||||
|
pub fn none() -> Self {
|
||||||
|
Style {
|
||||||
|
effect: None,
|
||||||
|
color: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Effect> for Style {
|
||||||
|
fn from(effect: Effect) -> Self {
|
||||||
|
Style {
|
||||||
|
effect: Some(effect),
|
||||||
|
color: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ColorStyle> for Style {
|
||||||
|
fn from(color: ColorStyle) -> Self {
|
||||||
|
Style {
|
||||||
|
effect: None,
|
||||||
|
color: Some(color),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Text effect
|
/// Text effect
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum Effect {
|
pub enum Effect {
|
||||||
|
150
src/utils/span_lines_iterator.rs
Normal file
150
src/utils/span_lines_iterator.rs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
use std::borrow::Cow;
|
||||||
|
use theme::Style;
|
||||||
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
use xi_unicode::LineBreakLeafIter;
|
||||||
|
|
||||||
|
pub struct Span<'a> {
|
||||||
|
text: Cow<'a, str>,
|
||||||
|
width: usize,
|
||||||
|
style: Style,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Row<'a> {
|
||||||
|
spans: Vec<Span<'a>>,
|
||||||
|
width: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct SpanLinesIterator<'a: 'b, 'b> {
|
||||||
|
/// Input that we want to split
|
||||||
|
content: &'b [Span<'a>],
|
||||||
|
|
||||||
|
/// Available width
|
||||||
|
width: usize,
|
||||||
|
|
||||||
|
current_span: usize,
|
||||||
|
offset: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a: 'b, 'b> SpanLinesIterator<'a, 'b> {
|
||||||
|
pub fn new(content: &'b [Span<'a>], width: usize) -> Self {
|
||||||
|
SpanLinesIterator {
|
||||||
|
content,
|
||||||
|
width,
|
||||||
|
current_span: 0,
|
||||||
|
offset: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intermediate representation of a Span, easier to manipulate.
|
||||||
|
struct Segment {
|
||||||
|
span_id: usize,
|
||||||
|
start: usize,
|
||||||
|
end: usize,
|
||||||
|
width: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> Iterator for SpanLinesIterator<'a, 'b> {
|
||||||
|
type Item = Row<'a>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Row<'a>> {
|
||||||
|
if self.current_span >= self.content.len() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_span = &self.content[self.current_span];
|
||||||
|
|
||||||
|
let mut available = self.width;
|
||||||
|
let mut iter = LineBreakLeafIter::new(¤t_span.text, self.offset);
|
||||||
|
|
||||||
|
let mut spans = Vec::new();
|
||||||
|
let mut width = 0;
|
||||||
|
|
||||||
|
// We'll build a list of segments.
|
||||||
|
// There will be a 1-for-1 mapping from segments to spans.
|
||||||
|
// But segments are easier to manipulate and extend for now.
|
||||||
|
let mut segments: Vec<Segment> = Vec::new();
|
||||||
|
|
||||||
|
// When a span does not end on a possible break, its last segment
|
||||||
|
// can only be included depending on what comes after.
|
||||||
|
// So we keep a list of consecutive segments ids without breaks.
|
||||||
|
let mut carry_over: Vec<usize> = Vec::new();
|
||||||
|
// Whenever a segment is accepted, all of these can be inserted too.
|
||||||
|
|
||||||
|
'outer: for (span_id, span) in
|
||||||
|
self.content.iter().enumerate().skip(self.current_span)
|
||||||
|
{
|
||||||
|
// Make a new segment!
|
||||||
|
loop {
|
||||||
|
// Get the next possible break point.
|
||||||
|
let (pos, hard) = iter.next(&span.text);
|
||||||
|
|
||||||
|
// Lookup the corresponding text segment.
|
||||||
|
let segment = &span.text[self.offset..pos];
|
||||||
|
let width = segment.width();
|
||||||
|
|
||||||
|
// If it doesn't fit, it's time to go home.
|
||||||
|
if width > available {
|
||||||
|
// Early return!
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
|
||||||
|
available -= width;
|
||||||
|
|
||||||
|
// It fits, but... for real?
|
||||||
|
if pos == span.text.len() {
|
||||||
|
// It was too good to be true!
|
||||||
|
// It's just the end of a span, not an actual break.
|
||||||
|
// So save this stub for now, and move on to the next span.
|
||||||
|
carry_over.push(span_id);
|
||||||
|
// Start on the next span.
|
||||||
|
self.offset = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We got it! We got a chunk!
|
||||||
|
// First, append any carry-over segment
|
||||||
|
for carry in carry_over.drain(..) {
|
||||||
|
// We need to include this entire segment.
|
||||||
|
if segments.last().map(|s| s.span_id) == Some(carry) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
segments.push(Segment {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Include the present segment.
|
||||||
|
if pos != 0 {
|
||||||
|
segments.push(Segment {
|
||||||
|
span_id,
|
||||||
|
width,
|
||||||
|
start: self.offset,
|
||||||
|
end: pos,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.offset = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if hard {
|
||||||
|
// Stop here.
|
||||||
|
break 'outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let current_span = &self.content[self.current_span];
|
||||||
|
let (pos, hard) = iter.next(¤t_span.text);
|
||||||
|
|
||||||
|
// This is what we consider adding
|
||||||
|
let text = ¤t_span.text[self.offset..pos];
|
||||||
|
|
||||||
|
if hard {
|
||||||
|
// Stop there!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Some(Row { spans, width })
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user