Now, not to pester OP or anyone else for their attention about yet more of the same, but – mainly for my own use cases to do with longform writing – I decided to make and share an upgrade of what came above, in the form of a Templater Js script with the DV query embedded, which lets the user interact with what they want output.
It seems to be working well.
<%*
const currentFile = app.workspace.getActiveFile();
if (!currentFile) return;
let folderRegex = /(.*)([/\\])/; // Default regex for full vault – all OS environments are taken into consideration
const userinput = await tp.system.suggester(
["Query Full Vault", "Specify Unique Folder"],
["Query Full Vault", "Specify Unique Folder"],
false,
"Choose an option:"
);
if (userinput === "Specify Unique Folder") {
const items = app.vault.getAllLoadedFiles().filter(x => x instanceof tp.obsidian.TFolder);
const selectedItem = (await tp.system.suggester((item) => item.path, items)).path;
if (selectedItem) {
// Update folderRegex based on user selection
folderRegex = new RegExp(`(${selectedItem.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})([/\\\\])`);
} else {
return; // Exit if user cancels folder selection
}
}
const searchTerm = await tp.system.prompt("Enter search term:");
if (!searchTerm) return;
const editor = app.workspace.activeEditor.editor;
const fileContent = await app.vault.read(currentFile);
const dynamicContent = `
\%\%
\`\`\`dataviewjs
// Define the folder regex for filtering allPages
const folderRegex = ${folderRegex}; // Dynamically updated folder regex
const searchTerm = "${searchTerm}"; // Injecting searchTerm here as well
// Query all pages and filter based on folderRegex
const allPages = dv.pages("").filter(page => {
const path = page.file.path;
return folderRegex.test(path);
});
// Crawl content and render list
const pages = await Promise.all(
allPages.map(async (page) => {
const content = await dv.io.load(page.file.path);
const regexPattern = new RegExp(\`.*(\${searchTerm}).*\`, "gmi");
const regexMatches = content.match(regexPattern);
if (regexMatches && regexMatches.length > 0) {
// Apply replacements to each matched content before storing in pages
const processedContent = regexMatches
.map(match => {
let processed = match.replace(/>/g, '>'); // Replace > with >
processed = processed.replace(/(^>\\s*)|(^-\\s*)/gm, ''); // Remove > and - plus spaces at the start of each line
processed = processed.replace(new RegExp(\`(\${searchTerm})(?![^\\\\[]*\\\\]\\\\])\`, "gmi"), '==\$&==');
return processed;
})
.join('<br><br>'); // Separate each processed match with two line breaks
return {
link: page.file.link,
content: processedContent
};
}
return null;
})
);
// Filter out null entries and build the list string with proper formatting
const listOutput = pages
.filter(p => p !== null)
.map(p => \`\${p.link}\\n\${p.content}\` + \`<br><br>\`); // Include breaks between list items as well
// Output the formatted list fltering out the current file's line containing searchTerm
dv.list(listOutput.filter(line => !line.includes('const searchTerm')));
\`\`\`
\%\%
`;
const updatedContent = fileContent + '\n\n' + dynamicContent;
await app.vault.modify(currentFile, updatedContent);
_%>
Usage: save the script in your Templater folder and then in the current working editor run the Templater template and navigate through drop-downs and/or suggesters and finally enter search term.
If current working editor is set to Live Preview, search results – if any – will be printed in the file. (If there are no results, you may or will not get a notice about there being zero results, for some reason.)
Using ==highlight==
format and added support for case insensitivity (changed gm
to gmi
).
'==\$&=='
can be changed to some other markdown format, if needed.
I have removed the \b
’s to have compounds also come up in the results. If anyone wants strict results, exchange const regexPattern = new RegExp(\`.*(\${searchTerm}).*\`, "gmi");
with const regexPattern = new RegExp(\`.*\\\\b(\${searchTerm})\\\\b.*\`, "gmi");
.
(In the embedded DV query, backticks, dollar signs and backslashs had to be escaped with \
, if anyone is interested making similar things in the future.)
The line this.app.workspace.activeLeaf.view.editor.setCursor({line: 99999, ch: 0});
can be added above const updatedContent = fileContent + '\n\n' + dynamicContent;
if we want to add results to the very last line of the file.
EDIT. Changed the dv.list line to dv.list(listOutput.filter(line => !line.includes('const searchTerm')));
to filter out the unwanted line.
For anyone new with Templater and how to set it up, a tut-let of some sort I found in the following thread: