feat: add ability to preview markdown

This commit is contained in:
Stevan Freeborn
2026-01-21 07:12:20 -06:00
parent 9386fb38fd
commit 55bdbafce2
3 changed files with 320 additions and 15 deletions
Generated
+242
View File
@@ -37,6 +37,15 @@ dependencies = [
"zerocopy", "zerocopy",
] ]
[[package]]
name = "aho-corasick"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
dependencies = [
"memchr",
]
[[package]] [[package]]
name = "aligned" name = "aligned"
version = "0.4.3" version = "0.4.3"
@@ -345,6 +354,21 @@ dependencies = [
"arrayvec", "arrayvec",
] ]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "bit-set" name = "bit-set"
version = "0.8.0" version = "0.8.0"
@@ -792,6 +816,15 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"
[[package]]
name = "deranged"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587"
dependencies = [
"powerfmt",
]
[[package]] [[package]]
name = "dispatch" name = "dispatch"
version = "0.2.0" version = "0.2.0"
@@ -970,6 +1003,17 @@ dependencies = [
"zune-inflate", "zune-inflate",
] ]
[[package]]
name = "fancy-regex"
version = "0.16.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f"
dependencies = [
"bit-set",
"regex-automata",
"regex-syntax",
]
[[package]] [[package]]
name = "fastrand" name = "fastrand"
version = "2.3.0" version = "2.3.0"
@@ -1021,6 +1065,12 @@ dependencies = [
"miniz_oxide", "miniz_oxide",
] ]
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "foldhash" name = "foldhash"
version = "0.1.5" version = "0.1.5"
@@ -1205,6 +1255,15 @@ dependencies = [
"windows-link", "windows-link",
] ]
[[package]]
name = "getopts"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df"
dependencies = [
"unicode-width",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.3.4" version = "0.3.4"
@@ -1396,6 +1455,7 @@ dependencies = [
"iced_core", "iced_core",
"iced_debug", "iced_debug",
"iced_futures", "iced_futures",
"iced_highlighter",
"iced_renderer", "iced_renderer",
"iced_runtime", "iced_runtime",
"iced_widget", "iced_widget",
@@ -1468,6 +1528,16 @@ dependencies = [
"unicode-segmentation", "unicode-segmentation",
] ]
[[package]]
name = "iced_highlighter"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb24e1610502779b4e307c6f95da616ec7e883b67a18108cb0a036b169e50359"
dependencies = [
"iced_core",
"two-face",
]
[[package]] [[package]]
name = "iced_program" name = "iced_program"
version = "0.14.0" version = "0.14.0"
@@ -1547,9 +1617,11 @@ version = "0.14.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1596afa0d3109c2618e8bc12bae6c11d3064df8f95c42dfce570397dbe957ab" checksum = "b1596afa0d3109c2618e8bc12bae6c11d3064df8f95c42dfce570397dbe957ab"
dependencies = [ dependencies = [
"iced_highlighter",
"iced_renderer", "iced_renderer",
"log", "log",
"num-traits", "num-traits",
"pulldown-cmark",
"rustc-hash 2.1.1", "rustc-hash 2.1.1",
"thiserror 2.0.17", "thiserror 2.0.17",
"unicode-segmentation", "unicode-segmentation",
@@ -1644,6 +1716,12 @@ dependencies = [
"either", "either",
] ]
[[package]]
name = "itoa"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.21.1" version = "0.21.1"
@@ -1786,6 +1864,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4" checksum = "d4a5ff6bcca6c4867b1c4fd4ef63e4db7436ef363e0ad7531d1558856bae64f4"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.15" version = "0.4.15"
@@ -2043,6 +2127,12 @@ dependencies = [
"num-traits", "num-traits",
] ]
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]] [[package]]
name = "num-derive" name = "num-derive"
version = "0.4.2" version = "0.4.2"
@@ -2615,6 +2705,19 @@ version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "plist"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07"
dependencies = [
"base64",
"indexmap",
"quick-xml",
"serde",
"time",
]
[[package]] [[package]]
name = "png" name = "png"
version = "0.18.0" version = "0.18.0"
@@ -2663,6 +2766,12 @@ dependencies = [
"portable-atomic", "portable-atomic",
] ]
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]] [[package]]
name = "ppv-lite86" name = "ppv-lite86"
version = "0.2.21" version = "0.2.21"
@@ -2715,6 +2824,25 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "pulldown-cmark"
version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
dependencies = [
"bitflags 2.10.0",
"getopts",
"memchr",
"pulldown-cmark-escape",
"unicase",
]
[[package]]
name = "pulldown-cmark-escape"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae"
[[package]] [[package]]
name = "pxfm" name = "pxfm"
version = "0.1.27" version = "0.1.27"
@@ -2918,6 +3046,23 @@ dependencies = [
"bitflags 2.10.0", "bitflags 2.10.0",
] ]
[[package]]
name = "regex-automata"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58"
[[package]] [[package]]
name = "renderdoc-sys" name = "renderdoc-sys"
version = "1.1.0" version = "1.1.0"
@@ -3077,6 +3222,19 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "serde_json"
version = "1.0.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
dependencies = [
"itoa",
"memchr",
"serde",
"serde_core",
"zmij",
]
[[package]] [[package]]
name = "serde_repr" name = "serde_repr"
version = "0.1.20" version = "0.1.20"
@@ -3308,6 +3466,27 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "syntect"
version = "5.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925"
dependencies = [
"bincode",
"fancy-regex",
"flate2",
"fnv",
"once_cell",
"plist",
"regex-syntax",
"serde",
"serde_derive",
"serde_json",
"thiserror 2.0.17",
"walkdir",
"yaml-rust",
]
[[package]] [[package]]
name = "sys-locale" name = "sys-locale"
version = "0.3.2" version = "0.3.2"
@@ -3393,6 +3572,37 @@ dependencies = [
"zune-jpeg 0.4.21", "zune-jpeg 0.4.21",
] ]
[[package]]
name = "time"
version = "0.3.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d"
dependencies = [
"deranged",
"itoa",
"num-conv",
"powerfmt",
"serde",
"time-core",
"time-macros",
]
[[package]]
name = "time-core"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b"
[[package]]
name = "time-macros"
version = "0.2.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3"
dependencies = [
"num-conv",
"time-core",
]
[[package]] [[package]]
name = "tiny-skia" name = "tiny-skia"
version = "0.11.4" version = "0.11.4"
@@ -3517,6 +3727,17 @@ dependencies = [
"core_maths", "core_maths",
] ]
[[package]]
name = "two-face"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e51b6e60e545cfdae5a4639ff423818f52372211a8d9a3e892b4b0761f76b2"
dependencies = [
"serde",
"serde_derive",
"syntect",
]
[[package]] [[package]]
name = "uds_windows" name = "uds_windows"
version = "1.1.0" version = "1.1.0"
@@ -3528,6 +3749,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "unicase"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
version = "0.3.18" version = "0.3.18"
@@ -4508,6 +4735,15 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448" checksum = "7a5a4b21e1a62b67a2970e6831bc091d7b87e119e7f9791aef9702e3bef04448"
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]
[[package]] [[package]]
name = "yazi" name = "yazi"
version = "0.2.1" version = "0.2.1"
@@ -4601,6 +4837,12 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "zmij"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"
[[package]] [[package]]
name = "zoeae" name = "zoeae"
version = "0.1.0" version = "0.1.0"
+1 -1
View File
@@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2024" edition = "2024"
[dependencies] [dependencies]
iced = { version = "0.14.0", features = ["image"] } iced = { version = "0.14.0", features = ["image", "markdown", "highlighter"] }
rfd = "0.17.1" rfd = "0.17.1"
uuid = { version = "1.19.0", features = ["v4"] } uuid = { version = "1.19.0", features = ["v4"] }
+77 -14
View File
@@ -4,9 +4,11 @@ use std::path::PathBuf;
use iced::padding::bottom; use iced::padding::bottom;
use iced::widget::text_editor::{Binding, KeyPress}; use iced::widget::text_editor::{Binding, KeyPress};
use iced::widget::{button, column, container, pick_list, row, scrollable, text, text_editor}; use iced::widget::{
button, column, container, markdown, pick_list, row, scrollable, text, text_editor,
};
use iced::window::icon; use iced::window::icon;
use iced::{Background, Border, Element, border}; use iced::{Background, Border, Element, Task, border};
use iced::{Font, Length, Theme}; use iced::{Font, Length, Theme};
use iced::{keyboard, window}; use iced::{keyboard, window};
use rfd::FileDialog; use rfd::FileDialog;
@@ -36,10 +38,10 @@ const MIN_EDITOR_FONT_SIZE: u32 = 12;
// TODO: Handle creating new files // TODO: Handle creating new files
// TODO: Opening another window // TODO: Opening another window
struct File { struct File {
content: text_editor::Content, content: text_editor::Content,
path: Option<PathBuf>, path: Option<PathBuf>,
markdown: Vec<markdown::Item>,
} }
impl Default for File { impl Default for File {
@@ -47,18 +49,21 @@ impl Default for File {
File { File {
content: text_editor::Content::new(), content: text_editor::Content::new(),
path: None, path: None,
markdown: Vec::new(),
} }
} }
} }
// TODO: Chat says I need to update #[derive(Default)]
// the files map to be a map between enum Mode {
// an id and an index #[default]
// Then files need to be held in; Edit,
// list Preview,
}
#[derive(Default)] #[derive(Default)]
struct State { struct State {
mode: Mode,
files: Vec<File>, files: Vec<File>,
current_file: usize, current_file: usize,
editor_font_size: u32, editor_font_size: u32,
@@ -108,6 +113,7 @@ enum ViewAction {
Increase, Increase,
Decrease, Decrease,
Reset, Reset,
TogglePreview,
} }
impl ViewAction { impl ViewAction {
@@ -115,6 +121,7 @@ impl ViewAction {
ViewAction::Increase, ViewAction::Increase,
ViewAction::Decrease, ViewAction::Decrease,
ViewAction::Reset, ViewAction::Reset,
ViewAction::TogglePreview,
]; ];
} }
@@ -124,6 +131,7 @@ impl std::fmt::Display for ViewAction {
ViewAction::Decrease => write!(f, "Decrease font"), ViewAction::Decrease => write!(f, "Decrease font"),
ViewAction::Increase => write!(f, "Increase font"), ViewAction::Increase => write!(f, "Increase font"),
ViewAction::Reset => write!(f, "Reset font"), ViewAction::Reset => write!(f, "Reset font"),
ViewAction::TogglePreview => write!(f, "Preview"),
} }
} }
} }
@@ -134,8 +142,14 @@ enum Message {
FileActionSelected(FileAction), FileActionSelected(FileAction),
ViewActionSelected(ViewAction), ViewActionSelected(ViewAction),
SwitchTab(usize), SwitchTab(usize),
LinkClicked(String),
} }
// TODO: Can we at least make
// theme configurable
// and then maybe even define
// complete custom and/or use
// existing as starter
fn theme(_state: &State) -> Theme { fn theme(_state: &State) -> Theme {
Theme::Dark Theme::Dark
} }
@@ -212,6 +226,7 @@ fn view(state: &State) -> Element<'_, Message> {
let n = keyboard::Key::Character("n".into()); let n = keyboard::Key::Character("n".into());
let s = keyboard::Key::Character("s".into()); let s = keyboard::Key::Character("s".into());
let o = keyboard::Key::Character("o".into()); let o = keyboard::Key::Character("o".into());
let w = keyboard::Key::Character("w".into());
let minus = keyboard::Key::Character("-".into()); let minus = keyboard::Key::Character("-".into());
let equals = keyboard::Key::Character("=".into()); let equals = keyboard::Key::Character("=".into());
let zero = keyboard::Key::Character("0".into()); let zero = keyboard::Key::Character("0".into());
@@ -221,11 +236,18 @@ fn view(state: &State) -> Element<'_, Message> {
let is_save_as = let is_save_as =
key_press.modifiers.command() && key_press.modifiers.shift() && key_press.key == s; key_press.modifiers.command() && key_press.modifiers.shift() && key_press.key == s;
let is_open = key_press.modifiers.command() && key_press.key == o; let is_open = key_press.modifiers.command() && key_press.key == o;
let is_close = key_press.modifiers.command() && key_press.key == w;
let is_increase_font = key_press.modifiers.command() && key_press.key == equals; let is_increase_font = key_press.modifiers.command() && key_press.key == equals;
let is_decrease_font = key_press.modifiers.command() && key_press.key == minus; let is_decrease_font = key_press.modifiers.command() && key_press.key == minus;
let is_reset_font = key_press.modifiers.command() && key_press.key == zero; let is_reset_font = key_press.modifiers.command() && key_press.key == zero;
if is_close {
return Some(Binding::Custom(Message::FileActionSelected(
FileAction::Close(Some(state.current_file)),
)));
}
if is_reset_font { if is_reset_font {
return Some(Binding::Custom(Message::ViewActionSelected( return Some(Binding::Custom(Message::ViewActionSelected(
ViewAction::Reset, ViewAction::Reset,
@@ -271,6 +293,14 @@ fn view(state: &State) -> Element<'_, Message> {
text_editor::Binding::from_key_press(key_press) text_editor::Binding::from_key_press(key_press)
}); });
let mut markdown_styles: markdown::Style = Theme::Dark.into();
markdown_styles.font = CUSTOM_FONT;
let markdown_settings = markdown::Settings::with_text_size(state.editor_font_size, markdown_styles);
let markdown_preview =
markdown::view(&current_file.markdown, markdown_settings).map(Message::LinkClicked);
let preview_container = container(row![markdown_preview]).height(Length::Fill);
let editor_container = container(row![editor]).height(Length::Fill); let editor_container = container(row![editor]).height(Length::Fill);
let cursor_position = current_file.content.cursor().position; let cursor_position = current_file.content.cursor().position;
@@ -290,7 +320,12 @@ fn view(state: &State) -> Element<'_, Message> {
let status_bar = container(row![file_path_text, cursor_text].spacing(10)); let status_bar = container(row![file_path_text, cursor_text].spacing(10));
container(column![tabs, action_bar, editor_container, status_bar]) let main = match state.mode {
Mode::Edit => editor_container,
Mode::Preview => preview_container,
};
container(column![tabs, action_bar, main, status_bar])
.padding(10) .padding(10)
.into() .into()
} }
@@ -336,11 +371,13 @@ fn open_file() -> (Option<PathBuf>, String) {
} }
} }
fn update(state: &mut State, message: Message) { fn update(state: &mut State, message: Message) -> Task<Message> {
match message { match message {
Message::Edit(action) => { Message::Edit(action) => {
// TODO: Probably shouldn't parse every time we edited
let current_file = &mut state.files[state.current_file]; let current_file = &mut state.files[state.current_file];
current_file.content.perform(action); current_file.content.perform(action);
current_file.markdown = markdown::parse(&current_file.content.text()).collect();
} }
Message::FileActionSelected(action) => { Message::FileActionSelected(action) => {
state.selected_file_action = None; state.selected_file_action = None;
@@ -361,13 +398,14 @@ fn update(state: &mut State, message: Message) {
{ {
file.content = text_editor::Content::with_text(&content); file.content = text_editor::Content::with_text(&content);
state.current_file = file_index; state.current_file = file_index;
return; return Task::none();
} }
} }
let opened_file = File { let opened_file = File {
path, path,
content: text_editor::Content::with_text(&content), content: text_editor::Content::with_text(&content),
markdown: markdown::parse(&content).collect(),
}; };
state.files.push(opened_file); state.files.push(opened_file);
@@ -391,6 +429,17 @@ fn update(state: &mut State, message: Message) {
None => state.current_file, None => state.current_file,
}; };
if state.files.len() == 1 {
return iced::exit();
}
if state.files.len() - 1 == idx_to_close {
state.current_file = state.files.len() - 2;
state.files.remove(idx_to_close);
return Task::none();
}
state.current_file -= 1;
state.files.remove(idx_to_close); state.files.remove(idx_to_close);
} }
} }
@@ -401,25 +450,39 @@ fn update(state: &mut State, message: Message) {
match action { match action {
ViewAction::Increase => { ViewAction::Increase => {
if state.editor_font_size >= MAX_EDITOR_FONT_SIZE { if state.editor_font_size >= MAX_EDITOR_FONT_SIZE {
return; return Task::none();
} }
state.editor_font_size += 2; state.editor_font_size += 2;
} }
ViewAction::Decrease => { ViewAction::Decrease => {
if state.editor_font_size <= MIN_EDITOR_FONT_SIZE { if state.editor_font_size <= MIN_EDITOR_FONT_SIZE {
return; return Task::none();
} }
state.editor_font_size -= 2; state.editor_font_size -= 2;
} }
ViewAction::Reset => state.editor_font_size = DEFAULT_EDITOR_FONT_SIZE, ViewAction::Reset => {
state.editor_font_size = DEFAULT_EDITOR_FONT_SIZE;
}
// TODO: Carry previous mode when toggling
// so that if we already in preview we can
// just put the user back where they were
ViewAction::TogglePreview => match state.mode {
Mode::Edit => state.mode = Mode::Preview,
Mode::Preview => state.mode = Mode::Edit,
},
} }
} }
Message::SwitchTab(file_id) => { Message::SwitchTab(file_id) => {
state.current_file = file_id; state.current_file = file_id;
} }
Message::LinkClicked(link) => {
print!("Link clicked: {}", link);
}
} }
Task::none()
} }
fn boot() -> State { fn boot() -> State {