Open josephalevin opened 4 weeks ago
Hi. I think it is not possible for now. Each feature resolves title through async, but all chain from resolving to processor and final result is a sync chain.
It takes some time to think about the options.
I've managed to hack together a working proof of concept by using my own cache and dispatching a metadata:cache:changed event to trick the plugin into resolving again so I can return my cached value syncronously
// passed object has 2 params
const title = obj.title;
const path = obj.path;
//check for prefix on the fallback to avoid endless loop
if (title !== null && !title.startsWith("<MAGIC_TITLE>")){
return title;
}
//check if the magic link callback has set something in the cache
const plugin = window.app.plugins.plugins['obsidian-front-matter-title-plugin'];
// setup a hacky cache if null
var cache = plugin.magic_link_cache;
if (cache == null || cache == undefined){
//console.log('init magic title cache');
cache = new Map();
plugin.magic_link_cache = cache;
}
//check the cache for a set title
if (cache.has(path)){
const cachedTitle = cache.get(path);
delete cache.delete(path);
return cachedTitle;
}
// the fallback to our magic callback hack
const vault = window.app.vault;
const file = vault.getFileByPath(path);
// test that it's really a file
if (file !== null) {
const text = vault.cachedRead(file);
// callback when the file contents are read
text.then((value) => {
//console.log("reading note contents")
// find the first line of content
if (value == null || value == undefined){
return;
}
const lines = value.split(/\r?\n/);
let inFrontMatter = false;
let magicTitle = 'untitled';
// read the note file and find the first row of content after any front matter
for (line of lines){
line = line.trim();
if (inFrontMatter){
if (line.startsWith('---')){
inFrontMatter = false;
}
continue;
} else if (line.startsWith('---')){
inFrontMatter = true;
continue;
}
else if (line.length == 0 ){
// skip empty lines
continue;
}
// we found the magic title line! Now remove any leading markdown
// Remove headings
line = line.replace(/^\W*#+\W*/, "");
// remove lists
line = line.replace(/^\W*\+\W*/, "");
magicTitle = line;
break;
}
// TODO: trim the first line if too long
//HACK: get the front-matter-title event dispatcher
const dispatcher = window.app.plugins.plugins['obsidian-front-matter-title-plugin'].dispatcher;
cache.set(path, magicTitle);
const data = {
path: path,
cache: window.app.metadataCache
};
const event = {
get() {return data;},
stop() {}
};
// trick the plugin into refreshing to look at our cached value the next time this processor runs
dispatcher.dispatch('metadata:cache:changed', event);
});
// return a placeholder value until content is parsed
return 'loading...';
}
Yea, you hacked it. :D
Thank you for this plugin! How can I have a processor function update the title asynchronously after reading the contents of the note?
Use case: I want to use the first line of content in the note as the title. The file names are timestamps. I capture fleeting notes in my workflow from several sources so setting the first line as a header isn't an option.
I recognise there will may be a performance lag with opening all the files, but I assume it's an initial hit while the cache is loaded. I'm ok with that.
Here's what I'm trying:
Main template: title Fallback template: {{_path}}
Function V2: