Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 37 additions & 55 deletions src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,29 @@ use nucleo_matcher::{
Matcher,
};
use tower_lsp::lsp_types::{
DocumentSymbol, DocumentSymbolParams, DocumentSymbolResponse, Location, SymbolInformation,
SymbolKind, Url, WorkspaceSymbolParams,
DocumentSymbol, DocumentSymbolParams, DocumentSymbolResponse, SymbolInformation, SymbolKind,
WorkspaceSymbolParams,
};

use crate::vault::{MDHeading, Referenceable, Vault};
use crate::vault::{MDHeading, Vault};

fn compute_match_score(
matcher: &mut Matcher,
pattern: &pattern::Pattern,
symbol: SymbolInformation,
) -> (u32, SymbolInformation) {
let mut buf = Vec::new();
(
match pattern.score(
nucleo_matcher::Utf32Str::new(symbol.name.as_str(), &mut buf),
matcher,
) {
None => 0,
Some(score) => score,
},
symbol,
)
}

pub fn workspace_symbol(
vault: &Vault,
Expand All @@ -23,60 +41,23 @@ pub fn workspace_symbol(
pattern::CaseMatching::Smart,
Normalization::Smart,
);
let mut buf = Vec::new();

// Collect symbols and order by fuzzy matching score
let referenceables = vault.select_referenceable_nodes(None);
let symbol_informations = referenceables
.into_iter()
.flat_map(|referenceable| {
let range = match referenceable {
Referenceable::File(..) => tower_lsp::lsp_types::Range {
start: tower_lsp::lsp_types::Position {
line: 0,
character: 0,
},
end: tower_lsp::lsp_types::Position {
line: 0,
character: 1,
},
},
_ => *referenceable.get_range()?,
};

Some(SymbolInformation {
name: referenceable.get_refname(vault.root_dir())?.to_string(),
kind: match referenceable {
Referenceable::File(_, _) => SymbolKind::FILE,
Referenceable::Tag(_, _) => SymbolKind::CONSTANT,
_ => SymbolKind::KEY,
},
location: Location {
uri: Url::from_file_path(referenceable.get_path()).ok()?,
range,
},
container_name: None,
tags: None,
deprecated: None,
})
})
// Fuzzy matcher - compute match score
.map(|symbol| {
let score = pattern.score(
nucleo_matcher::Utf32Str::new(symbol.name.as_str(), &mut buf),
&mut matcher,
);
(score, symbol)
})
// Remove all items with no matches
.filter(|(score, _)| score.is_some() && score.unwrap() > 0)
// Sort by match score descending
.sorted_by(|(a, _), (b, _)| Option::cmp(b, a))
// Strip the score from the result
.map(|(_score, symbol)| symbol)
.collect_vec();

Some(symbol_informations)
Some(
vault
.select_referenceable_nodes(None)
.into_iter()
.flat_map(|referenceable| vault.to_symbol_information(referenceable))
// Fuzzy matcher - compute match score
.map(|symbol| compute_match_score(&mut matcher, &pattern, symbol))
// Remove all items with no matches
.filter(|(score, _)| *score > 0)
// Sort by match score descending
.sorted_by(|(a, _), (b, _)| Ord::cmp(b, a))
// Strip the score from the result
.map(|(_score, symbol)| symbol)
.collect_vec(),
)
}

pub fn document_symbol(
Expand Down Expand Up @@ -139,6 +120,7 @@ fn construct_tree(headings: &[MDHeading]) -> Option<Vec<Node>> {
}
}

#[allow(deprecated)] // field deprecated has been deprecated in favor of using tags and will be removed in the future
fn map_to_lsp_tree(tree: Vec<Node>) -> Vec<DocumentSymbol> {
tree.into_iter()
.map(|node| DocumentSymbol {
Expand Down
44 changes: 41 additions & 3 deletions src/vault/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use rayon::prelude::*;
use regex::{Captures, Match, Regex};
use ropey::Rope;
use serde::{Deserialize, Serialize};
use tower_lsp::lsp_types::Position;
use tower_lsp::lsp_types::{Location, Position, SymbolInformation, SymbolKind, Url};
use walkdir::WalkDir;

impl Vault {
Expand Down Expand Up @@ -128,6 +128,25 @@ impl Hash for Vault {
}
}

fn find_range(referenceable: &Referenceable) -> Option<tower_lsp::lsp_types::Range> {
match referenceable {
Referenceable::File(..) => Some(tower_lsp::lsp_types::Range {
start: tower_lsp::lsp_types::Position {
line: 0,
character: 0,
},
end: tower_lsp::lsp_types::Position {
line: 0,
character: 1,
},
}),
_ => match referenceable.get_range() {
None => None,
Some(a_my_range) => Some(*a_my_range),
},
}
}

#[derive(Debug, PartialEq, Eq, Clone)]
/// The in memory representation of the obsidian vault files. This data is exposed through an interface of methods to select the vaults data.
/// These methods do not do any interpretation or analysis of the data. That is up to the consumer of this struct. The methods are analogous to selecting on a database.
Expand Down Expand Up @@ -358,14 +377,33 @@ impl Vault {
&self,
reference: &Reference,
reference_path: &Path,
) -> Vec<Referenceable> {
) -> Vec<Referenceable<'_>> {
let referenceables = self.select_referenceable_nodes(None);

referenceables
.into_iter()
.filter(|i| reference.references(self.root_dir(), reference_path, i))
.collect()
}

#[allow(deprecated)] // field deprecated has been deprecated in favor of using tags and will be removed in the future
pub fn to_symbol_information(&self, referenceable: Referenceable) -> Option<SymbolInformation> {
Some(SymbolInformation {
name: referenceable.get_refname(self.root_dir())?.to_string(),
kind: match referenceable {
Referenceable::File(_, _) => SymbolKind::FILE,
Referenceable::Tag(_, _) => SymbolKind::CONSTANT,
_ => SymbolKind::KEY,
},
location: Location {
uri: Url::from_file_path(referenceable.get_path()).ok()?,
range: find_range(&referenceable)?,
},
container_name: None,
tags: None,
deprecated: None,
})
}
}

pub enum Preview {
Expand Down Expand Up @@ -606,7 +644,7 @@ impl MDFile {
}

impl MDFile {
fn get_referenceables(&self) -> Vec<Referenceable> {
fn get_referenceables(&self) -> Vec<Referenceable<'_>> {
let MDFile {
references: _,
headings,
Expand Down