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: title completions!

+158 -14
+4 -5
flake.nix
··· 125 125 env = { 126 126 RUST_SRC_PATH = "${pkgs.rustToolchain}/lib/rustlib/src/rust/library"; 127 127 128 - # project specific vars 129 - FIL_CONFIG = "./.config"; 130 - FIL_DATA = "./.data"; 131 128 FIL_LOG_LEVEL = "DEBUG"; 132 129 }; 133 130 134 - # Add any shell logic you want executed any time the environment is activated 135 - shellHook = ""; 131 + shellHook = '' 132 + export FIL_CONFIG="$(pwd)/.config" 133 + export FIL_DATA="$(pwd)/.data" 134 + ''; 136 135 }; 137 136 } 138 137 );
+8 -1
src/cli/process.rs
··· 57 57 } 58 58 } 59 59 Self::Lsp => { 60 + let conf = Config::parse().with_context(|| "Failed to parse the config!!")?; 61 + let kt = Kasten::instansiate(conf.fil_dir) 62 + .await 63 + .with_context(|| "Failed to initialize a kasten!!")?; 64 + 60 65 let stdin = tokio::io::stdin(); 61 66 let stdout = tokio::io::stdout(); 62 67 63 - let (service, socket) = LspService::new(|client| Backend { client }); 68 + let (service, socket) = 69 + LspService::new(|client| Backend::new(client, kt.db.clone())); 70 + 64 71 Server::new(stdin, stdout, socket).serve(service).await; 65 72 } 66 73 }
+10 -4
src/config/mod.rs
··· 5 5 sync::LazyLock, 6 6 }; 7 7 8 - use color_eyre::eyre::Result; 8 + use color_eyre::eyre::{Context, Result}; 9 9 use directories::ProjectDirs; 10 10 use ron::ser::PrettyConfig; 11 11 ··· 63 63 pub fn parse() -> Result<Self> { 64 64 let ron: RonConfig = { 65 65 let file_path = get_config_dir().join("config.ron"); 66 - ron::from_str(&read_to_string(file_path)?)? 66 + ron::from_str(&read_to_string(&file_path).with_context(|| { 67 + format!("Failed to read config from path: {}", file_path.display()) 68 + })?)? 67 69 }; 68 70 69 - let keymap = KeyMap::try_from(&ron)?; 71 + let keymap = 72 + KeyMap::try_from(&ron).with_context(|| "Unable to parse keymap from config!")?; 70 73 71 74 Ok(Self { 72 - fil_dir: ron.directory.canonicalize()?, 75 + fil_dir: ron 76 + .directory 77 + .canonicalize() 78 + .with_context(|| "Failed to canonicalize the directory provided in the config!")?, 73 79 keymap, 74 80 }) 75 81 }
+136 -4
src/lsp/mod.rs
··· 1 + use dto::{DatabaseConnection, TagEntity, ZettelEntity}; 2 + use nucleo_matcher::{ 3 + Matcher, Utf32Str, 4 + pattern::{CaseMatching, Normalization, Pattern}, 5 + }; 1 6 use tower_lsp::{ 2 7 Client, LanguageServer, 3 - jsonrpc::Result, 4 - lsp_types::{InitializeParams, InitializeResult, InitializedParams, MessageType}, 8 + jsonrpc::{self, Result}, 9 + lsp_types::{ 10 + CompletionItem, CompletionOptions, CompletionParams, CompletionResponse, InitializeParams, 11 + InitializeResult, InitializedParams, MessageType, ServerCapabilities, 12 + TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions, Url, 13 + }, 5 14 }; 6 15 16 + use crate::types::{Zettel, ZettelId}; 17 + 7 18 #[derive(Debug)] 8 19 pub struct Backend { 9 - pub client: Client, 20 + client: Client, 21 + db: DatabaseConnection, 22 + } 23 + 24 + impl Backend { 25 + pub const fn new(client: Client, db: DatabaseConnection) -> Self { 26 + Self { client, db } 27 + } 10 28 } 11 29 12 30 #[tower_lsp::async_trait] 13 31 impl LanguageServer for Backend { 14 32 async fn initialize(&self, _: InitializeParams) -> Result<InitializeResult> { 15 - Ok(InitializeResult::default()) 33 + Ok(InitializeResult { 34 + capabilities: ServerCapabilities { 35 + text_document_sync: Some(TextDocumentSyncCapability::Options( 36 + TextDocumentSyncOptions { 37 + open_close: Some(true), 38 + change: Some(TextDocumentSyncKind::FULL), 39 + ..Default::default() 40 + }, 41 + )), 42 + completion_provider: Some(CompletionOptions { 43 + resolve_provider: Some(false), 44 + trigger_characters: Some(vec!["[".to_string()]), 45 + ..Default::default() 46 + }), 47 + ..ServerCapabilities::default() 48 + }, 49 + ..Default::default() 50 + }) 16 51 } 17 52 18 53 async fn initialized(&self, _: InitializedParams) { 19 54 self.client 20 55 .log_message(MessageType::INFO, "server initialized!") 21 56 .await; 57 + } 58 + 59 + async fn completion(&self, params: CompletionParams) -> Result<Option<CompletionResponse>> { 60 + let file_path = params 61 + .text_document_position 62 + .text_document 63 + .uri 64 + .to_file_path() 65 + .expect("The uri should be in file format."); 66 + 67 + eprintln!( 68 + "Hello, processing completion in file: {}", 69 + file_path.display() 70 + ); 71 + 72 + let Ok(file) = tokio::fs::read_to_string(&file_path).await else { 73 + return Ok(None); 74 + }; 75 + eprintln!("here are the file contents: {file}"); 76 + 77 + let Ok::<ZettelId, color_eyre::eyre::Error>(src_zid) = file_path.try_into() else { 78 + return Ok(None); 79 + }; 80 + 81 + let position = params.text_document_position.position; 82 + 83 + eprintln!("here is the position we are given: {position:#?}"); 84 + 85 + // for some weird reason we have to add +1 here?? 86 + let line = file.lines().nth(position.line as usize + 1).unwrap_or(""); 87 + 88 + eprintln!("params: {params:#?}"); 89 + 90 + // this means they are looking for a link completion 91 + if let Some(context) = params.context 92 + && Some("[") == context.trigger_character.as_deref() 93 + { 94 + eprintln!("we are looking for link stuff"); 95 + // let mut matcher = Matcher::default(); 96 + // // the query is going to be anything between the '[' character and the last known cursor position 97 + 98 + // let query = { 99 + // let Some(start) = line.rfind('[') else { 100 + // eprintln!( 101 + // "could not find the start of the link thingy: here is the line: {line}" 102 + // ); 103 + // return Ok(None); 104 + // }; 105 + 106 + // // .expect("it has to exist in the line for this completion request to be fired"); 107 + // let end = position.character as usize; 108 + 109 + // Pattern::parse( 110 + // &line[start..=end], 111 + // CaseMatching::Ignore, 112 + // Normalization::Smart, 113 + // ) 114 + // }; 115 + 116 + let responses = ZettelEntity::load() 117 + .with(TagEntity) 118 + .all(&self.db) 119 + .await 120 + .map_err(|_| jsonrpc::Error::internal_error())? 121 + .into_iter() 122 + .map(Into::<Zettel>::into) 123 + .filter_map(|z| { 124 + // let mut buf = Vec::new(); 125 + 126 + // let score = query 127 + // .score(Utf32Str::new(&z.title, &mut buf), &mut matcher) 128 + // .unwrap_or_default(); 129 + 130 + // if score > 0 { 131 + Some(CompletionItem::new_simple( 132 + z.title, 133 + "The title of the thing".to_owned(), 134 + )) 135 + // } else { 136 + // None 137 + // } 138 + }) 139 + .collect(); 140 + 141 + return Ok(Some(CompletionResponse::Array(responses))); 142 + } 143 + 144 + return Ok(None); 145 + 146 + // // multi threaded zig 147 + // // async rust with tokio 148 + 149 + // // this is for what completion again? 150 + // Ok(Some(CompletionResponse::Array(vec![ 151 + // CompletionItem::new_simple("Hello".to_string(), "Some detail".to_string()), 152 + // CompletionItem::new_simple("Bye".to_string(), "More detail".to_string()), 153 + // ]))) 22 154 } 23 155 24 156 async fn shutdown(&self) -> Result<()> {