aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPolesznyák Márk <contact@pml68.dev>2025-10-20 13:35:38 +0200
committerPolesznyák Márk <contact@pml68.dev>2025-10-20 13:36:22 +0200
commit6107291a672ffc912d2cfae9ffa33dcfc7b50399 (patch)
treea266c6d8f21490e4899fee905df1534a99068bd2
parentci(doc): build docs with (diff)
downloadiced_selection-6107291a672ffc912d2cfae9ffa33dcfc7b50399.tar.gz
feat: add `markdown` example
-rw-r--r--.builds/ci.yml1
-rw-r--r--Cargo.toml4
-rw-r--r--examples/markdown/Cargo.toml13
-rw-r--r--examples/markdown/overview.md93
-rw-r--r--examples/markdown/src/main.rs74
-rw-r--r--examples/rich/src/main.rs2
-rw-r--r--src/markdown.rs7
7 files changed, 186 insertions, 8 deletions
diff --git a/.builds/ci.yml b/.builds/ci.yml
index 689ad52..8f7aa1d 100644
--- a/.builds/ci.yml
+++ b/.builds/ci.yml
@@ -23,3 +23,4 @@ tasks:
cd iced_selection
cargo build --package name
cargo build --package rich
+ cargo build --package markdown
diff --git a/Cargo.toml b/Cargo.toml
index a2c7a29..396241e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,9 +22,9 @@ iced_widget.workspace = true
unicode-segmentation.workspace = true
[workspace.dependencies]
-iced_widget = { git = "https://github.com/iced-rs/iced" }
+iced_widget = { git = "https://github.com/iced-rs/iced", branch = "master" }
unicode-segmentation = "1.0"
-iced = { git = "https://github.com/iced-rs/iced" }
+iced = { git = "https://github.com/iced-rs/iced", branch = "master" }
open = "5.3"
[workspace]
diff --git a/examples/markdown/Cargo.toml b/examples/markdown/Cargo.toml
new file mode 100644
index 0000000..ba97085
--- /dev/null
+++ b/examples/markdown/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "markdown"
+version = "0.0.0"
+edition = "2024"
+
+[dependencies]
+iced.workspace = true
+iced.features = ["highlighter"]
+
+iced_selection.path = "../.."
+iced_selection.features = ["markdown"]
+
+open.workspace = true
diff --git a/examples/markdown/overview.md b/examples/markdown/overview.md
new file mode 100644
index 0000000..2bb2d93
--- /dev/null
+++ b/examples/markdown/overview.md
@@ -0,0 +1,93 @@
+# 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<'_, Message> {
+ // 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
new file mode 100644
index 0000000..fae13ca
--- /dev/null
+++ b/examples/markdown/src/main.rs
@@ -0,0 +1,74 @@
+use iced::widget::{operation, row, scrollable, text_editor};
+use iced::{Element, Fill, Font, Theme, highlighter};
+use iced_selection::markdown;
+
+fn main() -> iced::Result {
+ iced::application(State::new, State::update, State::view)
+ .theme(Theme::CatppuccinMocha)
+ .run()
+}
+
+#[derive(Default)]
+struct State {
+ content: markdown::Content,
+ raw: text_editor::Content,
+}
+
+#[derive(Debug, Clone)]
+enum Message {
+ Edit(text_editor::Action),
+ LinkClicked(markdown::Url),
+}
+
+impl State {
+ fn new() -> (Self, iced::Task<Message>) {
+ const INITIAL_CONTENT: &str = include_str!("../overview.md");
+
+ (
+ Self {
+ content: markdown::Content::parse(INITIAL_CONTENT),
+ raw: text_editor::Content::with_text(INITIAL_CONTENT),
+ },
+ operation::focus_next(),
+ )
+ }
+
+ fn update(&mut self, message: Message) {
+ match message {
+ Message::Edit(action) => {
+ let is_edit = action.is_edit();
+
+ self.raw.perform(action);
+
+ if is_edit {
+ self.content = markdown::Content::parse(&self.raw.text());
+ }
+ }
+ Message::LinkClicked(link) => {
+ let _ = open::that_in_background(link.to_string());
+ }
+ }
+ }
+
+ fn view(&self) -> Element<'_, Message> {
+ let editor = text_editor(&self.raw)
+ .placeholder("Type your Markdown here...")
+ .on_action(Message::Edit)
+ .height(Fill)
+ .padding(10)
+ .font(Font::MONOSPACE)
+ .highlight("markdown", highlighter::Theme::Base16Ocean);
+
+ let preview =
+ markdown::view(self.content.items(), &Theme::CatppuccinMocha)
+ .map(Message::LinkClicked);
+
+ row![
+ editor,
+ scrollable(preview).spacing(10).width(Fill).height(Fill)
+ ]
+ .spacing(10)
+ .padding(10)
+ .into()
+ }
+}
diff --git a/examples/rich/src/main.rs b/examples/rich/src/main.rs
index 6c47e0f..f8f7414 100644
--- a/examples/rich/src/main.rs
+++ b/examples/rich/src/main.rs
@@ -20,7 +20,7 @@ impl State {
fn update(&mut self, message: Message) {
match message {
Message::LinkClicked(link) => {
- let _ = open::that(&link);
+ let _ = open::that_in_background(&link);
self.link = Some(link);
}
};
diff --git a/src/markdown.rs b/src/markdown.rs
index a3c939a..3083d3c 100644
--- a/src/markdown.rs
+++ b/src/markdown.rs
@@ -1,12 +1,9 @@
//! A custom markdown viewer and its corresponding functions.
-//!
-//! To be used with [`view_with`]
-//!
-//! [`view_with`]: iced_widget::markdown::view_with
use iced_widget::graphics::text::Paragraph;
use iced_widget::markdown::{
- Catalog, HeadingLevel, Item, Settings, Text, Url, Viewer, view_with,
+ Catalog, HeadingLevel, Item, Settings, Text, Viewer, view_with,
};
+pub use iced_widget::markdown::{Content, Url, parse};
use iced_widget::{column, container, row, scrollable};
use crate::core::Font;