diff --git a/src/completion/footnote_completer.rs b/src/completion/footnote_completer.rs new file mode 100644 index 00000000..6bae2c39 --- /dev/null +++ b/src/completion/footnote_completer.rs @@ -0,0 +1,96 @@ +use std::path::Path; + +use tower_lsp::lsp_types::{CompletionItem, CompletionItemKind, Documentation}; + +use crate::{ui::preview_referenceable, vault::{MDFootnote, Preview, Referenceable, Vault}}; + +use super::{Completable, Completer}; + +use rayon::prelude::*; + +pub struct FootnoteCompleter<'a> { + vault: &'a Vault, + line: usize, + character: usize, + path: &'a Path +} + +impl<'a> Completer<'a> for FootnoteCompleter<'a> { + fn construct(context: super::Context<'a>, line: usize, character: usize) -> Option + where Self: Sized + Completer<'a> { + + + let selected_line = context.vault.select_line(context.path, line as isize)?; + + if character + .checked_sub(1) + .and_then(|start| selected_line.get(start..character)) + == Some(&['[']) { + Some(FootnoteCompleter{path: context.path, character, line, vault: context.vault}) + } else { + None + } + } + + fn completions(&self) -> Vec> where Self: Sized { + + let path_footnotes = self.vault.select_referenceable_nodes(Some(&self.path)) + .into_par_iter() + .flat_map(|referenceable| FootnoteCompletion::from_referenceable(referenceable)) + .collect::>(); + + path_footnotes + + + } + + type FilterParams = (&'a str, Referenceable<'a>); + fn completion_filter_text(&self, params: Self::FilterParams) -> String { + self.vault + .select_referenceable_preview(¶ms.1) + .and_then(|preview| match preview { + Preview::Text(string) => Some(string), + Preview::Empty => None, + }) + .map(|preview_string| format!("{}{}", params.0, &preview_string)).unwrap_or("".to_owned()) + } + +} + +struct FootnoteCompletion<'a> { + footnote: (&'a Path, &'a MDFootnote) +} + + impl FootnoteCompletion<'_> { + fn from_referenceable(referenceable: Referenceable<'_>) -> Option> { + match referenceable { + Referenceable::Footnote(path, footnote) => Some(FootnoteCompletion{footnote: (path, footnote)}), + _ => None + } + } + } + + +impl<'a> Completable<'a, FootnoteCompleter<'a>> for FootnoteCompletion<'a> { + fn completions(&self, completer: &FootnoteCompleter<'a>) -> impl Iterator { + + + + + let refname = &self.footnote.1.index; + + let path = self.footnote.0; + let path_buf = path.to_path_buf(); + let self_referenceable = Referenceable::Footnote(&path_buf, self.footnote.1); + + Some(CompletionItem { + label: refname.to_string(), + kind: Some(CompletionItemKind::REFERENCE), + documentation: preview_referenceable(completer.vault, &self_referenceable) + .map(Documentation::MarkupContent), + filter_text: Some(completer.completion_filter_text((refname, self_referenceable))), + ..Default::default() + }).into_iter() + + } +} diff --git a/src/completion/link_completer.rs b/src/completion/link_completer.rs index e8f7fdf8..33ae51fa 100644 --- a/src/completion/link_completer.rs +++ b/src/completion/link_completer.rs @@ -103,10 +103,10 @@ impl<'a> LinkCompleter<'a> for MarkdownLinkCompleter<'a> { impl<'a> Completer<'a> for MarkdownLinkCompleter<'a> { - fn construct(context: Context<'a>, path: &std::path::Path, line: usize, character: usize) -> Option + fn construct(context: Context<'a>, line: usize, character: usize) -> Option where Self: Sized { - let Context { vault, opened_files: _ } = context; + let Context { vault, opened_files: _, path } = context; let line_chars = vault.select_line(path, line as isize)?; let line_to_cursor = line_chars.get(0..character)?; @@ -424,10 +424,10 @@ impl<'a> LinkCompleter<'a> for WikiLinkCompleter<'a> { impl<'a> Completer<'a> for WikiLinkCompleter<'a> { - fn construct(context: Context<'a>, path: &std::path::Path, line: usize, character: usize) -> Option + fn construct(context: Context<'a>, line: usize, character: usize) -> Option where Self: Sized { - let Context { vault, opened_files } = context; + let Context { vault, opened_files, path } = context; let line_chars = vault.select_line(path, line as isize)?; diff --git a/src/completion/mod.rs b/src/completion/mod.rs index f3a0abcb..d864ad6a 100644 --- a/src/completion/mod.rs +++ b/src/completion/mod.rs @@ -22,23 +22,25 @@ use crate::{ }, }; -use self::{link_completer::MarkdownLinkCompleter, matcher::fuzzy_match, tag_completer::TagCompleter, unindexed_block_completer::UnindexedBlockCompleter}; +use self::{footnote_completer::FootnoteCompleter, link_completer::MarkdownLinkCompleter, matcher::fuzzy_match, tag_completer::TagCompleter, unindexed_block_completer::UnindexedBlockCompleter}; use self::link_completer::WikiLinkCompleter; mod link_completer; mod matcher; mod unindexed_block_completer; mod tag_completer; +mod footnote_completer; #[derive(Clone, Copy)] pub struct Context<'a>{ vault: &'a Vault, opened_files: &'a [PathBuf], + path: &'a Path } pub trait Completer<'a> : Sized { - fn construct(context: Context<'a>, path: &Path, line: usize, character: usize) -> Option + fn construct(context: Context<'a>, line: usize, character: usize) -> Option where Self: Sized + Completer<'a>; fn completions(&self) -> Vec> where Self: Sized; @@ -63,27 +65,20 @@ pub fn get_completions( vault: &Vault, initial_completion_files: &[PathBuf], params: &CompletionParams, - _path: &Path, + path: &Path, ) -> Option { - let Ok(path) = params - .text_document_position - .text_document - .uri - .to_file_path() - else { - return None; - }; - let completion_context = Context { vault, - opened_files: initial_completion_files + opened_files: initial_completion_files, + path: &path, }; - run_completer::>(completion_context, &path, params.text_document_position.position.line, params.text_document_position.position.character) - .or_else(|| run_completer::>(completion_context, &path, params.text_document_position.position.line, params.text_document_position.position.character)) - .or_else(|| run_completer::(completion_context, &path, params.text_document_position.position.line, params.text_document_position.position.character)) - .or_else(|| run_completer::(completion_context, &path, params.text_document_position.position.line, params.text_document_position.position.character)) - .or_else(|| run_completer::(completion_context, &path, params.text_document_position.position.line, params.text_document_position.position.character)) + run_completer::>(completion_context, params.text_document_position.position.line, params.text_document_position.position.character) + .or_else(|| run_completer::>(completion_context, params.text_document_position.position.line, params.text_document_position.position.character)) + .or_else(|| run_completer::(completion_context, params.text_document_position.position.line, params.text_document_position.position.character)) + .or_else(|| run_completer::(completion_context, params.text_document_position.position.line, params.text_document_position.position.character)) + .or_else(|| run_completer::(completion_context, params.text_document_position.position.line, params.text_document_position.position.character)) + .or_else(|| run_completer::(completion_context, params.text_document_position.position.line, params.text_document_position.position.character)) } // } else if character @@ -384,9 +379,9 @@ pub fn get_completions( // } -fn run_completer<'a, T: Completer<'a>>(context: Context<'a>, path: &Path, line: u32, character: u32) -> Option { +fn run_completer<'a, T: Completer<'a>>(context: Context<'a>, line: u32, character: u32) -> Option { - let completer = T::construct(context, path, line as usize, character as usize)?; + let completer = T::construct(context, line as usize, character as usize)?; let completions = completer.completions(); let completions = completions diff --git a/src/completion/tag_completer.rs b/src/completion/tag_completer.rs index 6bf425b5..7f306d63 100644 --- a/src/completion/tag_completer.rs +++ b/src/completion/tag_completer.rs @@ -23,14 +23,14 @@ pub struct TagCompleter<'a> { } impl<'a> Completer<'a> for TagCompleter<'a> { - fn construct(context: super::Context<'a>, path: &std::path::Path, line: usize, character: usize) -> Option + fn construct(context: super::Context<'a>, line: usize, character: usize) -> Option where Self: Sized + Completer<'a> { static PARTIAL_TAG_REGEX: Lazy = Lazy::new(|| { Regex::new(r"\#(?[a-zA-Z0-9\/]*)").unwrap() }); - let line_chars = context.vault.select_line(path, line as isize)?; + let line_chars = context.vault.select_line(context.path, line as isize)?; let line_string = String::from_iter(line_chars); let captures_iter = PARTIAL_TAG_REGEX.captures_iter(&line_string); diff --git a/src/completion/unindexed_block_completer.rs b/src/completion/unindexed_block_completer.rs index 558f02dd..20cbc024 100644 --- a/src/completion/unindexed_block_completer.rs +++ b/src/completion/unindexed_block_completer.rs @@ -66,10 +66,10 @@ impl<'a, C: LinkCompleter<'a>> UnindexedBlockCompleter<'a, C> { impl<'a> Completer<'a> for UnindexedBlockCompleter<'a, MarkdownLinkCompleter<'a>> { - fn construct(context: super::Context<'a>, path: &std::path::Path, line: usize, character: usize) -> Option + fn construct(context: super::Context<'a>, line: usize, character: usize) -> Option where Self: Sized { - let markdown_link_completer = MarkdownLinkCompleter::construct(context, path, line, character)?; + let markdown_link_completer = MarkdownLinkCompleter::construct(context, line, character)?; Self::from_link_completer(markdown_link_completer) } @@ -92,10 +92,10 @@ where Self: Sized { } impl<'a> Completer<'a> for UnindexedBlockCompleter<'a, WikiLinkCompleter<'a>> { - fn construct(context: super::Context<'a>, path: &std::path::Path, line: usize, character: usize) -> Option + fn construct(context: super::Context<'a>, line: usize, character: usize) -> Option where Self: Sized { - let wiki_link_completer = WikiLinkCompleter::construct(context, path, line, character)?; + let wiki_link_completer = WikiLinkCompleter::construct(context, line, character)?; UnindexedBlockCompleter::from_link_completer(wiki_link_completer) } diff --git a/src/vault/mod.rs b/src/vault/mod.rs index 506a7039..e2144ade 100644 --- a/src/vault/mod.rs +++ b/src/vault/mod.rs @@ -1032,9 +1032,9 @@ impl MDIndexedBlock { #[derive(Debug, Eq, PartialEq, Clone)] pub struct MDFootnote { - index: String, - footnote_text: String, - range: MyRange, + pub index: String, + pub footnote_text: String, + pub range: MyRange, } impl Hash for MDFootnote {