Support self-references
This commit is contained in:
parent
8e4238645b
commit
9418f20d61
40
src/lib.rs
40
src/lib.rs
@ -26,7 +26,7 @@ type MarkdownTree<'a> = Vec<Event<'a>>;
|
|||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref OBSIDIAN_NOTE_LINK_RE: Regex =
|
static ref OBSIDIAN_NOTE_LINK_RE: Regex =
|
||||||
Regex::new(r"^(?P<file>[^#|]+)(#(?P<section>.+?))??(\|(?P<label>.+?))??$").unwrap();
|
Regex::new(r"^(?P<file>[^#|]+)??(#(?P<section>.+?))??(\|(?P<label>.+?))??$").unwrap();
|
||||||
}
|
}
|
||||||
const PERCENTENCODE_CHARS: &AsciiSet = &CONTROLS.add(b' ').add(b'(').add(b')').add(b'%');
|
const PERCENTENCODE_CHARS: &AsciiSet = &CONTROLS.add(b' ').add(b'(').add(b')').add(b'%');
|
||||||
const NOTE_RECURSION_LIMIT: usize = 10;
|
const NOTE_RECURSION_LIMIT: usize = 10;
|
||||||
@ -121,7 +121,8 @@ struct Context {
|
|||||||
/// ObsidianNoteReference represents the structure of a `[[note]]` or `![[embed]]` reference.
|
/// ObsidianNoteReference represents the structure of a `[[note]]` or `![[embed]]` reference.
|
||||||
struct ObsidianNoteReference<'a> {
|
struct ObsidianNoteReference<'a> {
|
||||||
/// The file (note name or partial path) being referenced.
|
/// The file (note name or partial path) being referenced.
|
||||||
file: &'a str,
|
/// This will be None in the case that the reference is to a section within the same document
|
||||||
|
file: Option<&'a str>,
|
||||||
/// If specific, a specific section/heading being referenced.
|
/// If specific, a specific section/heading being referenced.
|
||||||
section: Option<&'a str>,
|
section: Option<&'a str>,
|
||||||
/// If specific, the custom label/text which was specified.
|
/// If specific, the custom label/text which was specified.
|
||||||
@ -186,10 +187,7 @@ impl<'a> ObsidianNoteReference<'a> {
|
|||||||
let captures = OBSIDIAN_NOTE_LINK_RE
|
let captures = OBSIDIAN_NOTE_LINK_RE
|
||||||
.captures(&text)
|
.captures(&text)
|
||||||
.expect("note link regex didn't match - bad input?");
|
.expect("note link regex didn't match - bad input?");
|
||||||
let file = captures
|
let file = captures.name("file").map(|v| v.as_str());
|
||||||
.name("file")
|
|
||||||
.expect("Obsidian links should always reference a file")
|
|
||||||
.as_str();
|
|
||||||
let label = captures.name("label").map(|v| v.as_str());
|
let label = captures.name("label").map(|v| v.as_str());
|
||||||
let section = captures.name("section").map(|v| v.as_str());
|
let section = captures.name("section").map(|v| v.as_str());
|
||||||
|
|
||||||
@ -210,9 +208,12 @@ impl<'a> fmt::Display for ObsidianNoteReference<'a> {
|
|||||||
let label = self
|
let label = self
|
||||||
.label
|
.label
|
||||||
.map(|v| v.to_string())
|
.map(|v| v.to_string())
|
||||||
.unwrap_or_else(|| match self.section {
|
.unwrap_or_else(|| match (self.file, self.section) {
|
||||||
Some(section) => format!("{} > {}", self.file, section),
|
(Some(file), Some(section)) => format!("{} > {}", file, section),
|
||||||
None => self.file.to_string(),
|
(Some(file), None) => file.to_string(),
|
||||||
|
(None, Some(section)) => section.to_string(),
|
||||||
|
|
||||||
|
_ => panic!("Reference exists without file or section!"),
|
||||||
})
|
})
|
||||||
.to_string();
|
.to_string();
|
||||||
write!(f, "{}", label)
|
write!(f, "{}", label)
|
||||||
@ -458,12 +459,18 @@ impl<'a> Exporter<'a> {
|
|||||||
fn embed_file<'b>(&self, link_text: &'a str, context: &'a Context) -> Result<MarkdownTree<'a>> {
|
fn embed_file<'b>(&self, link_text: &'a str, context: &'a Context) -> Result<MarkdownTree<'a>> {
|
||||||
let note_ref = ObsidianNoteReference::from_str(link_text);
|
let note_ref = ObsidianNoteReference::from_str(link_text);
|
||||||
|
|
||||||
let path = lookup_filename_in_vault(note_ref.file, &self.vault_contents.as_ref().unwrap());
|
let path = note_ref
|
||||||
|
.file
|
||||||
|
.map(|file| lookup_filename_in_vault(file, &self.vault_contents.as_ref().unwrap()))
|
||||||
|
.unwrap_or_else(|| Some(context.current_file()));
|
||||||
|
|
||||||
if path.is_none() {
|
if path.is_none() {
|
||||||
// TODO: Extract into configurable function.
|
// TODO: Extract into configurable function.
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Warning: Unable to find embedded note\n\tReference: '{}'\n\tSource: '{}'\n",
|
"Warning: Unable to find embedded note\n\tReference: '{}'\n\tSource: '{}'\n",
|
||||||
note_ref.file,
|
note_ref
|
||||||
|
.file
|
||||||
|
.unwrap_or_else(|| context.current_file().to_str().unwrap()),
|
||||||
context.current_file().display(),
|
context.current_file().display(),
|
||||||
);
|
);
|
||||||
return Ok(vec![]);
|
return Ok(vec![]);
|
||||||
@ -525,13 +532,18 @@ impl<'a> Exporter<'a> {
|
|||||||
reference: ObsidianNoteReference<'b>,
|
reference: ObsidianNoteReference<'b>,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
) -> MarkdownTree<'b> {
|
) -> MarkdownTree<'b> {
|
||||||
let target_file =
|
let target_file = reference
|
||||||
lookup_filename_in_vault(reference.file, &self.vault_contents.as_ref().unwrap());
|
.file
|
||||||
|
.map(|file| lookup_filename_in_vault(file, &self.vault_contents.as_ref().unwrap()))
|
||||||
|
.unwrap_or_else(|| Some(context.current_file()));
|
||||||
|
|
||||||
if target_file.is_none() {
|
if target_file.is_none() {
|
||||||
// TODO: Extract into configurable function.
|
// TODO: Extract into configurable function.
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"Warning: Unable to find referenced note\n\tReference: '{}'\n\tSource: '{}'\n",
|
"Warning: Unable to find referenced note\n\tReference: '{}'\n\tSource: '{}'\n",
|
||||||
reference.file,
|
reference
|
||||||
|
.file
|
||||||
|
.unwrap_or_else(|| context.current_file().to_str().unwrap()),
|
||||||
context.current_file().display(),
|
context.current_file().display(),
|
||||||
);
|
);
|
||||||
return vec![
|
return vec![
|
||||||
|
Loading…
Reference in New Issue
Block a user