Add table support to markdown widget
This commit is contained in:
parent
291e615c0b
commit
dcea10f707
2 changed files with 240 additions and 52 deletions
|
|
@ -43,6 +43,7 @@
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
use crate::core::alignment;
|
||||||
use crate::core::border;
|
use crate::core::border;
|
||||||
use crate::core::font::{self, Font};
|
use crate::core::font::{self, Font};
|
||||||
use crate::core::padding;
|
use crate::core::padding;
|
||||||
|
|
@ -107,13 +108,17 @@ impl Content {
|
||||||
let mut leftover = std::mem::take(&mut self.state.leftover);
|
let mut leftover = std::mem::take(&mut self.state.leftover);
|
||||||
leftover.push_str(markdown);
|
leftover.push_str(markdown);
|
||||||
|
|
||||||
|
let input = if leftover.trim_end().ends_with('|') {
|
||||||
|
leftover.trim_end().trim_end_matches('|')
|
||||||
|
} else {
|
||||||
|
leftover.as_str()
|
||||||
|
};
|
||||||
|
|
||||||
// Pop the last item
|
// Pop the last item
|
||||||
let _ = self.items.pop();
|
let _ = self.items.pop();
|
||||||
|
|
||||||
// Re-parse last item and new text
|
// Re-parse last item and new text
|
||||||
for (item, source, broken_links) in
|
for (item, source, broken_links) in parse_with(&mut self.state, input) {
|
||||||
parse_with(&mut self.state, &leftover)
|
|
||||||
{
|
|
||||||
if !broken_links.is_empty() {
|
if !broken_links.is_empty() {
|
||||||
let _ = self.incomplete.insert(
|
let _ = self.incomplete.insert(
|
||||||
self.items.len(),
|
self.items.len(),
|
||||||
|
|
@ -127,6 +132,8 @@ impl Content {
|
||||||
self.items.push(item);
|
self.items.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.state.leftover.push_str(&leftover[input.len()..]);
|
||||||
|
|
||||||
// Re-parse incomplete sections if new references are available
|
// Re-parse incomplete sections if new references are available
|
||||||
if !self.incomplete.is_empty() {
|
if !self.incomplete.is_empty() {
|
||||||
self.incomplete.retain(|index, section| {
|
self.incomplete.retain(|index, section| {
|
||||||
|
|
@ -215,6 +222,29 @@ pub enum Item {
|
||||||
Quote(Vec<Item>),
|
Quote(Vec<Item>),
|
||||||
/// A horizontal separator.
|
/// A horizontal separator.
|
||||||
Rule,
|
Rule,
|
||||||
|
/// A table.
|
||||||
|
Table {
|
||||||
|
/// The columns of the table.
|
||||||
|
columns: Vec<Column>,
|
||||||
|
/// The rows of the table.
|
||||||
|
rows: Vec<Row>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The column of a table.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Column {
|
||||||
|
/// The header of the column.
|
||||||
|
pub header: Vec<Item>,
|
||||||
|
/// The alignment of the column.
|
||||||
|
pub alignment: pulldown_cmark::Alignment,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The row of a table.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Row {
|
||||||
|
/// The cells of the row.
|
||||||
|
cells: Vec<Vec<Item>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A bunch of parsed Markdown text.
|
/// A bunch of parsed Markdown text.
|
||||||
|
|
@ -462,6 +492,12 @@ fn parse_with<'a>(
|
||||||
enum Scope {
|
enum Scope {
|
||||||
List(List),
|
List(List),
|
||||||
Quote(Vec<Item>),
|
Quote(Vec<Item>),
|
||||||
|
Table {
|
||||||
|
alignment: Vec<pulldown_cmark::Alignment>,
|
||||||
|
columns: Vec<Column>,
|
||||||
|
rows: Vec<Row>,
|
||||||
|
current: Vec<Item>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
struct List {
|
struct List {
|
||||||
|
|
@ -479,7 +515,6 @@ fn parse_with<'a>(
|
||||||
let mut emphasis = false;
|
let mut emphasis = false;
|
||||||
let mut strikethrough = false;
|
let mut strikethrough = false;
|
||||||
let mut metadata = false;
|
let mut metadata = false;
|
||||||
let mut table = false;
|
|
||||||
let mut code_block = false;
|
let mut code_block = false;
|
||||||
let mut link = None;
|
let mut link = None;
|
||||||
let mut image = None;
|
let mut image = None;
|
||||||
|
|
@ -535,6 +570,9 @@ fn parse_with<'a>(
|
||||||
Scope::Quote(items) => {
|
Scope::Quote(items) => {
|
||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
}
|
||||||
|
Scope::Table { current, .. } => {
|
||||||
|
current.push(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
|
@ -555,21 +593,19 @@ fn parse_with<'a>(
|
||||||
#[allow(clippy::drain_collect)]
|
#[allow(clippy::drain_collect)]
|
||||||
parser.filter_map(move |(event, source)| match event {
|
parser.filter_map(move |(event, source)| match event {
|
||||||
pulldown_cmark::Event::Start(tag) => match tag {
|
pulldown_cmark::Event::Start(tag) => match tag {
|
||||||
pulldown_cmark::Tag::Strong if !metadata && !table => {
|
pulldown_cmark::Tag::Strong if !metadata => {
|
||||||
strong = true;
|
strong = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::Emphasis if !metadata && !table => {
|
pulldown_cmark::Tag::Emphasis if !metadata => {
|
||||||
emphasis = true;
|
emphasis = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::Strikethrough if !metadata && !table => {
|
pulldown_cmark::Tag::Strikethrough if !metadata => {
|
||||||
strikethrough = true;
|
strikethrough = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::Link { dest_url, .. }
|
pulldown_cmark::Tag::Link { dest_url, .. } if !metadata => {
|
||||||
if !metadata && !table =>
|
|
||||||
{
|
|
||||||
match Url::parse(&dest_url) {
|
match Url::parse(&dest_url) {
|
||||||
Ok(url)
|
Ok(url)
|
||||||
if url.scheme() == "http"
|
if url.scheme() == "http"
|
||||||
|
|
@ -584,13 +620,13 @@ fn parse_with<'a>(
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::Image {
|
pulldown_cmark::Tag::Image {
|
||||||
dest_url, title, ..
|
dest_url, title, ..
|
||||||
} if !metadata && !table => {
|
} if !metadata => {
|
||||||
image = Url::parse(&dest_url)
|
image = Url::parse(&dest_url)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|url| (url, title.into_string()));
|
.map(|url| (url, title.into_string()));
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::List(first_item) if !metadata && !table => {
|
pulldown_cmark::Tag::List(first_item) if !metadata => {
|
||||||
let prev = if spans.is_empty() {
|
let prev = if spans.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -616,7 +652,7 @@ fn parse_with<'a>(
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::BlockQuote(_kind) if !metadata && !table => {
|
pulldown_cmark::Tag::BlockQuote(_kind) if !metadata => {
|
||||||
let prev = if spans.is_empty() {
|
let prev = if spans.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -634,7 +670,7 @@ fn parse_with<'a>(
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::CodeBlock(
|
pulldown_cmark::Tag::CodeBlock(
|
||||||
pulldown_cmark::CodeBlockKind::Fenced(language),
|
pulldown_cmark::CodeBlockKind::Fenced(language),
|
||||||
) if !metadata && !table => {
|
) if !metadata => {
|
||||||
#[cfg(feature = "highlighter")]
|
#[cfg(feature = "highlighter")]
|
||||||
{
|
{
|
||||||
highlighter = Some({
|
highlighter = Some({
|
||||||
|
|
@ -672,38 +708,54 @@ fn parse_with<'a>(
|
||||||
metadata = true;
|
metadata = true;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Tag::Table(_) => {
|
pulldown_cmark::Tag::Table(alignment) => {
|
||||||
table = true;
|
stack.push(Scope::Table {
|
||||||
|
columns: Vec::with_capacity(alignment.len()),
|
||||||
|
alignment,
|
||||||
|
current: Vec::new(),
|
||||||
|
rows: Vec::new(),
|
||||||
|
});
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pulldown_cmark::Tag::TableHead => {
|
||||||
|
strong = true;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pulldown_cmark::Tag::TableRow => {
|
||||||
|
let Scope::Table { rows, .. } = stack.last_mut()? else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
rows.push(Row { cells: Vec::new() });
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
pulldown_cmark::Event::End(tag) => match tag {
|
pulldown_cmark::Event::End(tag) => match tag {
|
||||||
pulldown_cmark::TagEnd::Heading(level) if !metadata && !table => {
|
pulldown_cmark::TagEnd::Heading(level) if !metadata => produce(
|
||||||
produce(
|
state.borrow_mut(),
|
||||||
state.borrow_mut(),
|
&mut stack,
|
||||||
&mut stack,
|
Item::Heading(level, Text::new(spans.drain(..).collect())),
|
||||||
Item::Heading(level, Text::new(spans.drain(..).collect())),
|
source,
|
||||||
source,
|
),
|
||||||
)
|
pulldown_cmark::TagEnd::Strong if !metadata => {
|
||||||
}
|
|
||||||
pulldown_cmark::TagEnd::Strong if !metadata && !table => {
|
|
||||||
strong = false;
|
strong = false;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::Emphasis if !metadata && !table => {
|
pulldown_cmark::TagEnd::Emphasis if !metadata => {
|
||||||
emphasis = false;
|
emphasis = false;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::Strikethrough if !metadata && !table => {
|
pulldown_cmark::TagEnd::Strikethrough if !metadata => {
|
||||||
strikethrough = false;
|
strikethrough = false;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::Link if !metadata && !table => {
|
pulldown_cmark::TagEnd::Link if !metadata => {
|
||||||
link = None;
|
link = None;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::Paragraph if !metadata && !table => {
|
pulldown_cmark::TagEnd::Paragraph if !metadata => {
|
||||||
if spans.is_empty() {
|
if spans.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -715,7 +767,7 @@ fn parse_with<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::Item if !metadata && !table => {
|
pulldown_cmark::TagEnd::Item if !metadata => {
|
||||||
if spans.is_empty() {
|
if spans.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -727,7 +779,7 @@ fn parse_with<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::List(_) if !metadata && !table => {
|
pulldown_cmark::TagEnd::List(_) if !metadata => {
|
||||||
let scope = stack.pop()?;
|
let scope = stack.pop()?;
|
||||||
|
|
||||||
let Scope::List(list) = scope else {
|
let Scope::List(list) = scope else {
|
||||||
|
|
@ -744,9 +796,7 @@ fn parse_with<'a>(
|
||||||
source,
|
source,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::BlockQuote(_kind)
|
pulldown_cmark::TagEnd::BlockQuote(_kind) if !metadata => {
|
||||||
if !metadata && !table =>
|
|
||||||
{
|
|
||||||
let scope = stack.pop()?;
|
let scope = stack.pop()?;
|
||||||
|
|
||||||
let Scope::Quote(quote) = scope else {
|
let Scope::Quote(quote) = scope else {
|
||||||
|
|
@ -760,7 +810,7 @@ fn parse_with<'a>(
|
||||||
source,
|
source,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::Image if !metadata && !table => {
|
pulldown_cmark::TagEnd::Image if !metadata => {
|
||||||
let (url, title) = image.take()?;
|
let (url, title) = image.take()?;
|
||||||
let alt = Text::new(spans.drain(..).collect());
|
let alt = Text::new(spans.drain(..).collect());
|
||||||
|
|
||||||
|
|
@ -774,7 +824,7 @@ fn parse_with<'a>(
|
||||||
source,
|
source,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::CodeBlock if !metadata && !table => {
|
pulldown_cmark::TagEnd::CodeBlock if !metadata => {
|
||||||
code_block = false;
|
code_block = false;
|
||||||
|
|
||||||
#[cfg(feature = "highlighter")]
|
#[cfg(feature = "highlighter")]
|
||||||
|
|
@ -798,12 +848,60 @@ fn parse_with<'a>(
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::TagEnd::Table => {
|
pulldown_cmark::TagEnd::Table => {
|
||||||
table = false;
|
let scope = stack.pop()?;
|
||||||
|
|
||||||
|
let Scope::Table { columns, rows, .. } = scope else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
produce(
|
||||||
|
state.borrow_mut(),
|
||||||
|
&mut stack,
|
||||||
|
Item::Table { columns, rows },
|
||||||
|
source,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
pulldown_cmark::TagEnd::TableHead => {
|
||||||
|
strong = false;
|
||||||
|
None
|
||||||
|
}
|
||||||
|
pulldown_cmark::TagEnd::TableCell => {
|
||||||
|
if !spans.is_empty() {
|
||||||
|
let _ = produce(
|
||||||
|
state.borrow_mut(),
|
||||||
|
&mut stack,
|
||||||
|
Item::Paragraph(Text::new(spans.drain(..).collect())),
|
||||||
|
source,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Scope::Table {
|
||||||
|
alignment,
|
||||||
|
columns,
|
||||||
|
rows,
|
||||||
|
current,
|
||||||
|
} = stack.last_mut()?
|
||||||
|
else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if columns.len() < alignment.len() {
|
||||||
|
columns.push(Column {
|
||||||
|
header: std::mem::take(current),
|
||||||
|
alignment: alignment[columns.len()],
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
rows.last_mut()
|
||||||
|
.expect("table row")
|
||||||
|
.cells
|
||||||
|
.push(std::mem::take(current));
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
pulldown_cmark::Event::Text(text) if !metadata && !table => {
|
pulldown_cmark::Event::Text(text) if !metadata => {
|
||||||
if code_block {
|
if code_block {
|
||||||
code.push_str(&text);
|
code.push_str(&text);
|
||||||
|
|
||||||
|
|
@ -844,7 +942,7 @@ fn parse_with<'a>(
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Event::Code(code) if !metadata && !table => {
|
pulldown_cmark::Event::Code(code) if !metadata => {
|
||||||
let span = Span::Standard {
|
let span = Span::Standard {
|
||||||
text: code.into_string(),
|
text: code.into_string(),
|
||||||
strong,
|
strong,
|
||||||
|
|
@ -857,7 +955,7 @@ fn parse_with<'a>(
|
||||||
spans.push(span);
|
spans.push(span);
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Event::SoftBreak if !metadata && !table => {
|
pulldown_cmark::Event::SoftBreak if !metadata => {
|
||||||
spans.push(Span::Standard {
|
spans.push(Span::Standard {
|
||||||
text: String::from(" "),
|
text: String::from(" "),
|
||||||
strikethrough,
|
strikethrough,
|
||||||
|
|
@ -868,7 +966,7 @@ fn parse_with<'a>(
|
||||||
});
|
});
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
pulldown_cmark::Event::HardBreak if !metadata && !table => {
|
pulldown_cmark::Event::HardBreak if !metadata => {
|
||||||
spans.push(Span::Standard {
|
spans.push(Span::Standard {
|
||||||
text: String::from("\n"),
|
text: String::from("\n"),
|
||||||
strikethrough,
|
strikethrough,
|
||||||
|
|
@ -1113,6 +1211,7 @@ where
|
||||||
} => viewer.ordered_list(settings, *start, items),
|
} => viewer.ordered_list(settings, *start, items),
|
||||||
Item::Quote(quote) => viewer.quote(settings, quote),
|
Item::Quote(quote) => viewer.quote(settings, quote),
|
||||||
Item::Rule => viewer.rule(settings),
|
Item::Rule => viewer.rule(settings),
|
||||||
|
Item::Table { columns, rows } => viewer.table(settings, columns, rows),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1313,6 +1412,74 @@ where
|
||||||
horizontal_rule(2).into()
|
horizontal_rule(2).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Displays a table using the default look.
|
||||||
|
pub fn table<'a, Message, Theme, Renderer>(
|
||||||
|
viewer: &impl Viewer<'a, Message, Theme, Renderer>,
|
||||||
|
settings: Settings,
|
||||||
|
columns: &'a [Column],
|
||||||
|
rows: &'a [Row],
|
||||||
|
) -> Element<'a, Message, Theme, Renderer>
|
||||||
|
where
|
||||||
|
Message: 'a,
|
||||||
|
Theme: Catalog + 'a,
|
||||||
|
Renderer: core::text::Renderer<Font = Font> + 'a,
|
||||||
|
{
|
||||||
|
use crate::table;
|
||||||
|
|
||||||
|
table(
|
||||||
|
columns.iter().enumerate().map(move |(i, column)| {
|
||||||
|
table::column(
|
||||||
|
items(viewer, settings, &column.header),
|
||||||
|
move |row: &Row| {
|
||||||
|
if let Some(cells) = row.cells.get(i) {
|
||||||
|
items(viewer, settings, cells)
|
||||||
|
} else {
|
||||||
|
text("").into()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.align_x(match column.alignment {
|
||||||
|
pulldown_cmark::Alignment::None
|
||||||
|
| pulldown_cmark::Alignment::Left => {
|
||||||
|
alignment::Horizontal::Left
|
||||||
|
}
|
||||||
|
pulldown_cmark::Alignment::Center => {
|
||||||
|
alignment::Horizontal::Center
|
||||||
|
}
|
||||||
|
pulldown_cmark::Alignment::Right => {
|
||||||
|
alignment::Horizontal::Right
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
rows,
|
||||||
|
)
|
||||||
|
.padding_x(settings.spacing.0)
|
||||||
|
.padding_y(settings.spacing.0 / 2.0)
|
||||||
|
.separator_x(0)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Displays a column of items with the default look.
|
||||||
|
pub fn items<'a, Message, Theme, Renderer>(
|
||||||
|
viewer: &impl Viewer<'a, Message, Theme, Renderer>,
|
||||||
|
settings: Settings,
|
||||||
|
items: &'a [Item],
|
||||||
|
) -> Element<'a, Message, Theme, Renderer>
|
||||||
|
where
|
||||||
|
Message: 'a,
|
||||||
|
Theme: Catalog + 'a,
|
||||||
|
Renderer: core::text::Renderer<Font = Font> + 'a,
|
||||||
|
{
|
||||||
|
column(
|
||||||
|
items
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, content)| item(viewer, settings, content, i)),
|
||||||
|
)
|
||||||
|
.spacing(settings.spacing.0)
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
/// A view strategy to display a Markdown [`Item`].
|
/// A view strategy to display a Markdown [`Item`].
|
||||||
pub trait Viewer<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>
|
pub trait Viewer<'a, Message, Theme = crate::Theme, Renderer = crate::Renderer>
|
||||||
where
|
where
|
||||||
|
|
@ -1429,6 +1596,18 @@ where
|
||||||
) -> Element<'a, Message, Theme, Renderer> {
|
) -> Element<'a, Message, Theme, Renderer> {
|
||||||
rule()
|
rule()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Displays a table.
|
||||||
|
///
|
||||||
|
/// By default, it calls [`table`].
|
||||||
|
fn table(
|
||||||
|
&self,
|
||||||
|
settings: Settings,
|
||||||
|
columns: &'a [Column],
|
||||||
|
rows: &'a [Row],
|
||||||
|
) -> Element<'a, Message, Theme, Renderer> {
|
||||||
|
table(self, settings, columns, rows)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -1446,7 +1625,11 @@ where
|
||||||
|
|
||||||
/// The theme catalog of Markdown items.
|
/// The theme catalog of Markdown items.
|
||||||
pub trait Catalog:
|
pub trait Catalog:
|
||||||
container::Catalog + scrollable::Catalog + rule::Catalog + text::Catalog
|
container::Catalog
|
||||||
|
+ scrollable::Catalog
|
||||||
|
+ rule::Catalog
|
||||||
|
+ text::Catalog
|
||||||
|
+ crate::table::Catalog
|
||||||
{
|
{
|
||||||
/// The styling class of a Markdown code block.
|
/// The styling class of a Markdown code block.
|
||||||
fn code_block<'a>() -> <Self as container::Catalog>::Class<'a>;
|
fn code_block<'a>() -> <Self as container::Catalog>::Class<'a>;
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ use crate::core::{
|
||||||
Widget,
|
Widget,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn table<'a, T, Message, Theme, Renderer>(
|
pub fn table<'a, 'b, T, Message, Theme, Renderer>(
|
||||||
columns: impl IntoIterator<Item = Column<'a, T, Message, Theme, Renderer>>,
|
columns: impl IntoIterator<Item = Column<'a, 'b, T, Message, Theme, Renderer>>,
|
||||||
rows: impl IntoIterator<Item = T>,
|
rows: impl IntoIterator<Item = T>,
|
||||||
) -> Table<'a, Message, Theme, Renderer>
|
) -> Table<'a, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
|
|
@ -22,10 +22,10 @@ where
|
||||||
Table::new(columns, rows)
|
Table::new(columns, rows)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn column<'a, T, E, Message, Theme, Renderer>(
|
pub fn column<'a, 'b, T, E, Message, Theme, Renderer>(
|
||||||
header: impl Into<Element<'a, Message, Theme, Renderer>>,
|
header: impl Into<Element<'a, Message, Theme, Renderer>>,
|
||||||
view: impl Fn(T) -> E + 'a,
|
view: impl Fn(T) -> E + 'b,
|
||||||
) -> Column<'a, T, Message, Theme, Renderer>
|
) -> Column<'a, 'b, T, Message, Theme, Renderer>
|
||||||
where
|
where
|
||||||
T: 'a,
|
T: 'a,
|
||||||
E: Into<Element<'a, Message, Theme, Renderer>>,
|
E: Into<Element<'a, Message, Theme, Renderer>>,
|
||||||
|
|
@ -65,8 +65,10 @@ where
|
||||||
Theme: Catalog,
|
Theme: Catalog,
|
||||||
Renderer: core::Renderer,
|
Renderer: core::Renderer,
|
||||||
{
|
{
|
||||||
pub fn new<T>(
|
pub fn new<'b, T>(
|
||||||
columns: impl IntoIterator<Item = Column<'a, T, Message, Theme, Renderer>>,
|
columns: impl IntoIterator<
|
||||||
|
Item = Column<'a, 'b, T, Message, Theme, Renderer>,
|
||||||
|
>,
|
||||||
rows: impl IntoIterator<Item = T>,
|
rows: impl IntoIterator<Item = T>,
|
||||||
) -> Self
|
) -> Self
|
||||||
where
|
where
|
||||||
|
|
@ -122,7 +124,7 @@ where
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
padding_x: 10.0,
|
padding_x: 10.0,
|
||||||
padding_y: 10.0,
|
padding_y: 5.0,
|
||||||
separator_x: 1.0,
|
separator_x: 1.0,
|
||||||
separator_y: 1.0,
|
separator_y: 1.0,
|
||||||
class: Theme::default(),
|
class: Theme::default(),
|
||||||
|
|
@ -526,19 +528,22 @@ where
|
||||||
|
|
||||||
pub struct Column<
|
pub struct Column<
|
||||||
'a,
|
'a,
|
||||||
|
'b,
|
||||||
T,
|
T,
|
||||||
Message,
|
Message,
|
||||||
Theme = crate::Theme,
|
Theme = crate::Theme,
|
||||||
Renderer = crate::Renderer,
|
Renderer = crate::Renderer,
|
||||||
> {
|
> {
|
||||||
header: Element<'a, Message, Theme, Renderer>,
|
header: Element<'a, Message, Theme, Renderer>,
|
||||||
view: Box<dyn Fn(T) -> Element<'a, Message, Theme, Renderer> + 'a>,
|
view: Box<dyn Fn(T) -> Element<'a, Message, Theme, Renderer> + 'b>,
|
||||||
width: Length,
|
width: Length,
|
||||||
align_x: alignment::Horizontal,
|
align_x: alignment::Horizontal,
|
||||||
align_y: alignment::Vertical,
|
align_y: alignment::Vertical,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T, Message, Theme, Renderer> Column<'a, T, Message, Theme, Renderer> {
|
impl<'a, 'b, T, Message, Theme, Renderer>
|
||||||
|
Column<'a, 'b, T, Message, Theme, Renderer>
|
||||||
|
{
|
||||||
pub fn width(mut self, width: impl Into<Length>) -> Self {
|
pub fn width(mut self, width: impl Into<Length>) -> Self {
|
||||||
self.width = width.into();
|
self.width = width.into();
|
||||||
self
|
self
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue