pub struct LinkIndex {
pub collisions: usize,
/* private fields */
}Expand description
A suffix index: every file is reachable by any suffix of its path.
§Examples
use markdown_link::LinkIndex;
let index = LinkIndex::build(&["notes/a.md".to_string(), "deep/er/b.md".to_string()]);
assert_eq!(index.resolve("a"), Some("notes/a.md"));
assert_eq!(index.resolve("er/b"), Some("deep/er/b.md"));
assert_eq!(index.resolve("missing"), None);Fields§
§collisions: usizeHow many times a path claimed a key that a different path already held while the index was built.
Implementations§
Source§impl LinkIndex
impl LinkIndex
Sourcepub fn build(paths: &[String]) -> LinkIndex
pub fn build(paths: &[String]) -> LinkIndex
Build from vault-relative paths (with extensions).
Shortest path first, measured in CHARACTERS (not depth), then deterministic
collation. Character length is the observed tie-break:
x/y/tie.md (10 chars, 3 segments) beats length-versus-depth-long-folder/tie.md
(38 chars, 2 segments).
§Examples
use markdown_link::LinkIndex;
let index = LinkIndex::build(&["x/y/tie.md".to_string(), "long-folder/tie.md".to_string()]);
// The shorter path wins the bare name.
assert_eq!(index.resolve("tie"), Some("x/y/tie.md"));
assert_eq!(index.resolve("long-folder/tie"), Some("long-folder/tie.md"));
assert!(index.collisions > 0);Sourcepub fn resolve(&self, target: &str) -> Option<&str>
pub fn resolve(&self, target: &str) -> Option<&str>
Resolve one target to a vault-relative path, or None.
Source-independent, and therefore the same answer everywhere in the
vault. Equivalent to LinkIndex::resolve_from called from the vault
root, where the folder preference cannot apply.
§Examples
use markdown_link::LinkIndex;
let index = LinkIndex::build(&["notes/glutes.md".to_string()]);
assert_eq!(index.resolve("glutes"), Some("notes/glutes.md"));
// A pathed miss falls back to its basename.
assert_eq!(index.resolve("muscle-groups/glutes"), Some("notes/glutes.md"));
assert_eq!(index.resolve("nothing"), None);Sourcepub fn resolve_from(&self, target: &str, from: &str) -> Option<&str>
pub fn resolve_from(&self, target: &str, from: &str) -> Option<&str>
Resolve one target as it was written in from, a vault-relative path.
Differs from LinkIndex::resolve in two cases, the only ones where
where the link sits can change the answer. A ./ or ../ target names
the file at that path from the linking note’s folder (see
join_relative). An AMBIGUOUS name — several files answer to it —
takes two observed behaviours, in order: a candidate inside the linking
note’s own folder beats one outside it, and otherwise the shorter full
path wins.
The folder test is a plain string prefix, not a segment-aligned one,
which is what the application does: a note in notes/ also prefers a
candidate under notes-archive/. Small, real, and deliberately
matched — a reader seeing one file while a rename rewrites a different
one is worse than either rule alone.
§Examples
use markdown_link::LinkIndex;
let index = LinkIndex::build(&["b/a.md".to_string(), "notes/a.md".to_string(), "notes/x.md".to_string()]);
// Ambiguous name: the candidate in the linking note's folder wins.
assert_eq!(index.resolve_from("a", "notes/x.md"), Some("notes/a.md"));
assert_eq!(index.resolve_from("a", "other.md"), Some("b/a.md"));
// A `./` target is relative to the linking note.
assert_eq!(index.resolve_from("./a", "notes/x.md"), Some("notes/a.md"));Sourcepub fn candidates(&self, target: &str, from: &str) -> &[String]
pub fn candidates(&self, target: &str, from: &str) -> &[String]
Every path target, written in from, could mean, shortest first:
the field LinkIndex::resolve_from chooses from. Empty when nothing
answers to it.
A ./ or ../ target that names a file gives that one file. A pathed
target that misses gives the field of its last segment, the same
fallback resolve_from takes.
§Examples
use markdown_link::LinkIndex;
let index = LinkIndex::build(&["b/a.md".to_string(), "notes/a.md".to_string()]);
assert_eq!(index.candidates("a", "x.md"), ["b/a.md", "notes/a.md"]);
assert_eq!(index.candidates("./a", "notes/x.md"), ["notes/a.md"]);
assert!(index.candidates("nothing", "x.md").is_empty());Sourcepub fn resolve_strict(
&self,
target: &str,
from: &str,
) -> Result<&str, ResolveError>
pub fn resolve_strict( &self, target: &str, from: &str, ) -> Result<&str, ResolveError>
Resolve target, written in from, refusing to guess.
Where LinkIndex::resolve_from picks among several candidates (same
folder first, then the shortest path), this takes one only when the
link names it outright:
- a
./or../target that names a file; - the only candidate;
- the candidate whose whole vault-relative path is the target;
- the candidate at the target’s path from the linking note’s folder.
Anything else with more than one candidate is
ResolveError::Ambiguous, with every candidate, shortest first. An
empty target (a link to the note it is written in) is
ResolveError::NotFound; the caller knows which note that is.
§Examples
use markdown_link::{LinkIndex, ResolveError};
let index = LinkIndex::build(&["b/a.md".to_string(), "notes/a.md".to_string()]);
assert_eq!(
index.resolve_strict("a", "x.md"),
Err(ResolveError::Ambiguous(vec!["b/a.md".into(), "notes/a.md".into()]))
);
assert_eq!(index.resolve_strict("notes/a", "x.md"), Ok("notes/a.md"));
// `a` from inside `notes/` is `notes/a.md` by its path from there.
assert_eq!(index.resolve_strict("a", "notes/x.md"), Ok("notes/a.md"));
assert_eq!(index.resolve_strict("zzz", "x.md"), Err(ResolveError::NotFound));