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: new zettel

+81 -11
+1
.config/config.kdl
··· 10 10 j MoveDown 11 11 k MoveUp 12 12 o OpenZettel 13 + n NewZettel 13 14 } 14 15 }
+12 -3
src/tui/app.rs
··· 11 11 use crate::{ 12 12 config::Config, 13 13 tui::{Event, Tui, components::Zk}, 14 - types::{KastenHandle, ZettelId}, 14 + types::{KastenHandle, Zettel}, 15 15 }; 16 16 17 17 use super::{components::Component, signal::Signal}; ··· 167 167 168 168 Signal::Quit => self.should_quit = true, 169 169 170 + Signal::NewZettel => { 171 + // what the fuck am i going to do in here 172 + 173 + let ws = &self.kh.read().await.ws; 174 + let z = Zettel::new("", ws).await?; 175 + let path = z.absolute_path(ws); 176 + 177 + self.signal_tx.send(Signal::Helix { path })?; 178 + } 179 + 170 180 Signal::Helix { path } => { 171 181 tui.exit()?; 172 182 ··· 187 197 hx.join().unwrap().unwrap(); 188 198 // once we get out of the edit, we need to update the zettel for this 189 199 // path and then update the db and the kasten for this stuff 190 - let zid = ZettelId::try_from(path)?; 191 200 192 - self.kh.write().await.process_zid(&zid).await?; 201 + self.kh.write().await.process_path(&path).await?; 193 202 194 203 self.signal_tx.send(Signal::ClosedZettel)?; 195 204
+3 -1
src/tui/signal.rs
··· 22 22 MoveDown, 23 23 MoveUp, 24 24 25 + /// New `Zettel` 26 + NewZettel, 25 27 /// User asks to open a `Zettel` 26 28 OpenZettel, 27 - 28 29 /// The user is done editing a `Zettel` 29 30 ClosedZettel, 30 31 ··· 45 46 "movedown" => Self::MoveDown, 46 47 "moveup" => Self::MoveUp, 47 48 "openzettel" => Self::OpenZettel, 49 + "newzettel" => Self::NewZettel, 48 50 _ => { 49 51 return Err(eyre!(format!( 50 52 "Attempt to construct a non-user Signal from str: {s}"
+63 -7
src/types/kasten.rs
··· 1 1 use crate::types::{Link, Zettel, ZettelId}; 2 2 use color_eyre::eyre::Result; 3 + use dto::{TagEntity, ZettelEntity}; 3 4 use eframe::emath; 4 5 use egui_graphs::{ 5 6 Graph, Node, 6 - petgraph::{Directed, graph::NodeIndex, prelude::StableGraph}, 7 + petgraph::{Directed, Direction, graph::NodeIndex, prelude::StableGraph, visit::EdgeRef}, 7 8 }; 8 9 use rayon::iter::{ParallelBridge as _, ParallelIterator as _}; 9 - use std::{cmp::max, collections::HashMap, sync::Arc}; 10 + use std::{cmp::max, collections::HashMap, path::Path, sync::Arc}; 10 11 use tokio::sync::RwLock; 11 12 12 13 use crate::types::Workspace; ··· 108 109 /// processes the `Zettel` for the provided `ZettelId`, 109 110 /// meaning it updates the internal state of the `Kasten` 110 111 /// with the changes in `Zettel`. 111 - pub async fn process_zid(&mut self, zid: &ZettelId) -> Result<()> { 112 + pub async fn process_path(&mut self, path: &Path) -> Result<()> { 112 113 //NOTE: need to clone to get around borrowing rules but 113 114 // ideally we dont have to do this, kind of cringe imo. 114 115 let ws = self.ws.clone(); 115 116 116 - let zettel = self 117 - .get_node_by_zettel_id_mut(zid) 118 - .expect("this should not happen ever") 119 - .payload_mut(); 117 + let zid = ZettelId::try_from(path)?; 118 + 119 + let mut gid = self.zid_to_gid.get(&zid).copied(); 120 + // sometimes this zid is new, so it wont be in the kasten 121 + let zettel = if let Some(existing) = self.get_node_by_zettel_id_mut(&zid) { 122 + existing.payload_mut() 123 + } else { 124 + // this should aleady be in the database though so lets get it from there first 125 + let zettel: Zettel = ZettelEntity::load() 126 + .filter_by_nano_id(zid) 127 + .with(TagEntity) 128 + .one(&ws.db) 129 + .await? 130 + .expect("This should be in the database already") 131 + .into(); 132 + 133 + let zid = zettel.id.clone(); 134 + let idx = self.graph.add_node(zettel); 135 + 136 + gid = Some( 137 + self.zid_to_gid 138 + .insert(zid.clone(), idx) 139 + .expect("this cannot have existed already"), 140 + ); 141 + 142 + self.get_node_by_zettel_id_mut(&zid) 143 + .expect("we just inserted it") 144 + .payload_mut() 145 + }; 146 + 147 + // to get past borrowchecker rules 148 + let mut zettel = zettel.clone(); 149 + 150 + // gid must be set 151 + let gid = gid.unwrap(); 120 152 153 + // and then we sync with the file 121 154 zettel.sync_with_file(&ws).await?; 155 + 156 + // and now we manage the links going out of the file 157 + 158 + // remove all the old shit 159 + self.graph 160 + .edges_directed(gid, Direction::Outgoing) 161 + .map(|e| e.id()) 162 + .collect::<Vec<_>>() 163 + .into_iter() 164 + .for_each(|e| { 165 + let _ = self.graph.remove_edge(e); 166 + }); 167 + 168 + // add the links that actually exist 169 + zettel.links(&ws).await?.into_iter().for_each(|link| { 170 + // this is an option because a user c 171 + let dest = self 172 + .zid_to_gid 173 + .get(&link.dest) 174 + .expect("Links should be valid"); 175 + 176 + self.graph.add_edge(gid, *dest, link); 177 + }); 122 178 123 179 Ok(()) 124 180 }
+2
src/types/zettel.rs
··· 314 314 continue; 315 315 }; 316 316 317 + // TODO: check that the thing actually exists inside the ws.db 318 + // instead of just seeing if we can turn it into a ZettelId 317 319 let dst_id = ZettelId::try_from(canon_url)?; 318 320 319 321 let link = Link::new(self.id.clone(), dst_id);