@@ -567,4 +567,40 @@ function AttachCore:sync(node, delete_empty_dir)
567567 end )
568568end
569569
570+ --- Call `callback` with every attachment link in the file.
571+ ---
572+ --- @param file OrgFile
573+ --- @param callback fun ( attach_dir : string | false , basename : string ): string | nil
574+ --- @return OrgPromise<nil>
575+ function AttachCore :on_every_attachment_link (file , callback )
576+ -- TODO: In a better world, this would use treesitter for parsing ...
577+ return file :update (function ()
578+ local lines = vim .api .nvim_buf_get_lines (0 , 0 , - 1 , true )
579+ local prev_node = nil --- @type OrgAttachNode | nil
580+ local attach_dir = nil --- @type string | false | nil
581+ for i , line in ipairs (lines ) do
582+ -- Check if node has changed; if yes, invalidate cached attach_dir.
583+ local node = AttachNode .at_cursor (file , { i + 1 , 0 })
584+ if node ~= prev_node then
585+ attach_dir = nil
586+ end
587+ --- @param basename string
588+ --- @param bracket ' [' | ' ]'
589+ --- @return string
590+ local replaced = line :gsub (' %[%[attachment:([^%]]+)%]([%[%]])' , function (basename , bracket )
591+ -- Only compute attach_dir when we know that we need it!
592+ if attach_dir == nil then
593+ attach_dir = self :get_dir_or_nil (node , true ) or false
594+ end
595+ local res = callback (attach_dir , basename )
596+ return res and (' [[%s]%s' ):format (res , bracket ) or (' [[attachment:%s]%s' ):format (basename , bracket )
597+ end )
598+ if replaced ~= line then
599+ vim .api .nvim_buf_set_lines (0 , i - 1 , i , true , { replaced })
600+ end
601+ prev_node = node
602+ end
603+ end )
604+ end
605+
570606return AttachCore
0 commit comments