Misc. hacks

This commit is contained in:
FliegendeWurst 2022-06-20 15:42:27 +02:00
parent 8ec46107e1
commit 924684215a
11 changed files with 100 additions and 18 deletions

View File

@ -31,6 +31,10 @@ use unicode_width::UnicodeWidthStr;
/// [1]: ../struct.Cursive.html#method.new
/// [`Event`]: ../event/enum.Event.html
pub trait Backend {
/// .
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
panic!()
}
/// Polls the backend for any input.
///
/// Should return immediately:

View File

@ -13,7 +13,8 @@ const INPUT_POLL_DELAY_MS: u64 = 30;
/// The `C` type is usually either `Cursive` or `&mut Cursive`.
pub struct CursiveRunner<C> {
siv: C,
backend: Box<dyn backend::Backend>,
/// .
pub backend: Box<dyn backend::Backend>,
boring_frame_count: u32,
// Last layer sizes of the stack view.
// If it changed, clear the screen.

View File

@ -68,6 +68,7 @@ pub use self::cursive_run::CursiveRunner;
pub use self::dump::Dump;
pub use self::printer::Printer;
pub use self::rect::Rect;
pub use self::utils::lines::spans::WrapMethod;
pub use self::vec::Vec2;
pub use self::view::View;
pub use self::with::With;

View File

@ -1,3 +1,4 @@
use super::WrapMethod;
use super::chunk::Chunk;
use super::segment::Segment;
use crate::utils::span::SpannedText;
@ -18,15 +19,18 @@ pub struct ChunkIterator<S> {
/// How much of the current span has been processed already.
offset: usize,
wrap_method: WrapMethod,
}
impl<S> ChunkIterator<S> {
/// Creates a new ChunkIterator on the given styled string.
pub fn new(source: Rc<S>) -> Self {
pub fn new(source: Rc<S>, wrap_method: WrapMethod) -> Self {
ChunkIterator {
source,
current_span: 0,
offset: 0,
wrap_method,
}
}
}
@ -63,7 +67,9 @@ where
let mut segments: Vec<Segment> = Vec::new();
// We'll use an iterator from xi-unicode to detect possible breaks.
let mut iter = LineBreakLeafIter::new(span_text, self.offset);
let mut iter = if self.wrap_method == WrapMethod::XiUnicode {
Some(LineBreakLeafIter::new(span_text, self.offset))
} else { None };
// When we reach the end of a span, xi-unicode returns a break, but it
// actually depends on the next span. Such breaks are "fake" breaks.
@ -77,7 +83,14 @@ where
// Look at next possible break
// `hard_stop = true` means that the break is non-optional,
// like after a `\n`.
let (pos, hard_stop) = iter.next(span_text);
let (pos, mut hard_stop) = if let Some(iter) = iter.as_mut() {
iter.next(span_text)
} else {
span_text[self.offset..].find('\n').map(|x| (x + self.offset + 1, true)).unwrap_or((span_text.len(), false))
};
if pos == span_text.len() && iter.is_none() {
hard_stop = false;
}
// When xi-unicode reaches the end of a span, it returns a "fake"
// break. To know if it's actually a true break, we need to give

View File

@ -10,6 +10,19 @@ use std::rc::Rc;
use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr;
// TODO docs
#[derive(Clone, Copy, PartialEq, Eq)]
/// Wrapping method
pub enum WrapMethod {
/// Default wrapping method based on xi-unicode.
XiUnicode,
/// Wrap when row width is exceeded
Newlines,
/// Do not wrap
Dont
}
/// Generates rows of text in constrainted width.
///
/// Works on spans of text.
@ -41,7 +54,7 @@ where
let source = Rc::new(source);
let chunk_source = source.clone();
LinesIterator {
iter: ChunkIterator::new(chunk_source).peekable(),
iter: ChunkIterator::new(chunk_source, WrapMethod::XiUnicode).peekable(),
source,
width,
chunk_offset: ChunkPart::default(),
@ -49,6 +62,12 @@ where
}
}
/// Set the wrapping method. Resets the iterator position.
pub fn with_method(mut self, wrap_method: WrapMethod) -> Self {
self.iter = ChunkIterator::new(self.source.clone(), wrap_method).peekable();
self
}
/// Leave a blank cell at the end of lines.
///
/// Unless a word had to be truncated, in which case

View File

@ -15,6 +15,6 @@ mod segment_merge_iterator;
#[cfg(test)]
mod tests;
pub use self::lines_iterator::LinesIterator;
pub use self::lines_iterator::{LinesIterator, WrapMethod};
pub use self::row::Row;
pub use self::segment::Segment;

View File

@ -1,4 +1,4 @@
use crate::view::View;
use crate::{cursive, view::View};
use std::any::Any;
/// A view that can be downcasted to its concrete type.

View File

@ -227,7 +227,7 @@ impl Core {
self.last_available = last_size.saturating_sub(
scrolling
.swap()
.select_or(self.scrollbar_padding + (1, 1), Vec2::zero()),
.select_or(if self.show_scrollbars { self.scrollbar_padding + (1, 1) } else { Vec2::zero() }, Vec2::zero()),
);
}
@ -523,7 +523,7 @@ impl Core {
}
/// Clears the cache.
fn invalidate_cache(&mut self) {
pub(crate) fn invalidate_cache(&mut self) {
self.size_cache = None;
}
@ -544,6 +544,9 @@ impl Core {
///
/// The scrollbar_size().x will be the horizontal space taken by the vertical scrollbar.
pub fn scrollbar_size(&self) -> Vec2 {
if !self.show_scrollbars {
return Vec2::zero();
}
self.is_scrolling()
.swap()
.select_or(self.scrollbar_padding + (1, 1), Vec2::zero())

View File

@ -99,6 +99,14 @@ impl<V> ScrollView<V> {
///
/// Defaults to `true`.
pub fn set_show_scrollbars(&mut self, show_scrollbars: bool) {
/*
let mut xy = self.core.inner_size();
if show_scrollbars {
xy.x -= 2;
} else {
xy.x += 2;
}
self.core.set_inner_size(xy);*/
self.core.set_show_scrollbars(show_scrollbars);
}

View File

@ -7,7 +7,7 @@ use unicode_width::UnicodeWidthStr;
use crate::align::*;
use crate::theme::{Effect, Style};
use crate::utils::lines::spans::{LinesIterator, Row};
use crate::utils::lines::spans::{LinesIterator, Row, WrapMethod};
use crate::utils::markup::StyledString;
use crate::view::{SizeCache, View};
use crate::{Printer, Vec2, With, XY};
@ -197,8 +197,7 @@ pub struct TextView {
style: Style,
// True if we can wrap long lines.
wrap: bool,
wrap: WrapMethod,
// ScrollBase make many scrolling-related things easier
last_size: Vec2,
@ -235,7 +234,7 @@ impl TextView {
content,
style: Style::default(),
rows: Vec::new(),
wrap: true,
wrap: WrapMethod::XiUnicode,
align: Align::top_left(),
last_size: Vec2::zero(),
width: None,
@ -284,7 +283,16 @@ impl TextView {
///
/// If `true` (the default), text will wrap long lines when needed.
pub fn set_content_wrap(&mut self, wrap: bool) {
self.wrap = wrap;
if wrap {
self.wrap = WrapMethod::XiUnicode;
} else {
self.wrap = WrapMethod::Dont;
}
}
/// TODO docs
pub fn set_wrap_method(&mut self, method: WrapMethod) {
self.wrap = method;
}
/// Sets the horizontal alignment for this view.
@ -357,7 +365,8 @@ impl TextView {
// This must be non-destructive, as it may be called
// multiple times during layout.
fn compute_rows(&mut self, size: Vec2) {
let size = if self.wrap { size } else { Vec2::max_value() };
eprintln!("computing rows with {:?}!", size);
let size = if self.wrap != WrapMethod::Dont { size } else { Vec2::max_value() };
let mut content = self.content.content.lock().unwrap();
if content.is_cache_valid(size) {
@ -375,7 +384,7 @@ impl TextView {
}
self.rows =
LinesIterator::new(content.get_cache().as_ref(), size.x).collect();
LinesIterator::new(content.get_cache().as_ref(), size.x).with_method(self.wrap).collect();
// Desired width
self.width = if self.rows.iter().any(|row| row.is_wrapped) {
@ -422,12 +431,14 @@ impl View for TextView {
}
fn required_size(&mut self, size: Vec2) -> Vec2 {
eprintln!("required_size {:?}", size);
self.compute_rows(size);
Vec2::new(self.width.unwrap_or(0), self.rows.len())
}
fn layout(&mut self, size: Vec2) {
eprintln!("layout {:?}", size);
// Compute the text rows.
self.last_size = size;
self.compute_rows(size);

View File

@ -29,8 +29,8 @@ use std::thread;
/// Backend using termion
pub struct Backend {
// Do we want to make this generic on the writer?
terminal:
/// Do we want to make this generic on the writer?
pub terminal:
RefCell<AlternateScreen<MouseTerminal<RawTerminal<BufWriter<File>>>>>,
current_style: Cell<theme::ColorPair>,
@ -39,6 +39,8 @@ pub struct Backend {
input_receiver: Receiver<TEvent>,
resize_receiver: Receiver<()>,
/// .
pub locked: RefCell<bool>,
}
impl Backend {
@ -112,11 +114,24 @@ impl Backend {
last_button: None,
input_receiver,
resize_receiver,
locked: false.into()
};
Ok(Box::new(c))
}
fn lock(&self) {
use std::time::*;
let mut locked = self.locked.borrow_mut();
if !*locked {
eprintln!("{} lock!", SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap().as_millis());
self.terminal.borrow_mut().write_all(&[b'\x1b', b'\x50', b't', b'm', b'u', b'x', b';', b'\x1b', b'\x1b', b'\x50', b'=', b'1', b's', b'\x1b', b'\x1b', b'\x5c', b'\x1b', b'\\']).unwrap();
*locked = true;
}
}
fn apply_colors(&self, colors: theme::ColorPair) {
with_color(colors.front, |c| self.write(tcolor::Fg(c)));
with_color(colors.back, |c| self.write(tcolor::Bg(c)));
@ -225,6 +240,9 @@ impl Drop for Backend {
}
impl backend::Backend for Backend {
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
self
}
fn name(&self) -> &str {
"termion"
}
@ -241,6 +259,7 @@ impl backend::Backend for Backend {
}
fn set_effect(&self, effect: theme::Effect) {
self.lock();
match effect {
theme::Effect::Simple => (),
theme::Effect::Reverse => self.write(tstyle::Invert),
@ -253,6 +272,7 @@ impl backend::Backend for Backend {
}
fn unset_effect(&self, effect: theme::Effect) {
self.lock();
match effect {
theme::Effect::Simple => (),
theme::Effect::Reverse => self.write(tstyle::NoInvert),
@ -290,6 +310,7 @@ impl backend::Backend for Backend {
}
fn print_at(&self, pos: Vec2, text: &str) {
self.lock();
write!(
self.terminal.borrow_mut(),
"{}{}",
@ -300,6 +321,7 @@ impl backend::Backend for Backend {
}
fn print_at_rep(&self, pos: Vec2, repetitions: usize, text: &str) {
self.lock();
if repetitions > 0 {
let mut out = self.terminal.borrow_mut();
write!(