mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Use spans::LinesIterator from simple::LinesIterator
This commit is contained in:
parent
0ff08f3a9f
commit
2760e92ce6
@ -1,16 +1,16 @@
|
|||||||
use super::{prefix, Row};
|
use super::{prefix, Row};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
use utils::lines::spans;
|
||||||
|
use utils::span::{IndexedSpan, SpannedText};
|
||||||
|
|
||||||
/// Generates rows of text in constrained width.
|
/// Generates rows of text in constrained width.
|
||||||
///
|
///
|
||||||
/// Given a long text and a width constraint, it iterates over
|
/// Given a long text and a width constraint, it iterates over
|
||||||
/// substrings of the text, each within the constraint.
|
/// substrings of the text, each within the constraint.
|
||||||
pub struct LinesIterator<'a> {
|
pub struct LinesIterator<'a> {
|
||||||
/// Content to iterate on.
|
iter: spans::LinesIterator<DummySpannedText<'a>>,
|
||||||
content: &'a str,
|
|
||||||
/// Current offset in the content.
|
|
||||||
offset: usize,
|
|
||||||
/// Available width. Don't output lines wider than that.
|
/// Available width. Don't output lines wider than that.
|
||||||
width: usize,
|
width: usize,
|
||||||
|
|
||||||
@ -19,16 +19,42 @@ pub struct LinesIterator<'a> {
|
|||||||
show_spaces: bool,
|
show_spaces: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DummySpannedText<'a> {
|
||||||
|
content: &'a str,
|
||||||
|
attrs: Vec<IndexedSpan<()>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> DummySpannedText<'a> {
|
||||||
|
fn new(content: &'a str) -> Self {
|
||||||
|
let attrs = vec![IndexedSpan::simple(content, ())];
|
||||||
|
DummySpannedText { content, attrs }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SpannedText for DummySpannedText<'a> {
|
||||||
|
type S = IndexedSpan<()>;
|
||||||
|
|
||||||
|
fn source(&self) -> &str {
|
||||||
|
self.content
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spans(&self) -> &[IndexedSpan<()>] {
|
||||||
|
&self.attrs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> LinesIterator<'a> {
|
impl<'a> LinesIterator<'a> {
|
||||||
/// Returns a new `LinesIterator` on `content`.
|
/// Returns a new `LinesIterator` on `content`.
|
||||||
///
|
///
|
||||||
/// Yields rows of `width` cells or less.
|
/// Yields rows of `width` cells or less.
|
||||||
pub fn new(content: &'a str, width: usize) -> Self {
|
pub fn new(content: &'a str, width: usize) -> Self {
|
||||||
|
let iter =
|
||||||
|
spans::LinesIterator::new(DummySpannedText::new(content), width);
|
||||||
|
let show_spaces = false;
|
||||||
LinesIterator {
|
LinesIterator {
|
||||||
content,
|
iter,
|
||||||
width,
|
width,
|
||||||
offset: 0,
|
show_spaces,
|
||||||
show_spaces: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,70 +72,13 @@ impl<'a> Iterator for LinesIterator<'a> {
|
|||||||
type Item = Row;
|
type Item = Row;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Row> {
|
fn next(&mut self) -> Option<Row> {
|
||||||
if self.offset >= self.content.len() {
|
let row = self.iter.next()?;
|
||||||
// This is the end.
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We start at the current offset.
|
let start = row.segments.first()?.start;
|
||||||
let start = self.offset;
|
let end = row.segments.last()?.end;
|
||||||
let content = &self.content[start..];
|
|
||||||
|
|
||||||
// Find the ideal line, in an infinitely wide world.
|
let width = row.width;
|
||||||
// We'll make a line larger than that.
|
|
||||||
let next = content.find('\n').unwrap_or_else(|| content.len());
|
|
||||||
let content = &content[..next];
|
|
||||||
|
|
||||||
let allowed_width = if self.show_spaces {
|
Some(Row { start, end, width })
|
||||||
// Remove 1 from the available space, if possible.
|
|
||||||
self.width.saturating_sub(1)
|
|
||||||
} else {
|
|
||||||
self.width
|
|
||||||
};
|
|
||||||
|
|
||||||
let line_width = content.width();
|
|
||||||
if line_width <= allowed_width {
|
|
||||||
// We found a newline before the allowed limit.
|
|
||||||
// Break early.
|
|
||||||
// Advance the cursor to after the newline.
|
|
||||||
self.offset += next + 1;
|
|
||||||
return Some(Row {
|
|
||||||
start: start,
|
|
||||||
end: start + next,
|
|
||||||
width: line_width,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// First attempt: only break on spaces.
|
|
||||||
let prefix_length =
|
|
||||||
match prefix(content.split(' '), allowed_width, " ").length {
|
|
||||||
// If this fail, fallback: only break on graphemes.
|
|
||||||
// There's no whitespace to skip there.
|
|
||||||
// And don't reserve the white space anymore.
|
|
||||||
0 => prefix(content.graphemes(true), self.width, "").length,
|
|
||||||
other => {
|
|
||||||
// If it works, advance the cursor by 1
|
|
||||||
// to jump the whitespace.
|
|
||||||
// We don't want to add 1 to `prefix_length` though, it
|
|
||||||
// would include the whitespace in the row.
|
|
||||||
self.offset += 1;
|
|
||||||
other
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if prefix_length == 0 {
|
|
||||||
// This mean we can't even get a single char?
|
|
||||||
// Sucks. Let's bail.
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advance the offset to the end of the line.
|
|
||||||
self.offset += prefix_length;
|
|
||||||
|
|
||||||
Some(Row {
|
|
||||||
start: start,
|
|
||||||
end: start + prefix_length,
|
|
||||||
width: self.width,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ impl Row {
|
|||||||
where
|
where
|
||||||
S: AsRef<IndexedCow>,
|
S: AsRef<IndexedCow>,
|
||||||
{
|
{
|
||||||
let (start, _) = self.segments.get(0)?.source_indices(spans)?;
|
let (start, _) = self.segments.first()?.source_indices(spans)?;
|
||||||
let (_, end) = self.segments.last()?.source_indices(spans)?;
|
let (_, end) = self.segments.last()?.source_indices(spans)?;
|
||||||
|
|
||||||
Some((start, end))
|
Some((start, end))
|
||||||
|
Loading…
Reference in New Issue
Block a user