From 910eb72a0620b34e5b3d7793bbd5ab7290e08dd6 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 17 Jul 2024 22:04:11 +0200 Subject: Implement `rich_text` widget and `markdown` example --- examples/markdown/Cargo.toml | 12 +++ examples/markdown/src/main.rs | 172 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 examples/markdown/Cargo.toml create mode 100644 examples/markdown/src/main.rs (limited to 'examples') diff --git a/examples/markdown/Cargo.toml b/examples/markdown/Cargo.toml new file mode 100644 index 00000000..f9bf4042 --- /dev/null +++ b/examples/markdown/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "markdown" +version = "0.1.0" +authors = ["Héctor Ramón Jiménez "] +edition = "2021" +publish = false + +[dependencies] +iced.workspace = true +iced.features = ["debug"] + +pulldown-cmark = "0.11" diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs new file mode 100644 index 00000000..43adaf72 --- /dev/null +++ b/examples/markdown/src/main.rs @@ -0,0 +1,172 @@ +use iced::font; +use iced::padding; +use iced::widget::{ + self, column, container, rich_text, row, span, text_editor, +}; +use iced::{Element, Fill, Font, Task, Theme}; + +pub fn main() -> iced::Result { + iced::application("Markdown - Iced", Markdown::update, Markdown::view) + .theme(Markdown::theme) + .run_with(Markdown::new) +} + +struct Markdown { + content: text_editor::Content, +} + +#[derive(Debug, Clone)] +enum Message { + Edit(text_editor::Action), +} + +impl Markdown { + fn new() -> (Self, Task) { + ( + Self { + content: text_editor::Content::with_text( + "# Markdown Editor\nType your Markdown here...", + ), + }, + widget::focus_next(), + ) + } + fn update(&mut self, message: Message) { + match message { + Message::Edit(action) => { + self.content.perform(action); + } + } + } + + fn view(&self) -> Element { + let editor = text_editor(&self.content) + .on_action(Message::Edit) + .height(Fill) + .padding(10) + .font(Font::MONOSPACE); + + let preview = { + let markdown = self.content.text(); + let parser = pulldown_cmark::Parser::new(&markdown); + + let mut strong = false; + let mut emphasis = false; + let mut heading = None; + let mut spans = Vec::new(); + + let items = parser.filter_map(|event| match event { + pulldown_cmark::Event::Start(tag) => match tag { + pulldown_cmark::Tag::Strong => { + strong = true; + None + } + pulldown_cmark::Tag::Emphasis => { + emphasis = true; + None + } + pulldown_cmark::Tag::Heading { level, .. } => { + heading = Some(level); + None + } + _ => None, + }, + pulldown_cmark::Event::End(tag) => match tag { + pulldown_cmark::TagEnd::Emphasis => { + emphasis = false; + None + } + pulldown_cmark::TagEnd::Strong => { + strong = false; + None + } + pulldown_cmark::TagEnd::Heading(_) => { + heading = None; + Some( + container(rich_text(spans.drain(..))) + .padding(padding::bottom(5)) + .into(), + ) + } + pulldown_cmark::TagEnd::Paragraph => Some( + container(rich_text(spans.drain(..))) + .padding(padding::bottom(15)) + .into(), + ), + pulldown_cmark::TagEnd::CodeBlock => Some( + container( + container( + rich_text(spans.drain(..)) + .font(Font::MONOSPACE), + ) + .width(Fill) + .padding(10) + .style(container::rounded_box), + ) + .padding(padding::bottom(15)) + .into(), + ), + _ => None, + }, + pulldown_cmark::Event::Text(text) => { + let span = span(text.into_string()); + + let span = match heading { + None => span, + Some(heading) => span.size(match heading { + pulldown_cmark::HeadingLevel::H1 => 32, + pulldown_cmark::HeadingLevel::H2 => 28, + pulldown_cmark::HeadingLevel::H3 => 24, + pulldown_cmark::HeadingLevel::H4 => 20, + pulldown_cmark::HeadingLevel::H5 => 16, + pulldown_cmark::HeadingLevel::H6 => 16, + }), + }; + + let span = if strong || emphasis { + span.font(Font { + weight: if strong { + font::Weight::Bold + } else { + font::Weight::Normal + }, + style: if emphasis { + font::Style::Italic + } else { + font::Style::Normal + }, + ..Font::default() + }) + } else { + span + }; + + spans.push(span); + + None + } + pulldown_cmark::Event::Code(code) => { + spans.push(span(code.into_string()).font(Font::MONOSPACE)); + None + } + pulldown_cmark::Event::SoftBreak => { + spans.push(span(" ")); + None + } + pulldown_cmark::Event::HardBreak => { + spans.push(span("\n")); + None + } + _ => None, + }); + + column(items).width(Fill) + }; + + row![editor, preview].spacing(10).padding(10).into() + } + + fn theme(&self) -> Theme { + Theme::TokyoNight + } +} -- cgit From 904704d7c1b006c850654dcf3bf9e856e23cb317 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 18 Jul 2024 13:14:56 +0200 Subject: Flesh out the `markdown` example a bit more --- examples/editor/src/main.rs | 2 +- examples/markdown/Cargo.toml | 2 +- examples/markdown/overview.md | 102 ++++++++++++ examples/markdown/src/main.rs | 356 +++++++++++++++++++++++++++--------------- 4 files changed, 337 insertions(+), 125 deletions(-) create mode 100644 examples/markdown/overview.md (limited to 'examples') diff --git a/examples/editor/src/main.rs b/examples/editor/src/main.rs index 71b1a719..9ffb4d1a 100644 --- a/examples/editor/src/main.rs +++ b/examples/editor/src/main.rs @@ -189,7 +189,7 @@ impl Editor { .highlight::( highlighter::Settings { theme: self.theme, - extension: self + token: self .file .as_deref() .and_then(Path::extension) diff --git a/examples/markdown/Cargo.toml b/examples/markdown/Cargo.toml index f9bf4042..6875ee94 100644 --- a/examples/markdown/Cargo.toml +++ b/examples/markdown/Cargo.toml @@ -7,6 +7,6 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["debug"] +iced.features = ["highlighter", "debug"] pulldown-cmark = "0.11" diff --git a/examples/markdown/overview.md b/examples/markdown/overview.md new file mode 100644 index 00000000..ca3250f1 --- /dev/null +++ b/examples/markdown/overview.md @@ -0,0 +1,102 @@ +# Overview + +Inspired by [The Elm Architecture], Iced expects you to split user interfaces +into four different concepts: + +* __State__ — the state of your application +* __Messages__ — user interactions or meaningful events that you care + about +* __View logic__ — a way to display your __state__ as widgets that + may produce __messages__ on user interaction +* __Update logic__ — a way to react to __messages__ and update your + __state__ + +We can build something to see how this works! Let's say we want a simple counter +that can be incremented and decremented using two buttons. + +We start by modelling the __state__ of our application: + +```rust +#[derive(Default)] +struct Counter { + value: i32, +} +``` + +Next, we need to define the possible user interactions of our counter: +the button presses. These interactions are our __messages__: + +```rust +#[derive(Debug, Clone, Copy)] +pub enum Message { + Increment, + Decrement, +} +``` + +Now, let's show the actual counter by putting it all together in our +__view logic__: + +```rust +use iced::widget::{button, column, text, Column}; + +impl Counter { + pub fn view(&self) -> Column { + // We use a column: a simple vertical layout + column![ + // The increment button. We tell it to produce an + // `Increment` message when pressed + button("+").on_press(Message::Increment), + + // We show the value of the counter here + text(self.value).size(50), + + // The decrement button. We tell it to produce a + // `Decrement` message when pressed + button("-").on_press(Message::Decrement), + ] + } +} +``` + +Finally, we need to be able to react to any produced __messages__ and change our +__state__ accordingly in our __update logic__: + +```rust +impl Counter { + // ... + + pub fn update(&mut self, message: Message) { + match message { + Message::Increment => { + self.value += 1; + } + Message::Decrement => { + self.value -= 1; + } + } + } +} +``` + +And that's everything! We just wrote a whole user interface. Let's run it: + +```rust +fn main() -> iced::Result { + iced::run("A cool counter", Counter::update, Counter::view) +} +``` + +Iced will automatically: + + 1. Take the result of our __view logic__ and layout its widgets. + 1. Process events from our system and produce __messages__ for our + __update logic__. + 1. Draw the resulting user interface. + +Read the [book], the [documentation], and the [examples] to learn more! + +[book]: https://book.iced.rs/ +[documentation]: https://docs.rs/iced/ +[examples]: https://github.com/iced-rs/iced/tree/master/examples#examples +[The Elm Architecture]: https://guide.elm-lang.org/architecture/ diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs index 43adaf72..384645fa 100644 --- a/examples/markdown/src/main.rs +++ b/examples/markdown/src/main.rs @@ -1,7 +1,6 @@ -use iced::font; -use iced::padding; use iced::widget::{ - self, column, container, rich_text, row, span, text_editor, + self, column, container, rich_text, row, scrollable, span, text, + text_editor, }; use iced::{Element, Fill, Font, Task, Theme}; @@ -13,6 +12,8 @@ pub fn main() -> iced::Result { struct Markdown { content: text_editor::Content, + items: Vec, + theme: Theme, } #[derive(Debug, Clone)] @@ -22,11 +23,15 @@ enum Message { impl Markdown { fn new() -> (Self, Task) { + const INITIAL_CONTENT: &str = include_str!("../overview.md"); + + let theme = Theme::TokyoNight; + ( Self { - content: text_editor::Content::with_text( - "# Markdown Editor\nType your Markdown here...", - ), + content: text_editor::Content::with_text(INITIAL_CONTENT), + items: parse(INITIAL_CONTENT, &theme).collect(), + theme, }, widget::focus_next(), ) @@ -34,7 +39,14 @@ impl Markdown { fn update(&mut self, message: Message) { match message { Message::Edit(action) => { + let is_edit = action.is_edit(); + self.content.perform(action); + + if is_edit { + self.items = + parse(&self.content.text(), &self.theme).collect(); + } } } } @@ -46,127 +58,225 @@ impl Markdown { .padding(10) .font(Font::MONOSPACE); - let preview = { - let markdown = self.content.text(); - let parser = pulldown_cmark::Parser::new(&markdown); - - let mut strong = false; - let mut emphasis = false; - let mut heading = None; - let mut spans = Vec::new(); - - let items = parser.filter_map(|event| match event { - pulldown_cmark::Event::Start(tag) => match tag { - pulldown_cmark::Tag::Strong => { - strong = true; - None - } - pulldown_cmark::Tag::Emphasis => { - emphasis = true; - None - } - pulldown_cmark::Tag::Heading { level, .. } => { - heading = Some(level); - None - } - _ => None, - }, - pulldown_cmark::Event::End(tag) => match tag { - pulldown_cmark::TagEnd::Emphasis => { - emphasis = false; - None - } - pulldown_cmark::TagEnd::Strong => { - strong = false; - None - } - pulldown_cmark::TagEnd::Heading(_) => { - heading = None; - Some( - container(rich_text(spans.drain(..))) - .padding(padding::bottom(5)) - .into(), - ) - } - pulldown_cmark::TagEnd::Paragraph => Some( - container(rich_text(spans.drain(..))) - .padding(padding::bottom(15)) - .into(), - ), - pulldown_cmark::TagEnd::CodeBlock => Some( - container( - container( - rich_text(spans.drain(..)) - .font(Font::MONOSPACE), - ) - .width(Fill) - .padding(10) - .style(container::rounded_box), - ) - .padding(padding::bottom(15)) - .into(), - ), - _ => None, - }, - pulldown_cmark::Event::Text(text) => { - let span = span(text.into_string()); - - let span = match heading { - None => span, - Some(heading) => span.size(match heading { - pulldown_cmark::HeadingLevel::H1 => 32, - pulldown_cmark::HeadingLevel::H2 => 28, - pulldown_cmark::HeadingLevel::H3 => 24, - pulldown_cmark::HeadingLevel::H4 => 20, - pulldown_cmark::HeadingLevel::H5 => 16, - pulldown_cmark::HeadingLevel::H6 => 16, - }), - }; - - let span = if strong || emphasis { - span.font(Font { - weight: if strong { - font::Weight::Bold - } else { - font::Weight::Normal - }, - style: if emphasis { - font::Style::Italic - } else { - font::Style::Normal - }, - ..Font::default() - }) - } else { - span - }; - - spans.push(span); - - None - } - pulldown_cmark::Event::Code(code) => { - spans.push(span(code.into_string()).font(Font::MONOSPACE)); - None - } - pulldown_cmark::Event::SoftBreak => { - spans.push(span(" ")); - None - } - pulldown_cmark::Event::HardBreak => { - spans.push(span("\n")); - None - } - _ => None, - }); - - column(items).width(Fill) - }; + let preview = markdown(&self.items); - row![editor, preview].spacing(10).padding(10).into() + row![ + editor, + scrollable(preview).spacing(10).width(Fill).height(Fill) + ] + .spacing(10) + .padding(10) + .into() } fn theme(&self) -> Theme { Theme::TokyoNight } } + +fn markdown<'a>( + items: impl IntoIterator, +) -> Element<'a, Message> { + use iced::padding; + + let blocks = items.into_iter().enumerate().map(|(i, item)| match item { + Item::Heading(heading) => container(rich_text(heading)) + .padding(padding::top(if i > 0 { 8 } else { 0 })) + .into(), + Item::Paragraph(paragraph) => rich_text(paragraph).into(), + Item::List { start: None, items } => column( + items + .iter() + .map(|item| row!["•", rich_text(item)].spacing(10).into()), + ) + .spacing(10) + .into(), + Item::List { + start: Some(start), + items, + } => column(items.iter().enumerate().map(|(i, item)| { + row![text!("{}.", i as u64 + *start), rich_text(item)] + .spacing(10) + .into() + })) + .spacing(10) + .into(), + Item::CodeBlock(code) => { + container(rich_text(code).font(Font::MONOSPACE).size(12)) + .width(Fill) + .padding(10) + .style(container::rounded_box) + .into() + } + }); + + column(blocks).width(Fill).spacing(16).into() +} + +#[derive(Debug, Clone)] +enum Item { + Heading(Vec>), + Paragraph(Vec>), + CodeBlock(Vec>), + List { + start: Option, + items: Vec>>, + }, +} + +fn parse<'a>( + markdown: &'a str, + theme: &'a Theme, +) -> impl Iterator + 'a { + use iced::font; + use iced::highlighter::{self, Highlighter}; + use text::Highlighter as _; + + let mut spans = Vec::new(); + let mut heading = None; + let mut strong = false; + let mut emphasis = false; + let mut link = false; + let mut list = Vec::new(); + let mut list_start = None; + let mut highlighter = None; + + let parser = pulldown_cmark::Parser::new(markdown); + + // We want to keep the `spans` capacity + #[allow(clippy::drain_collect)] + parser.filter_map(move |event| match event { + pulldown_cmark::Event::Start(tag) => match tag { + pulldown_cmark::Tag::Heading { level, .. } => { + heading = Some(level); + None + } + pulldown_cmark::Tag::Strong => { + strong = true; + None + } + pulldown_cmark::Tag::Emphasis => { + emphasis = true; + None + } + pulldown_cmark::Tag::Link { .. } => { + link = true; + None + } + pulldown_cmark::Tag::List(first_item) => { + list_start = first_item; + None + } + pulldown_cmark::Tag::CodeBlock( + pulldown_cmark::CodeBlockKind::Fenced(language), + ) => { + highlighter = Some(Highlighter::new(&highlighter::Settings { + theme: highlighter::Theme::Base16Ocean, + token: language.to_string(), + })); + + None + } + _ => None, + }, + pulldown_cmark::Event::End(tag) => match tag { + pulldown_cmark::TagEnd::Heading(_) => { + heading = None; + Some(Item::Heading(spans.drain(..).collect())) + } + pulldown_cmark::TagEnd::Emphasis => { + emphasis = false; + None + } + pulldown_cmark::TagEnd::Strong => { + strong = false; + None + } + pulldown_cmark::TagEnd::Link => { + link = false; + None + } + pulldown_cmark::TagEnd::Paragraph => { + Some(Item::Paragraph(spans.drain(..).collect())) + } + pulldown_cmark::TagEnd::List(_) => Some(Item::List { + start: list_start, + items: list.drain(..).collect(), + }), + pulldown_cmark::TagEnd::Item => { + list.push(spans.drain(..).collect()); + None + } + pulldown_cmark::TagEnd::CodeBlock => { + highlighter = None; + Some(Item::CodeBlock(spans.drain(..).collect())) + } + _ => None, + }, + pulldown_cmark::Event::Text(text) => { + if let Some(highlighter) = &mut highlighter { + for (range, highlight) in + highlighter.highlight_line(text.as_ref()) + { + let span = span(text[range].to_owned()) + .color_maybe(highlight.color()) + .font_maybe(highlight.font()); + + spans.push(span); + } + } else { + let span = span(text.into_string()); + + let span = match heading { + None => span, + Some(heading) => span.size(match heading { + pulldown_cmark::HeadingLevel::H1 => 32, + pulldown_cmark::HeadingLevel::H2 => 28, + pulldown_cmark::HeadingLevel::H3 => 24, + pulldown_cmark::HeadingLevel::H4 => 20, + pulldown_cmark::HeadingLevel::H5 => 16, + pulldown_cmark::HeadingLevel::H6 => 16, + }), + }; + + let span = if strong || emphasis { + span.font(Font { + weight: if strong { + font::Weight::Bold + } else { + font::Weight::Normal + }, + style: if emphasis { + font::Style::Italic + } else { + font::Style::Normal + }, + ..Font::default() + }) + } else { + span + }; + + let span = + span.color_maybe(link.then(|| theme.palette().primary)); + + spans.push(span); + } + + None + } + pulldown_cmark::Event::Code(code) => { + spans.push(span(code.into_string()).font(Font::MONOSPACE)); + None + } + pulldown_cmark::Event::SoftBreak => { + spans.push(span(" ")); + None + } + pulldown_cmark::Event::HardBreak => { + spans.push(span("\n")); + None + } + _ => None, + }) +} -- cgit From aa62fa2ce992949d20ddbe8683ed2be0d922a568 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 18 Jul 2024 13:22:53 +0200 Subject: Adapt `scrollable` sizing strategy to contents --- examples/markdown/src/main.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'examples') diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs index 384645fa..1e3769ff 100644 --- a/examples/markdown/src/main.rs +++ b/examples/markdown/src/main.rs @@ -60,13 +60,10 @@ impl Markdown { let preview = markdown(&self.items); - row![ - editor, - scrollable(preview).spacing(10).width(Fill).height(Fill) - ] - .spacing(10) - .padding(10) - .into() + row![editor, scrollable(preview).spacing(10).height(Fill)] + .spacing(10) + .padding(10) + .into() } fn theme(&self) -> Theme { -- cgit From 47b7a36f36b99e346909390621b04f6691ff46d4 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 18 Jul 2024 14:34:00 +0200 Subject: Create `markdown` widget helpers in `iced_widget` --- examples/markdown/Cargo.toml | 4 +- examples/markdown/src/main.rs | 224 ++---------------------------------------- 2 files changed, 10 insertions(+), 218 deletions(-) (limited to 'examples') diff --git a/examples/markdown/Cargo.toml b/examples/markdown/Cargo.toml index 6875ee94..9404d5d2 100644 --- a/examples/markdown/Cargo.toml +++ b/examples/markdown/Cargo.toml @@ -7,6 +7,4 @@ publish = false [dependencies] iced.workspace = true -iced.features = ["highlighter", "debug"] - -pulldown-cmark = "0.11" +iced.features = ["markdown", "highlighter", "debug"] diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs index 1e3769ff..28b5941f 100644 --- a/examples/markdown/src/main.rs +++ b/examples/markdown/src/main.rs @@ -1,7 +1,4 @@ -use iced::widget::{ - self, column, container, rich_text, row, scrollable, span, text, - text_editor, -}; +use iced::widget::{self, markdown, row, scrollable, text_editor}; use iced::{Element, Fill, Font, Task, Theme}; pub fn main() -> iced::Result { @@ -12,7 +9,7 @@ pub fn main() -> iced::Result { struct Markdown { content: text_editor::Content, - items: Vec, + items: Vec, theme: Theme, } @@ -30,7 +27,8 @@ impl Markdown { ( Self { content: text_editor::Content::with_text(INITIAL_CONTENT), - items: parse(INITIAL_CONTENT, &theme).collect(), + items: markdown::parse(INITIAL_CONTENT, theme.palette()) + .collect(), theme, }, widget::focus_next(), @@ -44,8 +42,11 @@ impl Markdown { self.content.perform(action); if is_edit { - self.items = - parse(&self.content.text(), &self.theme).collect(); + self.items = markdown::parse( + &self.content.text(), + self.theme.palette(), + ) + .collect(); } } } @@ -70,210 +71,3 @@ impl Markdown { Theme::TokyoNight } } - -fn markdown<'a>( - items: impl IntoIterator, -) -> Element<'a, Message> { - use iced::padding; - - let blocks = items.into_iter().enumerate().map(|(i, item)| match item { - Item::Heading(heading) => container(rich_text(heading)) - .padding(padding::top(if i > 0 { 8 } else { 0 })) - .into(), - Item::Paragraph(paragraph) => rich_text(paragraph).into(), - Item::List { start: None, items } => column( - items - .iter() - .map(|item| row!["•", rich_text(item)].spacing(10).into()), - ) - .spacing(10) - .into(), - Item::List { - start: Some(start), - items, - } => column(items.iter().enumerate().map(|(i, item)| { - row![text!("{}.", i as u64 + *start), rich_text(item)] - .spacing(10) - .into() - })) - .spacing(10) - .into(), - Item::CodeBlock(code) => { - container(rich_text(code).font(Font::MONOSPACE).size(12)) - .width(Fill) - .padding(10) - .style(container::rounded_box) - .into() - } - }); - - column(blocks).width(Fill).spacing(16).into() -} - -#[derive(Debug, Clone)] -enum Item { - Heading(Vec>), - Paragraph(Vec>), - CodeBlock(Vec>), - List { - start: Option, - items: Vec>>, - }, -} - -fn parse<'a>( - markdown: &'a str, - theme: &'a Theme, -) -> impl Iterator + 'a { - use iced::font; - use iced::highlighter::{self, Highlighter}; - use text::Highlighter as _; - - let mut spans = Vec::new(); - let mut heading = None; - let mut strong = false; - let mut emphasis = false; - let mut link = false; - let mut list = Vec::new(); - let mut list_start = None; - let mut highlighter = None; - - let parser = pulldown_cmark::Parser::new(markdown); - - // We want to keep the `spans` capacity - #[allow(clippy::drain_collect)] - parser.filter_map(move |event| match event { - pulldown_cmark::Event::Start(tag) => match tag { - pulldown_cmark::Tag::Heading { level, .. } => { - heading = Some(level); - None - } - pulldown_cmark::Tag::Strong => { - strong = true; - None - } - pulldown_cmark::Tag::Emphasis => { - emphasis = true; - None - } - pulldown_cmark::Tag::Link { .. } => { - link = true; - None - } - pulldown_cmark::Tag::List(first_item) => { - list_start = first_item; - None - } - pulldown_cmark::Tag::CodeBlock( - pulldown_cmark::CodeBlockKind::Fenced(language), - ) => { - highlighter = Some(Highlighter::new(&highlighter::Settings { - theme: highlighter::Theme::Base16Ocean, - token: language.to_string(), - })); - - None - } - _ => None, - }, - pulldown_cmark::Event::End(tag) => match tag { - pulldown_cmark::TagEnd::Heading(_) => { - heading = None; - Some(Item::Heading(spans.drain(..).collect())) - } - pulldown_cmark::TagEnd::Emphasis => { - emphasis = false; - None - } - pulldown_cmark::TagEnd::Strong => { - strong = false; - None - } - pulldown_cmark::TagEnd::Link => { - link = false; - None - } - pulldown_cmark::TagEnd::Paragraph => { - Some(Item::Paragraph(spans.drain(..).collect())) - } - pulldown_cmark::TagEnd::List(_) => Some(Item::List { - start: list_start, - items: list.drain(..).collect(), - }), - pulldown_cmark::TagEnd::Item => { - list.push(spans.drain(..).collect()); - None - } - pulldown_cmark::TagEnd::CodeBlock => { - highlighter = None; - Some(Item::CodeBlock(spans.drain(..).collect())) - } - _ => None, - }, - pulldown_cmark::Event::Text(text) => { - if let Some(highlighter) = &mut highlighter { - for (range, highlight) in - highlighter.highlight_line(text.as_ref()) - { - let span = span(text[range].to_owned()) - .color_maybe(highlight.color()) - .font_maybe(highlight.font()); - - spans.push(span); - } - } else { - let span = span(text.into_string()); - - let span = match heading { - None => span, - Some(heading) => span.size(match heading { - pulldown_cmark::HeadingLevel::H1 => 32, - pulldown_cmark::HeadingLevel::H2 => 28, - pulldown_cmark::HeadingLevel::H3 => 24, - pulldown_cmark::HeadingLevel::H4 => 20, - pulldown_cmark::HeadingLevel::H5 => 16, - pulldown_cmark::HeadingLevel::H6 => 16, - }), - }; - - let span = if strong || emphasis { - span.font(Font { - weight: if strong { - font::Weight::Bold - } else { - font::Weight::Normal - }, - style: if emphasis { - font::Style::Italic - } else { - font::Style::Normal - }, - ..Font::default() - }) - } else { - span - }; - - let span = - span.color_maybe(link.then(|| theme.palette().primary)); - - spans.push(span); - } - - None - } - pulldown_cmark::Event::Code(code) => { - spans.push(span(code.into_string()).font(Font::MONOSPACE)); - None - } - pulldown_cmark::Event::SoftBreak => { - spans.push(span(" ")); - None - } - pulldown_cmark::Event::HardBreak => { - spans.push(span("\n")); - None - } - _ => None, - }) -} -- cgit From 06acb740fba1889c6a9fb48dfa3ae3aaac1df3ab Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 18 Jul 2024 15:14:54 +0200 Subject: Return proper `theme` in `markdown` example --- examples/markdown/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'examples') diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs index 28b5941f..d902a4f7 100644 --- a/examples/markdown/src/main.rs +++ b/examples/markdown/src/main.rs @@ -68,6 +68,6 @@ impl Markdown { } fn theme(&self) -> Theme { - Theme::TokyoNight + self.theme.clone() } } -- cgit