@@ -479,6 +479,114 @@ export async function getEmbedMap(
479479 return embedMap ;
480480}
481481
482+ /**
483+ * Extract block content from a file using block reference ID
484+ */
485+ async function getBlockContent (
486+ plugin : MarkdownExportPlugin ,
487+ filePath : string ,
488+ blockId : string
489+ ) : Promise < string | null > {
490+ try {
491+ // Get the file metadata
492+ const file = plugin . app . vault . getAbstractFileByPath ( filePath ) ;
493+ if ( ! ( file instanceof TFile ) ) {
494+ return null ;
495+ }
496+
497+ // Read file content and get metadata
498+ const content = await plugin . app . vault . cachedRead ( file ) ;
499+ const metadata = plugin . app . metadataCache . getFileCache ( file ) ;
500+
501+ if ( ! metadata || ! metadata . blocks ) {
502+ return null ;
503+ }
504+
505+ // Find the block by ID
506+ const block = metadata . blocks [ blockId ] ;
507+ if ( ! block ) {
508+ return null ;
509+ }
510+
511+ // Extract the block content from the file
512+ const lines = content . split ( "\n" ) ;
513+ const startLine = block . position . start . line ;
514+ const endLine = block . position . end . line ;
515+
516+ if ( startLine >= lines . length ) {
517+ return null ;
518+ }
519+
520+ const blockLines = lines . slice ( startLine , endLine + 1 ) ;
521+ let blockContent = blockLines . join ( "\n" ) ;
522+
523+ // Remove the block ID from the content if present at the end
524+ blockContent = blockContent . replace ( / \s * \^ ( [ a - z A - Z 0 - 9 ] + ) \s * $ / , "" ) ;
525+
526+ return blockContent ;
527+ } catch ( error ) {
528+ console . error ( "Error getting block content:" , error ) ;
529+ return null ;
530+ }
531+ }
532+
533+ /**
534+ * Parse embed link to extract file path and block reference
535+ * Examples:
536+ * - "My Note#^abc123" -> { filePath: "My Note.md", blockId: "abc123" }
537+ * - "#^abc123" -> { filePath: null, blockId: "abc123" }
538+ * - "My Note" -> { filePath: "My Note.md", blockId: null }
539+ */
540+ function parseEmbedLink ( embedLink : string , currentPath : string ) : {
541+ filePath : string | null ;
542+ blockId : string | null ;
543+ heading : string | null ;
544+ } {
545+ const blockMatch = embedLink . match ( / ^ ( .* ?) # ? \^ ( [ a - z A - Z 0 - 9 ] + ) $ / ) ;
546+ if ( blockMatch ) {
547+ const [ , filePart , blockId ] = blockMatch ;
548+ let filePath = filePart ;
549+ if ( filePart && filePart . trim ( ) ) {
550+ // Resolve relative path
551+ const currentDir = currentPath . substring ( 0 , currentPath . lastIndexOf ( "/" ) ) ;
552+ filePath = currentDir ? `${ currentDir } /${ filePart } ` : filePart ;
553+ if ( ! filePath . endsWith ( ".md" ) ) {
554+ filePath += ".md" ;
555+ }
556+ } else {
557+ filePath = currentPath ;
558+ }
559+ return { filePath, blockId, heading : null } ;
560+ }
561+
562+ // Check for heading link
563+ const headingMatch = embedLink . match ( / ^ ( .* ?) # ( [ ^ # ] + ) $ / ) ;
564+ if ( headingMatch ) {
565+ const [ , filePart , heading ] = headingMatch ;
566+ let filePath = filePart || currentPath ;
567+ if ( filePart && filePart . trim ( ) ) {
568+ const currentDir = currentPath . substring ( 0 , currentPath . lastIndexOf ( "/" ) ) ;
569+ filePath = currentDir ? `${ currentDir } /${ filePart } ` : filePart ;
570+ if ( ! filePath . endsWith ( ".md" ) ) {
571+ filePath += ".md" ;
572+ }
573+ }
574+ return { filePath, blockId : null , heading } ;
575+ }
576+
577+ // Regular file link
578+ if ( embedLink . trim ( ) ) {
579+ const currentDir = currentPath . substring ( 0 , currentPath . lastIndexOf ( "/" ) ) ;
580+ let filePath = currentDir ? `${ currentDir } /${ embedLink } ` : embedLink ;
581+ if ( ! filePath . endsWith ( ".md" ) ) {
582+ filePath += ".md" ;
583+ }
584+ return { filePath, blockId : null , heading : null } ;
585+ }
586+
587+ return { filePath : null , blockId : null , heading : null } ;
588+ }
589+
482590// Convert Markdown to plain text with specific formatting
483591export function convertMarkdownToText (
484592 plugin : MarkdownExportPlugin ,
@@ -690,32 +798,53 @@ export async function tryCopyMarkdownByRead(
690798 content = content . replaceAll ( OUTGOING_LINK_REGEXP , "$1" ) ;
691799 }
692800
693- if ( plugin . settings . convertWikiLinksToMarkdown ) {
694- content = content . replace (
695- / \[ \[ ( .* ?) \] \] / g,
696- ( match , linkText ) => {
697- const encodedLink = encodeURIComponent ( linkText ) ;
698- return `[${ linkText } ](${ encodedLink } )` ;
699- }
700- ) ;
701- }
702-
801+ // Process embeds BEFORE converting WikiLinks to Markdown
802+ // This ensures block embeds like ![[#^blockid]] are handled correctly
703803 const cfile = plugin . app . workspace . getActiveFile ( ) ;
704804 if ( cfile != undefined ) {
705805 const embedMap = await getEmbedMap ( plugin , content , cfile . path ) ;
706806 const embeds = await getEmbeds ( content ) ;
707807 for ( const index in embeds ) {
708- const url = embeds [ index ] [ 1 ] ;
709- const replacement = embedMap . get ( url ) ;
808+ const embedMatch = embeds [ index ] ;
809+ const fullMatch = embedMatch [ 0 ] ;
810+ const embedLink = embedMatch [ 1 ] ;
811+
812+ let replacement = embedMap . get ( embedLink ) ;
813+
814+ // If not in embedMap and inlineBlockEmbeds is enabled, try to extract block content
815+ if ( replacement === undefined && plugin . settings . inlineBlockEmbeds ) {
816+ const parsed = parseEmbedLink ( embedLink , cfile . path ) ;
817+ if ( parsed . blockId && parsed . filePath ) {
818+ const blockContent = await getBlockContent (
819+ plugin ,
820+ parsed . filePath ,
821+ parsed . blockId
822+ ) ;
823+ if ( blockContent !== null ) {
824+ // Format block content as quote block
825+ replacement = "> " + blockContent . replace ( / \n / g, "\n> " ) ;
826+ }
827+ }
828+ }
829+
830+ // Only replace if we found a replacement
831+ // This prevents replacing with "undefined"
710832 if ( replacement !== undefined ) {
711- content = content . replace (
712- embeds [ index ] [ 0 ] ,
713- replacement
714- ) ;
833+ content = content . replace ( fullMatch , replacement ) ;
715834 }
716835 }
717836 }
718837
838+ if ( plugin . settings . convertWikiLinksToMarkdown ) {
839+ content = content . replace (
840+ / \[ \[ ( .* ?) \] \] / g,
841+ ( match , linkText ) => {
842+ const encodedLink = encodeURIComponent ( linkText ) ;
843+ return `[${ linkText } ](${ encodedLink } )` ;
844+ }
845+ ) ;
846+ }
847+
719848 await tryCopyImage ( plugin , file . name , file . path ) ;
720849
721850 // If the user has a custom filename set, we enforce subdirectories to
0 commit comments