My personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities.
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: filaments spawn new node on new zettel

+162 -81
+47 -7
src/gui/mod.rs
··· 1 1 use eframe::egui; 2 2 use egui_graphs::{SettingsInteraction, SettingsNavigation}; 3 + use futures::executor::block_on; 4 + use tokio::sync::mpsc::UnboundedReceiver; 5 + use tracing::debug; 3 6 4 - use crate::types::FilamentsHandle; 7 + use crate::{ 8 + tui::Signal, 9 + types::{Filaments, Index, KastenHandle}, 10 + }; 5 11 6 12 /// The `Filaments Visualizer`, which is an instance of `eframe`, which uses `egui` 7 13 pub struct FilViz { 8 - fh: FilamentsHandle, 14 + kh: KastenHandle, 15 + signal_rx: UnboundedReceiver<Signal>, 16 + filaments: Filaments, 9 17 } 10 18 11 19 impl FilViz { 12 20 /// Create a new instance of the `FiLViz` 13 - const fn new(_cc: &eframe::CreationContext<'_>, fh: FilamentsHandle) -> Self { 21 + fn new( 22 + _cc: &eframe::CreationContext<'_>, 23 + kh: KastenHandle, 24 + signal_rx: UnboundedReceiver<Signal>, 25 + index: &Index, 26 + ) -> Self { 14 27 // Customize egui here with cc.egui_ctx.set_fonts and cc.egui_ctx.set_global_style. 15 28 // Restore app state using cc.storage (requires the "persistence" feature). 16 29 // Use the cc.gl (a glow::Context) to create graphics shaders and buffers that you can use 17 30 // for e.g. egui::PaintCallback. 18 - Self { fh } 31 + Self { 32 + kh, 33 + signal_rx, 34 + filaments: index.into(), 35 + } 19 36 } 20 37 21 38 /// Create and run the `FilViz`. 22 - pub fn run(fh: FilamentsHandle) -> color_eyre::Result<()> { 39 + pub fn run( 40 + kh: KastenHandle, 41 + signal_rx: UnboundedReceiver<Signal>, 42 + index: &Index, 43 + ) -> color_eyre::Result<()> { 23 44 let native_options = eframe::NativeOptions::default(); 24 45 eframe::run_native( 25 46 "Filaments Visualizer", 26 47 native_options, 27 - Box::new(|cc| Ok(Box::new(Self::new(cc, fh)))), 48 + Box::new(|cc| Ok(Box::new(Self::new(cc, kh, signal_rx, index)))), 28 49 )?; 29 50 30 51 Ok(()) ··· 37 58 impl eframe::App for FilViz { 38 59 fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) { 39 60 egui::CentralPanel::default().show_inside(ui, |ui| { 40 - let g = &mut self.fh.lock().expect("Lock must not be poisoned").graph; 61 + // let g = &mut self.fh.lock().expect("Lock must not be poisoned").graph; 62 + let g = &mut self.filaments.graph; 41 63 42 64 let mut view = egui_graphs::GraphView::<_, _, _, _, _, _, S, L>::new(g) 43 65 .with_interactions( ··· 62 84 egui::warn_if_debug_build(ui); 63 85 }); 64 86 }); 87 + } 88 + 89 + fn logic(&mut self, _ctx: &egui::Context, _frame: &mut eframe::Frame) { 90 + if let Ok(signal) = self.signal_rx.try_recv() { 91 + debug!("received signal in filaments: {signal}"); 92 + 93 + #[allow(clippy::single_match)] 94 + match signal { 95 + Signal::CreatedZettel { zid } => { 96 + block_on(async { 97 + let index = &self.kh.read().await.index; 98 + self.filaments.insert_zettel(zid, index); 99 + }); 100 + } 101 + 102 + _ => {} 103 + } 104 + } 65 105 } 66 106 } 67 107
+15 -16
src/main.rs
··· 9 9 config::Config, 10 10 gui::FilViz, 11 11 tui::TuiApp, 12 - types::{Deimos, Filaments, Kasten, KastenHandle}, 12 + types::{Kasten, KastenHandle}, 13 13 }; 14 14 use clap::Parser; 15 - use tokio::sync::RwLock; 15 + use tokio::sync::{RwLock, mpsc}; 16 16 use tracing::debug; 17 17 18 18 mod cli; ··· 48 48 49 49 debug!("Kasten Handle: {kh:#?}"); 50 50 51 + let (signal_tx, signal_rx) = mpsc::unbounded_channel(); 52 + 51 53 // then we spawn the tui on its own thread 52 54 let tui_handle = std::thread::spawn({ 53 55 // arc stuff ··· 58 60 move || -> color_eyre::Result<()> { 59 61 // block the tui on the same runtime as above 60 62 tui_rt.block_on(async { 61 - let mut tui = TuiApp::new(args.tick_rate, args.frame_rate, kh).await?; 63 + let mut tui = TuiApp::new(args.tick_rate, args.frame_rate, kh, signal_tx).await?; 62 64 tui.run().await?; 63 65 // just close everything as soon as the tui is done running 64 66 process::exit(0); ··· 66 68 } 67 69 }); 68 70 69 - let fh = rt.block_on(async { 70 - Arc::new(std::sync::Mutex::new(Filaments::from( 71 - &kh.read().await.index, 72 - ))) 73 - }); 74 71 // spawn deimos 75 - { 76 - let fh = fh.clone(); 72 + // { 77 73 78 - rt.spawn(async { 79 - let deimos = Deimos::new(kh, fh); 80 - deimos.watch().await 81 - }); 82 - } 74 + // rt.spawn(async { 75 + // let deimos = Deimos::new(kh, fh); 76 + // deimos.watch().await 77 + // }); 78 + // } 83 79 84 80 // if they asked for the visualizer, we give them the visualizer 85 81 if args.visualizer { 86 82 // enter the guard so egui_async works properly 87 83 let _rt_guard = rt.enter(); 88 - FilViz::run(fh)?; 84 + 85 + let index = rt.block_on(async { kh.read().await.index.clone() }); 86 + 87 + FilViz::run(kh, signal_rx, &index)?; 89 88 } 90 89 91 90 // join on the tui
+12 -3
src/tui/app.rs
··· 29 29 kh: KastenHandle, 30 30 signal_tx: UnboundedSender<Signal>, 31 31 signal_rx: UnboundedReceiver<Signal>, 32 + viz_signal_tx: UnboundedSender<Signal>, 32 33 } 33 34 34 35 /// The different regions of the application that the user can ··· 45 46 46 47 impl App { 47 48 /// Construct a new `App` instance. 48 - pub async fn new(tick_rate: f64, frame_rate: f64, kh: KastenHandle) -> Result<Self> { 49 + pub async fn new( 50 + tick_rate: f64, 51 + frame_rate: f64, 52 + kh: KastenHandle, 53 + viz_signal_tx: UnboundedSender<Signal>, 54 + ) -> Result<Self> { 49 55 let (signal_tx, signal_rx) = mpsc::unbounded_channel(); 50 56 51 57 Ok(Self { ··· 61 67 kh, 62 68 signal_tx, 63 69 signal_rx, 70 + viz_signal_tx, 64 71 }) 65 72 } 66 73 ··· 162 169 while let Ok(signal) = self.signal_rx.try_recv() { 163 170 if signal != Signal::Tick && signal != Signal::Render { 164 171 debug!("handling signal: {signal:?}"); 172 + // we dont care if the receiver is dropped, its fine 173 + let _ = self.viz_signal_tx.send(signal.clone()); 165 174 } 166 175 167 176 match signal.clone() { ··· 176 185 177 186 let hx = spawn({ 178 187 let file_path = path.clone(); 179 - let fil_dir = self.config.fil_dir.clone(); 188 + let _fil_dir = self.config.fil_dir.clone(); 180 189 move || -> Result<()> { 181 190 Command::new("hx") 182 191 .stdin(std::process::Stdio::inherit()) 183 192 .stdout(std::process::Stdio::inherit()) 184 193 .stderr(std::process::Stdio::inherit()) 185 194 .arg(file_path) 186 - .arg(format!("-w {}", fil_dir.display())) 195 + // .arg(format!("-w {}", fil_dir.display())) 187 196 .status()?; 188 197 189 198 Ok(())
+16 -1
src/tui/components/zk/mod.rs
··· 240 240 .await 241 241 .with_context(|| "Failed to create a new Zettel!")?; 242 242 243 - let path = z.absolute_path(&kt.index).to_path_buf(); 243 + // let path = z.absolute_path(&kt.index).to_path_buf(); 244 + 245 + drop(kt); 246 + 247 + return Ok(Some(Signal::CreatedZettel { zid: z.id })); 248 + 249 + // return Ok(Some(Signal::Helix { path })); 250 + } 251 + Signal::CreatedZettel { zid } => { 252 + // what the fuck am i going to do in here 253 + 254 + let kt = self.kh.read().await; 255 + 256 + let path = kt.index.get_zod(&zid).path.clone(); 257 + 258 + // let path = z.absolute_path(&kt.index).to_path_buf(); 244 259 245 260 drop(kt); 246 261
+6 -1
src/tui/signal.rs
··· 28 28 MoveDown, 29 29 MoveUp, 30 30 31 - /// New `Zettel` 31 + /// Create a New `Zettel` 32 32 NewZettel, 33 + 34 + CreatedZettel { 35 + zid: ZettelId, 36 + }, 37 + 33 38 /// User asks to open a `Zettel` 34 39 OpenZettel, 35 40 /// The user is done editing a `Zettel`
+37 -36
src/types/deimos.rs
··· 1 - use color_eyre::eyre::Context; 2 - use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Result, Watcher as _}; 3 - use tracing::{error, info}; 1 + // use color_eyre::eyre::Context; 2 + // use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Result, Watcher as _}; 3 + // use tracing::{error, info}; 4 4 5 - use crate::types::{KastenHandle, filaments::FilamentsHandle}; 5 + use crate::types::KastenHandle; 6 6 7 7 #[derive(Debug)] 8 + #[expect(dead_code)] 8 9 pub struct Deimos { 9 10 kh: KastenHandle, 10 - fh: FilamentsHandle, 11 + // fh: FilamentsHandle, 11 12 } 12 13 13 - impl Deimos { 14 - pub const fn new(kh: KastenHandle, fh: FilamentsHandle) -> Self { 15 - Self { kh, fh } 16 - } 14 + // impl Deimos { 15 + // pub const fn new(kh: KastenHandle, fh: FilamentsHandle) -> Self { 16 + // Self { kh, fh } 17 + // } 17 18 18 - /// Watches the `Filaments Directory` for file changes and updates 19 - /// the internal state of the kasten and the `Filaments` displayed in the 20 - /// gui. 21 - /// 22 - /// NOTE: This function must be spawned as a top level await 23 - pub async fn watch(&self) -> color_eyre::Result<()> { 24 - info!("deimos spawned!"); 19 + // /// Watches the `Filaments Directory` for file changes and updates 20 + // /// the internal state of the kasten and the `Filaments` displayed in the 21 + // /// gui. 22 + // /// 23 + // /// NOTE: This function must be spawned as a top level await 24 + // pub async fn watch(&self) -> color_eyre::Result<()> { 25 + // info!("deimos spawned!"); 25 26 26 - let (tx, mut rx) = tokio::sync::mpsc::channel::<Result<Event>>(10); 27 - let mut watcher = RecommendedWatcher::new( 28 - move |res| tx.blocking_send(res).expect("failed to send event"), 29 - Config::default(), 30 - )?; 27 + // let (tx, mut rx) = tokio::sync::mpsc::channel::<Result<Event>>(10); 28 + // let mut watcher = RecommendedWatcher::new( 29 + // move |res| tx.blocking_send(res).expect("failed to send event"), 30 + // Config::default(), 31 + // )?; 31 32 32 - watcher 33 - .watch(&self.kh.read().await.root, RecursiveMode::Recursive) 34 - .with_context(|| "failed to start the FS watcher")?; 33 + // watcher 34 + // .watch(&self.kh.read().await.root, RecursiveMode::Recursive) 35 + // .with_context(|| "failed to start the FS watcher")?; 35 36 36 - while let Some(res) = rx.recv().await { 37 - let kt = &mut *self.kh.write().await; 38 - let fh = &mut *self.fh.lock().expect("Lock must not be poisoned"); 37 + // while let Some(res) = rx.recv().await { 38 + // let kt = &mut *self.kh.write().await; 39 + // let fh = &mut *self.fh.lock().expect("Lock must not be poisoned"); 39 40 40 - match res { 41 - Ok(event) => info!("event: {event:?}"), 42 - Err(e) => error!("watch error: {e:?}"), 43 - } 41 + // match res { 42 + // Ok(event) => info!("event: {event:?}"), 43 + // Err(e) => error!("watch error: {e:?}"), 44 + // } 44 45 45 - *fh = (&kt.index).into(); 46 - } 46 + // *fh = (&kt.index).into(); 47 + // } 47 48 48 - Ok(()) 49 - } 50 - } 49 + // Ok(()) 50 + // } 51 + // }
+28 -16
src/types/filaments.rs
··· 1 - #![expect(dead_code)] 2 - use std::{cmp::max, collections::HashMap, sync::Arc}; 1 + use std::{cmp::max, collections::HashMap}; 3 2 4 3 use eframe::emath; 5 4 use egui_graphs::{ 6 - Graph, 5 + Graph, Node, 7 6 petgraph::{Directed, graph::NodeIndex, prelude::StableGraph}, 8 7 }; 9 8 10 - use crate::types::{Index, Link, ZettelId}; 9 + use crate::types::{Index, Link, ZettelId, index::ZettelOnDisk}; 11 10 12 11 pub type ZkGraph = Graph<ZettelId, Link, Directed>; 13 12 ··· 23 22 zid_to_gid: HashMap<ZettelId, NodeIndex>, 24 23 } 25 24 26 - pub type FilamentsHandle = Arc<std::sync::Mutex<Filaments>>; 25 + impl Filaments { 26 + pub fn insert_zettel(&mut self, zid: ZettelId, index: &Index) { 27 + let zod = index.get_zod(&zid); 28 + 29 + let node_idx = self 30 + .graph 31 + .add_node_custom(zid.clone(), |node| Self::custom_node_closure(zod, node)); 32 + 33 + let _ = self.zid_to_gid.insert(zid, node_idx); 34 + } 35 + 36 + fn custom_node_closure(zod: &ZettelOnDisk, node: &mut Node<ZettelId, Link>) { 37 + node.set_label(zod.fm.title.clone()); 38 + let disp = node.display_mut(); 39 + disp.radius = 50.0; 40 + 41 + // randomize position 42 + let x = rand::random_range(0.0..=100.0); 43 + let y = rand::random_range(0.0..=100.0); 44 + node.set_location(emath::Pos2 { x, y }); 45 + node.set_hovered(true); 46 + } 47 + } 27 48 28 49 impl From<&Index> for Filaments { 29 50 fn from(value: &Index) -> Self { ··· 37 58 )); 38 59 39 60 for (zid, zod) in value.zods() { 40 - let node_idx = graph.add_node_custom(zid.clone(), |node| { 41 - node.set_label(zod.fm.title.clone()); 42 - let disp = node.display_mut(); 43 - disp.radius = 50.0; 44 - 45 - // randomize position 46 - let x = rand::random_range(0.0..=100.0); 47 - let y = rand::random_range(0.0..=100.0); 48 - node.set_location(emath::Pos2 { x, y }); 49 - node.set_hovered(true); 50 - }); 61 + let node_idx = 62 + graph.add_node_custom(zid.clone(), |node| Self::custom_node_closure(zod, node)); 51 63 52 64 let _ = zid_to_gid.insert(zid.clone(), node_idx); 53 65 }
+1 -1
src/types/mod.rs
··· 23 23 24 24 mod filaments; 25 25 pub use filaments::Filaments; 26 - pub use filaments::FilamentsHandle; 27 26 28 27 mod index; 29 28 pub use index::Index; ··· 36 35 pub use frontmatter::FrontMatter; 37 36 38 37 mod deimos; 38 + #[expect(unused_imports)] 39 39 pub use deimos::Deimos;