From b76e16bfb60c558a88f70c6938450ce952fb52e6 Mon Sep 17 00:00:00 2001 From: Felix Zeller Date: Mon, 26 Feb 2024 17:54:00 -0500 Subject: [PATCH] Cargo format --- src/codeactions.rs | 5 +- src/codelens.rs | 5 +- src/completion.rs | 252 +++++++++++++----------- src/diagnostics.rs | 4 +- src/main.rs | 72 +++---- src/references.rs | 4 +- src/rename.rs | 24 +-- src/tokens.rs | 67 ++++--- src/vault/mod.rs | 479 ++++++++++++++++++++++++--------------------- 9 files changed, 500 insertions(+), 412 deletions(-) diff --git a/src/codeactions.rs b/src/codeactions.rs index 660a82f4..ae752bfc 100644 --- a/src/codeactions.rs +++ b/src/codeactions.rs @@ -2,8 +2,9 @@ use std::path::{Path, PathBuf}; use pathdiff::diff_paths; use tower_lsp::lsp_types::{ - CodeAction, CodeActionOrCommand, CodeActionParams, CreateFile, DocumentChangeOperation, - DocumentChanges, ResourceOp, Url, WorkspaceEdit, CreateFileOptions, TextDocumentEdit, OptionalVersionedTextDocumentIdentifier, OneOf, TextEdit, Range, Position, + CodeAction, CodeActionOrCommand, CodeActionParams, CreateFile, CreateFileOptions, + DocumentChangeOperation, DocumentChanges, OneOf, OptionalVersionedTextDocumentIdentifier, + Position, Range, ResourceOp, TextDocumentEdit, TextEdit, Url, WorkspaceEdit, }; use crate::{ diff --git a/src/codelens.rs b/src/codelens.rs index 949b0b50..4ae0ed1a 100644 --- a/src/codelens.rs +++ b/src/codelens.rs @@ -1,9 +1,7 @@ use std::path::Path; use itertools::Itertools; -use tower_lsp::{ - lsp_types::{CodeLens, CodeLensParams, Command, Location, Position, Url}, -}; +use tower_lsp::lsp_types::{CodeLens, CodeLensParams, Command, Location, Position, Url}; use crate::vault::Vault; @@ -34,7 +32,6 @@ pub fn code_lens(vault: &Vault, path: &Path, _params: &CodeLensParams) -> Option .into_iter() .filter(|(_, references)| !references.is_empty()) .filter_map(|(referenceable, references)| { - let title = match references.len() { 1 => "1 reference".into(), n => format!("{} references", n), diff --git a/src/completion.rs b/src/completion.rs index e58a1de8..90266075 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -1,21 +1,23 @@ -use std::path::{PathBuf, Path}; - +use std::path::{Path, PathBuf}; use itertools::Itertools; use nanoid::nanoid; - -use nucleo_matcher::{pattern::{Normalization, self, Matchable}, Matcher}; +use nucleo_matcher::{ + pattern::{self, Matchable, Normalization}, + Matcher, +}; use rayon::prelude::*; use tower_lsp::lsp_types::{ - CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionParams, - CompletionResponse, Documentation, CompletionTextEdit, TextEdit, Range, Position, CompletionList, Url, Command, MarkupContent, MarkupKind, + Command, CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionList, + CompletionParams, CompletionResponse, CompletionTextEdit, Documentation, MarkupContent, + MarkupKind, Position, Range, TextEdit, Url, }; use crate::{ ui::preview_referenceable, - vault::{Preview, Referenceable, Vault, get_obsidian_ref_path, Block}, + vault::{get_obsidian_ref_path, Block, Preview, Referenceable, Vault}, }; fn get_link_index(line: &Vec, cursor_character: usize) -> Option { @@ -26,11 +28,16 @@ fn get_link_index(line: &Vec, cursor_character: usize) -> Option { .collect::>() .into_iter() .rev() // search from the cursor back - .find(|((_,&c1), (_,&c2))| c1 == '[' && c2 == '[') + .find(|((_, &c1), (_, &c2))| c1 == '[' && c2 == '[') .map(|(_, (i, _))| i) // only take the index; using map because find returns an option } -pub fn get_completions(vault: &Vault, initial_completion_files: &[PathBuf], params: &CompletionParams, _path: &Path) -> Option { +pub fn get_completions( + vault: &Vault, + initial_completion_files: &[PathBuf], + params: &CompletionParams, + _path: &Path, +) -> Option { let Ok(path) = params .text_document_position .text_document @@ -45,184 +52,209 @@ pub fn get_completions(vault: &Vault, initial_completion_files: &[PathBuf], para let selected_line = vault.select_line(&path.to_path_buf(), line as isize)?; - - let link_index = get_link_index(&selected_line, character); - if let Some(index) = link_index { - let range = Range { start: Position { line: line as u32, - character: index as u32 + 1 + character: index as u32 + 1, }, end: Position { line: line as u32, - character: character as u32 - } + character: character as u32, + }, }; - let cmp_text = selected_line.get(index + 1 .. character)?; + let cmp_text = selected_line.get(index + 1..character)?; return match *cmp_text { - [] => Some(CompletionResponse::List(CompletionList{ + [] => Some(CompletionResponse::List(CompletionList { items: initial_completion_files .iter() .filter_map(|path_i| { - Some(vault - .select_referenceable_nodes(Some(path_i)) - .into_iter() - .filter(|referenceable| { - if initial_completion_files.len() > 1 { - - if *path_i != path { - !matches!(referenceable, Referenceable::Tag(_, _)) - && !matches!(referenceable, Referenceable::Footnote(_, _)) + Some( + vault + .select_referenceable_nodes(Some(path_i)) + .into_iter() + .filter(|referenceable| { + if initial_completion_files.len() > 1 { + if *path_i != path { + !matches!(referenceable, Referenceable::Tag(_, _)) + && !matches!( + referenceable, + Referenceable::Footnote(_, _) + ) + } else { + false + } } else { - false + !matches!(referenceable, Referenceable::Tag(_, _)) + && !matches!( + referenceable, + Referenceable::Footnote(_, _) + ) } - - } else { - - !matches!(referenceable, Referenceable::Tag(_, _)) - && !matches!(referenceable, Referenceable::Footnote(_, _)) - - } - }) - .collect_vec() - )}) + }) + .collect_vec(), + ) + }) .flatten() .filter_map(|referenceable| completion_item(vault, &referenceable, None)) .collect::>(), - is_incomplete: true + is_incomplete: true, })), [' ', ref text @ ..] if !text.contains(&']') => { let blocks = vault.select_blocks(); let mut matcher = Matcher::new(nucleo_matcher::Config::DEFAULT); - let matches = pattern::Pattern::parse(String::from_iter(text).as_str(), pattern::CaseMatching::Ignore, Normalization::Smart).match_list(blocks, &mut matcher); - + let matches = pattern::Pattern::parse( + String::from_iter(text).as_str(), + pattern::CaseMatching::Ignore, + Normalization::Smart, + ) + .match_list(blocks, &mut matcher); let rand_id = nanoid!(5); - - - - return Some(CompletionResponse::List(CompletionList { is_incomplete: true, items: matches .into_par_iter() .take(50) - .filter(|(block, _)| String::from_iter(selected_line.clone()).trim() != block.text) + .filter(|(block, _)| { + String::from_iter(selected_line.clone()).trim() != block.text + }) .flat_map(|(block, rank)| { let path_ref = get_obsidian_ref_path(vault.root_dir(), &block.file)?; let url = Url::from_file_path(&block.file).ok()?; Some(CompletionItem { label: block.text.clone(), sort_text: Some(rank.to_string()), - documentation: Some(Documentation::MarkupContent(MarkupContent{ + documentation: Some(Documentation::MarkupContent(MarkupContent { kind: MarkupKind::Markdown, - value: (block.range.start.line as isize -5..=block.range.start.line as isize+5) + value: (block.range.start.line as isize - 5 + ..=block.range.start.line as isize + 5) .flat_map(|i| Some((vault.select_line(&block.file, i)?, i))) - .map(|(iter, ln)| if ln == block.range.start.line as isize { - format!("**{}**\n", String::from_iter(iter).trim()) // highlight the block to be references - } else { + .map(|(iter, ln)| { + if ln == block.range.start.line as isize { + format!("**{}**\n", String::from_iter(iter).trim()) + // highlight the block to be references + } else { String::from_iter(iter) - }) - .join("") + } + }) + .join(""), })), filter_text: Some(format!(" {}", block.text)), text_edit: Some(CompletionTextEdit::Edit(TextEdit { range, - new_text: format!("{}#^{}", path_ref, rand_id) + new_text: format!("{}#^{}", path_ref, rand_id), })), command: Some(Command { title: "Insert Block Reference Into File".into(), command: "apply_edits".into(), - arguments: Some(vec![ - serde_json::to_value(tower_lsp::lsp_types::WorkspaceEdit { + arguments: Some(vec![serde_json::to_value( + tower_lsp::lsp_types::WorkspaceEdit { changes: Some( - vec![( url, vec![ - TextEdit { + vec![( + url, + vec![TextEdit { range: Range { start: Position { line: block.range.end.line, - character: block.range.end.character - 1 + character: block + .range + .end + .character + - 1, }, end: Position { line: block.range.end.line, - character: block.range.end.character - 1 - } + character: block + .range + .end + .character + - 1, + }, }, - new_text: format!(" ^{}", rand_id) - } - ])] - .into_iter() - .collect()), + new_text: format!(" ^{}", rand_id), + }], + )] + .into_iter() + .collect(), + ), change_annotations: None, - document_changes: None - }).ok()? - ]), + document_changes: None, + }, + ) + .ok()?]), }), ..Default::default() }) }) - .collect() - })) + .collect(), + })); } ref filter_text @ [..] if !filter_text.contains(&']') => { - - let all_links = vault .select_referenceable_nodes(None) .into_par_iter() .filter(|referenceable| { !matches!(referenceable, Referenceable::Tag(..)) - && !matches!(referenceable, Referenceable::Footnote(..)) + && !matches!(referenceable, Referenceable::Footnote(..)) + }) + .filter_map(|referenceable| { + referenceable + .get_refname(vault.root_dir()) + .map(|string| MatchableReferenceable(referenceable, string)) }) - .filter_map(|referenceable| referenceable.get_refname(vault.root_dir()).map(|string| MatchableReferenceable(referenceable, string))) .collect::>(); - let mut matcher = Matcher::new(nucleo_matcher::Config::DEFAULT); - let mut matches = pattern::Pattern::parse(String::from_iter(filter_text).as_str(), pattern::CaseMatching::Ignore, Normalization::Smart).match_list(all_links, &mut matcher); + let mut matches = pattern::Pattern::parse( + String::from_iter(filter_text).as_str(), + pattern::CaseMatching::Ignore, + Normalization::Smart, + ) + .match_list(all_links, &mut matcher); matches.par_sort_by_key(|(_, rank)| -(*rank as i32)); - return Some(CompletionResponse::List(CompletionList{ + return Some(CompletionResponse::List(CompletionList { is_incomplete: true, items: matches .into_iter() .take(30) - .filter(|(MatchableReferenceable(_, name), _)| *name != String::from_iter(filter_text)) + .filter(|(MatchableReferenceable(_, name), _)| { + *name != String::from_iter(filter_text) + }) .filter_map(|(MatchableReferenceable(referenceable, _), rank)| { - completion_item(vault, &referenceable, Some(range)) - .map(|item| CompletionItem { + completion_item(vault, &referenceable, Some(range)).map(|item| { + CompletionItem { sort_text: Some(rank.to_string()), ..item - }) + } + }) }) .collect::>(), })); - }, - _ => None - } - + } + _ => None, + }; } else if character .checked_sub(1) .and_then(|start| selected_line.get(start..character)) - == Some(&['#']) + == Some(&['#']) { // Initial Tag completion let tag_refereneables = - vault - .select_referenceable_nodes(None) - .into_iter() - .flat_map(|referenceable| match referenceable { - tag @ Referenceable::Tag(_, _) => Some(tag), - _ => None, - }); + vault + .select_referenceable_nodes(None) + .into_iter() + .flat_map(|referenceable| match referenceable { + tag @ Referenceable::Tag(_, _) => Some(tag), + _ => None, + }); return Some(CompletionResponse::Array( tag_refereneables @@ -240,7 +272,7 @@ pub fn get_completions(vault: &Vault, initial_completion_files: &[PathBuf], para } else if character .checked_sub(1) .and_then(|start| selected_line.get(start..character)) - == Some(&['[']) + == Some(&['[']) { let footnote_referenceables = vault .select_referenceable_nodes(Some(&path)) @@ -248,9 +280,9 @@ pub fn get_completions(vault: &Vault, initial_completion_files: &[PathBuf], para .flat_map(|referenceable| match referenceable { Referenceable::Footnote(footnote_path, _) if footnote_path.as_path() == path.as_path() => - { - Some(referenceable) - } + { + Some(referenceable) + } _ => None, }); @@ -282,8 +314,11 @@ pub fn get_completions(vault: &Vault, initial_completion_files: &[PathBuf], para } } - -fn completion_item(vault: &Vault, referenceable: &Referenceable, range: Option) -> Option { +fn completion_item( + vault: &Vault, + referenceable: &Referenceable, + range: Option, +) -> Option { let refname = referenceable.get_refname(vault.root_dir())?; let completion = CompletionItem { kind: Some(CompletionItemKind::FILE), @@ -295,10 +330,12 @@ fn completion_item(vault: &Vault, referenceable: &Referenceable, range: Option None, }, - text_edit: range.map(|range| CompletionTextEdit::Edit(TextEdit { - range, - new_text: refname.clone(), - })), + text_edit: range.map(|range| { + CompletionTextEdit::Edit(TextEdit { + range, + new_text: refname.clone(), + }) + }), documentation: preview_referenceable(vault, referenceable) .map(Documentation::MarkupContent), filter_text: match referenceable { @@ -317,10 +354,8 @@ fn completion_item(vault: &Vault, referenceable: &Referenceable, range: Option(Referenceable<'a>, String); - impl Matchable for MatchableReferenceable<'_> { fn string(&self) -> &str { &self.1 @@ -333,8 +368,6 @@ impl Matchable for Block { } } - - #[cfg(test)] mod tests { use super::get_link_index; @@ -349,7 +382,6 @@ mod tests { assert_eq!(Some(expected), actual); - assert_eq!(Some("lin"), s.get(expected + 1 .. 10)); + assert_eq!(Some("lin"), s.get(expected + 1..10)); } } - diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a12a5a1b..a3664fd4 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,9 +1,7 @@ use std::path::{Path, PathBuf}; use rayon::prelude::*; -use tower_lsp::lsp_types::{ - Diagnostic, DiagnosticSeverity, Url, -}; +use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Url}; use crate::vault::{self, Reference, Referenceable, Vault}; diff --git a/src/main.rs b/src/main.rs index 05d3e13a..a216a6a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,8 @@ use std::collections::HashSet; use std::ops::{Deref, DerefMut}; use std::path::{Path, PathBuf}; -use completion::get_completions; use diagnostics::diagnostics; +use completion::get_completions; +use diagnostics::diagnostics; use itertools::Itertools; use references::references; use serde_json::Value; @@ -26,9 +27,9 @@ mod macros; mod references; mod rename; mod symbol; +mod tokens; mod ui; mod vault; -mod tokens; #[derive(Debug)] struct Backend { @@ -272,15 +273,20 @@ impl LanguageServer for Backend { commands: vec!["apply_edits".into()], ..Default::default() }), - semantic_tokens_provider: Some(SemanticTokensServerCapabilities::SemanticTokensOptions(SemanticTokensOptions{ - full: Some(SemanticTokensFullOptions::Bool(true)), range: Some(false), legend: SemanticTokensLegend { - token_types: vec![SemanticTokenType::DECORATOR], - token_modifiers: vec![SemanticTokenModifier::DECLARATION] - }, - ..Default::default() - })), + semantic_tokens_provider: Some( + SemanticTokensServerCapabilities::SemanticTokensOptions( + SemanticTokensOptions { + full: Some(SemanticTokensFullOptions::Bool(true)), + range: Some(false), + legend: SemanticTokensLegend { + token_types: vec![SemanticTokenType::DECORATOR], + token_modifiers: vec![SemanticTokenModifier::DECLARATION], + }, + ..Default::default() + }, + ), + ), ..Default::default() - }, }); } @@ -395,20 +401,21 @@ impl LanguageServer for Backend { .await } - - async fn completion(&self, params: CompletionParams) -> Result> { - let timer = std::time::Instant::now(); let path = params_position_path!(params)?; - let files = self.bind_opened_files(|files| Ok(files.clone().into_iter().collect::>())).await?; + let files = self + .bind_opened_files(|files| Ok(files.clone().into_iter().collect::>())) + .await?; let res = self .bind_vault(|vault| Ok(get_completions(vault, &files, ¶ms, &path))) .await; - self.client.log_message(MessageType::LOG, format!("Completions: {:?}", res)).await; + self.client + .log_message(MessageType::LOG, format!("Completions: {:?}", res)) + .await; let elapsed = timer.elapsed(); @@ -422,24 +429,25 @@ impl LanguageServer for Backend { res } - async fn execute_command(&self, params: ExecuteCommandParams) -> Result> { match params { - ExecuteCommandParams { command, .. } if *command == *"apply_edits" => { - let edits = params.arguments.into_iter().filter_map(|arg| serde_json::from_value::(arg).ok()).collect_vec(); + ExecuteCommandParams { command, .. } if *command == *"apply_edits" => { + let edits = params + .arguments + .into_iter() + .filter_map(|arg| serde_json::from_value::(arg).ok()) + .collect_vec(); for edit in edits { let _ = self.client.apply_edit(edit).await; } Ok(None) - }, - _ => Ok(None) + } + _ => Ok(None), } } - - async fn hover(&self, params: HoverParams) -> Result> { self.bind_vault(|vault| { let path = params_path!(params.text_document_position_params)?; @@ -483,23 +491,21 @@ impl LanguageServer for Backend { .await } - async fn semantic_tokens_full( &self, params: SemanticTokensParams, ) -> Result> { - let path = params_path!(params)?; - let res = self.bind_vault(|vault| { - Ok(tokens::semantic_tokens_full(vault, &path, params)) - }).await; - - self.client.log_message(MessageType::LOG, format!("{:?}", res)).await; + let res = self + .bind_vault(|vault| Ok(tokens::semantic_tokens_full(vault, &path, params))) + .await; - return res + self.client + .log_message(MessageType::LOG, format!("{:?}", res)) + .await; + return res; } - } #[tokio::main] @@ -512,5 +518,5 @@ async fn main() { vault: None.into(), opened_files: HashSet::new().into(), }); - Server::new(stdin, stdout, socket).serve(service).await; } - + Server::new(stdin, stdout, socket).serve(service).await; +} diff --git a/src/references.rs b/src/references.rs index 2abb2ab4..3b4400f2 100644 --- a/src/references.rs +++ b/src/references.rs @@ -15,7 +15,9 @@ pub fn references(vault: &Vault, cursor_position: Position, path: &Path) -> Opti let referenceables = vault.select_referenceables_for_reference(reference, path); let references = referenceables .into_iter() - .filter_map(|referenceable| vault.select_references_for_referenceable(&referenceable)) // drop the Nones on the options + .filter_map(|referenceable| { + vault.select_references_for_referenceable(&referenceable) + }) // drop the Nones on the options .flatten() .collect_vec(); diff --git a/src/rename.rs b/src/rename.rs index ecc21723..fee4d93b 100644 --- a/src/rename.rs +++ b/src/rename.rs @@ -72,7 +72,9 @@ pub fn rename(vault: &Vault, params: &RenameParams, path: &Path) -> Option { + Reference::WikiFileLink(data) + if matches!(referenceable, Referenceable::File(..)) => + { let new_text = format!( "[[{}{}]]", new_ref_name, @@ -164,7 +166,7 @@ pub fn rename(vault: &Vault, params: &RenameParams, path: &Path) -> Option { let new_text = format!( "[{}]({})", @@ -186,12 +188,12 @@ pub fn rename(vault: &Vault, params: &RenameParams, path: &Path) -> Option { - + } + Reference::MDHeadingLink(data, _file, infile) + | Reference::MDIndexedBlockLink(data, _file, infile) + if matches!(referenceable, Referenceable::File(..)) => + { let new_text = format!( "[{}]({}#{})", data.display_text @@ -213,9 +215,10 @@ pub fn rename(vault: &Vault, params: &RenameParams, path: &Path) -> Option { + } + Reference::WikiHeadingLink(data, _file, _heading) + if matches!(referenceable, Referenceable::Heading(..)) => + { let new_text = format!( "[{}]({})", data.display_text @@ -225,7 +228,6 @@ pub fn rename(vault: &Vault, params: &RenameParams, path: &Path) -> Option Option { - - let references_in_file = vault.select_references(Some(path))?; let tokens = references_in_file .into_iter() - .sorted_by_key(|(_, reference)| (reference.data().range.start.line, reference.data().range.start.character)) + .sorted_by_key(|(_, reference)| { + ( + reference.data().range.start.line, + reference.data().range.start.character, + ) + }) .fold(vec![], |acc, (_, reference)| { - let range = reference.data().range; match acc[..] { - [] => vec![(reference, SemanticToken { - delta_line: range.start.line, - delta_start: range.start.character, - length: range.end.character - range.start.character, - token_type: 0, - token_modifiers_bitset: 0 - })], - [.., (prev_ref, _)] => acc.into_iter().chain(iter::once((reference, SemanticToken { - delta_line: range.start.line - prev_ref.data().range.start.line, - delta_start: if range.start.line == prev_ref.data().range.start.line { - range.start.character - prev_ref.data().range.start.character - } else { - range.start.character + [] => vec![( + reference, + SemanticToken { + delta_line: range.start.line, + delta_start: range.start.character, + length: range.end.character - range.start.character, + token_type: 0, + token_modifiers_bitset: 0, }, - length: range.end.character - range.start.character, - token_type: 0, - token_modifiers_bitset: 0 - }))).collect_vec() + )], + [.., (prev_ref, _)] => acc + .into_iter() + .chain(iter::once(( + reference, + SemanticToken { + delta_line: range.start.line - prev_ref.data().range.start.line, + delta_start: if range.start.line == prev_ref.data().range.start.line { + range.start.character - prev_ref.data().range.start.character + } else { + range.start.character + }, + length: range.end.character - range.start.character, + token_type: 0, + token_modifiers_bitset: 0, + }, + ))) + .collect_vec(), } }) .into_iter() .map(|(_, token)| token) .collect_vec(); // TODO: holy this is bad - - Some(SemanticTokensResult::Tokens(tower_lsp::lsp_types::SemanticTokens { result_id: None, data: tokens })) - + Some(SemanticTokensResult::Tokens( + tower_lsp::lsp_types::SemanticTokens { + result_id: None, + data: tokens, + }, + )) } diff --git a/src/vault/mod.rs b/src/vault/mod.rs index 839f3de8..deb5fc9d 100644 --- a/src/vault/mod.rs +++ b/src/vault/mod.rs @@ -10,10 +10,10 @@ use itertools::Itertools; use once_cell::sync::Lazy; use pathdiff::diff_paths; use rayon::prelude::*; -use regex::{Regex, Match, Captures}; +use regex::{Captures, Match, Regex}; use ropey::Rope; -use serde::{Serialize, Deserialize}; -use tower_lsp::lsp_types::{Position}; +use serde::{Deserialize, Serialize}; +use tower_lsp::lsp_types::Position; use walkdir::WalkDir; impl Vault { @@ -235,19 +235,19 @@ impl Vault { Some(Referenceable::UnresovledFile(path, &data.reference_text)) } - Reference::WikiHeadingLink(_data, end_path, heading) | Reference::MDHeadingLink(_data, end_path, heading) => { + Reference::WikiHeadingLink(_data, end_path, heading) + | Reference::MDHeadingLink(_data, end_path, heading) => { let mut path = self.root_dir().clone(); path.push(end_path); Some(Referenceable::UnresolvedHeading(path, end_path, heading)) } - Reference::WikiIndexedBlockLink(_data, end_path, index) | Reference::MDIndexedBlockLink(_data, end_path, index)=> { + Reference::WikiIndexedBlockLink(_data, end_path, index) + | Reference::MDIndexedBlockLink(_data, end_path, index) => { let mut path = self.root_dir().clone(); path.push(end_path); - Some(Referenceable::UnresovledIndexedBlock( - path, end_path, index, - )) + Some(Referenceable::UnresovledIndexedBlock(path, end_path, index)) } Reference::Tag(..) | Reference::Footnote(..) => None, }) @@ -267,7 +267,8 @@ impl Vault { let usize: usize = line.try_into().ok()?; - rope.get_line(usize).map(|slice| slice.chars().collect_vec()) + rope.get_line(usize) + .map(|slice| slice.chars().collect_vec()) } pub fn select_headings(&self, path: &Path) -> Option<&Vec> { @@ -368,36 +369,36 @@ impl Vault { } } - pub fn select_blocks(&self) -> Vec { - - return self.ropes + return self + .ropes .par_iter() - .map(|(path, rope)| rope - .lines() - .enumerate() - .filter_map(|(i, line)| { - let string = line.as_str()?; - - Some(Block { - text: String::from(string.trim()), - range: MyRange(tower_lsp::lsp_types::Range { - start: Position { - line: i as u32, - character: 0 - }, - end: Position { - line: i as u32, - character: string.len() as u32 - } - }), - file: path.clone() + .map(|(path, rope)| { + rope.lines() + .enumerate() + .filter_map(|(i, line)| { + let string = line.as_str()?; + + Some(Block { + text: String::from(string.trim()), + range: MyRange(tower_lsp::lsp_types::Range { + start: Position { + line: i as u32, + character: 0, + }, + end: Position { + line: i as u32, + character: string.len() as u32, + }, + }), + file: path.clone(), + }) }) - }).collect_vec() - ) - .flatten() + .collect_vec() + }) + .flatten() .filter(|block| !block.text.is_empty()) - .collect() + .collect(); } } @@ -405,7 +406,7 @@ impl Vault { pub struct Block { pub text: String, pub range: MyRange, - pub file: PathBuf + pub file: PathBuf, } impl AsRef for Block { @@ -435,7 +436,7 @@ fn range_to_position(rope: &Rope, range: Range) -> MyRange { character: end_offset as u32, }, } - .into() + .into() } #[derive(Debug, PartialEq, Eq, Default, Hash, Clone)] @@ -470,13 +471,13 @@ impl MDFile { impl MDFile { fn get_referenceables(&self) -> Vec { let MDFile { - references: _, - headings, - indexed_blocks, - tags, - footnotes, - path: _, - } = self; + references: _, + headings, + indexed_blocks, + tags, + footnotes, + path: _, + } = self; iter::once(Referenceable::File(&self.path, self)) .chain( @@ -577,14 +578,11 @@ impl Reference { }) .collect_vec(); - - static MD_LINK_RE: Lazy = Lazy::new(|| { Regex::new(r"\[(?[^\[\]\.]+)\]\((\.\/)?(?[^\[\]\|\.\#]+)(\.[^\# ]+)?(\#(?[^\[\]\.\|]+))?\)") .expect("MD Link Not Constructing") }); // [display](relativePath) - let md_links: Vec = MD_LINK_RE .captures_iter(text) .flat_map(RegexTuple::new) @@ -603,7 +601,7 @@ impl Reference { .collect(); static FOOTNOTE_LINK_RE: Lazy = - Lazy::new(|| Regex::new(r"[^\[](?\[(?\^[^\[\] ]+)\])[^\:]").unwrap()); + Lazy::new(|| Regex::new(r"[^\[](?\[(?\^[^\[\] ]+)\])[^\:]").unwrap()); let footnote_references: Vec = FOOTNOTE_LINK_RE .captures_iter(text) .flat_map( @@ -649,43 +647,46 @@ impl Reference { Footnote(_) => false, // (no I don't write all of these by hand; I use rust-analyzers code action; I do this because when I add new item to the Reference enum, I want workspace errors everywhere relevant) } } - &Referenceable::Footnote(path, _footnote) => { - match self { - Footnote(..) => referenceable.get_refname(root_dir).as_ref() == Some(text) && path.as_path() == file_path, - Tag(_) => false, - WikiFileLink(_) => false, - WikiHeadingLink(_, _, _) => false, - WikiIndexedBlockLink(_, _, _) => false, - MDFileLink(_) => false, - MDHeadingLink(_, _, _) => false, - MDIndexedBlockLink(_, _, _) => false, + &Referenceable::Footnote(path, _footnote) => match self { + Footnote(..) => { + referenceable.get_refname(root_dir).as_ref() == Some(text) + && path.as_path() == file_path } - } - &Referenceable::File(..) | &Referenceable::UnresovledFile(..) => { - match self { - WikiFileLink(..) | MDFileLink(..) => referenceable.get_refname(root_dir).as_ref() == Some(text), - Tag(_) => false, - WikiHeadingLink(_, _, _) => false, - WikiIndexedBlockLink(_, _, _) => false, - MDHeadingLink(_, _, _) => false, - MDIndexedBlockLink(_, _, _) => false, - Footnote(_) => false, + Tag(_) => false, + WikiFileLink(_) => false, + WikiHeadingLink(_, _, _) => false, + WikiIndexedBlockLink(_, _, _) => false, + MDFileLink(_) => false, + MDHeadingLink(_, _, _) => false, + MDIndexedBlockLink(_, _, _) => false, + }, + &Referenceable::File(..) | &Referenceable::UnresovledFile(..) => match self { + WikiFileLink(..) | MDFileLink(..) => { + referenceable.get_refname(root_dir).as_ref() == Some(text) } - } - &Referenceable::Heading(..) | &Referenceable::UnresolvedHeading(..) => { - match self { - WikiHeadingLink(..) | MDHeadingLink(..) => referenceable.get_refname(root_dir).as_ref() == Some(text), - Tag(_) => false, - WikiFileLink(_) => false, - WikiIndexedBlockLink(_, _, _) => false, - MDFileLink(_) => false, - MDIndexedBlockLink(_, _, _) => false, - Footnote(_) => false, + Tag(_) => false, + WikiHeadingLink(_, _, _) => false, + WikiIndexedBlockLink(_, _, _) => false, + MDHeadingLink(_, _, _) => false, + MDIndexedBlockLink(_, _, _) => false, + Footnote(_) => false, + }, + &Referenceable::Heading(..) | &Referenceable::UnresolvedHeading(..) => match self { + WikiHeadingLink(..) | MDHeadingLink(..) => { + referenceable.get_refname(root_dir).as_ref() == Some(text) } - } + Tag(_) => false, + WikiFileLink(_) => false, + WikiIndexedBlockLink(_, _, _) => false, + MDFileLink(_) => false, + MDIndexedBlockLink(_, _, _) => false, + Footnote(_) => false, + }, &Referenceable::IndexedBlock(..) | &Referenceable::UnresovledIndexedBlock(..) => { match self { - WikiIndexedBlockLink(..) | MDIndexedBlockLink(..) => referenceable.get_refname(root_dir).as_ref() == Some(text), + WikiIndexedBlockLink(..) | MDIndexedBlockLink(..) => { + referenceable.get_refname(root_dir).as_ref() == Some(text) + } Tag(_) => false, WikiFileLink(_) => false, WikiHeadingLink(_, _, _) => false, @@ -698,11 +699,11 @@ impl Reference { } } -struct RegexTuple<'a>{ +struct RegexTuple<'a> { range: Match<'a>, file_path: Match<'a>, infile_ref: Option>, - display_text: Option> + display_text: Option>, } impl RegexTuple<'_> { @@ -713,11 +714,14 @@ impl RegexTuple<'_> { capture.name("infileref"), capture.name("display"), ) { - (Some(range), Some(file_path), infile_ref, display_text) => { - Some(RegexTuple{range, file_path, infile_ref, display_text}) - } - _ => None, - } + (Some(range), Some(file_path), infile_ref, display_text) => Some(RegexTuple { + range, + file_path, + infile_ref, + display_text, + }), + _ => None, + } } } @@ -754,9 +758,15 @@ impl ParseableReferenceConstructor for MDReferenceConstructor { } } - -fn generic_link_constructor(text: &str, RegexTuple { range, file_path, infile_ref, display_text }: RegexTuple) -> Reference { - +fn generic_link_constructor( + text: &str, + RegexTuple { + range, + file_path, + infile_ref, + display_text, + }: RegexTuple, +) -> Reference { match (range, file_path, infile_ref, display_text) { // Pure file reference as there is no infileref such as #... for headings or #^... for indexed blocks (full, filepath, None, display) => { @@ -766,31 +776,21 @@ fn generic_link_constructor(text: &str, RegexT display_text: display.map(|d| d.as_str().into()), }) } - (full, filepath, Some(infile), display) - if infile.as_str().get(0..1) == Some("^") => - { - return T::new_indexed_block_link( - ReferenceData { - reference_text: format!( - "{}#{}", - filepath.as_str(), - infile.as_str() - ), - range: range_to_position(&Rope::from_str(text), full.range()), - display_text: display.map(|d| d.as_str().into()), - }, - filepath.as_str(), - infile.as_str(), - ) - } + (full, filepath, Some(infile), display) if infile.as_str().get(0..1) == Some("^") => { + return T::new_indexed_block_link( + ReferenceData { + reference_text: format!("{}#{}", filepath.as_str(), infile.as_str()), + range: range_to_position(&Rope::from_str(text), full.range()), + display_text: display.map(|d| d.as_str().into()), + }, + filepath.as_str(), + infile.as_str(), + ) + } (full, filepath, Some(infile), display) => { return T::new_heading( ReferenceData { - reference_text: format!( - "{}#{}", - filepath.as_str(), - infile.as_str() - ), + reference_text: format!("{}#{}", filepath.as_str(), infile.as_str()), range: range_to_position(&Rope::from_str(text), full.range()), display_text: display.map(|d| d.as_str().into()), }, @@ -801,12 +801,6 @@ fn generic_link_constructor(text: &str, RegexT } } - - - - - - #[derive(Eq, PartialEq, Debug, PartialOrd, Ord, Clone, Hash)] pub struct HeadingLevel(pub usize); @@ -858,7 +852,7 @@ impl From for MyRange { impl MDHeading { fn new(text: &str) -> Vec { static HEADING_RE: Lazy = - Lazy::new(|| Regex::new(r"(?#+) (?.+)").unwrap()); + Lazy::new(|| Regex::new(r"(?#+) (?.+)").unwrap()); let headings: Vec = HEADING_RE .captures_iter(text) @@ -896,7 +890,7 @@ impl Hash for MDIndexedBlock { impl MDIndexedBlock { fn new(text: &str) -> Vec { static INDEXED_BLOCK_RE: Lazy = - Lazy::new(|| Regex::new(r".+ (\^(?\w+))").unwrap()); + Lazy::new(|| Regex::new(r".+ (\^(?\w+))").unwrap()); let indexed_blocks: Vec = INDEXED_BLOCK_RE .captures_iter(text) @@ -932,7 +926,7 @@ impl MDFootnote { fn new(text: &str) -> Vec { // static FOOTNOTE_RE: Lazy = Lazy::new(|| Regex::new(r".+ (\^(?\w+))").unwrap()); static FOOTNOTE_RE: Lazy = - Lazy::new(|| Regex::new(r"\[(?\^[^ \[\]]+)\]\:(?.+)").unwrap()); + Lazy::new(|| Regex::new(r"\[(?\^[^ \[\]]+)\]\:(?.+)").unwrap()); let footnotes: Vec = FOOTNOTE_RE .captures_iter(text) @@ -968,7 +962,7 @@ impl Hash for MDTag { impl MDTag { fn new(text: &str) -> Vec { static TAG_RE: Lazy = - Lazy::new(|| Regex::new(r"(\n|\A| )(?#(?[.[^ \n\#]]+))(\n|\z| )").unwrap()); + Lazy::new(|| Regex::new(r"(\n|\A| )(?#(?[.[^ \n\#]]+))(\n|\z| )").unwrap()); let tagged_blocks = TAG_RE .captures_iter(text) @@ -987,8 +981,6 @@ impl MDTag { } } - - #[derive(Debug, Clone, Eq, PartialEq, Hash)] /** An Algebreic type for methods for all referenceables, which are anything able to be referenced through obsidian link or tag. These include @@ -1045,53 +1037,60 @@ impl Referenceable<'_> { match &self { Referenceable::Tag(_, _) => { matches!(reference, Tag(_)) - && self.get_refname(root_dir) - .is_some_and(|refname| { + && self.get_refname(root_dir).is_some_and(|refname| { let refname_split = refname.split('/').collect_vec(); let text_split = text.split('/').collect_vec(); - return text_split.get(0..refname_split.len()) == Some(&refname_split) + return text_split.get(0..refname_split.len()) == Some(&refname_split); }) } - Referenceable::Footnote(path, _footnote) => { - match reference { - Footnote(..) => self.get_refname(root_dir).as_ref() == Some(text) && path.as_path() == reference_path, - MDFileLink(..) => false, - Tag(_) => false, - WikiFileLink(_) => false, - WikiHeadingLink(_, _, _) => false, - WikiIndexedBlockLink(_, _, _) => false, - MDHeadingLink(_, _, _) => false, - MDIndexedBlockLink(_, _, _) => false, - } - } - Referenceable::File(..) | Referenceable::UnresovledFile(..) => { - match reference { - WikiFileLink(ReferenceData{ reference_text: file_ref_text, ..}) - | WikiHeadingLink(.., file_ref_text, _) - | WikiIndexedBlockLink(.., file_ref_text, _) - | MDFileLink(ReferenceData{ reference_text: file_ref_text, ..}) - | MDHeadingLink(.., file_ref_text, _) - | MDIndexedBlockLink(.., file_ref_text, _) - => self.get_refname(root_dir).is_some_and(|refname| refname == *file_ref_text), - Tag(_) => false, - Footnote(_) => false, + Referenceable::Footnote(path, _footnote) => match reference { + Footnote(..) => { + self.get_refname(root_dir).as_ref() == Some(text) + && path.as_path() == reference_path } - } - Referenceable::Heading(..) | Referenceable::UnresolvedHeading(..) => { - match reference { - WikiHeadingLink(data, ..) | MDHeadingLink(data, ..) => Some(&data.reference_text) == self.get_refname(root_dir).as_ref(), - Tag(..) => false, - WikiFileLink(..) => false, - WikiIndexedBlockLink(..) => false, - MDFileLink(..) => false, - MDIndexedBlockLink(..) => false, - Footnote(..) => false, + MDFileLink(..) => false, + Tag(_) => false, + WikiFileLink(_) => false, + WikiHeadingLink(_, _, _) => false, + WikiIndexedBlockLink(_, _, _) => false, + MDHeadingLink(_, _, _) => false, + MDIndexedBlockLink(_, _, _) => false, + }, + Referenceable::File(..) | Referenceable::UnresovledFile(..) => match reference { + WikiFileLink(ReferenceData { + reference_text: file_ref_text, + .. + }) + | WikiHeadingLink(.., file_ref_text, _) + | WikiIndexedBlockLink(.., file_ref_text, _) + | MDFileLink(ReferenceData { + reference_text: file_ref_text, + .. + }) + | MDHeadingLink(.., file_ref_text, _) + | MDIndexedBlockLink(.., file_ref_text, _) => self + .get_refname(root_dir) + .is_some_and(|refname| refname == *file_ref_text), + Tag(_) => false, + Footnote(_) => false, + }, + Referenceable::Heading(..) | Referenceable::UnresolvedHeading(..) => match reference { + WikiHeadingLink(data, ..) | MDHeadingLink(data, ..) => { + Some(&data.reference_text) == self.get_refname(root_dir).as_ref() } - } + Tag(..) => false, + WikiFileLink(..) => false, + WikiIndexedBlockLink(..) => false, + MDFileLink(..) => false, + MDIndexedBlockLink(..) => false, + Footnote(..) => false, + }, Referenceable::IndexedBlock(..) | Referenceable::UnresovledIndexedBlock(..) => { match reference { - WikiIndexedBlockLink(..) | MDIndexedBlockLink(..) => Some(text) == self.get_refname(root_dir).as_ref(), + WikiIndexedBlockLink(..) | MDIndexedBlockLink(..) => { + Some(text) == self.get_refname(root_dir).as_ref() + } Tag(_) => false, WikiFileLink(_) => false, WikiHeadingLink(_, _, _) => false, @@ -1129,15 +1128,15 @@ impl Referenceable<'_> { character: 1, }, } - .into(), + .into(), ), &Referenceable::Heading(_, heading) => Some(heading.range), &Referenceable::IndexedBlock(_, indexed_block) => Some(indexed_block.range), &Referenceable::Tag(_, tag) => Some(tag.range), &Referenceable::Footnote(_, footnote) => Some(footnote.range), &Referenceable::UnresovledFile(..) - | &Referenceable::UnresolvedHeading(..) - | &Referenceable::UnresovledIndexedBlock(..) => None, + | &Referenceable::UnresolvedHeading(..) + | &Referenceable::UnresovledIndexedBlock(..) => None, } } @@ -1145,8 +1144,8 @@ impl Referenceable<'_> { matches!( self, Referenceable::UnresolvedHeading(..) - | Referenceable::UnresovledFile(..) - | Referenceable::UnresovledIndexedBlock(..) + | Referenceable::UnresovledFile(..) + | Referenceable::UnresovledIndexedBlock(..) ) } } @@ -1182,7 +1181,7 @@ mod vault_tests { character: 18, }, } - .into(), + .into(), ..ReferenceData::default() }), WikiFileLink(ReferenceData { @@ -1197,7 +1196,7 @@ mod vault_tests { character: 29, }, } - .into(), + .into(), ..ReferenceData::default() }), WikiFileLink(ReferenceData { @@ -1212,7 +1211,7 @@ mod vault_tests { character: 10, }, } - .into(), + .into(), ..ReferenceData::default() }), ]; @@ -1238,7 +1237,7 @@ mod vault_tests { character: 39, }, } - .into(), + .into(), display_text: Some("but called different".into()), }), WikiFileLink(ReferenceData { @@ -1253,7 +1252,7 @@ mod vault_tests { character: 54, }, } - .into(), + .into(), display_text: Some("222".into()), }), WikiFileLink(ReferenceData { @@ -1268,7 +1267,7 @@ mod vault_tests { character: 14, }, } - .into(), + .into(), display_text: Some("333".into()), }), ]; @@ -1276,44 +1275,71 @@ mod vault_tests { assert_eq!(parsed, expected) } - #[test] fn md_link_parsing() { let text = "Test text test text [link](path/to/link)"; let parsed = Reference::new(text); - let expected = vec![Reference::MDFileLink(ReferenceData { reference_text: "path/to/link".into(), display_text: Some("link".into()), range: Range { - start: Position {line: 0, character: 20}, - end: Position {line: 0, character: 40 } - }.into() })]; - + let expected = vec![Reference::MDFileLink(ReferenceData { + reference_text: "path/to/link".into(), + display_text: Some("link".into()), + range: Range { + start: Position { + line: 0, + character: 20, + }, + end: Position { + line: 0, + character: 40, + }, + } + .into(), + })]; assert_eq!(parsed, expected); - let text = "Test text test text [link](./path/to/link)"; let parsed = Reference::new(text); - let expected = vec![Reference::MDFileLink(ReferenceData { reference_text: "path/to/link".into(), display_text: Some("link".into()), range: Range { - start: Position {line: 0, character: 20}, - end: Position {line: 0, character: 42 } - }.into() })]; - + let expected = vec![Reference::MDFileLink(ReferenceData { + reference_text: "path/to/link".into(), + display_text: Some("link".into()), + range: Range { + start: Position { + line: 0, + character: 20, + }, + end: Position { + line: 0, + character: 42, + }, + } + .into(), + })]; assert_eq!(parsed, expected); - let text = "Test text test text [link](./path/to/link.md)"; let parsed = Reference::new(text); - let expected = vec![Reference::MDFileLink(ReferenceData { reference_text: "path/to/link".into(), display_text: Some("link".into()), range: Range { - start: Position {line: 0, character: 20}, - end: Position {line: 0, character: 45 } - }.into() })]; - + let expected = vec![Reference::MDFileLink(ReferenceData { + reference_text: "path/to/link".into(), + display_text: Some("link".into()), + range: Range { + start: Position { + line: 0, + character: 20, + }, + end: Position { + line: 0, + character: 45, + }, + } + .into(), + })]; assert_eq!(parsed, expected) } @@ -1325,40 +1351,51 @@ mod vault_tests { let parsed = Reference::new(text); let expected = vec![Reference::MDHeadingLink( - ReferenceData { - reference_text: "path/to/link#heading".into(), - display_text: Some("link".into()), + ReferenceData { + reference_text: "path/to/link#heading".into(), + display_text: Some("link".into()), range: Range { - start: Position {line: 0, character: 20}, - end: Position {line: 0, character: 48 } - }.into(), + start: Position { + line: 0, + character: 20, + }, + end: Position { + line: 0, + character: 48, + }, + } + .into(), }, "path/to/link".into(), - "heading".into() + "heading".into(), )]; - assert_eq!(parsed, expected); - let text = "Test text test text [link](path/to/link.md#heading)"; let parsed = Reference::new(text); let expected = vec![Reference::MDHeadingLink( - ReferenceData { - reference_text: "path/to/link#heading".into(), - display_text: Some("link".into()), + ReferenceData { + reference_text: "path/to/link#heading".into(), + display_text: Some("link".into()), range: Range { - start: Position {line: 0, character: 20}, - end: Position {line: 0, character: 51 } - }.into(), + start: Position { + line: 0, + character: 20, + }, + end: Position { + line: 0, + character: 51, + }, + } + .into(), }, "path/to/link".into(), - "heading".into() + "heading".into(), )]; - assert_eq!(parsed, expected) } @@ -1380,7 +1417,7 @@ mod vault_tests { character: 22, }, } - .into(), + .into(), ..ReferenceData::default() })]; @@ -1425,7 +1462,7 @@ more text character: 19, }, } - .into(), + .into(), ..Default::default() }, MDHeading { @@ -1440,7 +1477,7 @@ more text character: 28, }, } - .into(), + .into(), level: HeadingLevel(2), }, ]; @@ -1532,7 +1569,7 @@ more text character: 18, }, } - .into(), + .into(), ..ReferenceData::default() }), WikiFileLink(ReferenceData { @@ -1547,7 +1584,7 @@ more text character: 29, }, } - .into(), + .into(), ..ReferenceData::default() }), WikiFileLink(ReferenceData { @@ -1562,7 +1599,7 @@ more text character: 10, }, } - .into(), + .into(), ..ReferenceData::default() }), ]; @@ -1607,7 +1644,7 @@ and a third tag#notatag [[link#not a tag]] character: 14, }, } - .into(), + .into(), }, MDTag { tag_ref: "tag/ttagg".into(), @@ -1621,7 +1658,7 @@ and a third tag#notatag [[link#not a tag]] character: 22, }, } - .into(), + .into(), }, MDTag { tag_ref: "MapOfContext/apworld".into(), @@ -1635,7 +1672,7 @@ and a third tag#notatag [[link#not a tag]] character: 21, }, } - .into(), + .into(), }, ]; @@ -1661,7 +1698,7 @@ and a third tag#notatag [[link#not a tag]] character: 24, }, } - .into(), + .into(), }]; assert_eq!(parsed, expected); @@ -1692,7 +1729,7 @@ Continued character: 19, }, } - .into(), + .into(), }, MDFootnote { index: "^2".into(), @@ -1707,7 +1744,7 @@ Continued character: 22, }, } - .into(), + .into(), }, MDFootnote { index: "^a".into(), @@ -1722,7 +1759,7 @@ Continued character: 19, }, } - .into(), + .into(), }, ];