diff --git a/.vscode/settings.json b/.vscode/settings.json
index 6295553f..70feafe3 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -20,6 +20,7 @@
"TraverseNote",
"DownView",
"DendronNote",
- "Threading"
+ "Threading",
+ "RegexNote"
]
}
\ No newline at end of file
diff --git a/main.js b/main.js
index c62d2d40..172a236f 100644
--- a/main.js
+++ b/main.js
@@ -20983,6 +20983,8 @@ const DUCK_ICON = "BC-duck-icon";
const DUCK_ICON_SVG = '';
const splitLinksRegex = new RegExp(/\[\[(.+?)\]\]/g);
const dropHeaderOrAlias = new RegExp(/\[\[([^#|]+)\]\]/);
+/** A meta-regex that takes in a string of the form `/regex/flags`, and returns 2 groups, the inner `regex`, and the `flags`. */
+const regNFlags = new RegExp(/^.(.*?)\W(\w*)$/);
const VISTYPES = [
"Force Directed Graph",
"Tidy Tree",
@@ -21017,13 +21019,15 @@ const blankRealNImplied = () => {
prev: { reals: [], implieds: [] },
};
};
-const [BC_FOLDER_NOTE, BC_TAG_NOTE, BC_TAG_NOTE_FIELD, BC_TAG_NOTE_EXACT, BC_LINK_NOTE, BC_TRAVERSE_NOTE, BC_HIDE_TRAIL, BC_ORDER,] = [
+const [BC_FOLDER_NOTE, BC_TAG_NOTE, BC_TAG_NOTE_FIELD, BC_TAG_NOTE_EXACT, BC_LINK_NOTE, BC_TRAVERSE_NOTE, BC_REGEX_NOTE, BC_REGEX_NOTE_FIELD, BC_HIDE_TRAIL, BC_ORDER,] = [
"BC-folder-note",
"BC-tag-note",
"BC-tag-note-field",
"BC-tag-note-exact",
"BC-link-note",
"BC-traverse-note",
+ "BC-regex-note",
+ "BC-regex-note-field",
"BC-hide-trail",
"BC-order",
];
@@ -21064,6 +21068,18 @@ const BC_FIELDS_INFO = [
after: ": ",
alt: true,
},
+ {
+ field: BC_REGEX_NOTE,
+ desc: "Set this note as a Breadcrumbs regex-note. The value of this field is a regular expression (of the form '/regex/flags'). All note names that match the regex will be added to the BC graph using the default fieldName specified in `Settings > Alternative Hierarchies > Regex Note > Default Field`, or using the fieldName you specify in 'BC-regex-note-field'.",
+ after: ": '/",
+ alt: true,
+ },
+ {
+ field: BC_REGEX_NOTE_FIELD,
+ desc: "Manually choose the field for this regex-note to use",
+ after: ": ",
+ alt: false,
+ },
{
field: BC_HIDE_TRAIL,
desc: "Don't show the trail in this note",
@@ -21112,6 +21128,7 @@ const DEFAULT_SETTINGS = {
parseJugglLinksWithoutJuggl: false,
showNameOrType: true,
showRelationType: true,
+ regexNoteField: "",
rlLeaf: true,
showAllPathsIfNoneToIndexNote: false,
showBCs: true,
@@ -25575,6 +25592,20 @@ class BCSettingTab extends require$$0.PluginSettingTab {
await plugin.refreshIndex();
});
});
+ const regexNoteDetails = subDetails("Regex Notes", alternativeHierarchyDetails);
+ new require$$0.Setting(regexNoteDetails)
+ .setName("Default Regex Note Field")
+ .setDesc(fragWithHTML("By default, regex notes use the first field in your hierarchies (usually an ↑
field). Choose a different one to use by default, without having to specify BC-regex-note-field: {field}
.If you don't want to choose a default, select the blank option at the bottom of the list."))
+ .addDropdown((dd) => {
+ const options = {};
+ getFields(settings.userHiers).forEach((field) => (options[field] = field));
+ dd.addOptions(Object.assign(options, { "": "" }));
+ dd.onChange(async (field) => {
+ settings.regexNoteField = field;
+ await plugin.saveSettings();
+ await plugin.refreshIndex();
+ });
+ });
const hierarchyNoteDetails = subDetails("Hierarchy Notes", alternativeHierarchyDetails);
new require$$0.Setting(hierarchyNoteDetails)
.setName("Hierarchy Note(s)")
@@ -52530,6 +52561,32 @@ class BCPlugin extends require$$0.Plugin {
}
});
}
+ addRegexNotesToGraph(eligableAlts, frontms, mainG) {
+ const { userHiers, regexNoteField } = this.settings;
+ const fields = getFields(userHiers);
+ eligableAlts.forEach((altFile) => {
+ const regexNoteFile = altFile.file;
+ const regexNoteBasename = getDVBasename(regexNoteFile);
+ const outerRegex = altFile[BC_REGEX_NOTE];
+ const [_, innerRegex, flags] = outerRegex.match(regNFlags);
+ const regex = new RegExp(innerRegex, flags);
+ loglevel.info({ innerRegex, regex });
+ let field = altFile[BC_REGEX_NOTE_FIELD];
+ if (typeof field !== "string" || !fields.includes(field))
+ field = regexNoteField || fields[0];
+ const targets = [];
+ frontms.forEach((page) => {
+ const basename = getDVBasename(page.file);
+ if (basename !== regexNoteBasename && regex.test(basename))
+ targets.push(basename);
+ });
+ for (const target of targets) {
+ const sourceOrder = this.getSourceOrder(altFile);
+ const targetOrder = this.getTargetOrder(frontms, regexNoteBasename);
+ this.populateMain(mainG, regexNoteBasename, field, target, sourceOrder, targetOrder, true);
+ }
+ });
+ }
addTraverseNotesToGraph(traverseNotes, frontms, mainG, obsG) {
const { userHiers } = this.settings;
traverseNotes.forEach((altFile) => {
@@ -52677,10 +52734,11 @@ class BCPlugin extends require$$0.Plugin {
}
db.end2G();
// !SECTION Hierarchy Notes
+ db.start1G("Alternative Hierarchies");
this.addFolderNotesToGraph(eligableAlts[BC_FOLDER_NOTE], frontms, mainG);
this.addTagNotesToGraph(eligableAlts[BC_TAG_NOTE], frontms, mainG);
this.addLinkNotesToGraph(eligableAlts[BC_LINK_NOTE], frontms, mainG);
- db.start1G("Traverse-Notes");
+ this.addRegexNotesToGraph(eligableAlts[BC_REGEX_NOTE], frontms, mainG);
this.addTraverseNotesToGraph(eligableAlts[BC_TRAVERSE_NOTE], frontms, mainG, this.buildObsGraph());
this.addDendronNotesToGraph(frontms, mainG);
db.end1G();
diff --git a/src/BreadcrumbsSettingTab.ts b/src/BreadcrumbsSettingTab.ts
index 2faee616..725425d1 100644
--- a/src/BreadcrumbsSettingTab.ts
+++ b/src/BreadcrumbsSettingTab.ts
@@ -745,6 +745,31 @@ export class BCSettingTab extends PluginSettingTab {
});
});
+ const regexNoteDetails = subDetails(
+ "Regex Notes",
+ alternativeHierarchyDetails
+ );
+
+ new Setting(regexNoteDetails)
+ .setName("Default Regex Note Field")
+ .setDesc(
+ fragWithHTML(
+ "By default, regex notes use the first field in your hierarchies (usually an ↑
field). Choose a different one to use by default, without having to specify BC-regex-note-field: {field}
.If you don't want to choose a default, select the blank option at the bottom of the list."
+ )
+ )
+ .addDropdown((dd: DropdownComponent) => {
+ const options = {};
+ getFields(settings.userHiers).forEach(
+ (field) => (options[field] = field)
+ );
+ dd.addOptions(Object.assign(options, { "": "" }));
+ dd.onChange(async (field) => {
+ settings.regexNoteField = field;
+ await plugin.saveSettings();
+ await plugin.refreshIndex();
+ });
+ });
+
const hierarchyNoteDetails = subDetails(
"Hierarchy Notes",
alternativeHierarchyDetails
diff --git a/src/constants.ts b/src/constants.ts
index 5e4be9b2..608a6633 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -22,6 +22,9 @@ export const DUCK_ICON_SVG =
export const splitLinksRegex = new RegExp(/\[\[(.+?)\]\]/g);
export const dropHeaderOrAlias = new RegExp(/\[\[([^#|]+)\]\]/);
+/** A meta-regex that takes in a string of the form `/regex/flags`, and returns 2 groups, the inner `regex`, and the `flags`. */
+export const regNFlags = new RegExp(/^.(.*?)\W(\w*)$/);
+
export const VISTYPES: visTypes[] = [
"Force Directed Graph",
"Tidy Tree",
@@ -76,6 +79,8 @@ export const [
BC_TAG_NOTE_EXACT,
BC_LINK_NOTE,
BC_TRAVERSE_NOTE,
+ BC_REGEX_NOTE,
+ BC_REGEX_NOTE_FIELD,
BC_HIDE_TRAIL,
BC_ORDER,
] = [
@@ -85,6 +90,8 @@ export const [
"BC-tag-note-exact",
"BC-link-note",
"BC-traverse-note",
+ "BC-regex-note",
+ "BC-regex-note-field",
"BC-hide-trail",
"BC-order",
];
@@ -126,6 +133,18 @@ export const BC_FIELDS_INFO = [
after: ": ",
alt: true,
},
+ {
+ field: BC_REGEX_NOTE,
+ desc: "Set this note as a Breadcrumbs regex-note. The value of this field is a regular expression (of the form '/regex/flags'). All note names that match the regex will be added to the BC graph using the default fieldName specified in `Settings > Alternative Hierarchies > Regex Note > Default Field`, or using the fieldName you specify in 'BC-regex-note-field'.",
+ after: ": '/",
+ alt: true,
+ },
+ {
+ field: BC_REGEX_NOTE_FIELD,
+ desc: "Manually choose the field for this regex-note to use",
+ after: ": ",
+ alt: false,
+ },
{
field: BC_HIDE_TRAIL,
desc: "Don't show the trail in this note",
@@ -178,6 +197,7 @@ export const DEFAULT_SETTINGS: BCSettings = {
parseJugglLinksWithoutJuggl: false,
showNameOrType: true,
showRelationType: true,
+ regexNoteField: "",
rlLeaf: true,
showAllPathsIfNoneToIndexNote: false,
showBCs: true,
diff --git a/src/interfaces.ts b/src/interfaces.ts
index bddde415..150e4b0b 100644
--- a/src/interfaces.ts
+++ b/src/interfaces.ts
@@ -49,6 +49,7 @@ export interface BCSettings {
showNameOrType: boolean;
showRelationType: boolean;
showWriteAllBCsCmd: boolean;
+ regexNoteField: string;
rlLeaf: boolean;
showBCs: boolean;
showBCsInEditLPMode: boolean;
diff --git a/src/main.ts b/src/main.ts
index 9fdae5f7..703c9b5e 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -33,6 +33,8 @@ import {
BC_HIDE_TRAIL,
BC_LINK_NOTE,
BC_ORDER,
+ BC_REGEX_NOTE,
+ BC_REGEX_NOTE_FIELD,
BC_TAG_NOTE,
BC_TAG_NOTE_EXACT,
BC_TAG_NOTE_FIELD,
@@ -44,6 +46,7 @@ import {
DUCK_ICON_SVG,
DUCK_VIEW,
MATRIX_VIEW,
+ regNFlags,
splitLinksRegex,
STATS_VIEW,
TRAIL_ICON,
@@ -1168,6 +1171,48 @@ export default class BCPlugin extends Plugin {
}
});
}
+ addRegexNotesToGraph(
+ eligableAlts: dvFrontmatterCache[],
+ frontms: dvFrontmatterCache[],
+ mainG: MultiGraph
+ ) {
+ const { userHiers, regexNoteField } = this.settings;
+ const fields = getFields(userHiers);
+ eligableAlts.forEach((altFile) => {
+ const regexNoteFile = altFile.file;
+ const regexNoteBasename = getDVBasename(regexNoteFile);
+
+ const outerRegex = altFile[BC_REGEX_NOTE] as string;
+ const [_, innerRegex, flags] = outerRegex.match(regNFlags);
+ const regex = new RegExp(innerRegex, flags);
+ info({ innerRegex, regex });
+
+ let field = altFile[BC_REGEX_NOTE_FIELD] as string;
+ if (typeof field !== "string" || !fields.includes(field))
+ field = regexNoteField || fields[0];
+
+ const targets = [];
+ frontms.forEach((page) => {
+ const basename = getDVBasename(page.file);
+ if (basename !== regexNoteBasename && regex.test(basename))
+ targets.push(basename);
+ });
+
+ for (const target of targets) {
+ const sourceOrder = this.getSourceOrder(altFile);
+ const targetOrder = this.getTargetOrder(frontms, regexNoteBasename);
+ this.populateMain(
+ mainG,
+ regexNoteBasename,
+ field,
+ target,
+ sourceOrder,
+ targetOrder,
+ true
+ );
+ }
+ });
+ }
addTraverseNotesToGraph(
traverseNotes: dvFrontmatterCache[],
@@ -1381,12 +1426,12 @@ export default class BCPlugin extends Plugin {
db.end2G();
// !SECTION Hierarchy Notes
+ db.start1G("Alternative Hierarchies");
this.addFolderNotesToGraph(eligableAlts[BC_FOLDER_NOTE], frontms, mainG);
this.addTagNotesToGraph(eligableAlts[BC_TAG_NOTE], frontms, mainG);
this.addLinkNotesToGraph(eligableAlts[BC_LINK_NOTE], frontms, mainG);
-
- db.start1G("Traverse-Notes");
+ this.addRegexNotesToGraph(eligableAlts[BC_REGEX_NOTE], frontms, mainG);
this.addTraverseNotesToGraph(
eligableAlts[BC_TRAVERSE_NOTE],