diff options
| author | 2025-02-01 03:14:08 +0100 | |
|---|---|---|
| committer | 2025-02-01 03:14:08 +0100 | |
| commit | 91f94f3b6e62bf05fb82b3c3bd999eff7b3fd339 (patch) | |
| tree | d9cb9cdf2a2c59e9b0ca01f5760033c994df730d /examples/markdown | |
| parent | 30ee9d024d00403f2fc0571946fa9ca398117e05 (diff) | |
| parent | ed0ffb59634424bb58540bdfdc4994d6665028ea (diff) | |
| download | iced-91f94f3b6e62bf05fb82b3c3bd999eff7b3fd339.tar.gz iced-91f94f3b6e62bf05fb82b3c3bd999eff7b3fd339.tar.bz2 iced-91f94f3b6e62bf05fb82b3c3bd999eff7b3fd339.zip | |
Merge pull request #2776 from iced-rs/fix/markdown
Incremental `markdown` parsing and various fixes
Diffstat (limited to '')
| -rw-r--r-- | examples/markdown/Cargo.toml | 2 | ||||
| -rw-r--r-- | examples/markdown/src/main.rs | 111 | 
2 files changed, 100 insertions, 13 deletions
| diff --git a/examples/markdown/Cargo.toml b/examples/markdown/Cargo.toml index cb74b954..fa6ced74 100644 --- a/examples/markdown/Cargo.toml +++ b/examples/markdown/Cargo.toml @@ -7,6 +7,6 @@ publish = false  [dependencies]  iced.workspace = true -iced.features = ["markdown", "highlighter", "debug"] +iced.features = ["markdown", "highlighter", "tokio", "debug"]  open = "5.3" diff --git a/examples/markdown/src/main.rs b/examples/markdown/src/main.rs index 5605478f..5b9a3b4a 100644 --- a/examples/markdown/src/main.rs +++ b/examples/markdown/src/main.rs @@ -1,23 +1,37 @@  use iced::highlighter; -use iced::widget::{self, markdown, row, scrollable, text_editor}; -use iced::{Element, Fill, Font, Task, Theme}; +use iced::time::{self, milliseconds}; +use iced::widget::{ +    self, hover, markdown, right, row, scrollable, text_editor, toggler, +}; +use iced::{Element, Fill, Font, Subscription, Task, Theme};  pub fn main() -> iced::Result {      iced::application("Markdown - Iced", Markdown::update, Markdown::view) +        .subscription(Markdown::subscription)          .theme(Markdown::theme)          .run_with(Markdown::new)  }  struct Markdown {      content: text_editor::Content, -    items: Vec<markdown::Item>, +    mode: Mode,      theme: Theme,  } +enum Mode { +    Preview(Vec<markdown::Item>), +    Stream { +        pending: String, +        parsed: markdown::Content, +    }, +} +  #[derive(Debug, Clone)]  enum Message {      Edit(text_editor::Action),      LinkClicked(markdown::Url), +    ToggleStream(bool), +    NextToken,  }  impl Markdown { @@ -29,14 +43,14 @@ impl Markdown {          (              Self {                  content: text_editor::Content::with_text(INITIAL_CONTENT), -                items: markdown::parse(INITIAL_CONTENT).collect(), +                mode: Mode::Preview(markdown::parse(INITIAL_CONTENT).collect()),                  theme,              },              widget::focus_next(),          )      } -    fn update(&mut self, message: Message) { +    fn update(&mut self, message: Message) -> Task<Message> {          match message {              Message::Edit(action) => {                  let is_edit = action.is_edit(); @@ -44,12 +58,56 @@ impl Markdown {                  self.content.perform(action);                  if is_edit { -                    self.items = -                        markdown::parse(&self.content.text()).collect(); +                    self.mode = Mode::Preview( +                        markdown::parse(&self.content.text()).collect(), +                    );                  } + +                Task::none()              }              Message::LinkClicked(link) => {                  let _ = open::that_in_background(link.to_string()); + +                Task::none() +            } +            Message::ToggleStream(enable_stream) => { +                if enable_stream { +                    self.mode = Mode::Stream { +                        pending: self.content.text(), +                        parsed: markdown::Content::new(), +                    }; + +                    scrollable::snap_to( +                        "preview", +                        scrollable::RelativeOffset::END, +                    ) +                } else { +                    self.mode = Mode::Preview( +                        markdown::parse(&self.content.text()).collect(), +                    ); + +                    Task::none() +                } +            } +            Message::NextToken => { +                match &mut self.mode { +                    Mode::Preview(_) => {} +                    Mode::Stream { pending, parsed } => { +                        if pending.is_empty() { +                            self.mode = Mode::Preview(parsed.items().to_vec()); +                        } else { +                            let mut tokens = pending.split(' '); + +                            if let Some(token) = tokens.next() { +                                parsed.push_str(&format!("{token} ")); +                            } + +                            *pending = tokens.collect::<Vec<_>>().join(" "); +                        } +                    } +                } + +                Task::none()              }          }      } @@ -63,20 +121,49 @@ impl Markdown {              .font(Font::MONOSPACE)              .highlight("markdown", highlighter::Theme::Base16Ocean); +        let items = match &self.mode { +            Mode::Preview(items) => items.as_slice(), +            Mode::Stream { parsed, .. } => parsed.items(), +        }; +          let preview = markdown( -            &self.items, +            items,              markdown::Settings::default(),              markdown::Style::from_palette(self.theme.palette()),          )          .map(Message::LinkClicked); -        row![editor, scrollable(preview).spacing(10).height(Fill)] -            .spacing(10) -            .padding(10) -            .into() +        row![ +            editor, +            hover( +                scrollable(preview) +                    .spacing(10) +                    .width(Fill) +                    .height(Fill) +                    .id("preview"), +                right( +                    toggler(matches!(self.mode, Mode::Stream { .. })) +                        .label("Stream") +                        .on_toggle(Message::ToggleStream) +                ) +                .padding([0, 20]) +            ) +        ] +        .spacing(10) +        .padding(10) +        .into()      }      fn theme(&self) -> Theme {          self.theme.clone()      } + +    fn subscription(&self) -> Subscription<Message> { +        match self.mode { +            Mode::Preview(_) => Subscription::none(), +            Mode::Stream { .. } => { +                time::every(milliseconds(20)).map(|_| Message::NextToken) +            } +        } +    }  } | 
