Search code examples
htmlemacsorg-mode

How to replace all occurrences in emacs?


I'm building a blog with org-mode publish. But I'm wanting to edit the default style given by org-mode, that edition implies wrap some tags in other tags (like divs tags). So the way I am building this is based some ideas (check the link below).

e.g. The below function it's adding a class attribute to the body tag, and it works! (The idea is based on this question)

(defun my-html-body-onload-filter (output backend info)
"Add class to<body>  tag, if any."
(when (and (eq backend 'html)
       (string-match "<body>\n" output))
  (replace-match "<body class='uk-container-small uk-align-center uk-text-justify'> \n" nil nil output))
  )

So the thing I want to do right now, it's wrap img tags in other tags. I'm not a elisp programmer but I'm trying to build a function to reach some solution. So the actual problem is this: I have this:

<img src="images/photo.jpg" alt="">

I need to wrap img tags so I can see the next output:

<div uk-lightbox="animation: slide">
    <a href="images/photo.jpg">
        <img src="images/photo.jpg" alt="">
    </a>
</div>

So far I created this little function to extract the src value:

(defun xe ()
  (interactive)
  (search-forward "<img src=\"")
  (defvar x-start (point))
  (search-forward "\"")
  (backward-char)
  (defvar x-end (point))
  (kill-ring-save x-start x-end)
)

But I feel like lost, because I don't know much about elisp... so if anyone knows how to keep going (or has the solution) to solve this problem, I would be happy:)


Solution

  • Well Hello there, This was my final solution:

    I created this function(Note: as you can see this function is not optimized but works, maybe I will edit this answer to post the final optimized solution):

    (defun wrap-img-tags ()
      (setq text-to-search-1 "<img src=\"")
      (goto-char (point-min))
      (setq ntimes (count-matches text-to-search-1))
    
      (if (> ntimes 0)
          (cl-loop repeat ntimes do ;; this is like a for loop
    
           (search-forward "<img src=\"" nil t)
           (setq x-start (point))
           (search-forward "\"")
           (backward-char)
           (setq x-end (point))
           (kill-ring-save x-start x-end)
           (beginning-of-line)
           (insert (format "\n<div uk-lightbox=\"animation: slide\">
         <a href=\"%s\">\n" (car kill-ring)))
           (indent-for-tab-command)
           (forward-line)
           (insert (format "</a>\n</div>"))
                     
           )
          
          nil
          )
      )
    

    Additionally I wanted to add a class attribute on some tags, so I created this next function:

    (defun add-class-to-tag (tag class)
      "Add class attribute with the class variable value.
    TAG: Tag to modify.
    CLASS: Class in string form to add."
    ;  (interactive "sTag:\nsClass:")
    
      (setq text-to-search (format "<%s" tag))
      (goto-char (point-min))
    
      (setq does-it-have-class-attribute t)
      (cl-loop repeat (how-many text-to-search)  do ;; this is like a for loop
           
           (search-forward text-to-search)
           (setq x-start (point))
    
           (setq does-it-have-class-attribute (search-forward
                               "class=\""
                               (line-end-position)
                               t ; if fails return nil
                               ))
    
           (if (not does-it-have-class-attribute)
    
               (progn
             (insert (format " class=\"%s\"" class))
             (setq does-it-have-class-attribute nil)
             )
    
             (progn ; else
               (search-forward "\"")
               (backward-char)
               (insert (format " %s" class))
    
               ))
           )
      
      )
    

    Finally I execute it on a pre final processor of the created html files: (The below function idea was taken from this blog)

    (defun org-blog-publish-to-html (plist filename pub-dir)
      "Same as `org-html-publish-to-html' but modifies html before finishing."
      (let ((file-path (org-html-publish-to-html plist filename pub-dir)))
        (with-current-buffer (find-file-noselect file-path)
          (wrap-img-tags);; Here I'm executing the first solution
          (add-class-to-tag "h2" "uk-heading-bullet")
          (add-class-to-tag "section" "uk-card uk-card-body uk-align-center uk-text-justify")
          (add-class-to-tag "h1" "uk-h2 uk-panel uk-padding uk-background-secondary uk-light uk-margin-left uk-margin-right")
          (save-buffer)      
          (kill-buffer))
        file-path))
    

    And that's it! It works :)

    Additionally I would modify the wrap-img-tags function to wrap any kind of tags with other desired tags!

    PD: If this answer was helpful to you, please up vote. I spent around three days researching and testing to reach to this solution. Thank you!