···77use crate::{
88 cli::Cli,
99 config::Config,
1010- gui::FilViz,
1110 tui::TuiApp,
1212- types::{Kasten, KastenHandle},
1111+ types::{Deimos, Kasten, KastenHandle},
1212+ viz::FilViz,
1313};
1414use clap::Parser;
1515use tokio::sync::{RwLock, mpsc};
···1818mod cli;
1919mod config;
2020mod errors;
2121-mod gui;
2221mod logging;
2322mod lsp;
2423mod tui;
2524mod types;
2525+mod viz;
26262727fn main() -> color_eyre::Result<()> {
2828 errors::init()?;
···5555 // arc stuff
5656 let tui_rt = rt.clone();
5757 let kh = kh.clone();
5858+ let signal_tx = signal_tx.clone();
58595960 // closure to run the tui
6061 move || -> color_eyre::Result<()> {
···6869 }
6970 });
70717171- // spawn deimos
7272- // {
7373-7474- // rt.spawn(async {
7575- // let deimos = Deimos::new(kh, fh);
7676- // deimos.watch().await
7777- // });
7878- // }
7979-8072 // if they asked for the visualizer, we give them the visualizer
8173 if args.visualizer {
8274 // enter the guard so egui_async works properly
8375 let _rt_guard = rt.enter();
7676+7777+ // spawn deimos
7878+ {
7979+ let kh = kh.clone();
8080+ rt.spawn(async {
8181+ let deimos = Deimos::new(kh, signal_tx);
8282+ deimos.watch().await
8383+ });
8484+ }
84858586 let index = rt.block_on(async { kh.read().await.index.clone() });
8687
+11-1
src/tui/signal.rs
···5566use serde::{Deserialize, Serialize};
7788-use crate::{tui::Region, types::ZettelId};
88+use crate::{
99+ tui::Region,
1010+ types::{Link, ZettelId},
1111+};
9121013/// The varying signals that can be emitted.
1114#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
···3134 /// Create a New `Zettel`
3235 NewZettel,
33363737+ /// This zettel was created (filaments specific)
3438 CreatedZettel {
3539 zid: ZettelId,
4040+ },
4141+4242+ /// Set the links for this `ZettelId` (filaments specific)
4343+ SetLinks {
4444+ zid: ZettelId,
4545+ links: Vec<Link>,
3646 },
37473848 /// User asks to open a `Zettel`
+52-37
src/types/deimos.rs
···11-// use color_eyre::eyre::Context;
22-// use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Result, Watcher as _};
33-// use tracing::{error, info};
11+use color_eyre::eyre::Context;
22+use notify::{Config, Event, EventKind, RecommendedWatcher, RecursiveMode, Result, Watcher as _};
33+use tracing::{error, info};
4455-use crate::types::KastenHandle;
55+use tokio::sync::mpsc::UnboundedSender;
66+77+use crate::{
88+ tui::Signal,
99+ types::{KastenHandle, ZettelId},
1010+};
611712#[derive(Debug)]
88-#[expect(dead_code)]
913pub struct Deimos {
1014 kh: KastenHandle,
1111- // fh: FilamentsHandle,
1515+ signal_tx: UnboundedSender<Signal>,
1216}
13171414-// impl Deimos {
1515-// pub const fn new(kh: KastenHandle, fh: FilamentsHandle) -> Self {
1616-// Self { kh, fh }
1717-// }
1818+impl Deimos {
1919+ pub const fn new(kh: KastenHandle, signal_tx: UnboundedSender<Signal>) -> Self {
2020+ Self { kh, signal_tx }
2121+ }
2222+2323+ /// Watches the `Filaments Directory` for file changes and updates
2424+ /// the internal state of the kasten and the `Filaments` displayed in the
2525+ /// gui.
2626+ ///
2727+ /// NOTE: This function must be spawned as a top level await
2828+ pub async fn watch(&self) -> color_eyre::Result<()> {
2929+ info!("deimos spawned!");
18301919-// /// Watches the `Filaments Directory` for file changes and updates
2020-// /// the internal state of the kasten and the `Filaments` displayed in the
2121-// /// gui.
2222-// ///
2323-// /// NOTE: This function must be spawned as a top level await
2424-// pub async fn watch(&self) -> color_eyre::Result<()> {
2525-// info!("deimos spawned!");
3131+ let (tx, mut rx) = tokio::sync::mpsc::channel::<Result<Event>>(10);
3232+ let mut watcher = RecommendedWatcher::new(
3333+ move |res| tx.blocking_send(res).expect("failed to send event"),
3434+ Config::default(),
3535+ )?;
3636+3737+ watcher
3838+ .watch(&self.kh.read().await.root, RecursiveMode::Recursive)
3939+ .with_context(|| "failed to start the FS watcher")?;
26402727-// let (tx, mut rx) = tokio::sync::mpsc::channel::<Result<Event>>(10);
2828-// let mut watcher = RecommendedWatcher::new(
2929-// move |res| tx.blocking_send(res).expect("failed to send event"),
3030-// Config::default(),
3131-// )?;
4141+ while let Some(res) = rx.recv().await {
4242+ let Ok(event) = res.inspect_err(|e| error!("watcher error: {e:?}")) else {
4343+ continue;
4444+ };
32453333-// watcher
3434-// .watch(&self.kh.read().await.root, RecursiveMode::Recursive)
3535-// .with_context(|| "failed to start the FS watcher")?;
4646+ if let EventKind::Modify(notify::event::ModifyKind::Data(_)) = event.kind {
4747+ for path in event.paths {
4848+ let Ok(zid) = ZettelId::try_from(path.clone())
4949+ .inspect_err(|e| error!("Failed to convert path into zettel id! : {e}"))
5050+ else {
5151+ continue;
5252+ };
36533737-// while let Some(res) = rx.recv().await {
3838-// let kt = &mut *self.kh.write().await;
3939-// let fh = &mut *self.fh.lock().expect("Lock must not be poisoned");
5454+ let kt = &mut *self.kh.write().await;
5555+ kt.process_path(path).await?;
40564141-// match res {
4242-// Ok(event) => info!("event: {event:?}"),
4343-// Err(e) => error!("watch error: {e:?}"),
4444-// }
5757+ let links = kt.index.get_links(&zid).clone();
45584646-// *fh = (&kt.index).into();
4747-// }
5959+ self.signal_tx.send(Signal::SetLinks { zid, links })?;
6060+ }
6161+ }
6262+ }
48634949-// Ok(())
5050-// }
5151-// }
6464+ Ok(())
6565+ }
6666+}
+28-1
src/types/filaments.rs
···2323}
24242525impl Filaments {
2626+ pub fn get_gid(&self, zid: &ZettelId) -> NodeIndex {
2727+ *self
2828+ .zid_to_gid
2929+ .get(zid)
3030+ .expect("Invariant broken, any zid we ask for must have a corresponding gid")
3131+ }
3232+3333+ /// Inserts a `Zettel` into the graph.
2634 pub fn insert_zettel(&mut self, zid: ZettelId, index: &Index) {
2735 let zod = index.get_zod(&zid);
2836···3644 fn custom_node_closure(zod: &ZettelOnDisk, node: &mut Node<ZettelId, Link>) {
3745 node.set_label(zod.fm.title.clone());
3846 let disp = node.display_mut();
3939- disp.radius = 50.0;
4747+ disp.radius = 75.0;
40484149 // randomize position
4250 let x = rand::random_range(0.0..=100.0);
4351 let y = rand::random_range(0.0..=100.0);
4452 node.set_location(emath::Pos2 { x, y });
4553 node.set_hovered(true);
5454+ }
5555+5656+ /// Sets the `Links` for the given `ZettelId`
5757+ pub fn set_links_for_zid(&mut self, zid: &ZettelId, links: Vec<Link>) {
5858+ let gid = self.get_gid(zid);
5959+ self.graph
6060+ .g()
6161+ .edges(gid)
6262+ .map(|e| e.weight().id())
6363+ .collect::<Vec<_>>()
6464+ .iter()
6565+ .for_each(|edge_index| {
6666+ self.graph.remove_edge(*edge_index);
6767+ });
6868+6969+ for link in links {
7070+ let dest = self.get_gid(&link.dest);
7171+ self.graph.add_edge(gid, dest, link);
7272+ }
4673 }
4774}
4875
+14-2
src/types/index.rs
···5353 let zid: ZettelId = path.as_path().try_into()?;
5454 let (fm, body) = FrontMatter::extract_from_file(&path)?;
55555656- let outgoing_links = Self::parse_outgoing_links(&zid, &body);
5656+ let outgoing_links = Self::_parse_outgoing_links(&zid, &body);
57575858 Ok((
5959 zid,
···9494 })
9595 }
96969797- pub fn parse_outgoing_links(zid: &ZettelId, body: &str) -> Vec<Link> {
9797+ pub fn parse_outgoing_links(&mut self, zid: &ZettelId) {
9898+ let body = self.get_zod(zid).body.as_str();
9999+ let links = Self::_parse_outgoing_links(zid, body);
100100+ self.outgoing_links.insert(zid.clone(), links);
101101+ }
102102+103103+ fn _parse_outgoing_links(zid: &ZettelId, body: &str) -> Vec<Link> {
98104 let parser = Parser::new_ext(body, Options::ENABLE_WIKILINKS);
99105100106 // let mut links = vec![];
···230236231237 fn get_zod_mut(&mut self, zid: &ZettelId) -> &mut ZettelOnDisk {
232238 self.zods.get_mut(zid).expect("Invariant broken. Any zid we lookup must exist in the index, otherwise the db is corrupt or not sync'd.")
239239+ }
240240+241241+ pub fn get_links(&self, zid: &ZettelId) -> &Vec<Link> {
242242+ self.outgoing_links
243243+ .get(zid)
244244+ .expect("Invariant broken. Any zid we look up exist inside this map")
233245 }
234246235247 pub const fn zods(&self) -> &HashMap<ZettelId, ZettelOnDisk> {
+1
src/types/kasten.rs
···112112 // and then we sync tags
113113 self.index.sync_tags_with_db(&zid, &self.db).await?;
114114 self.index.sync_zettel_title_with_db(&zid, &self.db).await?;
115115+ self.index.parse_outgoing_links(&zid);
115116116117 Ok(())
117118 }
-1
src/types/mod.rs
···3535pub use frontmatter::FrontMatter;
36363737mod deimos;
3838-#[expect(unused_imports)]
3938pub use deimos::Deimos;