I have now 10-12 DV queries – the majority of them in a Dashboard canvas – that help me find mistakes I make during longform writing.
In order to use the scripts, you need to install and enable the Dataview community plugin. Upon enabling the plugin, it will start indexing your vault (or maybe it’s better to relaunch the vault). In the plugin’s General Settings tick on Javascript support if it is not enabled by default.
You create a note and paste any of the following scripts (which you may need to customize for your own specific folders but it will work out of the box). Once you cursor out of the script (press enter after the closing 3 backticks and cursor down), it will be activated.
- As you might be unsure about how to handle the folderregex part to customize it, I went ahead and changed those lines to
const folderRegex = /(.*)([/\\])/;
to target all folders in your vault (support any OS). This may not be what you want, though. But as I said, you can use the scripts as they are now.
I mainly decided to showcase these queries because I like the way I can target specific chunks of text in all my notes and match within that match so that only the matches within the match will be pushed to the table. This cannot be done with normal Obsidian vault searches. Hence we use Javascript.
Query to Show Files with Blockquoted Lines among Footnotes
One of those mistakes were adding blockquotes to lines where I shouldn’t (these mistakes came from when I batch converted stuff with regex replacements a year or so ago).
If you add >
to lines in your footnotes, the rendering process will elevate that line above your footnotes. Markdown doesn’t like blockquoted text among your footnotes.
You can tweak the following script to your use case. I filter my vault to include folders that I want to publish (A-Z) first. I have a ## Footnotes
heading above my footnotes always but you can target [^1]:
as well:
```dataviewjs
// Define folder names; here we target all folders with regex; but you can add anything between the slashes
const folderRegex = /(.*)([/\\])/;
// Query all pages
const allPages = dv.pages("");
// Filter pages further based on folder names to target notes
const filteredPages = allPages.filter(page => {
const path = page.file.path;
return folderRegex.test(path);
});
// Crawl the raw data content and filter pages based on content criteria
const pages = await Promise.all(
filteredPages.map(async (page) => {
const content = await dv.io.load(page.file.path);
const mainPattern = /#{2}\sFootnotes([\s\S]*)\z/;
const mainMatches = content.match(mainPattern);
if (mainMatches) {
const blockquotePattern = /^>\s.*/gm;
const blockquoteMatches = mainMatches[1].match(blockquotePattern);
if (blockquoteMatches && blockquoteMatches.length > 0) {
return {
link: page.file.link,
content: blockquoteMatches.join('\n')
};
}
}
return null;
})
);
// Remove null entries and render the result table
const filteredAndProcessedPages = pages.filter(p => p !== null);
dv.table(
["Note", "Content"],
filteredAndProcessedPages.map(p => [p.link, p.content])
);
```
Query to Find All Lines Starting with a Lowercase Character Bypassing the YAML Block
A no-no for longform writers. If a lowercase character starts a line, then it should be included in a list or the text was not properly pasted into the editor (see solution here), or some other problem occurred.
In the following query, we only match lines from the first Heading 1 to the end of the file, bypassing the YAML block where lowercase characters in line starting positions abound. Again, you may need to change the folder that you want to query. Currently, it will query all your vault.
```dataviewjs
// Define the regular expression to match folder names; here we target all folders; but you can add anything between the slashes
const folderRegex = /(.*)([/\\])/;
const allPages = dv.pages("");
const filteredPages = allPages.filter(page => {
const path = page.file.path;
return folderRegex.test(path);
});
const pages = await Promise.all(
filteredPages.map(async (page) => {
const content = await dv.io.load(page.file.path);
// We target chunks of text starting from Heading1 -- change this part if you want to anchor to something else
const mainPattern = /^#{1}[\s\S]*$/m;
const mainMatches = content.match(mainPattern);
if (mainMatches) {
// Secondary pattern to target lowercase letter starters in most or any languages with Latin, Cyrillic, Greek, etc. character sets
const secPattern = /^\p{Ll}.*/gmu;
const secMatches = mainMatches[0].split('\n').filter(line => secPattern.test(line));
if (secMatches && secMatches.length > 0) {
return {
link: page.file.link,
content: secMatches.join('\n')
};
}
}
return null;
})
);
const filteredAndProcessedPages = pages.filter(p => p !== null);
dv.table(
["Note", "Content"],
filteredAndProcessedPages.map(p => [p.link, p.content])
);
```