Return a string of text and the backlink via dataview

Search term accepts regular expressions so the script can be used for ‘range or so-called proximity search’: e.g. <searchterm1>.*?<searchterm2> will find the two terms in their closest vicinity of one another and the full paragraph will be printed for context. The < and > are not part of the syntax, of course.

  • Same thing as in the Obsidian search modal, but there you need to put in at least the opening / slash to indicate we want to use regex.
  • The search done in the DV query like this is more superior as one can copy out the results for further processing.

This proximity search helped me a great deal years ago when I started out being more efficient researching for material among my 3k+ books and papers (was and am using DocFetcher for PDFs).

EDIT.:
In the meantime I added abililty for further filtering:

<%*
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 filterRegex = await tp.system.prompt("Exclude from results if string is present (or regex matched) in paragraph:");
const additionalFilter = await tp.system.prompt("Filter search results by string or regex:");

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
const filterRegex = ${filterRegex ? `new RegExp(\`${filterRegex}\`, "gmi")` : 'null'}; // Exclude from results regex
const additionalFilter = ${additionalFilter ? `new RegExp(\`${additionalFilter}\`, "gmi")` : 'null'}; // Additional filter regex

// 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(/&gt;/g, '>'); // Replace &gt; with >
                    processed = processed.replace(/(^>\\s*)|(^-\\s*)/gm, ''); // Remove > and 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;
    })
);

// Apply additional filters and build the list string with proper formatting
const listOutput = pages
    .filter(p => p !== null)
    .filter(p => !filterRegex || !filterRegex.test(p.content)) // Exclude matches that meet the exclude filter condition
    .filter(p => !additionalFilter || additionalFilter.test(p.content)) // Apply additional filter if provided
    .map(p => \`\${p.link}\\n\${p.content}\` + \`<br><br>\`); // Include breaks between list items as well

// Output the formatted list excluding the searchTerm line
dv.list(listOutput.filter(line => !line.includes('const searchTerm'))); 
\`\`\`
\%\%
`;

this.app.workspace.activeLeaf.view.editor.setCursor({line: 99999, ch: 0});
const updatedContent = fileContent + '\n\n' + dynamicContent;
await app.vault.modify(currentFile, updatedContent);
_%>
  • If one wants no filters to be applied, an enter must be pressed in the box (can do it twice in succession and be done with it).