Implement inverse edge creation functionality in writerActions
- Added a new function to automatically create inverse edges in target notes/sections after inserting edges in the "note_links" and "candidates" zones. - Refactored the zone detection logic to separate content-based detection from file-based detection, improving code clarity and maintainability. - Enhanced logging for better tracking of edge creation processes and potential issues during execution.
This commit is contained in:
parent
725adb5302
commit
6d5f6203c4
|
|
@ -5,7 +5,7 @@
|
||||||
import { Modal, Setting, TFile, Notice } from "obsidian";
|
import { Modal, Setting, TFile, Notice } from "obsidian";
|
||||||
import type { App, Editor } from "obsidian";
|
import type { App, Editor } from "obsidian";
|
||||||
import type { MissingLinkTodo, CandidateCleanupTodo, MissingSlotTodo } from "./types";
|
import type { MissingLinkTodo, CandidateCleanupTodo, MissingSlotTodo } from "./types";
|
||||||
import { detectZone, findSection } from "./zoneDetector";
|
import { detectZone, detectZoneFromContent, findSection } from "./zoneDetector";
|
||||||
import { splitIntoSections } from "../mapping/sectionParser";
|
import { splitIntoSections } from "../mapping/sectionParser";
|
||||||
import { EntityPickerModal } from "../ui/EntityPickerModal";
|
import { EntityPickerModal } from "../ui/EntityPickerModal";
|
||||||
import { NoteIndex } from "../entityPicker/noteIndex";
|
import { NoteIndex } from "../entityPicker/noteIndex";
|
||||||
|
|
@ -84,12 +84,34 @@ export async function insertEdgeForward(
|
||||||
console.log("[insertEdgeForward] Inserting into note_links zone");
|
console.log("[insertEdgeForward] Inserting into note_links zone");
|
||||||
}
|
}
|
||||||
await insertEdgeInZone(app, editor, file, "note_links", edgeType, targetLink, settings);
|
await insertEdgeInZone(app, editor, file, "note_links", edgeType, targetLink, settings);
|
||||||
|
|
||||||
|
// Automatically create inverse edge in target note/section
|
||||||
|
await createInverseEdge(
|
||||||
|
app,
|
||||||
|
edgeType,
|
||||||
|
todo,
|
||||||
|
vocabulary,
|
||||||
|
edgeVocabulary,
|
||||||
|
settings,
|
||||||
|
debugLogging
|
||||||
|
);
|
||||||
} else if (targetZone === "candidates") {
|
} else if (targetZone === "candidates") {
|
||||||
// Insert in Kandidaten zone
|
// Insert in Kandidaten zone
|
||||||
if (debugLogging) {
|
if (debugLogging) {
|
||||||
console.log("[insertEdgeForward] Inserting into candidates zone");
|
console.log("[insertEdgeForward] Inserting into candidates zone");
|
||||||
}
|
}
|
||||||
await insertEdgeInZone(app, editor, file, "candidates", edgeType, targetLink, settings);
|
await insertEdgeInZone(app, editor, file, "candidates", edgeType, targetLink, settings);
|
||||||
|
|
||||||
|
// Automatically create inverse edge in target note/section
|
||||||
|
await createInverseEdge(
|
||||||
|
app,
|
||||||
|
edgeType,
|
||||||
|
todo,
|
||||||
|
vocabulary,
|
||||||
|
edgeVocabulary,
|
||||||
|
settings,
|
||||||
|
debugLogging
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Insert in source section - need to select section if multiple exist
|
// Insert in source section - need to select section if multiple exist
|
||||||
// IMPORTANT: Use source note (fromNodeRef.file), not current note!
|
// IMPORTANT: Use source note (fromNodeRef.file), not current note!
|
||||||
|
|
@ -218,9 +240,260 @@ export async function insertEdgeForward(
|
||||||
if (debugLogging) {
|
if (debugLogging) {
|
||||||
console.log("[insertEdgeForward] Edge insertion completed");
|
console.log("[insertEdgeForward] Edge insertion completed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Automatically create inverse edge in target note/section
|
||||||
|
await createInverseEdge(
|
||||||
|
app,
|
||||||
|
edgeType,
|
||||||
|
todo,
|
||||||
|
vocabulary,
|
||||||
|
edgeVocabulary,
|
||||||
|
settings,
|
||||||
|
debugLogging
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically create inverse edge in target note/section.
|
||||||
|
*/
|
||||||
|
async function createInverseEdge(
|
||||||
|
app: App,
|
||||||
|
forwardEdgeType: string,
|
||||||
|
todo: MissingLinkTodo,
|
||||||
|
vocabulary: Vocabulary,
|
||||||
|
edgeVocabulary: EdgeVocabulary,
|
||||||
|
settings: MindnetSettings,
|
||||||
|
debugLogging?: boolean
|
||||||
|
): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.log("[createInverseEdge] Starting inverse edge creation for:", forwardEdgeType);
|
||||||
|
|
||||||
|
// Get canonical type and inverse
|
||||||
|
const canonical = vocabulary.getCanonical(forwardEdgeType);
|
||||||
|
if (!canonical) {
|
||||||
|
console.log("[createInverseEdge] No canonical type found for:", forwardEdgeType);
|
||||||
|
return; // Can't create inverse without canonical type
|
||||||
|
}
|
||||||
|
|
||||||
|
const inverseCanonical = vocabulary.getInverse(canonical);
|
||||||
|
if (!inverseCanonical) {
|
||||||
|
console.log("[createInverseEdge] No inverse defined for:", canonical);
|
||||||
|
return; // No inverse defined, skip
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the raw inverse type (use canonical or find an alias)
|
||||||
|
const inverseEntry = edgeVocabulary.byCanonical.get(inverseCanonical);
|
||||||
|
const inverseEdgeType = inverseEntry?.aliases?.[0] || inverseCanonical;
|
||||||
|
|
||||||
|
console.log("[createInverseEdge] Forward:", forwardEdgeType, "-> Canonical:", canonical, "-> Inverse:", inverseEdgeType);
|
||||||
|
|
||||||
|
// Find target file
|
||||||
|
const targetFileRef = todo.toNodeRef.file;
|
||||||
|
let targetFile: TFile | null = null;
|
||||||
|
|
||||||
|
const possiblePaths = [
|
||||||
|
targetFileRef,
|
||||||
|
targetFileRef + ".md",
|
||||||
|
targetFileRef.replace(/\.md$/, ""),
|
||||||
|
targetFileRef.replace(/\.md$/, "") + ".md",
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const path of possiblePaths) {
|
||||||
|
const found = app.vault.getAbstractFileByPath(path);
|
||||||
|
if (found && found instanceof TFile) {
|
||||||
|
targetFile = found;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetFile) {
|
||||||
|
const basename = targetFileRef.replace(/\.md$/, "").split("/").pop() || targetFileRef;
|
||||||
|
const resolved = app.metadataCache.getFirstLinkpathDest(basename, todo.fromNodeRef.file);
|
||||||
|
if (resolved) {
|
||||||
|
targetFile = resolved;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetFile) {
|
||||||
|
console.log("[createInverseEdge] Target file not found:", targetFileRef);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build source link (for inverse edge, source is the original target)
|
||||||
|
const sourceBasename = todo.fromNodeRef.file.replace(/\.md$/, "").split("/").pop() || todo.fromNodeRef.file;
|
||||||
|
const sourceLink = todo.fromNodeRef.heading
|
||||||
|
? `${sourceBasename}#${todo.fromNodeRef.heading}`
|
||||||
|
: sourceBasename;
|
||||||
|
|
||||||
|
// Always ask user to select target section (or whole note)
|
||||||
|
// Open target file in editor first
|
||||||
|
console.log("[createInverseEdge] Opening target file:", targetFile.path);
|
||||||
|
await app.workspace.openLinkText(targetFile.path, "", false);
|
||||||
|
|
||||||
|
// Wait a bit for the editor to be ready
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100));
|
||||||
|
|
||||||
|
const targetEditor = app.workspace.activeEditor?.editor;
|
||||||
|
if (!targetEditor) {
|
||||||
|
console.error("[createInverseEdge] Could not get editor for target file:", targetFile.path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load sections from target file
|
||||||
|
const { splitIntoSections } = await import("../mapping/sectionParser");
|
||||||
|
const targetContent = await app.vault.read(targetFile);
|
||||||
|
const sections = splitIntoSections(targetContent);
|
||||||
|
|
||||||
|
// Filter out special zones
|
||||||
|
const contentSections = sections.filter(
|
||||||
|
(s) => s.heading !== "Kandidaten" && s.heading !== "Note-Verbindungen"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Show selection modal: user can choose a section or "whole note"
|
||||||
|
const selectedTarget = await selectTargetForInverseEdge(
|
||||||
|
app,
|
||||||
|
targetFile,
|
||||||
|
contentSections,
|
||||||
|
todo.toNodeRef.heading,
|
||||||
|
debugLogging
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!selectedTarget) {
|
||||||
|
console.log("[createInverseEdge] User cancelled target selection");
|
||||||
|
return; // User cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[createInverseEdge] Selected target:", selectedTarget.type, selectedTarget.heading || "(whole note)");
|
||||||
|
console.log("[createInverseEdge] Inverse edge type:", inverseEdgeType, "source link:", sourceLink);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (selectedTarget.type === "note_links") {
|
||||||
|
console.log("[createInverseEdge] Calling insertEdgeInZone with note_links");
|
||||||
|
await insertEdgeInZone(app, targetEditor, targetFile, "note_links", inverseEdgeType, sourceLink, settings);
|
||||||
|
console.log("[createInverseEdge] insertEdgeInZone completed");
|
||||||
|
} else {
|
||||||
|
// Use selected section
|
||||||
|
const targetSection = await findSection(app, targetFile, selectedTarget.heading);
|
||||||
|
if (targetSection) {
|
||||||
|
console.log("[createInverseEdge] Found target section:", targetSection.heading || "(root)");
|
||||||
|
await insertEdgeInSection(
|
||||||
|
app,
|
||||||
|
targetEditor,
|
||||||
|
targetFile,
|
||||||
|
targetSection,
|
||||||
|
inverseEdgeType,
|
||||||
|
sourceLink,
|
||||||
|
settings
|
||||||
|
);
|
||||||
|
console.log("[createInverseEdge] insertEdgeInSection completed");
|
||||||
|
} else {
|
||||||
|
console.log("[createInverseEdge] Target section not found, falling back to note_links");
|
||||||
|
// Fallback to note_links if section not found
|
||||||
|
await insertEdgeInZone(app, targetEditor, targetFile, "note_links", inverseEdgeType, sourceLink, settings);
|
||||||
|
console.log("[createInverseEdge] insertEdgeInZone (fallback) completed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("[createInverseEdge] Inverse edge creation completed successfully");
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[createInverseEdge] Error during edge insertion:", error);
|
||||||
|
throw error; // Re-throw to see the error
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("[createInverseEdge] Error creating inverse edge:", error);
|
||||||
|
// Don't throw - inverse edge creation is optional
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select target section or whole note for inverse edge insertion.
|
||||||
|
*/
|
||||||
|
async function selectTargetForInverseEdge(
|
||||||
|
app: App,
|
||||||
|
file: TFile,
|
||||||
|
sections: Array<{ heading: string | null; startLine: number; endLine: number }>,
|
||||||
|
preferredHeading: string | null,
|
||||||
|
debugLogging?: boolean
|
||||||
|
): Promise<{ type: "section" | "note_links"; heading: string | null } | null> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
let resolved = false;
|
||||||
|
const modal = new Modal(app);
|
||||||
|
modal.titleEl.textContent = "Ziel für inverse Kante wählen";
|
||||||
|
const description = preferredHeading
|
||||||
|
? `Wo soll die inverse Kante eingefügt werden? (Empfohlen: "${preferredHeading}")`
|
||||||
|
: "Wo soll die inverse Kante eingefügt werden?";
|
||||||
|
modal.contentEl.createEl("p", { text: description });
|
||||||
|
|
||||||
|
const doResolve = (value: { type: "section" | "note_links"; heading: string | null } | null) => {
|
||||||
|
if (!resolved) {
|
||||||
|
resolved = true;
|
||||||
|
resolve(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add "Whole note" option
|
||||||
|
const wholeNoteSetting = new Setting(modal.contentEl);
|
||||||
|
wholeNoteSetting.setName("📄 Ganze Note (Note-Verbindungen)");
|
||||||
|
wholeNoteSetting.setDesc("Edge wird in der Note-Verbindungen Zone eingefügt (note-level)");
|
||||||
|
wholeNoteSetting.addButton((btn) => {
|
||||||
|
btn.setButtonText("Auswählen");
|
||||||
|
btn.onClick(() => {
|
||||||
|
if (debugLogging) {
|
||||||
|
console.log("[selectTargetForInverseEdge] User selected: whole note");
|
||||||
|
}
|
||||||
|
doResolve({ type: "note_links", heading: null });
|
||||||
|
modal.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add section options
|
||||||
|
for (const section of sections) {
|
||||||
|
if (!section) continue;
|
||||||
|
const sectionName = section.heading || "(Root section)";
|
||||||
|
const isPreferred = preferredHeading && headingsMatch(section.heading, preferredHeading);
|
||||||
|
const setting = new Setting(modal.contentEl);
|
||||||
|
|
||||||
|
if (isPreferred) {
|
||||||
|
setting.setName(`⭐ ${sectionName} (empfohlen)`);
|
||||||
|
setting.setDesc(`Zeilen ${section.startLine + 1}-${section.endLine} - Empfohlen basierend auf Chain Template`);
|
||||||
|
} else {
|
||||||
|
setting.setName(sectionName);
|
||||||
|
setting.setDesc(`Zeilen ${section.startLine + 1}-${section.endLine}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
setting.addButton((btn) => {
|
||||||
|
if (isPreferred) {
|
||||||
|
btn.setButtonText("Auswählen (Empfohlen)");
|
||||||
|
btn.setCta(); // Highlight recommended option
|
||||||
|
} else {
|
||||||
|
btn.setButtonText("Auswählen");
|
||||||
|
}
|
||||||
|
btn.onClick(() => {
|
||||||
|
if (debugLogging) {
|
||||||
|
console.log("[selectTargetForInverseEdge] User selected section:", sectionName);
|
||||||
|
}
|
||||||
|
doResolve({ type: "section", heading: section.heading });
|
||||||
|
modal.close();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
modal.onClose = () => {
|
||||||
|
if (debugLogging) {
|
||||||
|
console.log("[selectTargetForInverseEdge] Modal closed, resolved:", resolved);
|
||||||
|
if (!resolved) {
|
||||||
|
console.log("[selectTargetForInverseEdge] Resolving with null (user cancelled)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!resolved) {
|
||||||
|
doResolve(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
modal.open();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Insert edge in zone (Kandidaten or Note-Verbindungen).
|
* Insert edge in zone (Kandidaten or Note-Verbindungen).
|
||||||
*/
|
*/
|
||||||
|
|
@ -233,7 +506,15 @@ async function insertEdgeInZone(
|
||||||
targetLink: string,
|
targetLink: string,
|
||||||
settings: MindnetSettings
|
settings: MindnetSettings
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const zone = await detectZone(app, file, zoneType);
|
console.log("[insertEdgeInZone] Starting, file:", file.path, "zoneType:", zoneType, "edgeType:", edgeType, "targetLink:", targetLink);
|
||||||
|
|
||||||
|
// Use editor content instead of reading from vault (editor might have unsaved changes)
|
||||||
|
const editorContent = editor.getValue();
|
||||||
|
console.log("[insertEdgeInZone] Editor content length:", editorContent.length);
|
||||||
|
|
||||||
|
// Detect zone from editor content
|
||||||
|
const zone = detectZoneFromContent(editorContent, zoneType);
|
||||||
|
console.log("[insertEdgeInZone] Zone detection result:", { exists: zone.exists, heading: zone.heading, startLine: zone.startLine, endLine: zone.endLine });
|
||||||
|
|
||||||
const wrapperCalloutType = settings.mappingWrapperCalloutType || "abstract";
|
const wrapperCalloutType = settings.mappingWrapperCalloutType || "abstract";
|
||||||
const wrapperTitle = settings.mappingWrapperTitle || "🕸️ Semantic Mapping";
|
const wrapperTitle = settings.mappingWrapperTitle || "🕸️ Semantic Mapping";
|
||||||
|
|
@ -241,40 +522,53 @@ async function insertEdgeInZone(
|
||||||
|
|
||||||
if (!zone.exists) {
|
if (!zone.exists) {
|
||||||
// Create zone
|
// Create zone
|
||||||
|
console.log("[insertEdgeInZone] Zone does not exist, creating new zone");
|
||||||
const content = editor.getValue();
|
const content = editor.getValue();
|
||||||
const newZone = `\n\n## ${zoneType === "candidates" ? "Kandidaten" : "Note-Verbindungen"}\n\n> [!${wrapperCalloutType}]${foldMarker} ${wrapperTitle}\n>> [!edge] ${edgeType}\n>> [[${targetLink}]]\n`;
|
const newZone = `\n\n## ${zoneType === "candidates" ? "Kandidaten" : "Note-Verbindungen"}\n\n> [!${wrapperCalloutType}]${foldMarker} ${wrapperTitle}\n>> [!edge] ${edgeType}\n>> [[${targetLink}]]\n`;
|
||||||
const newContent = content + newZone;
|
const newContent = content + newZone;
|
||||||
editor.setValue(newContent);
|
editor.setValue(newContent);
|
||||||
|
console.log("[insertEdgeInZone] New zone created and content set");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert in existing zone
|
// Insert in existing zone
|
||||||
|
console.log("[insertEdgeInZone] Zone exists, inserting into existing zone");
|
||||||
const content = editor.getValue();
|
const content = editor.getValue();
|
||||||
const lines = content.split(/\r?\n/);
|
const lines = content.split(/\r?\n/);
|
||||||
|
|
||||||
// Find insertion point (end of zone, before next heading)
|
// Find insertion point (end of zone, before next heading)
|
||||||
let insertLine = zone.endLine - 1;
|
let insertLine = zone.endLine - 1;
|
||||||
|
console.log("[insertEdgeInZone] Initial insertLine:", insertLine);
|
||||||
|
|
||||||
// Check if zone has a wrapper callout using settings
|
// Check if zone has a wrapper callout using settings
|
||||||
const zoneContent = zone.content;
|
const zoneContent = zone.content;
|
||||||
const hasWrapper = zoneContent.includes(`> [!${wrapperCalloutType}]`) &&
|
const hasWrapper = zoneContent.includes(`> [!${wrapperCalloutType}]`) &&
|
||||||
zoneContent.includes(wrapperTitle);
|
zoneContent.includes(wrapperTitle);
|
||||||
|
console.log("[insertEdgeInZone] Has wrapper:", hasWrapper, "wrapperCalloutType:", wrapperCalloutType, "wrapperTitle:", wrapperTitle);
|
||||||
|
|
||||||
if (hasWrapper) {
|
if (hasWrapper) {
|
||||||
// Insert inside wrapper - find the end of the wrapper block
|
// Insert inside wrapper - find the end of the wrapper block
|
||||||
|
console.log("[insertEdgeInZone] Inserting inside existing wrapper");
|
||||||
const wrapperEndLine = findWrapperBlockEnd(lines, zone.startLine, wrapperCalloutType, wrapperTitle);
|
const wrapperEndLine = findWrapperBlockEnd(lines, zone.startLine, wrapperCalloutType, wrapperTitle);
|
||||||
|
console.log("[insertEdgeInZone] Wrapper end line:", wrapperEndLine);
|
||||||
if (wrapperEndLine !== null) {
|
if (wrapperEndLine !== null) {
|
||||||
insertLine = wrapperEndLine - 1;
|
insertLine = wrapperEndLine - 1;
|
||||||
}
|
}
|
||||||
const newEdge = `>> [!edge] ${edgeType}\n>> [[${targetLink}]]\n`;
|
const newEdge = `>> [!edge] ${edgeType}\n>> [[${targetLink}]]\n`;
|
||||||
|
console.log("[insertEdgeInZone] Inserting edge at line:", insertLine, "edge:", newEdge);
|
||||||
lines.splice(insertLine, 0, ...newEdge.split("\n"));
|
lines.splice(insertLine, 0, ...newEdge.split("\n"));
|
||||||
} else {
|
} else {
|
||||||
// Create wrapper and insert edge
|
// Create wrapper and insert edge
|
||||||
|
console.log("[insertEdgeInZone] Creating new wrapper and inserting edge");
|
||||||
const wrapper = `\n> [!${wrapperCalloutType}]${foldMarker} ${wrapperTitle}\n>> [!edge] ${edgeType}\n>> [[${targetLink}]]\n`;
|
const wrapper = `\n> [!${wrapperCalloutType}]${foldMarker} ${wrapperTitle}\n>> [!edge] ${edgeType}\n>> [[${targetLink}]]\n`;
|
||||||
|
console.log("[insertEdgeInZone] Inserting wrapper at line:", insertLine, "wrapper:", wrapper);
|
||||||
lines.splice(insertLine, 0, ...wrapper.split("\n"));
|
lines.splice(insertLine, 0, ...wrapper.split("\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
editor.setValue(lines.join("\n"));
|
const newContent = lines.join("\n");
|
||||||
|
console.log("[insertEdgeInZone] Setting new content, length:", newContent.length);
|
||||||
|
editor.setValue(newContent);
|
||||||
|
console.log("[insertEdgeInZone] Content set successfully");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,12 @@ export interface ZoneInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Detect if a zone exists in a file.
|
* Detect if a zone exists in content (from editor or file).
|
||||||
*/
|
*/
|
||||||
export async function detectZone(
|
export function detectZoneFromContent(
|
||||||
app: App,
|
content: string,
|
||||||
file: TFile,
|
|
||||||
zoneType: "candidates" | "note_links"
|
zoneType: "candidates" | "note_links"
|
||||||
): Promise<ZoneInfo> {
|
): ZoneInfo {
|
||||||
const content = await app.vault.read(file);
|
|
||||||
const lines = content.split(/\r?\n/);
|
const lines = content.split(/\r?\n/);
|
||||||
|
|
||||||
const heading = zoneType === "candidates" ? "## Kandidaten" : "## Note-Verbindungen";
|
const heading = zoneType === "candidates" ? "## Kandidaten" : "## Note-Verbindungen";
|
||||||
|
|
@ -72,6 +70,18 @@ export async function detectZone(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detect if a zone exists in a file.
|
||||||
|
*/
|
||||||
|
export async function detectZone(
|
||||||
|
app: App,
|
||||||
|
file: TFile,
|
||||||
|
zoneType: "candidates" | "note_links"
|
||||||
|
): Promise<ZoneInfo> {
|
||||||
|
const content = await app.vault.read(file);
|
||||||
|
return detectZoneFromContent(content, zoneType);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find section by heading in file.
|
* Find section by heading in file.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user