mirror of
https://github.com/ratatui/ratatui.git
synced 2025-09-30 14:32:01 +00:00
refactor(widgets): replace text rendering in Paragraph
* remove custom markup language * add Text container for both raw and styled strings
This commit is contained in:
parent
7181970a32
commit
ad602a54bf
@ -21,6 +21,7 @@ bitflags = "1.0.1"
|
|||||||
cassowary = "0.3.0"
|
cassowary = "0.3.0"
|
||||||
itertools = "0.7.8"
|
itertools = "0.7.8"
|
||||||
log = "0.4.1"
|
log = "0.4.1"
|
||||||
|
either = "1.5.0"
|
||||||
unicode-segmentation = "1.2.0"
|
unicode-segmentation = "1.2.0"
|
||||||
unicode-width = "0.1.4"
|
unicode-width = "0.1.4"
|
||||||
termion = { version = "1.5.1", optional = true }
|
termion = { version = "1.5.1", optional = true }
|
||||||
|
@ -20,7 +20,7 @@ use tui::style::{Color, Modifier, Style};
|
|||||||
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution};
|
use tui::widgets::canvas::{Canvas, Line, Map, MapResolution};
|
||||||
use tui::widgets::{
|
use tui::widgets::{
|
||||||
Axis, BarChart, Block, Borders, Chart, Dataset, Gauge, Item, List, Marker, Paragraph, Row,
|
Axis, BarChart, Block, Borders, Chart, Dataset, Gauge, Item, List, Marker, Paragraph, Row,
|
||||||
SelectableList, Sparkline, Table, Tabs, Widget,
|
SelectableList, Sparkline, Table, Tabs, Widget, Text,
|
||||||
};
|
};
|
||||||
use tui::{Frame, Terminal};
|
use tui::{Frame, Terminal};
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ fn main() {
|
|||||||
let tx = tx.clone();
|
let tx = tx.clone();
|
||||||
loop {
|
loop {
|
||||||
tx.send(Event::Tick).unwrap();
|
tx.send(Event::Tick).unwrap();
|
||||||
thread::sleep(time::Duration::from_millis(200));
|
thread::sleep(time::Duration::from_millis(16));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -440,7 +440,24 @@ fn draw_charts(f: &mut Frame<MouseBackend>, app: &App, area: &Rect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_text(f: &mut Frame<MouseBackend>, area: &Rect) {
|
fn draw_text(f: &mut Frame<MouseBackend>, area: &Rect) {
|
||||||
Paragraph::default()
|
let text = [
|
||||||
|
Text::Data("This is a paragraph with several lines. You can change style your text the way you want.\n\nFox example: "),
|
||||||
|
Text::StyledData("under", Style::default().fg(Color::Red)),
|
||||||
|
Text::Data(" "),
|
||||||
|
Text::StyledData("the", Style::default().fg(Color::Green)),
|
||||||
|
Text::Data(" "),
|
||||||
|
Text::StyledData("rainbow", Style::default().fg(Color::Blue)),
|
||||||
|
Text::Data(".\nOh and if you didn't "),
|
||||||
|
Text::StyledData("notice", Style::default().modifier(Modifier::Italic)),
|
||||||
|
Text::Data(" you can "),
|
||||||
|
Text::StyledData("automatically", Style::default().modifier(Modifier::Bold)),
|
||||||
|
Text::Data(" "),
|
||||||
|
Text::StyledData("wrap", Style::default().modifier(Modifier::Invert)),
|
||||||
|
Text::Data(" your "),
|
||||||
|
Text::StyledData("text", Style::default().modifier(Modifier::Underline)),
|
||||||
|
Text::Data(".\nOne more thing is that it should display unicode characters: 10€")
|
||||||
|
];
|
||||||
|
Paragraph::new(text.iter())
|
||||||
.block(
|
.block(
|
||||||
Block::default()
|
Block::default()
|
||||||
.borders(Borders::ALL)
|
.borders(Borders::ALL)
|
||||||
@ -448,17 +465,6 @@ fn draw_text(f: &mut Frame<MouseBackend>, area: &Rect) {
|
|||||||
.title_style(Style::default().fg(Color::Magenta).modifier(Modifier::Bold)),
|
.title_style(Style::default().fg(Color::Magenta).modifier(Modifier::Bold)),
|
||||||
)
|
)
|
||||||
.wrap(true)
|
.wrap(true)
|
||||||
.text(
|
|
||||||
"This is a paragraph with several lines.\nYou can change the color.\nUse \
|
|
||||||
\\{fg=[color];bg=[color];mod=[modifier] [text]} to highlight the text with a color. \
|
|
||||||
For example, {fg=red u}{fg=green n}{fg=yellow d}{fg=magenta e}{fg=cyan r} \
|
|
||||||
{fg=gray t}{fg=light_gray h}{fg=light_red e} {fg=light_green r}{fg=light_yellow a} \
|
|
||||||
{fg=light_magenta i}{fg=light_cyan n}{fg=white b}{fg=red o}{fg=green w}.\n\
|
|
||||||
Oh, and if you didn't {mod=italic notice} you can {mod=bold automatically} \
|
|
||||||
{mod=invert wrap} your {mod=underline text} =).\nOne more thing is that \
|
|
||||||
it should display unicode characters properly: 日本国, ٩(-̮̮̃-̃)۶ ٩(●̮̮̃•̃)۶ ٩(͡๏̯͡๏)۶ \
|
|
||||||
٩(-̮̮̃•̃).",
|
|
||||||
)
|
|
||||||
.render(f, area);
|
.render(f, area);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ use termion::event;
|
|||||||
use termion::input::TermRead;
|
use termion::input::TermRead;
|
||||||
|
|
||||||
use tui::backend::MouseBackend;
|
use tui::backend::MouseBackend;
|
||||||
use tui::layout::{Constraint, Direction, Layout, Rect};
|
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
|
||||||
use tui::style::{Alignment, Color, Style};
|
use tui::style::{Color, Style, Modifier};
|
||||||
use tui::widgets::{Block, Paragraph, Widget};
|
use tui::widgets::{Block, Paragraph, Widget, Text};
|
||||||
use tui::Terminal;
|
use tui::Terminal;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@ -55,38 +55,24 @@ fn draw(t: &mut Terminal<MouseBackend>, size: &Rect) {
|
|||||||
)
|
)
|
||||||
.split(size);
|
.split(size);
|
||||||
|
|
||||||
Paragraph::default()
|
let text = [
|
||||||
.alignment(Alignment::Left)
|
Text::Data("This a line\n"),
|
||||||
.text(
|
Text::StyledData("This a line\n", Style::default().fg(Color::Red)),
|
||||||
"This is a line\n{fg=red This is a line}\n{bg=red This is a \
|
Text::StyledData("This a line\n", Style::default().bg(Color::Blue)),
|
||||||
line}\n{mod=italic This is a line}\n{mod=bold This is a \
|
Text::StyledData("This a longer line\n", Style::default().modifier(Modifier::CrossedOut)),
|
||||||
line}\n{mod=crossed_out This is a line}\n{mod=invert This is a \
|
Text::StyledData("This a line\n", Style::default().fg(Color::Green).modifier(Modifier::Italic)),
|
||||||
line}\n{mod=underline This is a \
|
];
|
||||||
line}\n{bg=green;fg=yellow;mod=italic This is a line}\n",
|
|
||||||
)
|
|
||||||
.render(&mut f, &chunks[0]);
|
|
||||||
|
|
||||||
Paragraph::default()
|
Paragraph::new(text.iter())
|
||||||
|
.alignment(Alignment::Left)
|
||||||
|
.render(&mut f, &chunks[0]);
|
||||||
|
Paragraph::new(text.iter())
|
||||||
.alignment(Alignment::Center)
|
.alignment(Alignment::Center)
|
||||||
.wrap(true)
|
.wrap(true)
|
||||||
.text(
|
|
||||||
"This is a line\n{fg=red This is a line}\n{bg=red This is a \
|
|
||||||
line}\n{mod=italic This is a line}\n{mod=bold This is a \
|
|
||||||
line}\n{mod=crossed_out This is a line}\n{mod=invert This is a \
|
|
||||||
line}\n{mod=underline This is a \
|
|
||||||
line}\n{bg=green;fg=yellow;mod=italic This is a line}\n",
|
|
||||||
)
|
|
||||||
.render(&mut f, &chunks[1]);
|
.render(&mut f, &chunks[1]);
|
||||||
Paragraph::default()
|
Paragraph::new(text.iter())
|
||||||
.alignment(Alignment::Right)
|
.alignment(Alignment::Right)
|
||||||
.wrap(true)
|
.wrap(true)
|
||||||
.text(
|
|
||||||
"This is a line\n{fg=red This is a line}\n{bg=red This is a \
|
|
||||||
line}\n{mod=italic This is a line}\n{mod=bold This is a \
|
|
||||||
line}\n{mod=crossed_out This is a line}\n{mod=invert This is a \
|
|
||||||
line}\n{mod=underline This is a \
|
|
||||||
line}\n{bg=green;fg=yellow;mod=italic This is a line}\n",
|
|
||||||
)
|
|
||||||
.render(&mut f, &chunks[2]);
|
.render(&mut f, &chunks[2]);
|
||||||
}
|
}
|
||||||
t.draw().unwrap();
|
t.draw().unwrap();
|
||||||
|
@ -22,7 +22,7 @@ use termion::input::TermRead;
|
|||||||
use tui::backend::MouseBackend;
|
use tui::backend::MouseBackend;
|
||||||
use tui::layout::{Constraint, Direction, Layout, Rect};
|
use tui::layout::{Constraint, Direction, Layout, Rect};
|
||||||
use tui::style::{Color, Style};
|
use tui::style::{Color, Style};
|
||||||
use tui::widgets::{Block, Borders, Item, List, Paragraph, Widget};
|
use tui::widgets::{Block, Borders, Item, List, Paragraph, Widget, Text};
|
||||||
use tui::Terminal;
|
use tui::Terminal;
|
||||||
|
|
||||||
struct App {
|
struct App {
|
||||||
@ -115,10 +115,9 @@ fn draw(t: &mut Terminal<MouseBackend>, app: &App) {
|
|||||||
.margin(2)
|
.margin(2)
|
||||||
.constraints([Constraint::Length(3), Constraint::Min(1)].as_ref())
|
.constraints([Constraint::Length(3), Constraint::Min(1)].as_ref())
|
||||||
.split(&app.size);
|
.split(&app.size);
|
||||||
Paragraph::default()
|
Paragraph::new([Text::Data(&app.input)].iter())
|
||||||
.style(Style::default().fg(Color::Yellow))
|
.style(Style::default().fg(Color::Yellow))
|
||||||
.block(Block::default().borders(Borders::ALL).title("Input"))
|
.block(Block::default().borders(Borders::ALL).title("Input"))
|
||||||
.text(&app.input)
|
|
||||||
.render(&mut f, &chunks[0]);
|
.render(&mut f, &chunks[0]);
|
||||||
List::new(
|
List::new(
|
||||||
app.messages
|
app.messages
|
||||||
|
@ -29,6 +29,13 @@ pub enum Constraint {
|
|||||||
Min(u16),
|
Min(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum Alignment {
|
||||||
|
Left,
|
||||||
|
Center,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: enforce constraints size once const generics has landed
|
// TODO: enforce constraints size once const generics has landed
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct Layout {
|
pub struct Layout {
|
||||||
|
@ -167,6 +167,7 @@
|
|||||||
extern crate bitflags;
|
extern crate bitflags;
|
||||||
extern crate cassowary;
|
extern crate cassowary;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
|
extern crate either;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
extern crate unicode_segmentation;
|
extern crate unicode_segmentation;
|
||||||
|
@ -40,13 +40,6 @@ pub enum Modifier {
|
|||||||
Underline,
|
Underline,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub enum Alignment {
|
|
||||||
Left,
|
|
||||||
Center,
|
|
||||||
Right,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct Style {
|
pub struct Style {
|
||||||
pub fg: Color,
|
pub fg: Color,
|
||||||
|
@ -14,7 +14,7 @@ pub use self::block::Block;
|
|||||||
pub use self::chart::{Axis, Chart, Dataset, Marker};
|
pub use self::chart::{Axis, Chart, Dataset, Marker};
|
||||||
pub use self::gauge::Gauge;
|
pub use self::gauge::Gauge;
|
||||||
pub use self::list::{Item, List, SelectableList};
|
pub use self::list::{Item, List, SelectableList};
|
||||||
pub use self::paragraph::Paragraph;
|
pub use self::paragraph::{Paragraph, Text};
|
||||||
pub use self::sparkline::Sparkline;
|
pub use self::sparkline::Sparkline;
|
||||||
pub use self::table::{Row, Table};
|
pub use self::table::{Row, Table};
|
||||||
pub use self::tabs::Tabs;
|
pub use self::tabs::Tabs;
|
||||||
|
@ -1,30 +1,38 @@
|
|||||||
|
use either::Either;
|
||||||
use itertools::{multipeek, MultiPeek};
|
use itertools::{multipeek, MultiPeek};
|
||||||
use unicode_segmentation::UnicodeSegmentation;
|
use unicode_segmentation::UnicodeSegmentation;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
|
|
||||||
use buffer::Buffer;
|
use buffer::Buffer;
|
||||||
use layout::Rect;
|
use layout::{Alignment, Rect};
|
||||||
use style::{Alignment, Color, Modifier, Style};
|
use style::Style;
|
||||||
use widgets::{Block, Widget};
|
use widgets::{Block, Widget};
|
||||||
|
|
||||||
/// A widget to display some text. You can specify colors using commands embedded in
|
/// A widget to display some text.
|
||||||
/// the text such as "{[color] [text]}".
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # extern crate tui;
|
/// # extern crate tui;
|
||||||
/// # use tui::widgets::{Block, Borders, Paragraph};
|
/// # use tui::widgets::{Block, Borders, Paragraph, Text};
|
||||||
/// # use tui::style::{Style, Color};
|
/// # use tui::style::{Style, Color};
|
||||||
|
/// # use tui::layout::{Alignment};
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// Paragraph::default()
|
/// let text = [
|
||||||
|
/// Text::Data("First line\n"),
|
||||||
|
/// Text::StyledData("Second line\n", Style::default().fg(Color::Red))
|
||||||
|
/// ];
|
||||||
|
/// Paragraph::new(text.iter())
|
||||||
/// .block(Block::default().title("Paragraph").borders(Borders::ALL))
|
/// .block(Block::default().title("Paragraph").borders(Borders::ALL))
|
||||||
/// .style(Style::default().fg(Color::White).bg(Color::Black))
|
/// .style(Style::default().fg(Color::White).bg(Color::Black))
|
||||||
/// .wrap(true)
|
/// .alignment(Alignment::Center)
|
||||||
/// .text("First line\nSecond line\n{red Colored text}.");
|
/// .wrap(true);
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub struct Paragraph<'a> {
|
pub struct Paragraph<'a, 't, T>
|
||||||
|
where
|
||||||
|
T: Iterator<Item = &'t Text<'t>>,
|
||||||
|
{
|
||||||
/// A block to wrap the widget in
|
/// A block to wrap the widget in
|
||||||
block: Option<Block<'a>>,
|
block: Option<Block<'a>>,
|
||||||
/// Widget style
|
/// Widget style
|
||||||
@ -32,7 +40,7 @@ pub struct Paragraph<'a> {
|
|||||||
/// Wrap the text or not
|
/// Wrap the text or not
|
||||||
wrapping: bool,
|
wrapping: bool,
|
||||||
/// The text to display
|
/// The text to display
|
||||||
text: &'a str,
|
text: T,
|
||||||
/// Should we parse the text for embedded commands
|
/// Should we parse the text for embedded commands
|
||||||
raw: bool,
|
raw: bool,
|
||||||
/// Scroll
|
/// Scroll
|
||||||
@ -41,195 +49,62 @@ pub struct Paragraph<'a> {
|
|||||||
alignment: Alignment,
|
alignment: Alignment,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Default for Paragraph<'a> {
|
pub enum Text<'b> {
|
||||||
fn default() -> Paragraph<'a> {
|
Data(&'b str),
|
||||||
|
StyledData(&'b str, Style),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 't, T> Paragraph<'a, 't, T>
|
||||||
|
where
|
||||||
|
T: Iterator<Item = &'t Text<'t>>,
|
||||||
|
{
|
||||||
|
pub fn new(text: T) -> Paragraph<'a, 't, T> {
|
||||||
Paragraph {
|
Paragraph {
|
||||||
block: None,
|
block: None,
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
wrapping: false,
|
wrapping: false,
|
||||||
raw: false,
|
raw: false,
|
||||||
text: "",
|
text,
|
||||||
scroll: 0,
|
scroll: 0,
|
||||||
alignment: Alignment::Left,
|
alignment: Alignment::Left,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Paragraph<'a> {
|
pub fn block(&'a mut self, block: Block<'a>) -> &mut Paragraph<'a, 't, T> {
|
||||||
pub fn block(&'a mut self, block: Block<'a>) -> &mut Paragraph<'a> {
|
|
||||||
self.block = Some(block);
|
self.block = Some(block);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn text(&mut self, text: &'a str) -> &mut Paragraph<'a> {
|
pub fn style(&mut self, style: Style) -> &mut Paragraph<'a, 't, T> {
|
||||||
self.text = text;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn style(&mut self, style: Style) -> &mut Paragraph<'a> {
|
|
||||||
self.style = style;
|
self.style = style;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wrap(&mut self, flag: bool) -> &mut Paragraph<'a> {
|
pub fn wrap(&mut self, flag: bool) -> &mut Paragraph<'a, 't, T> {
|
||||||
self.wrapping = flag;
|
self.wrapping = flag;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn raw(&mut self, flag: bool) -> &mut Paragraph<'a> {
|
pub fn raw(&mut self, flag: bool) -> &mut Paragraph<'a, 't, T> {
|
||||||
self.raw = flag;
|
self.raw = flag;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll(&mut self, offset: u16) -> &mut Paragraph<'a> {
|
pub fn scroll(&mut self, offset: u16) -> &mut Paragraph<'a, 't, T> {
|
||||||
self.scroll = offset;
|
self.scroll = offset;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn alignment(&mut self, alignment: Alignment) -> &mut Paragraph<'a> {
|
pub fn alignment(&mut self, alignment: Alignment) -> &mut Paragraph<'a, 't, T> {
|
||||||
self.alignment = alignment;
|
self.alignment = alignment;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Parser<'a, T>
|
impl<'a, 't, T> Widget for Paragraph<'a, 't, T>
|
||||||
where
|
where
|
||||||
T: Iterator<Item = &'a str>,
|
T: Iterator<Item = &'t Text<'t>>,
|
||||||
{
|
{
|
||||||
text: T,
|
|
||||||
mark: bool,
|
|
||||||
cmd_string: String,
|
|
||||||
style: Style,
|
|
||||||
base_style: Style,
|
|
||||||
escaping: bool,
|
|
||||||
styling: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Parser<'a, T>
|
|
||||||
where
|
|
||||||
T: Iterator<Item = &'a str>,
|
|
||||||
{
|
|
||||||
fn new(text: T, base_style: Style) -> Parser<'a, T> {
|
|
||||||
Parser {
|
|
||||||
text: text,
|
|
||||||
mark: false,
|
|
||||||
cmd_string: String::from(""),
|
|
||||||
style: base_style,
|
|
||||||
base_style: base_style,
|
|
||||||
escaping: false,
|
|
||||||
styling: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_style(&mut self) {
|
|
||||||
for cmd in self.cmd_string.split(';') {
|
|
||||||
let args = cmd.split('=').collect::<Vec<&str>>();
|
|
||||||
if let Some(first) = args.get(0) {
|
|
||||||
match *first {
|
|
||||||
"fg" => if let Some(snd) = args.get(1) {
|
|
||||||
self.style.fg = Parser::<T>::str_to_color(snd);
|
|
||||||
},
|
|
||||||
"bg" => if let Some(snd) = args.get(1) {
|
|
||||||
self.style.bg = Parser::<T>::str_to_color(snd);
|
|
||||||
},
|
|
||||||
"mod" => if let Some(snd) = args.get(1) {
|
|
||||||
self.style.modifier = Parser::<T>::str_to_modifier(snd);
|
|
||||||
},
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn str_to_color(string: &str) -> Color {
|
|
||||||
match string {
|
|
||||||
"black" => Color::Black,
|
|
||||||
"red" => Color::Red,
|
|
||||||
"green" => Color::Green,
|
|
||||||
"yellow" => Color::Yellow,
|
|
||||||
"blue" => Color::Blue,
|
|
||||||
"magenta" => Color::Magenta,
|
|
||||||
"cyan" => Color::Cyan,
|
|
||||||
"gray" => Color::Gray,
|
|
||||||
"dark_gray" => Color::DarkGray,
|
|
||||||
"light_red" => Color::LightRed,
|
|
||||||
"light_green" => Color::LightGreen,
|
|
||||||
"light_blue" => Color::LightBlue,
|
|
||||||
"light_yellow" => Color::LightYellow,
|
|
||||||
"light_magenta" => Color::LightMagenta,
|
|
||||||
"light_cyan" => Color::LightCyan,
|
|
||||||
"white" => Color::White,
|
|
||||||
_ => Color::Reset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn str_to_modifier(string: &str) -> Modifier {
|
|
||||||
match string {
|
|
||||||
"bold" => Modifier::Bold,
|
|
||||||
"italic" => Modifier::Italic,
|
|
||||||
"underline" => Modifier::Underline,
|
|
||||||
"invert" => Modifier::Invert,
|
|
||||||
"crossed_out" => Modifier::CrossedOut,
|
|
||||||
_ => Modifier::Reset,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reset(&mut self) {
|
|
||||||
self.styling = false;
|
|
||||||
self.mark = false;
|
|
||||||
self.style = self.base_style;
|
|
||||||
self.cmd_string.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Iterator for Parser<'a, T>
|
|
||||||
where
|
|
||||||
T: Iterator<Item = &'a str>,
|
|
||||||
{
|
|
||||||
type Item = (&'a str, Style);
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
|
||||||
match self.text.next() {
|
|
||||||
Some(s) => if s == "\\" {
|
|
||||||
if self.escaping {
|
|
||||||
Some((s, self.style))
|
|
||||||
} else {
|
|
||||||
self.escaping = true;
|
|
||||||
self.next()
|
|
||||||
}
|
|
||||||
} else if s == "{" {
|
|
||||||
if self.escaping {
|
|
||||||
self.escaping = false;
|
|
||||||
Some((s, self.style))
|
|
||||||
} else if self.mark {
|
|
||||||
Some((s, self.style))
|
|
||||||
} else {
|
|
||||||
self.style = self.base_style;
|
|
||||||
self.mark = true;
|
|
||||||
self.next()
|
|
||||||
}
|
|
||||||
} else if s == "}" && self.mark {
|
|
||||||
self.reset();
|
|
||||||
self.next()
|
|
||||||
} else if s == " " && self.mark {
|
|
||||||
if self.styling {
|
|
||||||
Some((s, self.style))
|
|
||||||
} else {
|
|
||||||
self.styling = true;
|
|
||||||
self.update_style();
|
|
||||||
self.next()
|
|
||||||
}
|
|
||||||
} else if self.mark && !self.styling {
|
|
||||||
self.cmd_string.push_str(s);
|
|
||||||
self.next()
|
|
||||||
} else {
|
|
||||||
Some((s, self.style))
|
|
||||||
},
|
|
||||||
None => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Widget for Paragraph<'a> {
|
|
||||||
fn draw(&mut self, area: &Rect, buf: &mut Buffer) {
|
fn draw(&mut self, area: &Rect, buf: &mut Buffer) {
|
||||||
let text_area = match self.block {
|
let text_area = match self.block {
|
||||||
Some(ref mut b) => {
|
Some(ref mut b) => {
|
||||||
@ -245,13 +120,15 @@ impl<'a> Widget for Paragraph<'a> {
|
|||||||
|
|
||||||
self.background(&text_area, buf, self.style.bg);
|
self.background(&text_area, buf, self.style.bg);
|
||||||
|
|
||||||
let graphemes = UnicodeSegmentation::graphemes(self.text, true);
|
let style = self.style;
|
||||||
let styled: Box<Iterator<Item = (&str, Style)>> = if self.raw {
|
let styled = self.text.by_ref().flat_map(|t| match t {
|
||||||
Box::new(graphemes.map(|g| (g, self.style)))
|
&Text::Data(d) => {
|
||||||
} else {
|
Either::Left(UnicodeSegmentation::graphemes(d, true).map(|g| (g, style)))
|
||||||
Box::new(Parser::new(graphemes, self.style))
|
}
|
||||||
};
|
&Text::StyledData(d, s) => {
|
||||||
|
Either::Right(UnicodeSegmentation::graphemes(d, true).map(move |g| (g, s)))
|
||||||
|
}
|
||||||
|
});
|
||||||
let mut styled = multipeek(styled);
|
let mut styled = multipeek(styled);
|
||||||
|
|
||||||
fn get_cur_line_len<'a, I: Iterator<Item = (&'a str, Style)>>(
|
fn get_cur_line_len<'a, I: Iterator<Item = (&'a str, Style)>>(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user