import { NoteLinkDefinition, Resource, ResourceLink } from '../model/note'; import { Range } from '../model/range'; import { createMarkdownReferences } from '../services/markdown-provider'; import { FoamWorkspace } from '../model/workspace'; import { TextEdit } from '../services/text-edit'; import { getLinkDefinitions } from '../services/markdown-parser'; export const LINK_REFERENCE_DEFINITION_HEADER = `[//begin]: # "Autogenerated link references for markdown compatibility"`; export const LINK_REFERENCE_DEFINITION_FOOTER = `[//end]: # "Autogenerated link references"`; export const generateLinkReferences = ( note: Resource, currentNoteText: string, eol: string, workspace: FoamWorkspace, includeExtensions: boolean ): TextEdit[] => { const lines = currentNoteText.split(eol); const nLines = lines.length; const updatedWikilinkDefinitions = createMarkdownReferences( workspace, note, includeExtensions ); const existingWikilinkDefinitions = getLinkDefinitions(currentNoteText); const toAddWikilinkDefinitions = updatedWikilinkDefinitions.filter( newDef => !existingWikilinkDefinitions.some( existingDef => existingDef.label === newDef.label ) ); const toRemovedWikilinkDefinitions = existingWikilinkDefinitions.filter( existingDef => { if (updatedWikilinkDefinitions.some(newDef => newDef.label === existingDef.label)) { return false; } if (existingDef.url.includes('://')) { return false; } if (note.links.some(link => ResourceLink.isResolvedReference(link) && link.definition.label === existingDef.label)) { return false; } return true; } ); const edits: TextEdit[] = []; for (const def of toRemovedWikilinkDefinitions) { edits.push({ range: Range.create(def.range.start.line, 0, def.range.end.line + 1, 0), newText: '', }); } if (toAddWikilinkDefinitions.length > 0) { const deletedLines = new Set( toRemovedWikilinkDefinitions.map(d => d.range.start.line) ); const lastLineIndex = nLines - 1; let insertLineIndex = lastLineIndex; while ( insertLineIndex > 0 && (lines[insertLineIndex].trim() === '' || deletedLines.has(insertLineIndex)) ) { insertLineIndex--; } const definitions = toAddWikilinkDefinitions.map(def => NoteLinkDefinition.format(def) ); const wikilinkLabels = new Set( note.links .filter(link => link.type === 'wikilink') .map(link => link.rawText.substring(link.isEmbed ? 3 : 2, link.rawText.length - 2) ) ); const isKeptFoamDefinitionAtInsert = existingWikilinkDefinitions.some( def => wikilinkLabels.has(def.label) && def.range?.start.line === insertLineIndex ); const prefix = isKeptFoamDefinitionAtInsert ? eol : eol + eol; // The generated edit owns its surrounding EOLs; callers apply it verbatim. const text = prefix + definitions.join(eol) + eol; edits.push({ range: Range.create( insertLineIndex, lines[insertLineIndex].length, lastLineIndex, lines[lastLineIndex].length ), newText: text, }); } return edits; };