mirror of
https://github.com/ratatui/ratatui.git
synced 2025-10-02 15:25:54 +00:00
Improve Paragraph widget
* Add the possibility to disable the markup rendering * Fix parser error
This commit is contained in:
parent
e585bfeab5
commit
116ee4439a
@ -132,7 +132,7 @@ impl<B> Terminal<B>
|
|||||||
self.current = 1 - self.current;
|
self.current = 1 - self.current;
|
||||||
|
|
||||||
// Flush
|
// Flush
|
||||||
try!(self.backend.flush());
|
self.backend.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,10 @@ pub struct Paragraph<'a> {
|
|||||||
wrapping: bool,
|
wrapping: bool,
|
||||||
/// The text to display
|
/// The text to display
|
||||||
text: &'a str,
|
text: &'a str,
|
||||||
|
/// Should we parse the text for embedded commands
|
||||||
|
raw: bool,
|
||||||
|
/// Scroll
|
||||||
|
scroll: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for Paragraph<'a> {
|
impl<'a> Default for Paragraph<'a> {
|
||||||
@ -40,7 +44,9 @@ impl<'a> Default for Paragraph<'a> {
|
|||||||
block: None,
|
block: None,
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
wrapping: false,
|
wrapping: false,
|
||||||
|
raw: false,
|
||||||
text: "",
|
text: "",
|
||||||
|
scroll: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,10 +71,22 @@ impl<'a> Paragraph<'a> {
|
|||||||
self.wrapping = flag;
|
self.wrapping = flag;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw(&mut self, flag: bool) -> &mut Paragraph<'a> {
|
||||||
|
self.raw = flag;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn scroll(&mut self, offset: u16) -> &mut Paragraph<'a> {
|
||||||
|
self.scroll = offset;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Parser<'a> {
|
struct Parser<'a, T>
|
||||||
text: Vec<&'a str>,
|
where T: Iterator<Item = &'a str>
|
||||||
|
{
|
||||||
|
text: T,
|
||||||
mark: bool,
|
mark: bool,
|
||||||
cmd_string: String,
|
cmd_string: String,
|
||||||
style: Style,
|
style: Style,
|
||||||
@ -77,10 +95,12 @@ struct Parser<'a> {
|
|||||||
styling: bool,
|
styling: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Parser<'a> {
|
impl<'a, T> Parser<'a, T>
|
||||||
fn new(text: &'a str, base_style: Style) -> Parser<'a> {
|
where T: Iterator<Item = &'a str>
|
||||||
|
{
|
||||||
|
fn new(text: T, base_style: Style) -> Parser<'a, T> {
|
||||||
Parser {
|
Parser {
|
||||||
text: UnicodeSegmentation::graphemes(text, true).rev().collect::<Vec<&str>>(),
|
text: text,
|
||||||
mark: false,
|
mark: false,
|
||||||
cmd_string: String::from(""),
|
cmd_string: String::from(""),
|
||||||
style: base_style,
|
style: base_style,
|
||||||
@ -97,17 +117,17 @@ impl<'a> Parser<'a> {
|
|||||||
match *first {
|
match *first {
|
||||||
"fg" => {
|
"fg" => {
|
||||||
if let Some(snd) = args.get(1) {
|
if let Some(snd) = args.get(1) {
|
||||||
self.style.fg = Parser::str_to_color(snd);
|
self.style.fg = Parser::<T>::str_to_color(snd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"bg" => {
|
"bg" => {
|
||||||
if let Some(snd) = args.get(1) {
|
if let Some(snd) = args.get(1) {
|
||||||
self.style.bg = Parser::str_to_color(snd);
|
self.style.bg = Parser::<T>::str_to_color(snd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"mod" => {
|
"mod" => {
|
||||||
if let Some(snd) = args.get(1) {
|
if let Some(snd) = args.get(1) {
|
||||||
self.style.modifier = Parser::str_to_modifier(snd);
|
self.style.modifier = Parser::<T>::str_to_modifier(snd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
@ -155,10 +175,12 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Parser<'a> {
|
impl<'a, T> Iterator for Parser<'a, T>
|
||||||
|
where T: Iterator<Item = &'a str>
|
||||||
|
{
|
||||||
type Item = (&'a str, Style);
|
type Item = (&'a str, Style);
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self.text.pop() {
|
match self.text.next() {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
if s == "\\" {
|
if s == "\\" {
|
||||||
if self.escaping {
|
if self.escaping {
|
||||||
@ -172,9 +194,13 @@ impl<'a> Iterator for Parser<'a> {
|
|||||||
self.escaping = false;
|
self.escaping = false;
|
||||||
Some((s, self.style))
|
Some((s, self.style))
|
||||||
} else {
|
} else {
|
||||||
self.style = self.base_style;
|
if self.mark {
|
||||||
self.mark = true;
|
Some((s, self.style))
|
||||||
self.next()
|
} else {
|
||||||
|
self.style = self.base_style;
|
||||||
|
self.mark = true;
|
||||||
|
self.next()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if s == "}" && self.mark {
|
} else if s == "}" && self.mark {
|
||||||
self.reset();
|
self.reset();
|
||||||
@ -217,7 +243,14 @@ impl<'a> Widget for Paragraph<'a> {
|
|||||||
|
|
||||||
let mut x = 0;
|
let mut x = 0;
|
||||||
let mut y = 0;
|
let mut y = 0;
|
||||||
for (string, style) in Parser::new(self.text, self.style) {
|
let graphemes = UnicodeSegmentation::graphemes(self.text, true);
|
||||||
|
let styled: Box<Iterator<Item = (&str, Style)>> = if self.raw {
|
||||||
|
Box::new(graphemes.map(|g| (g, self.style)))
|
||||||
|
} else {
|
||||||
|
Box::new(Parser::new(graphemes, self.style))
|
||||||
|
};
|
||||||
|
|
||||||
|
for (string, style) in styled {
|
||||||
if string == "\n" {
|
if string == "\n" {
|
||||||
x = 0;
|
x = 0;
|
||||||
y += 1;
|
y += 1;
|
||||||
@ -235,7 +268,11 @@ impl<'a> Widget for Paragraph<'a> {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.get_mut(text_area.left() + x, text_area.top() + y)
|
if y < self.scroll {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf.get_mut(text_area.left() + x, text_area.top() + y - self.scroll)
|
||||||
.set_symbol(string)
|
.set_symbol(string)
|
||||||
.set_style(style);
|
.set_style(style);
|
||||||
x += string.width() as u16;
|
x += string.width() as u16;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user