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],